cim_msr.c revision f29dbc25
1/* 2 * Copyright (c) 2006 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 * 22 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 23 * contributors may be used to endorse or promote products derived from this 24 * software without specific prior written permission. 25 */ 26 27 /* 28 * Cimarron MSR access routines. These routines allow the user to query the 29 * state of the GeodeLink Bus and read and write model-specfic registers. 30 */ 31 32/*--------------------------------------------------------------*/ 33/* MSR GLOBALS */ 34/* These variables hold a local copy of the GeodeLink mapping */ 35/* as well as a lookup table for easy device addressing. */ 36/*--------------------------------------------------------------*/ 37 38GEODELINK_NODE gliu_nodes[24]; 39GEODELINK_NODE msr_dev_lookup[MSR_DEVICE_EMPTY]; 40 41#define GET_DEVICE_ID(macrohigh, macrolow) ((macrolow >> 12) & 0xFF) 42 43/*--------------------------------------------------------------------------- 44 * msr_init_table 45 * 46 * This routine intializes the internal MSR table in Cimarron. This table is 47 * used for any MSR device accesses. 48 *--------------------------------------------------------------------------*/ 49 50int 51msr_init_table(void) 52{ 53 Q_WORD msr_value = {0, 0}; 54 unsigned int i, j; 55 int return_value = CIM_STATUS_OK; 56 57 /* CHECK FOR VALID GEODELINK CONFIGURATION 58 * The CPU and the three GLIUs are assumed to be at known static 59 * addresses, so we will check the device IDs at these addresses as proof 60 * of a valid GeodeLink configuration 61 */ 62 63 MSR_READ(MSR_GEODELINK_CAP, MSR_ADDRESS_VAIL, &msr_value); 64 if (GET_DEVICE_ID(msr_value.high, msr_value.low) != MSR_CLASS_CODE_VAIL) 65 return_value = CIM_STATUS_ERROR; 66 67 MSR_READ(MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU0, &msr_value); 68 if (GET_DEVICE_ID(msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU) 69 return_value = CIM_STATUS_ERROR; 70 71 MSR_READ(MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU1, &msr_value); 72 if (GET_DEVICE_ID(msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU) 73 return_value = CIM_STATUS_ERROR; 74 75 MSR_READ(MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU2, &msr_value); 76 if (GET_DEVICE_ID(msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU) 77 return_value = CIM_STATUS_ERROR; 78 79 if (return_value == CIM_STATUS_OK) { 80 /* BUILD LOCAL COPY OF THE GEODELINK BUS */ 81 82 msr_create_geodelink_table(gliu_nodes); 83 84 /* CLEAR TABLE STATUS */ 85 86 for (i = 0; i < MSR_DEVICE_EMPTY; i++) 87 msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND; 88 89 /* CREATE EASY LOOKUP TABLE FOR FUTURE HARDWARE ACCESS */ 90 /* Note that MSR_DEVICE_EMPTY is the index after the last */ 91 /* available device. Also note that we fill in known */ 92 /* devices before filling in the rest of the table. */ 93 94 msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU0].address_from_cpu = 95 MSR_ADDRESS_GLIU0; 96 msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU0].device_id = 97 MSR_DEVICE_PRESENT; 98 msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU1].address_from_cpu = 99 MSR_ADDRESS_GLIU1; 100 msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU1].device_id = 101 MSR_DEVICE_PRESENT; 102 msr_dev_lookup[MSR_DEVICE_5535_GLIU].address_from_cpu = 103 MSR_ADDRESS_GLIU2; 104 msr_dev_lookup[MSR_DEVICE_5535_GLIU].device_id = MSR_DEVICE_PRESENT; 105 msr_dev_lookup[MSR_DEVICE_GEODELX_VAIL].address_from_cpu = 106 MSR_ADDRESS_VAIL; 107 msr_dev_lookup[MSR_DEVICE_GEODELX_VAIL].device_id = 108 MSR_DEVICE_PRESENT; 109 110 for (i = 0; i < MSR_DEVICE_EMPTY; i++) { 111 if (msr_dev_lookup[i].device_id == MSR_DEVICE_NOTFOUND) { 112 for (j = 0; j < 24; j++) { 113 if (gliu_nodes[j].device_id == i) 114 break; 115 } 116 117 if (j == 24) 118 msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND; 119 else { 120 msr_dev_lookup[i].device_id = MSR_DEVICE_PRESENT; 121 msr_dev_lookup[i].address_from_cpu = 122 gliu_nodes[j].address_from_cpu; 123 } 124 } 125 } 126 } else { 127 /* ERROR OUT THE GEODELINK TABLES */ 128 129 for (i = 0; i < 24; i++) { 130 gliu_nodes[i].address_from_cpu = 0xFFFFFFFF; 131 gliu_nodes[i].device_id = MSR_DEVICE_EMPTY; 132 } 133 134 for (i = 0; i < MSR_DEVICE_EMPTY; i++) { 135 msr_dev_lookup[i].address_from_cpu = 0xFFFFFFFF; 136 msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND; 137 } 138 } 139 return return_value; 140} 141 142/*--------------------------------------------------------------------------- 143 * msr_create_geodelink_table 144 * 145 * This routine dumps the contents of the GeodeLink bus into an array of 146 * 24 GEODELINK_NODE structures. Indexes 0-7 represent ports 0-7 of GLIU0, 147 * indexes 8-15 represent ports 0-7 of GLIU1 and indexes 16-23 represent 148 * ports 0-7 of GLIU2 (5535). 149 *--------------------------------------------------------------------------*/ 150 151int 152msr_create_geodelink_table(GEODELINK_NODE * gliu_nodes) 153{ 154 unsigned long mbiu_port_count, reflective; 155 unsigned long port, index; 156 unsigned long gliu_count = 0; 157 int glcp_count = 0; 158 int usb_count = 0; 159 int mpci_count = 0; 160 Q_WORD msr_value = {0, 0}; 161 162 /* ALL THREE GLIUS ARE IN ONE ARRAY */ 163 /* Entries 0-7 contain the port information for GLIU0, entries */ 164 /* 8-15 contain GLIU1 and 15-23 contain GLIU2. We perform the */ 165 /* enumeration in two passes. The first simply fills in the */ 166 /* addresses and class codes at each node. The second pass */ 167 /* translates the class codes into indexes into Cimarron's device */ 168 /* lookup table. */ 169 170 /* COUNT GLIU0 PORTS */ 171 172 MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU0, &msr_value); 173 mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7; 174 175 /* FIND REFLECTIVE PORT */ 176 /* Query the GLIU for the port through which we are communicating. */ 177 /* We will avoid accesses to this port to avoid a self-reference. */ 178 179 MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU0, &msr_value); 180 reflective = msr_value.low & WHOAMI_MASK; 181 182 /* SPECIAL CASE FOR PORT 0 */ 183 /* GLIU0 port 0 is a special case, as it points back to GLIU0. GLIU0 */ 184 /* responds at address 0x10000xxx, which does not equal 0 << 29. */ 185 186 gliu_nodes[0].address_from_cpu = MSR_ADDRESS_GLIU0; 187 gliu_nodes[0].device_id = MSR_CLASS_CODE_GLIU; 188 189 /* ENUMERATE ALL PORTS */ 190 191 for (port = 1; port < 8; port++) { 192 /* FILL IN ADDRESS */ 193 194 gliu_nodes[port].address_from_cpu = port << 29; 195 196 if (port == reflective) 197 gliu_nodes[port].device_id = MSR_CLASS_CODE_REFLECTIVE; 198 else if (port > mbiu_port_count) 199 gliu_nodes[port].device_id = MSR_CLASS_CODE_UNPOPULATED; 200 else { 201 MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[port].address_from_cpu, 202 &msr_value); 203 gliu_nodes[port].device_id = 204 GET_DEVICE_ID(msr_value.high, msr_value.low); 205 } 206 } 207 208 /* COUNT GLIU1 PORTS */ 209 210 MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU1, &msr_value); 211 mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7; 212 213 /* FIND REFLECTIVE PORT */ 214 215 MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU1, &msr_value); 216 reflective = msr_value.low & WHOAMI_MASK; 217 218 /* ENUMERATE ALL PORTS */ 219 220 for (port = 0; port < 8; port++) { 221 index = port + 8; 222 223 /* FILL IN ADDRESS */ 224 225 gliu_nodes[index].address_from_cpu = (0x02l << 29) + (port << 26); 226 227 if (port == reflective) 228 gliu_nodes[index].device_id = MSR_CLASS_CODE_REFLECTIVE; 229 else if (port > mbiu_port_count) 230 gliu_nodes[index].device_id = MSR_CLASS_CODE_UNPOPULATED; 231 else { 232 MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[index].address_from_cpu, 233 &msr_value); 234 gliu_nodes[index].device_id = 235 GET_DEVICE_ID(msr_value.high, msr_value.low); 236 } 237 } 238 239 /* COUNT GLIU2 PORTS */ 240 241 MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU2, &msr_value); 242 mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7; 243 244 /* FIND REFLECTIVE PORT */ 245 246 MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU2, &msr_value); 247 reflective = msr_value.low & WHOAMI_MASK; 248 249 /* FILL IN PORT 0 AND 1 */ 250 /* Port 0 on 5535 is MBIU2. Port 1 is MPCI, but it is referenced at */ 251 /* a special address. */ 252 253 gliu_nodes[16].address_from_cpu = MSR_ADDRESS_GLIU2; 254 gliu_nodes[16].device_id = MSR_CLASS_CODE_GLIU; 255 256 gliu_nodes[17].address_from_cpu = MSR_ADDRESS_5535MPCI; 257 gliu_nodes[17].device_id = MSR_CLASS_CODE_MPCI; 258 259 /* ENUMERATE ALL PORTS */ 260 261 for (port = 2; port < 8; port++) { 262 index = port + 16; 263 264 /* FILL IN ADDRESS */ 265 266 gliu_nodes[index].address_from_cpu = 267 (0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20); 268 269 if (port == reflective) 270 gliu_nodes[index].device_id = MSR_CLASS_CODE_REFLECTIVE; 271 else if (port > mbiu_port_count) 272 gliu_nodes[index].device_id = MSR_CLASS_CODE_UNPOPULATED; 273 else { 274 MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[index].address_from_cpu, 275 &msr_value); 276 gliu_nodes[index].device_id = 277 GET_DEVICE_ID(msr_value.high, msr_value.low); 278 } 279 } 280 281 /* SECOND PASS - TRANSLATION */ 282 /* Now that the class codes for each device are stored in the */ 283 /* array, we walk through the array and translate the class */ 284 /* codes to table indexes. For class codes that have multiple */ 285 /* instances, the table indexes are sequential. */ 286 287 for (port = 0; port < 24; port++) { 288 /* SPECIAL CASE FOR GLIU UNITS */ 289 /* A GLIU can be both on another port and on its own port. These */ 290 /* end up as the same address, but are shown as duplicate nodes in */ 291 /* the GeodeLink table. */ 292 293 if ((port & 7) == 0) 294 gliu_count = port >> 3; 295 296 switch (gliu_nodes[port].device_id) { 297 /* UNPOPULATED OR REFLECTIVE NODES */ 298 299 case MSR_CLASS_CODE_UNPOPULATED: 300 index = MSR_DEVICE_EMPTY; 301 break; 302 case MSR_CLASS_CODE_REFLECTIVE: 303 index = MSR_DEVICE_REFLECTIVE; 304 break; 305 306 /* KNOWN CLASS CODES */ 307 308 case MSR_CLASS_CODE_GLIU: 309 index = MSR_DEVICE_GEODELX_GLIU0 + gliu_count++; 310 break; 311 case MSR_CLASS_CODE_GLCP: 312 index = MSR_DEVICE_GEODELX_GLCP + glcp_count++; 313 break; 314 case MSR_CLASS_CODE_MPCI: 315 index = MSR_DEVICE_GEODELX_MPCI + mpci_count++; 316 break; 317 case MSR_CLASS_CODE_USB: 318 index = MSR_DEVICE_5535_USB2 + usb_count++; 319 break; 320 case MSR_CLASS_CODE_USB2: 321 index = MSR_DEVICE_5536_USB_2_0; 322 break; 323 case MSR_CLASS_CODE_ATAC: 324 index = MSR_DEVICE_5535_ATAC; 325 break; 326 case MSR_CLASS_CODE_MDD: 327 index = MSR_DEVICE_5535_MDD; 328 break; 329 case MSR_CLASS_CODE_ACC: 330 index = MSR_DEVICE_5535_ACC; 331 break; 332 case MSR_CLASS_CODE_MC: 333 index = MSR_DEVICE_GEODELX_MC; 334 break; 335 case MSR_CLASS_CODE_GP: 336 index = MSR_DEVICE_GEODELX_GP; 337 break; 338 case MSR_CLASS_CODE_VG: 339 index = MSR_DEVICE_GEODELX_VG; 340 break; 341 case MSR_CLASS_CODE_DF: 342 index = MSR_DEVICE_GEODELX_DF; 343 break; 344 case MSR_CLASS_CODE_FG: 345 index = MSR_DEVICE_GEODELX_FG; 346 break; 347 case MSR_CLASS_CODE_VIP: 348 index = MSR_DEVICE_GEODELX_VIP; 349 break; 350 case MSR_CLASS_CODE_AES: 351 index = MSR_DEVICE_GEODELX_AES; 352 break; 353 case MSR_CLASS_CODE_VAIL: 354 index = MSR_DEVICE_GEODELX_VAIL; 355 break; 356 default: 357 index = MSR_DEVICE_EMPTY; 358 break; 359 } 360 361 gliu_nodes[port].device_id = index; 362 } 363 364 return CIM_STATUS_OK; 365} 366 367/*--------------------------------------------------------------------------- 368 * msr_create_device_list 369 * 370 * This routine dumps a list of all known GeodeLX/5535 devices as well as their 371 * respective status and address. 372 *--------------------------------------------------------------------------*/ 373 374int 375msr_create_device_list(GEODELINK_NODE * gliu_nodes, int max_devices) 376{ 377 int i, count; 378 379 if (max_devices < MSR_DEVICE_EMPTY) 380 count = max_devices; 381 else 382 count = MSR_DEVICE_EMPTY; 383 384 for (i = 0; i < count; i++) { 385 gliu_nodes[i].address_from_cpu = msr_dev_lookup[i].address_from_cpu; 386 gliu_nodes[i].device_id = msr_dev_lookup[i].device_id; 387 } 388 389 return CIM_STATUS_OK; 390} 391 392/*-------------------------------------------------------------------- 393 * msr_read64 394 * 395 * Performs a 64-bit read from 'msr_register' in device 'device'. 'device' is 396 * an index into Cimarron's table of known GeodeLink devices. 397 *-------------------------------------------------------------------*/ 398 399int 400msr_read64(unsigned long device, unsigned long msr_register, 401 Q_WORD * msr_value) 402{ 403 if (device < MSR_DEVICE_EMPTY) { 404 if (msr_dev_lookup[device].device_id == MSR_DEVICE_PRESENT) { 405 MSR_READ(msr_register, msr_dev_lookup[device].address_from_cpu, 406 msr_value); 407 return CIM_STATUS_OK; 408 } 409 } 410 411 msr_value->low = msr_value->high = 0; 412 return CIM_STATUS_DEVNOTFOUND; 413} 414 415/*-------------------------------------------------------------------- 416 * msr_write64 417 * 418 * Performs a 64-bit write to 'msr_register' in device 'device'. 'device' is 419 * an index into Cimarron's table of known GeodeLink devices. 420 *-------------------------------------------------------------------*/ 421 422int 423msr_write64(unsigned long device, unsigned long msr_register, 424 Q_WORD * msr_value) 425{ 426 if (device < MSR_DEVICE_EMPTY) { 427 if (msr_dev_lookup[device].device_id == MSR_DEVICE_PRESENT) { 428 MSR_WRITE(msr_register, msr_dev_lookup[device].address_from_cpu, 429 msr_value); 430 return CIM_STATUS_OK; 431 } 432 } 433 return CIM_STATUS_DEVNOTFOUND; 434} 435