msr_rdcl.c revision f29dbc25
1/* Copyright (c) 2005 Advanced Micro Devices, Inc. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 * 21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 22 * contributors may be used to endorse or promote products derived from this 23 * software without specific prior written permission. 24 * */ 25 26/* 27 * This file contains MSR access routines for Redcloud. 28 * */ 29 30void redcloud_build_mbus_tree(void); /* private routine definition */ 31int redcloud_init_msr_devices(MSR aDev[], unsigned int array_size); 32 33 /* private routine definition */ 34DEV_STATUS redcloud_find_msr_device(MSR * pDev); 35 36 /* private routine definition */ 37 38/* REDCLOUD MSR BITMASKS */ 39 40#define MBD_MSR_CAP 0x2000 41#define MSR_CAP_ID_MASK 0xFF000 42#define MSR_CAP_ID_SHIFT 12 43#define MSR_CAP_REV_MASK 0x0F 44#define MBIU_CAP 0x86 45#define NUM_PORTS_MASK 0x00380000 46#define NUM_PORTS_SHIFT 19 47#define MBIU_WHOAMI 0x8B 48#define WHOAMI_MASK 0x07 49 50/* REDCLOUD and CS5535 MSR DEVICES */ 51 52MSR msrDev[] = { 53 {FOUND, RC_CC_MBIU, RC_MB0_MBIU0}, 54 {FOUND, RC_CC_MBIU, RC_MB0_MBIU1}, 55 {NOT_KNOWN, RC_CC_MCP, FAKE_ADDRESS}, 56 {NOT_KNOWN, RC_CC_MPCI, FAKE_ADDRESS}, 57 {NOT_KNOWN, RC_CC_MC, FAKE_ADDRESS}, 58 {NOT_KNOWN, RC_CC_GP, FAKE_ADDRESS}, 59 {NOT_KNOWN, RC_CC_VG, FAKE_ADDRESS}, 60 {NOT_KNOWN, RC_CC_DF, FAKE_ADDRESS}, 61 {NOT_KNOWN, RC_CC_FG, FAKE_ADDRESS}, 62 {FOUND, RC_CC_VA, RC_MB0_CPU}, 63 {FOUND, CP_CC_MBIU, CP_MB0_MBIU0}, 64 {NOT_KNOWN, CP_CC_MPCI, FAKE_ADDRESS}, 65 {NOT_KNOWN, CP_CC_USB2, FAKE_ADDRESS}, 66 {NOT_KNOWN, CP_CC_ATAC, FAKE_ADDRESS}, 67 {NOT_KNOWN, CP_CC_MDD, FAKE_ADDRESS}, 68 {NOT_KNOWN, CP_CC_ACC, FAKE_ADDRESS}, 69 {NOT_KNOWN, CP_CC_USB1, FAKE_ADDRESS}, 70 {NOT_KNOWN, CP_CC_MCP, FAKE_ADDRESS}, 71}; 72 73#define NUM_DEVS sizeof(msrDev) / sizeof(struct msr) 74 75/* CAPISTRANO DEVICE INDEX LIMITS */ 76/* These defines represent the start and stop indexes into the device array 77 * for all Capistrano devices. These should be updated whenever a device is 78 * added or removed to the Capistrano list. 79 * */ 80 81#define CP_INDEX_START CP_ID_MBIU 82#define CP_INDEX_STOP CP_ID_MCP 83 84/* GLOBAL MBUS CACHE STRUCTURES */ 85/* These structures contain a "cached" copy of the MBUS topology */ 86/* for easy future lookup. */ 87 88MBUS_NODE MBIU0[8], MBIU1[8], MBIU2[8]; 89 90/* REGISTER MACROS */ 91 92#define GET_DEVICE_ID( CAPABILITIES_HIGH, CAPABILITIES_LOW ) \ 93 ((unsigned int)(( (CAPABILITIES_LOW) & MSR_CAP_ID_MASK ) >> MSR_CAP_ID_SHIFT )) 94 95#define GET_NUM_PORTS( MBIU_CAP_HIGH, MBIU_CAP_LOW ) (((MBIU_CAP_HIGH) & NUM_PORTS_MASK ) >> NUM_PORTS_SHIFT) 96 97/*---------------------------------------------------------------------------- 98 * gfx_msr_init 99 * 100 * This routine initializes the base addresses of all known MBUS devices. 101 *---------------------------------------------------------------------------- 102 */ 103#if GFX_MSR_DYNAMIC 104int 105redcloud_msr_init(void) 106#else 107int 108gfx_msr_init(void) 109#endif 110{ 111 Q_WORD msrValue; 112 int return_value = 1; 113 114 /* CHECK FOR VALID MBUS CONFIGURATION */ 115 /* The CPU and the two MBIUs are assumed to be at known static addresses, 116 * so we will check the device IDs at these addresses as proof of a valid 117 * mbus configuration. 118 * */ 119 120 MSR_READ(MBD_MSR_CAP, RC_MB0_CPU, &(msrValue.high), &(msrValue.low)); 121 if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_VA) 122 return_value = 0; 123 124 MSR_READ(MBD_MSR_CAP, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low)); 125 if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_MBIU) 126 return_value = 0; 127 128 MSR_READ(MBD_MSR_CAP, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low)); 129 if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_MBIU) 130 return_value = 0; 131 132 /* ENUMERATE VALID BUS */ 133 /* If all static devices were identified, continue with the enumeration */ 134 135 if (return_value) { 136 /* OPTIMIZATION */ 137 /* Build a local copy of the MBUS topology. This allows us to */ 138 /* quickly search the entire MBUS for a given device ID without */ 139 /* repeated MSR accesses. */ 140 141 redcloud_build_mbus_tree(); 142 143 /* INITIALIZE MSR DEVICES */ 144 145 return_value = redcloud_init_msr_devices(msrDev, NUM_DEVS); 146 147 } 148 149 return return_value; 150 151} 152 153/*-------------------------------------------------------------------------- 154 * void redcloud_build_mbus_tree() (PRIVATE ROUTINE - NOT PART OF DURANGO API) 155 * 156 * This routine walks through the MBUS and records the address value and 157 * device ID found at each node. If a node (aka port) is not populated, 158 * that node returns '0'. The deviceID for that node is set to '0' 159 * (NOT_POPULATED) to reflect this. If the node being queried points back to 160 * Vail or MBIU0, the deviceID for that node is set to 'REFLECTIVE'. 161 * Reflective nodes are nodes that forward the given MBUS address BACK to the 162 * initiator. 163 *---------------------------------------------------------------------------- 164 */ 165void 166redcloud_build_mbus_tree(void) 167{ 168 unsigned long mbiu_port_count, reflective; 169 unsigned long port; 170 Q_WORD msrValue; 171 172 /* */ 173 /* ENUMERATE MBIU0 */ 174 /* */ 175 176 /* COUNT MBIU PORTS */ 177 178 MSR_READ(MBIU_CAP, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low)); 179 mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low); 180 181 /* FIND REFLECTIVE PORT */ 182 /* Query the MBIU for the port through which we are communicating. */ 183 /* We will avoid accesses to this port to avoid a self-reference. */ 184 185 MSR_READ(MBIU_WHOAMI, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low)); 186 reflective = msrValue.low & WHOAMI_MASK; 187 188 /* ENUMERATE ALL PORTS */ 189 /* For every possible port, set the MBIU.deviceId to something. */ 190 191 for (port = 0; port < 8; port++) { 192 /* FILL IN CLAIMED FIELD */ 193 /* All MBIU ports can only be assigned to one device from the */ 194 /* Durango table */ 195 196 MBIU0[port].claimed = 0; 197 198 /* MBIU0 PORT NUMBERS ARE IN ADDRESS BITS 31:29 */ 199 200 MBIU0[port].address = port << 29; 201 202 /* SPECIAL CASE FOR MBIU0 */ 203 /* MBIU0 port 0 is a special case, as it points back to MBIU0. MBIU0 204 * responds at address 0x40000xxx, which does not equal 0 << 29. 205 * */ 206 207 if (port == 0) 208 MBIU0[port].deviceId = RC_CC_MBIU; 209 else if (port == reflective) 210 MBIU0[port].deviceId = REFLECTIVE; 211 else if (port > mbiu_port_count) 212 MBIU0[port].deviceId = NOT_POPULATED; 213 else { 214 MSR_READ(MBD_MSR_CAP, MBIU0[port].address, &(msrValue.high), 215 &(msrValue.low)); 216 MBIU0[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low); 217 } 218 } 219 220 /* */ 221 /* ENUMERATE MBIU1 */ 222 /* */ 223 224 /* COUNT MBIU PORTS */ 225 226 MSR_READ(MBIU_CAP, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low)); 227 mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low); 228 229 /* FIND REFLECTIVE PORT */ 230 /* Query the MBIU for the port through which we are communicating. */ 231 /* We will avoid accesses to this port to avoid a self-reference. */ 232 233 MSR_READ(MBIU_WHOAMI, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low)); 234 reflective = msrValue.low & WHOAMI_MASK; 235 236 /* ENUMERATE ALL PORTS */ 237 /* For every possible port, set the MBIU.deviceId to something. */ 238 239 for (port = 0; port < 8; port++) { 240 /* FILL IN CLAIMED FIELD */ 241 /* All MBIU ports can only be assigned to one device from the */ 242 /* Durango table */ 243 244 MBIU1[port].claimed = 0; 245 246 /* MBIU1 PORT NUMBERS ARE IN 28:26 AND 31:29 = 010B */ 247 248 MBIU1[port].address = (0x02l << 29) + (port << 26); 249 250 if (port == reflective) 251 MBIU1[port].deviceId = REFLECTIVE; 252 else if (port > mbiu_port_count) 253 MBIU1[port].deviceId = NOT_POPULATED; 254 else { 255 MSR_READ(MBD_MSR_CAP, MBIU1[port].address, &(msrValue.high), 256 &(msrValue.low)); 257 MBIU1[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low); 258 } 259 } 260 261 /* */ 262 /* ENUMERATE MBIU2 (CS5535) */ 263 /* (if present) */ 264 265 MSR_READ(MBD_MSR_CAP, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low)); 266 if (GET_DEVICE_ID(msrValue.high, msrValue.low) == CP_CC_MBIU) { 267 /* COUNT MBIU PORTS */ 268 269 MSR_READ(MBIU_CAP, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low)); 270 mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low); 271 272 /* FIND REFLECTIVE PORT */ 273 /* Query the MBIU for the port through which we are communicating. */ 274 /* We will avoid accesses to this port to avoid a self-reference. */ 275 276 MSR_READ(MBIU_WHOAMI, CP_MB0_MBIU0, &(msrValue.high), 277 &(msrValue.low)); 278 reflective = msrValue.low & WHOAMI_MASK; 279 280 /* ENUMERATE ALL PORTS */ 281 /* For every possible port, set the MBIU.deviceId to something. */ 282 283 for (port = 0; port < 8; port++) { 284 /* FILL IN CLAIMED FIELD */ 285 /* All MBIU ports can only be assigned to one device from the */ 286 /* Durango table */ 287 288 MBIU2[port].claimed = 0; 289 290 /* MBIU2 PORT NUMBERS ARE IN 22:20 AND 31:23 = 010100010B */ 291 292 MBIU2[port].address = 293 (0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20); 294 295 if (port == reflective) 296 MBIU2[port].deviceId = REFLECTIVE; 297 else if (port > mbiu_port_count) 298 MBIU2[port].deviceId = NOT_POPULATED; 299 else { 300 MSR_READ(MBD_MSR_CAP, MBIU2[port].address, &(msrValue.high), 301 &(msrValue.low)); 302 MBIU2[port].deviceId = 303 GET_DEVICE_ID(msrValue.high, msrValue.low); 304 } 305 } 306 } else { 307 /* NO 5535 */ 308 /* If the CS5535 is not installed, fill in the cached table */ 309 /* with the 'NOT_INSTALLED' flag. Also, fill in the device */ 310 /* status from NOT_KNOWN to REQ_NOT_INSTALLED. */ 311 312 for (port = 0; port < 8; port++) { 313 MBIU2[port].claimed = 0; 314 MBIU2[port].deviceId = NOT_INSTALLED; 315 MBIU2[port].address = 316 (0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20); 317 } 318 for (port = CP_INDEX_START; port <= CP_INDEX_STOP; port++) { 319 msrDev[port].Present = REQ_NOT_INSTALLED; 320 } 321 } 322} 323 324/*------------------------------------------------------------------ 325 * redcloud_init_msr_devices (PRIVATE ROUTINE - NOT PART OF DURANGO API) 326 * 327 * Handles the details of finding each possible device on the MBUS. 328 * If a given device is not found, its structure is left uninitialized. 329 * If a given device is found, its structure is updated. 330 * 331 * This init routine only checks for devices in aDev[]. 332 * 333 * Passed: 334 * aDev - is a pointer to the array of MBUS devices. 335 * arraySize - number of elements in aDev. 336 * 337 * Returns: 338 * 1 - If, for every device, its address was found. 339 * 0 - If, for any device, an error was encountered. 340 *------------------------------------------------------------------ 341 */ 342int 343redcloud_init_msr_devices(MSR aDev[], unsigned int array_size) 344{ 345 unsigned int i, issues = 0; 346 347 /* TRY TO FIND EACH ITEM IN THE ARRAY */ 348 349 for (i = 0; i < array_size; i++) { 350 /* IGNORE DEVICES THAT ARE ALREADY FOUND */ 351 /* The addresses for "found" devices are already known. */ 352 353 if (aDev[i].Present == FOUND || aDev[i].Present == REQ_NOT_INSTALLED) 354 continue; 355 356 /* TRY TO FIND THE DEVICE ON THE MBUS */ 357 358 aDev[i].Present = redcloud_find_msr_device(&aDev[i]); 359 360 /* INCREMENT ERROR COUNT IF DEVICE NOT FOUND */ 361 362 if (aDev[i].Present != FOUND) 363 issues++; 364 } 365 366 return (issues == 0); 367} 368 369/*------------------------------------------------------------------ 370 * redcloud_find_msr_device (PRIVATE ROUTINE - NOT PART OF DURANGO API) 371 * 372 * Passed: 373 * pDev - is a pointer to one element in the array of MBUS devices 374 * 375 * Returns: 376 * FOUND - Device was found and pDev->Address has been updated. 377 * 378 * REQ_NOT_FOUND - Device was not found and pDev->Address has not 379 * been updated. 380 * 381 *------------------------------------------------------------------ 382 */ 383DEV_STATUS 384redcloud_find_msr_device(MSR * pDev) 385{ 386 unsigned int i; 387 388 /* SEARCH DURANGO'S CACHED MBUS TOPOLOGY */ 389 /* This gets a little tricky. As the only identifier we have for each 390 * device is the device ID and we have multiple devices of the same type 391 * MCP, MPCI, USB, etc. we need to make some assumptions based on table 392 * order. These are as follows: 393 * 1. All Redcloud nodes are searched first, as we assume that they 394 * are first in the table. 395 * 2. If two devices have the same device ID and are found on the same 396 * device (GX2, CS5535, etc.) we assume that they are listed such 397 * that the first device in the table with this device ID has a lower 398 * port address. 399 * 3. After a device ID has been matched, the port is marked as 400 * 'claimed', such that future enumerations continue searching the 401 * GeodeLink topology. 402 */ 403 404 /* SEARCH MBIU0 */ 405 406 for (i = 0; i < 8; i++) { 407 if (MBIU0[i].deviceId == pDev->Id && !(MBIU0[i].claimed)) { 408 MBIU0[i].claimed = 1; 409 pDev->Address = MBIU0[i].address; 410 return FOUND; 411 } 412 } 413 414 /* SEARCH MBIU1 */ 415 416 for (i = 0; i < 8; i++) { 417 if (MBIU1[i].deviceId == pDev->Id && !(MBIU1[i].claimed)) { 418 MBIU1[i].claimed = 1; 419 pDev->Address = MBIU1[i].address; 420 return FOUND; 421 } 422 } 423 424 /* SEARCH MBIU2 */ 425 426 for (i = 0; i < 8; i++) { 427 if (MBIU2[i].deviceId == pDev->Id && !(MBIU2[i].claimed)) { 428 MBIU2[i].claimed = 1; 429 pDev->Address = MBIU2[i].address; 430 return FOUND; 431 } 432 } 433 434 return REQ_NOT_FOUND; 435} 436 437/*-------------------------------------------------------------------- 438 * gfx_id_msr_device 439 * 440 * This routine handles reading the capabilities MSR register (typically 441 * 0x2000) and checking if the 'id' field matchs pDev.Id. This routine is 442 * used by applications/drivers that need to extend the list of known 443 * MBUS devices beyond those known by Durango. 444 * 445 * Passed: 446 * pDev - Pointer to MSR structure containing the device's ID. 447 * address - device address. 448 * 449 * Returns: 450 * FOUND - The IDs do match. 451 * REQ_NOT_FOUND - There was not a match. 452 * 453 *-------------------------------------------------------------------- 454 */ 455#if GFX_MSR_DYNAMIC 456DEV_STATUS 457redcloud_id_msr_device(MSR * pDev, unsigned long address) 458#else 459DEV_STATUS 460gfx_id_msr_device(MSR * pDev, unsigned long address) 461#endif 462{ 463 Q_WORD msrValue; 464 465 MSR_READ(MBD_MSR_CAP, address, &(msrValue.high), &(msrValue.low)); 466 467 if (GET_DEVICE_ID(msrValue.high, msrValue.low) == pDev->Id) 468 return FOUND; 469 else 470 return REQ_NOT_FOUND; 471} 472 473/*-------------------------------------------------------------------- 474 * gfx_get_msr_dev_address 475 * 476 * This function returns the 32-bit address of the requested device. 477 * The device must be a known MBUS device. (It must be in Durango's 478 * device table.) DEV_STATUS should be checked to verify that the address 479 * was updated. 480 * 481 * 482 * Passed: 483 * device - device index of the device in question. 484 * *address - ptr to location where address should be stored. 485 * 486 * Returns: 487 * DEV_STATUS of device in question. (NOT_KNOWN if device is out of range.) 488 * *address - updated if 'device' is within range 489 * 490 * Notes: 491 * This function should only be called after gfx_msr_init 492 * 493 *-------------------------------------------------------------------- 494 */ 495#if GFX_MSR_DYNAMIC 496DEV_STATUS 497redcloud_get_msr_dev_address(unsigned int device, unsigned long *address) 498#else 499DEV_STATUS 500gfx_get_msr_dev_address(unsigned int device, unsigned long *address) 501#endif 502{ 503 if (device < NUM_DEVS) { 504 if (msrDev[device].Present == FOUND) 505 *address = msrDev[device].Address; 506 507 return msrDev[device].Present; 508 } 509 return NOT_KNOWN; 510 511} 512 513/*-------------------------------------------------------------------- 514 * gfx_get_glink_id_at_address 515 * 516 * This function returns the 16-bit deviceId at the requested address. 517 * DEV_STATUS should be checked to make sure that device was updated. 518 * 519 * Passed: 520 * device - ptr to location where device ID should be stored. 521 * address - address of desired device ID. 522 * 523 * Returns: 524 * FOUND if address is a valid address, NOT_KNOWN if address cannot be 525 * found on the mbus. 526 * *device - updated with device Id info. 527 * 528 * Notes: 529 * This function should be called after gfx_msr_init 530 * 531 *-------------------------------------------------------------------- 532 */ 533#if GFX_MSR_DYNAMIC 534DEV_STATUS 535redcloud_get_glink_id_at_address(unsigned int *device, unsigned long address) 536#else 537DEV_STATUS 538gfx_get_glink_id_at_address(unsigned int *device, unsigned long address) 539#endif 540{ 541 int port; 542 543 for (port = 0; port < 8; port++) { 544 if (MBIU0[port].address == address) { 545 *device = MBIU0[port].deviceId; 546 return FOUND; 547 } else if (MBIU1[port].address == address) { 548 *device = MBIU1[port].deviceId; 549 return FOUND; 550 } else if (MBIU2[port].address == address) { 551 *device = MBIU2[port].deviceId; 552 return FOUND; 553 } 554 } 555 556 return NOT_KNOWN; 557 558} 559 560/*-------------------------------------------------------------------- 561 * gfx_msr_read 562 * 563 * Performs a 64-bit read from 'msrRegister' in device 'device'. 'device' is 564 * an index into Durango's table of known MBUS devices. 565 * 566 * Returns: 567 * FOUND - if no errors were detected and msrValue has been 568 * updated. 569 * NOT_KNOWN - an error was detected. msrValue is not updated. 570 * REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown. Caller 571 * should call msrInit() first. msrValue is not 572 * updated. 573 * Notes: 574 * This function should be called after gfx_msr_init 575 *-------------------------------------------------------------------- 576 */ 577#if GFX_MSR_DYNAMIC 578DEV_STATUS 579redcloud_msr_read(unsigned int device, unsigned int msrRegister, 580 Q_WORD * msrValue) 581#else 582DEV_STATUS 583gfx_msr_read(unsigned int device, unsigned int msrRegister, Q_WORD * msrValue) 584#endif 585{ 586 if (device < NUM_DEVS) { 587 if (msrDev[device].Present == FOUND) 588 MSR_READ(msrRegister, msrDev[device].Address, &(msrValue->high), 589 &(msrValue->low)); 590 591 return msrDev[device].Present; 592 } 593 return NOT_KNOWN; 594} 595 596/*-------------------------------------------------------------------- 597 * gfx_msr_write 598 * 599 * Performs a 64-bit write to 'msrRegister' in device 'devID'. 600 * 601 * Returns: 602 * FOUND - if no errors were detected and msrValue has been 603 * updated. 604 * NOT_KNOWN - an error was detected. msrValue is not updated. 605 * REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown. Caller 606 * should call msrInit() first. msrValue is not 607 * updated. 608 * 609 *Notes: 610 * This function is valid to call after initMSR_API() 611 * 612 *-------------------------------------------------------------------- 613 */ 614#if GFX_MSR_DYNAMIC 615DEV_STATUS 616redcloud_msr_write(unsigned int device, unsigned int msrRegister, 617 Q_WORD * msrValue) 618#else 619DEV_STATUS 620gfx_msr_write(unsigned int device, unsigned int msrRegister, 621 Q_WORD * msrValue) 622#endif 623{ 624 if (device < NUM_DEVS) { 625 if (msrDev[device].Present == FOUND) 626 MSR_WRITE(msrRegister, msrDev[device].Address, &(msrValue->high), 627 &(msrValue->low)); 628 629 return msrDev[device].Present; 630 } 631 632 return NOT_KNOWN; 633} 634