1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 1999-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 /*! 25 * @file 26 * @brief NBSI table initialization routines. 27 */ 28 29 #include "os/os.h" 30 #include "platform/acpi_common.h" 31 #include "platform/nbsi/nbsi_read.h" 32 #include "platform/platform.h" 33 #include "nbci.h" 34 #include "nvRmReg.h" 35 #include "gpu/gpu.h" 36 #include "nvhybridacpi.h" 37 #include "nvlimits.h" 38 39 // Template to use to read in emulated nbsi table from registry. 40 41 #define NBSI_ROM_CODE_SIZE (256*1024) // allocate amt for ROMs to be read into 42 43 extern const GUID NV_GUID_UEFI_VARIABLE; 44 45 //---------------------------------------------------------------------------- 46 // NvU32 setNbsiOSstring(* data, data_len, nbsiOSndx, maxNbsiOS) 47 // 48 // This function computes the global nbsiOShash so that future 20 bit 49 // fnv hash calculations can start with this hash value. 50 // 51 // Input parameters: 52 // *data - Byte array 53 // dataLen - length of Byte array 54 // nbsiOSndx - index to place this hash to (0 based) 55 // maxNbsiOS - maximum supported OS. 56 // 57 // Example usage to set up searching for Vista64 first, then Vista generic 58 // then blank: 59 // setNbsiOSstring("Vista64",7,2,3); 60 // setNbsiOSstring("Vista",5,1,3); 61 // setNbsiOSstring("",0,0,3); 62 // Note: The highest OS index is searched first and the lowest (0) is last. 63 // 64 // Returns the current number of OSes supported. 65 // 66 //---------------------------------------------------------------------------- 67 static NvU32 setNbsiOSstring 68 ( 69 const void * data_v, 70 NvU32 dataLen, 71 NvU8 nbsiOSndx, 72 NvU8 maxNbsiOS 73 ) 74 { 75 NBSI_OBJ *pNbsiObj = getNbsiObject(); 76 NvU32 hash; 77 NvU8 i; 78 NvU8 nullPathStr[1] = {0}; 79 const NvU8 * data = (const NvU8 *)data_v; 80 81 NV_ASSERT(data); 82 NV_ASSERT(nbsiOSndx < MAX_NBSI_OS); 83 NV_ASSERT(maxNbsiOS < MAX_NBSI_OS+1); 84 85 if (maxNbsiOS <= MAX_NBSI_OS) 86 { 87 pNbsiObj->curMaxNbsiOSes = maxNbsiOS; 88 } 89 else 90 { 91 pNbsiObj->curMaxNbsiOSes = 1; 92 nbsiOSndx = 0; 93 } 94 95 if (dataLen > MAX_NBSI_OS_STR_LEN) 96 { 97 NV_PRINTF(LEVEL_ERROR, 98 "NBSI OS string length %d too long for OS ndx %d.\n", 99 dataLen, nbsiOSndx); 100 dataLen = MAX_NBSI_OS_STR_LEN; 101 } 102 103 // Copy the new string in. 104 for (i = 0; i < dataLen; i++) 105 { 106 pNbsiObj->nbsiOSstr[nbsiOSndx][i] = data[i]; 107 } 108 pNbsiObj->nbsiOSstr[nbsiOSndx][dataLen] = 0; 109 pNbsiObj->nbsiOSstrLen[nbsiOSndx] = dataLen; 110 111 // 112 // Compute the hash for this OS string. Used in the cases where 113 // the elements are blank and only the OS string is needed. 114 // Apparently a surprisingly common event for modes. 115 // 116 hash = fnv32buf(&pNbsiObj->nbsiOSstr[nbsiOSndx][0], 117 pNbsiObj->nbsiOSstrLen[nbsiOSndx], 118 FNV1_32_INIT, 119 0); 120 pNbsiObj->nbsiOSstrHash[nbsiOSndx] = ((hash>>20) ^ hash) & MASK_20; 121 122 // precompute a null Path hash 123 pNbsiObj->nbsiBlankPathHash = fnv1Hash16(&nullPathStr[0], 0); 124 125 return pNbsiObj->curMaxNbsiOSes; 126 } 127 128 //---------------------------------------------------------------------------- 129 // NV_STATUS testObjectHash(pGpu, PNBSI_GEN_OBJ) 130 // 131 // This function checks the hash of an object 132 // 133 // Input parameters: 134 // pGpu pointer to gpu object 135 // PNBSI_GEN_OBJ pointer to generic object 136 // 137 // Output parameters: 138 // NV_STATUS: NV_OK if the hash is valid 139 // 140 //---------------------------------------------------------------------------- 141 static NV_STATUS testObjectHash 142 ( 143 OBJGPU *pGpu, 144 PNBSI_GEN_OBJ pNbsiGenObj 145 ) 146 { 147 NV_STATUS status; 148 NvU64 tableHash; 149 NvU8 * hashStart; 150 NvU32 hashLen; 151 152 NV_ASSERT(pNbsiGenObj!=NULL); 153 154 status = NV_OK; 155 // validate the hash using Fnv1 CRC 156 hashStart = (NvU8 *) pNbsiGenObj; 157 hashStart = &hashStart[sizeof(pNbsiGenObj->objHdr.sig)]; 158 hashLen = pNbsiGenObj->objHdr.size - sizeof(pNbsiGenObj->objHdr.sig); 159 tableHash = fnv1Hash64(hashStart, hashLen); 160 if (tableHash != pNbsiGenObj->objHdr.sig) 161 { 162 status = NV_ERR_INVALID_DATA; 163 NV_PRINTF(LEVEL_ERROR, 164 "NBSI tbl computed hash %llx != hash %llx\n", 165 tableHash, pNbsiGenObj->objHdr.sig); 166 } 167 168 return status; 169 } 170 171 //---------------------------------------------------------------------------- 172 // NV_STATUS isGlobTypeInNbsiDir(pNbsiDir, wantedGlobType, 173 // *pCntOfGlobsWithThisGlobType, *pNumGlobs) 174 // 175 // This function counts the number of globs in the directory of the 176 // wanted type and the total number of globs. 177 // 178 // Input parameters: 179 // pNbsiDir pointer to nbsi directory object 180 // wantedGlobType wanted glob type (to count) 181 // 182 // Output parameters: 183 // NV_STATUS: NV_OK if the directory version is okay 184 // pCntOfGlobsWithThisGlobType pointer to count of wantedGlobs found 185 // pNumGlobs pointer to number of globs in directory 186 // found 187 // 188 //---------------------------------------------------------------------------- 189 190 static NV_STATUS isGlobTypeInNbsiDir 191 ( 192 PNBSI_DIRECTORY pNbsiDir, 193 NBSI_GLOB_TYPE wantedGlobType, 194 NvU8 * pCntOfGlobsWithThisGlobType, 195 NvU8 * pNumGlobs 196 ) 197 { 198 NvU8 curGlob; 199 NvU16 * pGlobType = NULL; 200 201 NV_ASSERT(pNbsiDir); 202 NV_ASSERT(pCntOfGlobsWithThisGlobType); 203 NV_ASSERT(pNumGlobs); 204 205 if (pNbsiDir->d.nbsiHeaderString == NBSIDIRHDRSTRING) 206 { 207 *pNumGlobs = pNbsiDir->d.numGlobs; 208 pGlobType = pNbsiDir->d.globType; 209 } 210 else 211 { 212 *pNumGlobs = pNbsiDir->od.numGlobs; 213 pGlobType = pNbsiDir->od.globType; 214 } 215 216 if (wantedGlobType == (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR) 217 { 218 *pCntOfGlobsWithThisGlobType = *pNumGlobs; 219 } 220 else 221 { 222 *pCntOfGlobsWithThisGlobType = 0; 223 for (curGlob = 0; curGlob < *pNumGlobs; curGlob++) 224 { 225 if (wantedGlobType == pGlobType[curGlob]) 226 { 227 *pCntOfGlobsWithThisGlobType += 1; 228 } 229 } 230 } 231 return NV_OK; 232 } 233 234 //---------------------------------------------------------------------------- 235 // NV_STATUS getNbsiDirSize( pGpu, idx, pNbsiDir, 236 // pRtnDirSize, tblSource); 237 // 238 // This function tests the integrity of the NBSI dir object 239 // 240 // Input parameters: 241 // pGpu pointer to gpu object 242 // idx index number of gpu 243 // pNbsiDir pointer to nbsi directory object 244 // pRtnDirSize pointer to return size of dir header 245 // (including globs types) 246 // tblSource indicator where the table came from. 247 // 248 // Output parameters: 249 // NV_STATUS: NV_OK if the directory version is okay and 250 // the directory fits in the allocated mem. 251 // 252 //---------------------------------------------------------------------------- 253 254 static NV_STATUS getNbsiDirSize 255 ( 256 OBJGPU *pGpu, 257 NvU32 idx, 258 PNBSI_DIRECTORY pNbsiDir, 259 NvU32 * pRtnDirSize, 260 NvU16 tblSource 261 ) 262 { 263 NvU8 nbsiDirVer; 264 265 NV_ASSERT(pNbsiDir); 266 NV_ASSERT(pRtnDirSize); 267 268 if (pNbsiDir->d.nbsiHeaderString == NBSIDIRHDRSTRING) 269 { 270 nbsiDirVer = pNbsiDir->d.dirVer; 271 *pRtnDirSize = 272 sizeof(pNbsiDir->d.nbsiHeaderString) + 273 sizeof(pNbsiDir->d.size) + 274 sizeof(pNbsiDir->d.numGlobs) + 275 sizeof(pNbsiDir->d.dirVer) + 276 (pNbsiDir->d.numGlobs * sizeof(pNbsiDir->d.globType[0])); 277 } 278 else 279 { 280 nbsiDirVer = pNbsiDir->od.dirVer; 281 *pRtnDirSize = 282 sizeof(pNbsiDir->od.numGlobs) + 283 sizeof(pNbsiDir->od.dirVer) + 284 (pNbsiDir->od.numGlobs * sizeof(pNbsiDir->od.globType[0])); 285 } 286 287 if (nbsiDirVer > MAXNBSIDIRVER) 288 { 289 NV_PRINTF(LEVEL_ERROR, 290 "GPU%d, source %d, NBSI dir ver %d > max ver %d.\n", 291 idx, tblSource, nbsiDirVer, MAXNBSIDIRVER); 292 return NV_ERR_GENERIC; 293 } 294 295 return NV_OK; 296 } 297 298 //---------------------------------------------------------------------------- 299 // NV_STATUS testNbsiDir( pGpu, idx, pNbsiDir, allocSize, tblSource) 300 // 301 // This function tests the integrity of the NBSI dir object 302 // 303 // Input parameters: 304 // pGpu pointer to gpu object 305 // idx index number of gpu 306 // pNbsiDir pointer to nbsi directory object 307 // allocSize size of memory allocated for dir (for 308 // testing) 309 // tblSource location of table (for error messages) 310 // 311 // Output parameters: 312 // NV_STATUS: NV_OK if the directory version is okay and 313 // the directory fits in the allocated mem. 314 // 315 //---------------------------------------------------------------------------- 316 317 static NV_STATUS testNbsiDir 318 ( 319 OBJGPU *pGpu, 320 NvU32 idx, 321 PNBSI_DIRECTORY pNbsiDir, 322 NvU32 allocSize, 323 NvU16 tblSource 324 ) 325 { 326 NvU32 testDirSize; 327 NV_STATUS status; 328 329 NV_ASSERT(pNbsiDir); 330 331 // Get the NBSI dir size (Varies with directory header). 332 status = getNbsiDirSize(pGpu, 333 idx, 334 pNbsiDir, 335 &testDirSize, 336 tblSource); 337 if (status != NV_OK) 338 { 339 return status; 340 } 341 342 if (testDirSize > allocSize) 343 { 344 NV_PRINTF(LEVEL_ERROR, 345 "GPU%d, source %d, Size of NBSI dir %x > alloc mem %x.\n", 346 idx, tblSource, testDirSize, allocSize); 347 return NV_ERR_GENERIC; 348 } 349 350 if (pNbsiDir->d.nbsiHeaderString == NBSIDIRHDRSTRING) 351 { 352 NV_PRINTF(LEVEL_INFO, 353 "nbsi dir (new fmt) entries=%x, source=%x\n", 354 pNbsiDir->d.numGlobs, tblSource); 355 } 356 else 357 { 358 NV_PRINTF(LEVEL_INFO, 359 "nbsi dir (old fmt) entries=%x, source=%x\n", 360 pNbsiDir->od.numGlobs, tblSource); 361 } 362 363 return NV_OK; 364 } 365 366 // useful defines to make calls to testNbsiTable more readable. 367 #define TEST_NBSI_TABLE_DO_ALLOC_SIZE_CHECK NV_TRUE 368 #define TEST_NBSI_TABLE_SKIP_ALLOC_SIZE_CHECK NV_FALSE 369 #define TEST_NBSI_TABLE_DO_HASH_CHECK NV_TRUE 370 #define TEST_NBSI_TABLE_SKIP_HASH_CHECK NV_FALSE 371 #define TEST_NBSI_TABLE_DO_GLOBTYPE_CHECK NV_TRUE 372 #define TEST_NBSI_TABLE_SKIP_GLOBTYPE_CHECK NV_FALSE 373 374 //---------------------------------------------------------------------------- 375 // NV_STATUS testNbsiTable( pGpu, pNbsiGenObj, wantedGlobType, 376 // i, idx, tableLoc, allocSize, 377 // bDoAllocSzCk, bDoHashCk, bGlobTypeCk ) 378 // 379 // This function tests an existing NBSI table. 380 // 381 // Input parameters: 382 // pGpu Current pGpu object 383 // pNbsiGenObj Current driver object to sanity check 384 // wantedGlobType glob type that we want 385 // i index within directory. 386 // idx GPU instance / index 387 // tableLoc indicator on the source of the table. 388 // allocSize memory allocated for table 389 // bDoAllocSzCk flag indicating to do allocated mem vs table test 390 // bDoHashCk flag indicating to do hash check test 391 // bGlobTypeCk flag indicating to do globtype test 392 // 393 // Output parameters: 394 // NV_STATUS: NV_OK if there were no operational issues 395 // NV_ERR_GENERIC if no table is present or table is bad. 396 // 397 //---------------------------------------------------------------------------- 398 399 static NV_STATUS testNbsiTable 400 ( 401 OBJGPU *pGpu, 402 PNBSI_GEN_OBJ pNbsiGenObj, 403 NvU16 wantedGlobType, 404 NvU32 i, 405 NvU32 idx, 406 NvU16 tableLoc, 407 NvU32 allocSize, 408 NvBool bDoAllocSzCk, 409 NvBool bDoHashCk, 410 NvBool bGlobTypeCk 411 ) 412 { 413 NV_STATUS status = NV_ERR_GENERIC; 414 PNBSI_DRIVER_OBJ pNbsiDriverObj = (PNBSI_DRIVER_OBJ) pNbsiGenObj; 415 416 NV_ASSERT(pNbsiGenObj); 417 NV_ASSERT(allocSize); 418 419 if (pNbsiGenObj && allocSize) 420 { 421 status = NV_OK; 422 423 // Sanity check 1 for globSize... must be larger than NBSI_MIN_GEN_OBJ_SIZE 424 if (pNbsiGenObj->objHdr.size < NBSI_MIN_GEN_OBJ_SIZE) 425 { 426 NV_PRINTF(LEVEL_ERROR, 427 "NBSI Gpu%d Tloc=%d/Glob=%d table size 0x%x < min 0x%x\n", 428 idx, tableLoc, i, 429 pNbsiGenObj->objHdr.size, (NvU32)NBSI_MIN_GEN_OBJ_SIZE); 430 status = NV_ERR_GENERIC; 431 } 432 433 // Sanity check 2 for globSize... must be less than maximum 434 if (pNbsiGenObj->objHdr.size > NBSI_MAX_TABLE_SIZE) 435 { 436 NV_PRINTF(LEVEL_ERROR, 437 "NBSI Gpu%d Tloc=%d/Glob=%d tbl size 0x%x > max 0x%x\n", 438 idx, tableLoc, i, 439 pNbsiGenObj->objHdr.size, NBSI_MAX_TABLE_SIZE); 440 status = NV_ERR_GENERIC; 441 } 442 443 // Sanity check 3 for globSize... must be less than allocated size 444 if (bDoAllocSzCk & (pNbsiGenObj->objHdr.size > allocSize)) 445 { 446 NV_PRINTF(LEVEL_ERROR, 447 "NBSI Gpu%d Tloc=%d/Glob=%d table size 0x%x > alloc 0x%x\n", 448 idx, tableLoc, i, 449 pNbsiGenObj->objHdr.size, allocSize); 450 status = NV_ERR_GENERIC; 451 } 452 453 // Sanity check for number of modules... must be less than max 454 if ((pNbsiGenObj->objHdr.globType == NBSI_DRIVER) && 455 (pNbsiDriverObj->numModules > NV2080_CTRL_BIOS_NBSI_NUM_MODULES)) 456 { 457 NV_PRINTF(LEVEL_ERROR, 458 "NBSI Gpu%d Tloc=%d/Glob=%d numModules %d > max %d\n", 459 idx, tableLoc, i, 460 pNbsiDriverObj->numModules, 461 NV2080_CTRL_BIOS_NBSI_NUM_MODULES); 462 status = NV_ERR_GENERIC; 463 } 464 465 // Sanity check globType matches the one we wanted. 466 if ((pNbsiGenObj->objHdr.globType != wantedGlobType) && bGlobTypeCk) 467 468 { 469 NV_PRINTF(LEVEL_ERROR, 470 "NBSI Gpu%d Tloc=%d/Glob=%d wantedGlobType = %04x != returned globtype = %04x\n", 471 idx, tableLoc, i, wantedGlobType, 472 pNbsiGenObj->objHdr.globType); 473 474 // 475 // BUG 986051 Regression... Adding the globtype confirmation to 476 // prevent a BSOD, exposed an ASL problem in the C89 SBIOS, where 477 // the SBIOS returned the Platform Info Object with a reversed 478 // globtype (PI vs IP). Since we won't likely get a fixed SBIOS... 479 // allow this exception. 480 // 481 482 if ((wantedGlobType != NBSI_PLAT_INFO) || 483 ((wantedGlobType == NBSI_PLAT_INFO) && (pNbsiGenObj->objHdr.globType != NBSI_PLAT_INFO_WAR))) 484 { 485 status = NV_ERR_GENERIC; 486 } 487 } 488 489 // Now bail if we've found any errors before the hash calc. 490 if (status == NV_OK && bDoHashCk) 491 { 492 status = testObjectHash(pGpu, pNbsiGenObj); 493 if (status != NV_OK) 494 { 495 // bad hash error message occurred in testObjectHash 496 NV_PRINTF(LEVEL_ERROR, 497 "NBSI Gpu%d TLoc=%d/globType=%x bad hash\n", 498 idx, tableLoc, 499 pNbsiGenObj->objHdr.globType); 500 } 501 } 502 } 503 504 return status; 505 } 506 507 //---------------------------------------------------------------------------- 508 // NvU8 checkUidMatch(pGpu, pNbsiGenObj, idx, tableLoc, globNdx, 509 // pDriverVersion) 510 // 511 // This function tests if the table matches our platform/device and 512 // returns a score of matching. 0 matches nothing, 5 matches all. 513 // Search qualifiers are: 514 // - First UID matching the Platform SVID/SSID and Chipset VID/DID/Rev 515 // - First UID matching the Platform SVID and Chipset VID/DID/Rev 516 // - First matching Chipset VID/DID/Rev 517 // - First matching Chipset VID/DID 518 // - First matching Chipset VID 519 // 520 // Input parameters: 521 // pGpu Current pGpu object 522 // pNbsiGenObj nbsi driver object to test (NULL for dbg print) 523 // idx GPU instance / index 524 // tableLoc indicator on the source of the table. 525 // globNdx index of glob (note if using get object by type 526 // this is index of driver objects NOT all object 527 // types. 528 // pDriverVersion pointer to return version (if best fit > 0) 529 // 530 // Output parameters: 531 // NvU8 Score 0..5 5 is best fit, 0 is least fit 532 // NvU32 Driver version is returned if score > 0. 533 // 534 //---------------------------------------------------------------------------- 535 static NvU8 checkUidMatch 536 ( 537 OBJGPU *pGpu, 538 PNBSI_DRIVER_OBJ pNbsiGenObj, 539 NvU32 idx, 540 NvU16 tableLoc, 541 NvU8 globNdx, 542 NvU32 * pDriverVersion 543 ) 544 { 545 PNBSI_DRIVER_OBJ0 pNbsiGenObj0 = (PNBSI_DRIVER_OBJ0) pNbsiGenObj; 546 NBSI_OBJ *pNbsiObj = getNbsiObject(); 547 NvU8 score = 0; 548 NvU16 ssid = (NvU16) (pGpu->idInfo.PCISubDeviceID >> 16) & 0xffff; 549 NvU16 svid = (NvU16) pGpu->idInfo.PCISubDeviceID & 0xffff; 550 NvU16 cdid = (NvU16) (pGpu->idInfo.PCIDeviceID >> 16) & 0xffff; 551 NvU16 cvid = (NvU16) pGpu->idInfo.PCIDeviceID & 0xffff; 552 NvU8 crev = (NvU8) pGpu->idInfo.PCIRevisionID & 0xff; 553 NvU32 tRev = pNbsiObj->DriverVer.Rev; 554 NvU32 tDX = pNbsiObj->DriverVer.DX; 555 NvU32 tOS = pNbsiObj->DriverVer.OS; 556 NvBool pTestVersionOnVer0100 = NV_FALSE; 557 558 if (pDriverVersion != NULL) 559 { 560 *pDriverVersion = 0; 561 } 562 563 if (pNbsiGenObj == NULL) 564 { 565 NV_PRINTF(LEVEL_INFO, 566 "NBSI current driver version: %d.%d.1%d.%d\n", 567 pNbsiObj->DriverVer.OS, 568 pNbsiObj->DriverVer.DX, 569 pNbsiObj->DriverVer.Rev / 10000, 570 pNbsiObj->DriverVer.Rev % 10000); 571 572 NV_PRINTF(LEVEL_INFO, 573 "NBSI Gpu%d ID info: svid=%x, ssid=%x, cvid=%x, cdid=%x, crev=%x\n", 574 idx, svid, ssid, cvid, cdid, crev); 575 } 576 else 577 { 578 if (pNbsiGenObj0->objHdr.majMinVer == NBSI_DRIVERVER_0100) 579 { 580 // 581 // check driver rev. If specified can be greater or equal to to use. 582 // if value was 0, assume current version. 583 // Driver revision example: 6.14.11.7782 584 // The format is: a.bb.1c.dddd a is OS, bb is DX, Rev is cdddd 585 // 586 if (pNbsiGenObj0->uid.Driver.majVer) 587 { 588 tOS = pNbsiGenObj0->uid.Driver.majVer; 589 } 590 if (pNbsiGenObj0->uid.Driver.minVer) 591 { 592 tDX = pNbsiGenObj0->uid.Driver.minVer; 593 } 594 if (pNbsiGenObj0->uid.Driver.majRev) 595 { 596 // 597 // this doesn't work correctly since the size is wrong 598 // fixed in v 0x101 of header 599 // 600 tRev = (pNbsiGenObj0->uid.Driver.majRev * 100) + 601 pNbsiGenObj0->uid.Driver.minRev; 602 } 603 if ((pTestVersionOnVer0100) && 604 ((tOS != pNbsiObj->DriverVer.OS) || 605 (tDX != pNbsiObj->DriverVer.DX) || 606 (tRev < pNbsiObj->DriverVer.Rev))) 607 { 608 score = 0; 609 tRev = 0; 610 } 611 else 612 { 613 if ((pNbsiGenObj0->uid.svid && 614 (pNbsiGenObj0->uid.svid == svid)) && 615 (pNbsiGenObj0->uid.ssid && 616 (pNbsiGenObj0->uid.ssid == ssid)) && 617 (pNbsiGenObj0->uid.Chip.vid && 618 (pNbsiGenObj0->uid.Chip.vid == cvid)) && 619 (pNbsiGenObj0->uid.Chip.did && 620 (pNbsiGenObj0->uid.Chip.did == cdid)) && 621 (pNbsiGenObj0->uid.Chip.revId && 622 (pNbsiGenObj0->uid.Chip.revId == crev))) 623 { 624 score = 5; 625 } 626 else if ((pNbsiGenObj0->uid.svid == svid) && 627 (pNbsiGenObj0->uid.Chip.vid == cvid) && 628 (pNbsiGenObj0->uid.Chip.did == cdid) && 629 (pNbsiGenObj0->uid.Chip.revId == crev)) 630 { 631 score = 4; 632 } 633 else if ((pNbsiGenObj0->uid.Chip.vid == cvid) && 634 (pNbsiGenObj0->uid.Chip.did == cdid) && 635 (pNbsiGenObj0->uid.Chip.revId == crev)) 636 { 637 score = 3; 638 } 639 else if ((pNbsiGenObj0->uid.Chip.vid == cvid) && 640 (pNbsiGenObj0->uid.Chip.did == cdid)) 641 { 642 score = 2; 643 } 644 else if (pNbsiGenObj0->uid.Chip.vid == cvid) 645 { 646 score = 1; 647 } 648 } 649 } 650 else 651 { 652 // 653 // check driver rev. If specified can be greater or equal to to use. 654 // if value was 0, assume current version. 655 // Driver revision example: 6.14.11.7782 656 // The format is: a.bb.1c.dddd a is OS, bb is DX, Rev is cdddd 657 // 658 if (pNbsiGenObj->uid.Driver.OS) 659 { 660 tOS = pNbsiGenObj->uid.Driver.OS; 661 } 662 if (pNbsiGenObj->uid.Driver.DX) 663 { 664 tDX = pNbsiGenObj->uid.Driver.DX; 665 } 666 if (pNbsiGenObj->uid.Driver.Rev) 667 { 668 tRev = pNbsiGenObj->uid.Driver.Rev; 669 } 670 if ((tOS != pNbsiObj->DriverVer.OS) || 671 (tDX != pNbsiObj->DriverVer.DX) || 672 (tRev < pNbsiObj->DriverVer.Rev)) 673 { 674 score = 0; 675 tRev = 0; 676 } 677 else 678 { 679 if (pDriverVersion != NULL) 680 { 681 *pDriverVersion = tRev; 682 } 683 684 if ((pNbsiGenObj->uid.svid && 685 (pNbsiGenObj->uid.svid == svid)) && 686 (pNbsiGenObj->uid.ssid && 687 (pNbsiGenObj->uid.ssid == ssid)) && 688 (pNbsiGenObj->uid.Chip.vid && 689 (pNbsiGenObj->uid.Chip.vid == cvid)) && 690 (pNbsiGenObj->uid.Chip.did && 691 (pNbsiGenObj->uid.Chip.did == cdid)) && 692 (pNbsiGenObj->uid.Chip.revId && 693 (pNbsiGenObj->uid.Chip.revId == crev))) 694 { 695 score = 5; 696 } 697 else if ((pNbsiGenObj->uid.svid == svid) && 698 (pNbsiGenObj->uid.Chip.vid == cvid) && 699 (pNbsiGenObj->uid.Chip.did == cdid) && 700 (pNbsiGenObj->uid.Chip.revId == crev)) 701 { 702 score = 4; 703 } 704 else if ((pNbsiGenObj->uid.Chip.vid == cvid) && 705 (pNbsiGenObj->uid.Chip.did == cdid) && 706 (pNbsiGenObj->uid.Chip.revId == crev)) 707 { 708 score = 3; 709 } 710 else if ((pNbsiGenObj->uid.Chip.vid == cvid) && 711 (pNbsiGenObj->uid.Chip.did == cdid)) 712 { 713 score = 2; 714 } 715 else if (pNbsiGenObj->uid.Chip.vid == cvid) 716 { 717 score = 1; 718 } 719 } 720 } 721 722 NV_PRINTF(LEVEL_ERROR, 723 "NBSI Gpu%d Tloc=%d/Glob=%d object match score/ver = (%x/%d)\n", 724 idx, tableLoc, globNdx, score, tRev); 725 } 726 727 return score; 728 } 729 730 //---------------------------------------------------------------------------- 731 // NV_STATUS extractNBSIObjFromDir(pGpu, idx, 732 // pNbsiDir, nbsiDirSize, tableLoc, 733 // wantedGlobType, wantedGlobIndex, 734 // * pActualGlobIdx, 735 // * pRtnObj, * pRtnObjSize, * pbFound) 736 // 737 // This function extracts an NBSI object from a memory based (as opposed 738 // to ACPI) NBSI directory. 739 // 740 // Input parameters: 741 // pGpu Current pGpu object 742 // idx GPU instance / index 743 // pNbsiDir pointer to nbsi directory 744 // nbsiDirSize size of nbsiDir 745 // tableLoc See NBSI_TABLE_LOC_xxxx defines (for debug) 746 // wantedGlobType wanted Glob Type 747 // wantedGlobIndex index of glob type desired (0=best fit) 748 // pActualGlobIdx pointer to actual glob index glob found at 749 // 750 // Output parameters: 751 // NV_STATUS NV_ERR_GENERIC if table structure is bad. 752 // NV_OK if table structure is good. 753 // pRtnObj pointer to memory to hold return object 754 // pRtnObjSize size of memory holding return object 755 // pbFound pointer to NvBool indicating object found. 756 // 757 //---------------------------------------------------------------------------- 758 759 static NV_STATUS extractNBSIObjFromDir 760 ( 761 OBJGPU *pGpu, 762 NvU32 idx, 763 PNBSI_DIRECTORY pNbsiDir, 764 NvU32 nbsiDirSize, 765 NvU16 tableLoc, 766 NBSI_GLOB_TYPE wantedGlobType, 767 NvU8 wantedGlobIdx, 768 NvU8 * pActualGlobIdx, 769 PNBSI_GEN_OBJ * pRtnObj, 770 NvU32 * pRtnObjSize, 771 NBSI_VALIDATE validationOption, 772 NvBool * pbFound 773 ) 774 { 775 NV_STATUS status; 776 PNBSI_GEN_OBJ pNbsiGenObj; 777 NvU8 numGlobs; 778 NvU8 curGlob; 779 NvU8 cntOfGlobsWithWantedGlobType; 780 NvBool bMyFound; 781 NvU8 cntOfMatchingGlobTypes; 782 NvU8 thisScore; 783 NvU8 bestDriverObjectMatchScore = 0; 784 PNBSI_GEN_OBJ pBestDriverObjectMatch = NULL; 785 NvU8 bestDriverObjectMatchGlob = 0; 786 NvU8 * tPtr; 787 NvU32 testDirSize; 788 NvU32 driverVersion = 0; 789 NvU32 bestFitDriverVersion = 0; 790 NvBool bCheckCRC = NV_TRUE; 791 792 NV_ASSERT(pNbsiDir); 793 NV_ASSERT(pbFound); 794 NV_ASSERT(pRtnObjSize); 795 NV_ASSERT(pRtnObj); 796 NV_ASSERT(pActualGlobIdx); 797 798 *pbFound = NV_FALSE; 799 800 // test the directory structure integrity 801 status = testNbsiDir(pGpu, 802 idx, 803 pNbsiDir, 804 nbsiDirSize, 805 tableLoc); 806 if (status != NV_OK) 807 { 808 return status; 809 } 810 811 if (wantedGlobType == (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR) 812 { 813 // they want it all. 814 *pbFound = NV_TRUE; 815 *pRtnObj = (PNBSI_GEN_OBJ) pNbsiDir; 816 *pRtnObjSize = nbsiDirSize; 817 *pActualGlobIdx = 1; 818 return NV_OK; 819 } 820 821 // Check if the glob type we want is in the directory 822 status = isGlobTypeInNbsiDir(pNbsiDir, 823 wantedGlobType, 824 &cntOfMatchingGlobTypes, 825 &numGlobs); 826 if (status != NV_OK) 827 { 828 return status; 829 } 830 831 if (cntOfMatchingGlobTypes == 0) 832 { 833 return NV_OK; 834 } 835 836 // Get the NBSI dir size (Varies with directory header). 837 status = getNbsiDirSize(pGpu, 838 idx, 839 pNbsiDir, 840 &testDirSize, 841 tableLoc); 842 if (status != NV_OK) 843 { 844 return status; 845 } 846 847 // point at the first object in the directory to start 848 tPtr = (NvU8 *) pNbsiDir; 849 tPtr = &tPtr[testDirSize]; 850 pNbsiGenObj = (PNBSI_GEN_OBJ) tPtr; 851 852 curGlob = 0; 853 cntOfGlobsWithWantedGlobType = 0; 854 bMyFound = NV_FALSE; 855 while ((status == NV_OK) && 856 !bMyFound && 857 (curGlob < numGlobs) && 858 (cntOfGlobsWithWantedGlobType < cntOfMatchingGlobTypes)) 859 { 860 861 if (validationOption == NBSI_VALIDATE_IGNORE_CRC) 862 { 863 bCheckCRC = NV_FALSE; 864 } 865 866 // Sanity check this object entry 867 status = testNbsiTable(pGpu, 868 (PNBSI_GEN_OBJ) pNbsiGenObj, 869 wantedGlobType, 870 curGlob, 871 idx, 872 tableLoc, 873 nbsiDirSize, 874 TEST_NBSI_TABLE_DO_ALLOC_SIZE_CHECK, 875 bCheckCRC, 876 TEST_NBSI_TABLE_SKIP_GLOBTYPE_CHECK); 877 878 if (status != NV_OK) 879 { 880 // Bad table format. Get out now. 881 return status; 882 } 883 884 if (pNbsiGenObj->objHdr.globType == wantedGlobType) 885 { 886 cntOfGlobsWithWantedGlobType++; 887 if (!wantedGlobIdx || 888 (cntOfGlobsWithWantedGlobType == wantedGlobIdx)) 889 { 890 // if wantedGlobIdx == 0 and driver object do best match 891 if (!wantedGlobIdx && (pNbsiGenObj->objHdr.globType == NBSI_DRIVER)) 892 { 893 // Check the match score for this table 894 thisScore = checkUidMatch(pGpu, 895 (PNBSI_DRIVER_OBJ) pNbsiGenObj, 896 idx, 897 tableLoc, 898 curGlob, 899 &driverVersion); 900 901 // Keep track of the best match 902 if ((thisScore > 0) && 903 ((thisScore > bestDriverObjectMatchScore) || 904 ((thisScore == bestDriverObjectMatchScore) && 905 (driverVersion > bestFitDriverVersion)))) 906 { 907 pBestDriverObjectMatch = pNbsiGenObj; 908 bestDriverObjectMatchGlob = curGlob; 909 bestDriverObjectMatchScore = thisScore; 910 bestFitDriverVersion = driverVersion; 911 } 912 } 913 else 914 { 915 bMyFound = NV_TRUE; 916 } 917 } 918 } 919 920 // if not found yet move to the next object 921 if (!bMyFound) 922 { 923 tPtr = (NvU8 *) pNbsiGenObj; 924 tPtr = &tPtr[pNbsiGenObj->objHdr.size]; 925 pNbsiGenObj = (PNBSI_GEN_OBJ) tPtr; 926 curGlob++; 927 } 928 } 929 930 if ((status == NV_OK) && 931 (pBestDriverObjectMatch != NULL) && 932 (wantedGlobType == NBSI_DRIVER) && 933 !wantedGlobIdx) 934 { 935 // replace last checked with best fit driver glob 936 pNbsiGenObj = pBestDriverObjectMatch; 937 curGlob = bestDriverObjectMatchGlob; 938 bMyFound = NV_TRUE; 939 NV_PRINTF(LEVEL_ERROR, 940 "NBSI Gpu%d Tloc=%d/Glob=%d best fit (score/ver = (%x/%d))\n", 941 idx, tableLoc, bestDriverObjectMatchGlob, 942 bestDriverObjectMatchScore, bestFitDriverVersion); 943 } 944 945 if ((status == NV_OK) && bMyFound) 946 { 947 *pbFound = bMyFound; 948 *pRtnObj = pNbsiGenObj; 949 *pRtnObjSize = pNbsiGenObj->objHdr.size; 950 *pActualGlobIdx = curGlob; 951 } 952 953 return status; 954 } 955 956 //---------------------------------------------------------------------------- 957 // NV_STATUS allocNbsiCache(pGpu, idx, cacheEntries) 958 // 959 // This function allocates a cache table (array) to hold the nbsi object cache 960 // 961 // Input parameters: 962 // pGpu Current pGpu object 963 // idx GPU instance / index 964 // cacheEntries Number of entries to allow 965 // 966 // Output parameters: 967 // NV_STATUS NV_ERR_GENERIC if unable to allocate memory 968 // NV_OK if memory is allocated for cache table. 969 // 970 //---------------------------------------------------------------------------- 971 972 #define NBSI_INITCACHEENTRYCNT 5 973 static NV_STATUS allocNbsiCache 974 ( 975 OBJGPU *pGpu, 976 NvU32 idx, 977 NvU8 cacheEntries 978 ) 979 { 980 NvU32 cacheSize; 981 NBSI_CACHE_OBJ cacheObj; 982 PNBSI_CACHE_OBJ pCacheObj; 983 PNBSI_CACHE_ENTRY_OBJ pCacheEntryObj; 984 NBSI_OBJ *pNbsiObj = getNbsiObject(); 985 NvU8 i; 986 987 NV_ASSERT(pNbsiObj->pTblCache[idx] == NULL); 988 989 cacheSize = sizeof(cacheObj) + 990 (sizeof(pCacheEntryObj) * (cacheEntries - 1)); 991 pNbsiObj->pTblCache[idx] = portMemAllocNonPaged(cacheSize); 992 if (pNbsiObj->pTblCache[idx] == NULL) 993 { 994 NV_PRINTF(LEVEL_ERROR, 995 "Unable to allocate 0x%x memory for NBSI cache.\n", 996 cacheSize); 997 return NV_ERR_NO_MEMORY; 998 } 999 pCacheObj = pNbsiObj->pTblCache[idx]; 1000 pCacheObj->tblCacheNumEntries = 0; 1001 pCacheObj->tblCacheMaxNumEntries = cacheEntries; 1002 for (i = 0; i < cacheEntries; i++) 1003 { 1004 pCacheObj->pCacheEntry[i] = NULL; 1005 } 1006 return NV_OK; 1007 } 1008 1009 //---------------------------------------------------------------------------- 1010 // NV_STATUS addNbsiCacheEntry(pGpu, idx, pTestObj, testObjSize, 1011 // testObjIndex, actualGlobIdx, 1012 // wantedGlobSource, globSource) 1013 // 1014 // This function allocates memory to hold a cached copy of an nbsi object. 1015 // 1016 // Input parameters: 1017 // pGpu Current pGpu object 1018 // idx GPU instance / index 1019 // pTestObj pointer to object to add to the cache 1020 // testObjSize size of object to add to the cache. 1021 // testObjIndex index the object was found in table. 1022 // actualGlobIdx actual glob idx for glob (when testObjIndex=0) 1023 // wantedGlobSource Original desired source directory 1024 // globSource Source of the object 1025 // 1026 // Output parameters: 1027 // NV_STATUS NV_ERR_GENERIC if unable to allocate memory 1028 // NV_OK if memory is allocated for cache table. 1029 // 1030 // Note: If there is not enough room in the cache, the add is skipped. 1031 // This could be changed in the future (by allocating new larger cache 1032 // table, copying the existing table to new larger cache table and 1033 // increase the entry count. Then releasing the previous memory). 1034 // 1035 //---------------------------------------------------------------------------- 1036 1037 static NV_STATUS addNbsiCacheEntry 1038 ( 1039 OBJGPU *pGpu, 1040 NvU32 idx, 1041 PNBSI_GEN_OBJ pTestObj, 1042 NvU32 testObjSize, 1043 NBSI_SOURCE_LOC wantedGlobSource, 1044 NvU8 wantedObjIndex, 1045 NBSI_SOURCE_LOC actualGlobSource, 1046 NvU8 actualGlobIdx 1047 ) 1048 { 1049 NvU8 cacheNdx; 1050 PNBSI_CACHE_OBJ pCacheObj; 1051 NBSI_CACHE_ENTRY_OBJ cacheEntry; 1052 NBSI_OBJ *pNbsiObj = getNbsiObject(); 1053 NvU16 szOfCacheEntry = sizeof(cacheEntry); 1054 1055 NV_ASSERT(pTestObj); 1056 1057 if (pNbsiObj->pTblCache[idx] != NULL) 1058 { 1059 pCacheObj = pNbsiObj->pTblCache[idx]; 1060 cacheNdx = pCacheObj->tblCacheNumEntries; 1061 1062 // 1063 // in the future we may allow growing the table dynamically 1064 // but for now just limit it. 1065 // 1066 if (cacheNdx < pCacheObj->tblCacheMaxNumEntries) 1067 { 1068 // Allocate memory for the new cache entry 1069 pCacheObj->pCacheEntry[cacheNdx] = portMemAllocNonPaged(szOfCacheEntry); 1070 1071 if (pCacheObj->pCacheEntry[cacheNdx] == NULL) 1072 { 1073 NV_PRINTF(LEVEL_ERROR, 1074 "Unable to alloc 0x%x mem for NBSI cache entry\n", 1075 szOfCacheEntry); 1076 return NV_ERR_NO_MEMORY; 1077 } 1078 1079 // Allocate memory for the new cache entry object 1080 pCacheObj->pCacheEntry[cacheNdx]->pObj = portMemAllocNonPaged(testObjSize); 1081 1082 if (pCacheObj->pCacheEntry[cacheNdx]->pObj == NULL) 1083 { 1084 NV_PRINTF(LEVEL_ERROR, 1085 "Unable to alloc 0x%x mem for NBSI cache entry\n", 1086 testObjSize); 1087 return NV_ERR_NO_MEMORY; 1088 } 1089 portMemCopy(pCacheObj->pCacheEntry[cacheNdx]->pObj, testObjSize, pTestObj, testObjSize); 1090 1091 pCacheObj->pCacheEntry[cacheNdx]->globType = pTestObj->objHdr.globType; 1092 pCacheObj->pCacheEntry[cacheNdx]->globSource = wantedGlobSource; 1093 pCacheObj->pCacheEntry[cacheNdx]->globIndex = wantedObjIndex; 1094 pCacheObj->pCacheEntry[cacheNdx]->altGlobSource = 1095 actualGlobSource; 1096 pCacheObj->pCacheEntry[cacheNdx]->altGlobIndex = actualGlobIdx; 1097 cacheNdx++; 1098 pCacheObj->tblCacheNumEntries = cacheNdx; 1099 } 1100 } 1101 return NV_OK; 1102 } 1103 1104 //---------------------------------------------------------------------------- 1105 // NV_STATUS freeNbsiCache(pGpu, idx) 1106 // 1107 // This function frees the memory used for the cache entries and the cache 1108 // table. 1109 // 1110 // Input parameters: 1111 // pGpu Current pGpu object 1112 // idx GPU instance / index 1113 // 1114 // Output parameters: 1115 // NV_STATUS NV_OK 1116 // 1117 //---------------------------------------------------------------------------- 1118 1119 static NV_STATUS freeNbsiCache 1120 ( 1121 OBJGPU *pGpu, 1122 NvU32 idx 1123 ) 1124 { 1125 NBSI_OBJ *pNbsiObj = getNbsiObject(); 1126 PNBSI_CACHE_OBJ pCacheObj; 1127 NvU8 i; 1128 1129 if (pNbsiObj->nbsiDrvrTable[idx] != NULL) 1130 { 1131 // 1132 // the nbsiDrvrTable is just a copy of a pointer in the cache, so we 1133 // just clear the pointer here, and release it with the rest of the 1134 // cache entries 1135 // 1136 1137 pNbsiObj->nbsiDrvrTable[idx] = NULL; 1138 } 1139 1140 // free the memory for the cache entries 1141 if (pNbsiObj->pTblCache[idx] != NULL) 1142 { 1143 pCacheObj = pNbsiObj->pTblCache[idx]; 1144 for (i = 0; i < pCacheObj->tblCacheNumEntries; i++) 1145 { 1146 portMemFree(pCacheObj->pCacheEntry[i]->pObj); 1147 pCacheObj->pCacheEntry[i]->pObj = NULL; 1148 1149 portMemFree(pCacheObj->pCacheEntry[i]); 1150 pCacheObj->pCacheEntry[i] = NULL; 1151 } 1152 1153 // release the memory for the cache table. 1154 pCacheObj->tblCacheNumEntries = 0; 1155 portMemFree(pNbsiObj->pTblCache[idx]); 1156 pNbsiObj->pTblCache[idx] = NULL; 1157 } 1158 return NV_OK; 1159 } 1160 1161 //---------------------------------------------------------------------------- 1162 // NV_STATUS getNbsiCacheInfoForGlobType(pGpu, idx, 1163 // globType, 1164 // *pWantedGlobSource, *pWantedGlobIndex, 1165 // *pNbsiDir, *pNbsiDirSize, *pCurTbl) 1166 // 1167 // This function checks if an object with the globType is in the cache and 1168 // if it is, returns it's info. 1169 // 1170 // Input parameters: 1171 // pGpu Current pGpu object 1172 // idx GPU instance / index 1173 // globType wanted globtype for cache entry. 1174 // pWantedGlobIndex wanted glob index 1175 // pWantedGlobSource wanted glob source 1176 // 1177 // Output parameters: 1178 // NV_STATUS NV_OK if object was found in the cache 1179 // NV_ERR_GENERIC if the object was not found in the cache 1180 // pNbsiDir pointer to object 1181 // pNbsiDirSize size of object found 1182 // pCurTbl index of cache object entry in table 1183 // 1184 //---------------------------------------------------------------------------- 1185 1186 static NV_STATUS getNbsiCacheInfoForGlobType 1187 ( 1188 OBJGPU *pGpu, 1189 NvU32 idx, 1190 NBSI_GLOB_TYPE globType, 1191 NBSI_SOURCE_LOC * pWantedGlobSource, 1192 NvU8 * pWantedGlobIndex, 1193 PNBSI_GEN_OBJ * pNbsiDir, 1194 NvU32 * pNbsiDirSize, 1195 NvU8 * pCurTbl 1196 ) 1197 { 1198 NBSI_OBJ *pNbsiObj = getNbsiObject(); 1199 PNBSI_CACHE_OBJ pCacheObj; 1200 PNBSI_GEN_OBJ pGenObj; 1201 NvU8 curTbl; 1202 1203 NV_ASSERT(pWantedGlobSource); 1204 NV_ASSERT(pWantedGlobIndex); 1205 NV_ASSERT(pNbsiDir); 1206 NV_ASSERT(pNbsiDirSize); 1207 NV_ASSERT(pCurTbl); 1208 1209 if (pNbsiObj->pTblCache[idx] == NULL) 1210 { 1211 return NV_ERR_GENERIC; 1212 } 1213 pCacheObj = pNbsiObj->pTblCache[idx]; 1214 // Check if a cache entry for this globType/wanted idx table exists 1215 *pCurTbl = 0; 1216 1217 for (curTbl = 0; curTbl < pCacheObj->tblCacheNumEntries; curTbl++) 1218 { 1219 if ((pCacheObj->pCacheEntry[curTbl]->globType == globType) && 1220 ((pCacheObj->pCacheEntry[curTbl]->pObj != NULL))) 1221 { 1222 // 1223 // This matches what we want if the globType is correct (dugh) and 1224 // either we want to catch the case where they ask for best fit and 1225 // later ask for the actual source/index we don't want to 1226 // duplicate this entry. The cached entry saves 1) whether this was 1227 // a best fit request in the beginning and it's index 1228 // first check for best fit request. 1229 if ((pCacheObj->pCacheEntry[curTbl]->globSource == 1230 *pWantedGlobSource) && 1231 (pCacheObj->pCacheEntry[curTbl]->globIndex == 1232 *pWantedGlobIndex)) 1233 { 1234 pGenObj = (PNBSI_GEN_OBJ) pCacheObj->pCacheEntry[curTbl]->pObj; 1235 *pNbsiDir = pGenObj; 1236 *pNbsiDirSize = pGenObj->objHdr.size; 1237 if (pCacheObj->pCacheEntry[curTbl]->globSource == 0) 1238 { 1239 *pWantedGlobSource = 1240 pCacheObj->pCacheEntry[curTbl]->altGlobSource; 1241 *pWantedGlobIndex = 1242 pCacheObj->pCacheEntry[curTbl]->altGlobIndex; 1243 } 1244 else 1245 { 1246 *pWantedGlobSource = 1247 pCacheObj->pCacheEntry[curTbl]->globSource; 1248 *pWantedGlobIndex = 1249 pCacheObj->pCacheEntry[curTbl]->globIndex; 1250 } 1251 *pCurTbl = curTbl; 1252 return NV_OK; 1253 } 1254 1255 if ((pCacheObj->pCacheEntry[curTbl]->altGlobSource == 1256 *pWantedGlobSource) && 1257 (pCacheObj->pCacheEntry[curTbl]->altGlobIndex == 1258 *pWantedGlobIndex)) 1259 { 1260 pGenObj = (PNBSI_GEN_OBJ) pCacheObj->pCacheEntry[curTbl]->pObj; 1261 *pNbsiDir = pGenObj; 1262 *pNbsiDirSize = pGenObj->objHdr.size; 1263 *pWantedGlobSource = 1264 pCacheObj->pCacheEntry[curTbl]->altGlobSource; 1265 *pWantedGlobIndex = 1266 pCacheObj->pCacheEntry[curTbl]->altGlobIndex; 1267 *pCurTbl = curTbl; 1268 return NV_OK; 1269 } 1270 } 1271 } 1272 return NV_ERR_GENERIC; 1273 } 1274 1275 //---------------------------------------------------------------------------- 1276 // NV_STATUS getNbsiObjFromCache(pGpu, idx, globType, 1277 // *pWantedGlobSource, *pWantedGlobIdx 1278 // *pRtnObj, *pRtnObjSize, *globTypeRtnStatus 1279 // 1280 // This function returns an object from the cache to the callers memory (if 1281 // it's large enough). If the object is present but the return memory is not 1282 // large enough to hold it, it returns it's size and sets the rtn status to 1283 // incomplete. 1284 // 1285 // Input parameters: 1286 // pGpu Current pGpu object 1287 // idx GPU instance / index 1288 // globType wanted globtype 1289 // pWantedGlobSource wanted glob source / returned glob source 1290 // pWantedGlobIdx wanted glob index 1291 // 1292 // Output parameters: 1293 // NV_STATUS NV_OK if object was found in the cache 1294 // NV_ERR_GENERIC if the object was not found in the cache 1295 // pRtnObj pointer to memory to hold object 1296 // pRtnObjSize pointer to size of memory allocated for object 1297 // pTotalObjSize pointer to return total object size 1298 // globTypeRtnStatus pointer to return status for extra return info. 1299 // NV2080_CTRL_BIOS_GET_NBSI_SUCCESS indicates 1300 // object fit in the pRtnObjSize 1301 // NV2080_CTRL_BIOS_GET_NBSI_INCOMPLETE indicates 1302 // object was found in cache but is too large for 1303 // allocated memory (as per pRtnObjSize). The 1304 // required pRtnObjSize to hold the object is 1305 // returned. 1306 // 1307 //---------------------------------------------------------------------------- 1308 1309 static NV_STATUS getNbsiObjFromCache 1310 ( 1311 OBJGPU *pGpu, 1312 NvU32 idx, 1313 NBSI_GLOB_TYPE globType, 1314 NBSI_SOURCE_LOC * pWantedGlobSource, 1315 NvU8 * pWantedGlobIdx, 1316 NvU32 rtnObjOffset, 1317 PNBSI_GEN_OBJ pRtnObj, 1318 NvU32 * pRtnObjSize, 1319 NvU32 * pTotalObjSize, 1320 NvU32 * globTypeRtnStatus 1321 ) 1322 { 1323 NvU8 curTbl; 1324 PNBSI_GEN_OBJ pTempGlob = NULL; 1325 NvU32 tempGlobSize; 1326 NV_STATUS status; 1327 NvU8 * bufPtr; 1328 1329 NV_ASSERT(pWantedGlobSource); 1330 NV_ASSERT(pWantedGlobIdx); 1331 NV_ASSERT(pRtnObjSize); 1332 NV_ASSERT(!(*pRtnObjSize != 0 && pRtnObj == NULL)); 1333 NV_ASSERT(pTotalObjSize); 1334 NV_ASSERT(globTypeRtnStatus); 1335 1336 // Check if the a cache entry for this NBSI_DRIVER table exists 1337 status = getNbsiCacheInfoForGlobType(pGpu, 1338 idx, 1339 globType, 1340 pWantedGlobSource, 1341 pWantedGlobIdx, 1342 &pTempGlob, 1343 &tempGlobSize, 1344 &curTbl); 1345 1346 // If we found it in cache... return it (if they have enough room) 1347 if (status == NV_OK) 1348 { 1349 NvU32 rtnObjSizeWithOffset; 1350 1351 // return the full table size 1352 *pTotalObjSize = tempGlobSize; 1353 1354 if (!portSafeSubU32(*pTotalObjSize, rtnObjOffset, &rtnObjSizeWithOffset)) 1355 { 1356 // Failed argument validation. 1357 status = NV_ERR_INVALID_OFFSET; 1358 } 1359 else 1360 { 1361 if (*pRtnObjSize >= rtnObjSizeWithOffset) 1362 { 1363 // if rtnsize is larger than remaining part of table, 1364 // then we can return it all this time. 1365 *pRtnObjSize = rtnObjSizeWithOffset; 1366 *globTypeRtnStatus = NV2080_CTRL_BIOS_GET_NBSI_SUCCESS; 1367 } 1368 else 1369 { 1370 // return what we can and indicate incomplete. 1371 *globTypeRtnStatus = NV2080_CTRL_BIOS_GET_NBSI_INCOMPLETE; 1372 } 1373 1374 if (*pRtnObjSize > 0) 1375 { 1376 bufPtr = (NvU8 *) pTempGlob; 1377 bufPtr = &bufPtr[rtnObjOffset]; 1378 portMemCopy(pRtnObj, *pRtnObjSize, bufPtr, *pRtnObjSize); 1379 } 1380 } 1381 } 1382 return status; 1383 } 1384 1385 1386 //---------------------------------------------------------------------------- 1387 // NV_STATUS getNbsiDirFromRegistry(pGpu, idx, 1388 // pNbsiDir, pNbsiDirSize) 1389 // 1390 // This function determines if an emulated NBSI table exists in the registry 1391 // and reads it. 1392 // 1393 // Input parameters: 1394 // pGpu Current pGpu object 1395 // idx GPU instance / index 1396 // 1397 // Output parameters: 1398 // NV_STATUS: NV_OK if there were no operational issues 1399 // (such as memory allocation failure) 1400 // looking for the table... or no registry 1401 // entry exists. 1402 // pNbsiDir pointer to directory object. 1403 // pNbsiDirSize size of directory object found. 1404 // 1405 //---------------------------------------------------------------------------- 1406 1407 static NV_STATUS getNbsiDirFromRegistry 1408 ( 1409 OBJGPU *pGpu, 1410 NvU32 idx, 1411 PNBSI_DIRECTORY * pNbsiDir, 1412 NvU32 * rtnNbsiDirSize 1413 ) 1414 { 1415 NV_STATUS status; 1416 NvU32 nbsiDirSize; 1417 1418 NV_ASSERT_OR_RETURN( pNbsiDir, NV_ERR_INVALID_POINTER ); 1419 NV_ASSERT_OR_RETURN( rtnNbsiDirSize, NV_ERR_INVALID_POINTER ); 1420 1421 // Check if the key is in the registry... and it's size 1422 nbsiDirSize = 0; 1423 status = osReadRegistryStringBase(pGpu, 1424 NV_REG_STR_EMULATED_NBSI_TABLE, 1425 (NvU8 *) *pNbsiDir, 1426 &nbsiDirSize); 1427 1428 // size returned is non 0 so key is present. 1429 if (nbsiDirSize) 1430 { 1431 // do some minimal testing of first block? 1432 if (nbsiDirSize > NBSI_MAX_TABLE_SIZE) 1433 { 1434 NV_PRINTF(LEVEL_ERROR, 1435 "Emulated NBSI table too big. 0x%x > than 0x%x!\n", 1436 nbsiDirSize, NBSI_MAX_TABLE_SIZE); 1437 return NV_ERR_GENERIC; 1438 } 1439 1440 // Allocate memory for the directory 1441 *pNbsiDir = portMemAllocNonPaged(nbsiDirSize); 1442 if (*pNbsiDir == NULL) 1443 { 1444 NV_PRINTF(LEVEL_ERROR, 1445 "Can't allocate 0x%x mem for emulated NBSI table.\n", 1446 nbsiDirSize); 1447 return NV_ERR_NO_MEMORY; 1448 } 1449 1450 // read the table in. 1451 status = osReadRegistryBinary(pGpu, 1452 NV_REG_STR_EMULATED_NBSI_TABLE, 1453 (NvU8 *) *pNbsiDir, 1454 &nbsiDirSize); 1455 if (status != NV_OK) 1456 { 1457 NV_PRINTF(LEVEL_ERROR, 1458 "Unable to read emulated NBSI table from reg.\n"); 1459 portMemFree((void*)pNbsiDir); 1460 pNbsiDir = NULL; 1461 return status; 1462 } 1463 1464 *rtnNbsiDirSize = nbsiDirSize; 1465 return NV_OK; 1466 } 1467 1468 return NV_ERR_GENERIC; 1469 } 1470 1471 //---------------------------------------------------------------------------- 1472 // NV_STATUS determineACPIAccess(pGpu, idx, pRtnMethod, acpiFunction) 1473 // 1474 // This function checks if we have ACPI access to the NBSI table 1475 // 1476 // Input parameters: 1477 // pGpu Current pGpu object 1478 // idx GPU instance / index 1479 // pRtnMethod status for methods available. 1480 // acpiFunction selector for acpi function (nbsi vs hybrid) 1481 // 1482 // Output parameters: 1483 // NV_STATUS: NV_OK if we have access 1484 // !NV_OK if we do not have ACPI access 1485 // 1486 //---------------------------------------------------------------------------- 1487 1488 static NV_STATUS determineACPIAccess 1489 ( 1490 OBJGPU *pGpu, 1491 NvU32 idx, 1492 PNBSI_ACPI_METHOD pRtnMethod, 1493 ACPI_DSM_FUNCTION acpiFunction 1494 ) 1495 { 1496 NV_STATUS status = NV_ERR_NOT_SUPPORTED; 1497 NV_STATUS statusByType = NV_ERR_NOT_SUPPORTED; 1498 NV_STATUS statusAllObj = NV_ERR_NOT_SUPPORTED; 1499 NvU32 getObjectByTypeSubfunction = NV_ACPI_GENERIC_FUNC_GETOBJBYTYPE; 1500 NvU32 getAllObjectsSubfunction = NV_ACPI_GENERIC_FUNC_GETALLOBJS; 1501 1502 NV_ASSERT(pRtnMethod); 1503 *pRtnMethod = NBSI_TBL_SOURCE_ACPI_UNKNOWN; 1504 1505 // Determine the subfunctions for getobjectbytype and getallobjects 1506 status = getDsmGetObjectSubfunction(pGpu, &acpiFunction, &getObjectByTypeSubfunction, &getAllObjectsSubfunction); 1507 if (status != NV_OK) 1508 { 1509 return status; 1510 } 1511 1512 status = testIfDsmSubFunctionEnabled(pGpu, acpiFunction, NV_ACPI_ALL_FUNC_SUPPORT); 1513 if (status != NV_OK) 1514 { 1515 return status; 1516 } 1517 1518 statusByType = testIfDsmSubFunctionEnabled(pGpu, acpiFunction, getObjectByTypeSubfunction); 1519 statusAllObj = testIfDsmSubFunctionEnabled(pGpu, acpiFunction, getAllObjectsSubfunction); 1520 if ((statusByType != NV_OK) && (statusAllObj != NV_OK)) 1521 { 1522 // return if both subfunctions are not supported get out 1523 return NV_ERR_NOT_SUPPORTED; 1524 } 1525 else 1526 { 1527 // one or both should work... indicate which 1528 if ((statusByType == NV_OK) && (statusAllObj == NV_OK)) 1529 { 1530 *pRtnMethod = NBSI_TBL_SOURCE_ACPI_BOTH_METHODS; 1531 } 1532 else if (statusByType == NV_OK) 1533 { 1534 *pRtnMethod = NBSI_TBL_SOURCE_ACPI_BY_OBJ_TYPE; 1535 } 1536 else if (statusAllObj == NV_OK) 1537 { 1538 *pRtnMethod = NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ; 1539 } 1540 status = NV_OK; 1541 } 1542 1543 return status; 1544 } 1545 1546 //---------------------------------------------------------------------------- 1547 // NV_STATUS getNbsiDirectory(pGpu, idx, 1548 // searchDir, *pNbsiDir, *pNbsiDirSize, 1549 // curSource, 1550 // *pbFreeDirMemRequired, 1551 // *pAcpiMethod, 1552 // acpiFunction) 1553 // 1554 // This function gets the NBSI directory (in all but ACPI and UEFI cases) 1555 // 1556 // Input parameters: 1557 // pGpu Current pGpu object 1558 // idx GPU instance / index 1559 // curSource source for the NBSI dir 1560 // acpiFunction selector for acpi function (nbsi vs hybrid) 1561 // 1562 // Output parameters: 1563 // NV_STATUS NV_OK 1564 // *pNbsiDir pointer to return directory found. 1565 // *activeDir bitmap of directory found to search. 1566 // *pNbsiDirSize pointer to the size of the NBSI dir. 1567 // *pbFreeDirMemRequired pointer to NvBool indicating if the directory 1568 // being returned is in newly allocated memory (or 1569 // just a pointer to existing memory ie VBIOS) 1570 // *pAcpiMethod for ACPI based tables, access method(s) 1571 // 1572 //---------------------------------------------------------------------------- 1573 1574 static NV_STATUS getNbsiDirectory 1575 ( 1576 OBJGPU *pGpu, 1577 NvU32 idx, 1578 PNBSI_DIRECTORY * pNbsiDir, 1579 NvU32 * pNbsiDirSize, 1580 NBSI_SOURCE_LOC curSource, 1581 NvBool * pbFreeDirMemRequired, 1582 PNBSI_ACPI_METHOD pAcpiMethod, 1583 ACPI_DSM_FUNCTION acpiFunction 1584 ) 1585 { 1586 NV_STATUS status; 1587 1588 NV_ASSERT(pNbsiDir); 1589 NV_ASSERT(pNbsiDirSize); 1590 NV_ASSERT(pbFreeDirMemRequired); 1591 NV_ASSERT(pAcpiMethod); 1592 1593 *pNbsiDir = NULL; 1594 *pNbsiDirSize = 0; 1595 *pbFreeDirMemRequired = NV_FALSE; 1596 1597 status = NV_ERR_GENERIC; 1598 if (curSource & NBSI_TBL_SOURCE_REGISTRY) 1599 { 1600 status = getNbsiDirFromRegistry(pGpu, 1601 idx, 1602 pNbsiDir, 1603 pNbsiDirSize); 1604 if (status == NV_OK) 1605 { 1606 *pbFreeDirMemRequired = NV_TRUE; 1607 } 1608 } 1609 else if (curSource & NBSI_TBL_SOURCE_VBIOS) 1610 { 1611 return NV_ERR_NOT_SUPPORTED; 1612 } 1613 else if (curSource & NBSI_TBL_SOURCE_SBIOS) 1614 { 1615 return NV_ERR_NOT_SUPPORTED; 1616 } 1617 else if (curSource & NBSI_TBL_SOURCE_ACPI) 1618 { 1619 status = determineACPIAccess(pGpu, idx, pAcpiMethod, acpiFunction); 1620 } 1621 else if (curSource & NBSI_TBL_SOURCE_UEFI) 1622 { 1623 status = NV_OK; 1624 } 1625 1626 return status; 1627 } 1628 1629 //---------------------------------------------------------------------------- 1630 // NV_STATUS nbsiObjTypeCallAcpi(pGpu, 1631 // acpiFunction, 1632 // inOutData, inOutDataSz, 1633 // outBuffer, outBufferSz, globTypeWanted, 1634 // curGlob, * sizeToRead) 1635 // 1636 // This function retrieves an ACPI based object. 1637 // 1638 // Input parameters: 1639 // pGpu Current pGpu object 1640 // acpiFunction selector for acpi function (nbsi vs hybrid) 1641 // inOutData ACPI inout buffer 1642 // inOutDataSz ACPI inout buffer size 1643 // outBuffer output buffer 1644 // outBufferSz output buffer size 1645 // globTypeWanted desired object Type 1646 // curGlob glob index 1647 // *sizeToRead size to read 1648 // 1649 // Output parameters: 1650 // NV_STATUS: NV_OK if there were no operational issues 1651 // Such as bad parameters or failed read. 1652 // rtnSize set to amount read (always set to inOutDataSz) 1653 // 1654 //---------------------------------------------------------------------------- 1655 static NV_STATUS nbsiObjTypeCallAcpi 1656 ( 1657 OBJGPU *pGpu, 1658 ACPI_DSM_FUNCTION acpiFunction, 1659 NvU8 * inOutData, 1660 NvU32 inOutDataSz, 1661 NvU8 * outBuffer, 1662 NvU32 outBufferSz, 1663 NBSI_GLOB_TYPE globTypeWanted, 1664 NvU8 curGlob, 1665 NvU32 * sizeToRead 1666 ) 1667 { 1668 NV_STATUS status = NV_OK; 1669 NvU32 leftToRead; 1670 NvU16 rtnSize; 1671 NvU16 acpiRtnSize = (NvU16) inOutDataSz; 1672 1673 // curGlob fits in 15:12... so make sure we don't ask for anything higher (can happen if the SBIOS keeps sending us the same one). 1674 NV_ASSERT_OR_RETURN((curGlob < 16), NV_ERR_INVALID_ARGUMENT); 1675 1676 leftToRead = *sizeToRead; 1677 *sizeToRead = 0; 1678 while ((status == NV_OK) && (leftToRead)) 1679 { 1680 // 31:16 object type, 15:12 object instance, 11:0 page offset 1681 *(NvU32 *) inOutData = (globTypeWanted & 0xffff) << 16 | 1682 (curGlob & 0xf) << 12 | 1683 ((*sizeToRead/inOutDataSz) & 0xfff); 1684 status = osCallACPI_DSM(pGpu, 1685 acpiFunction, 1686 NV_ACPI_GENERIC_FUNC_GETOBJBYTYPE, 1687 (NvU32 *)inOutData, 1688 (NvU16 *)&acpiRtnSize); 1689 1690 if ((acpiRtnSize == 0) || 1691 ((status == NV_OK) && 1692 (acpiRtnSize==4) && 1693 ((*(NvU32*)inOutData >= NVHG_ERROR_UNSPECIFIED) && 1694 (*(NvU32*)inOutData <= 0x80000005) ))) 1695 { 1696 status = NV_ERR_GENERIC; 1697 } 1698 1699 if (status == NV_OK) 1700 { 1701 rtnSize = NV_MIN((NvU16) leftToRead, (NvU16) acpiRtnSize); 1702 NV_ASSERT((*sizeToRead+rtnSize)<=outBufferSz); 1703 portMemCopy(&outBuffer[*sizeToRead], rtnSize, inOutData, rtnSize); 1704 leftToRead -= rtnSize; 1705 *sizeToRead += rtnSize; 1706 } 1707 } 1708 return status; 1709 } 1710 1711 //---------------------------------------------------------------------------- 1712 // NV_STATUS nbsiObjTypeCallUefi(pGpu, 1713 // inOutData, inOutDataSz, 1714 // outBuffer, outBufferSz, globTypeWanted, 1715 // curGlob, * sizeToRead) 1716 // 1717 // This function retrieves an UEFI based object. 1718 // 1719 // Input parameters: 1720 // pGpu Current pGpu object 1721 // inOutData inout buffer 1722 // inOutDataSz inout buffer size 1723 // outBuffer output buffer 1724 // outBufferSz output buffer size 1725 // globTypeWanted desired object Type 1726 // curGlob glob index 1727 // *sizeToRead size to read 1728 // 1729 // Output parameters: 1730 // NV_STATUS: NV_OK if there were no operational issues 1731 // Such as bad parameters or failed read. 1732 // rtnSize set to amount read (always set to inOutDataSz) 1733 // 1734 //---------------------------------------------------------------------------- 1735 static NV_STATUS nbsiObjTypeCallUefi 1736 ( 1737 OBJGPU *pGpu, 1738 NvU8 * inOutData, 1739 NvU32 inOutDataSz, 1740 NvU8 * outBuffer, 1741 NvU32 outBufferSz, 1742 NBSI_GLOB_TYPE globTypeWanted, 1743 NvU8 curGlob, 1744 NvU32 * sizeToRead 1745 ) 1746 { 1747 NV_STATUS status = NV_OK; 1748 NvU32 uefiRtnSize = inOutDataSz; 1749 char uefiVariableName[] = "NBSI_GLOB_000"; 1750 1751 NV_ASSERT_OR_RETURN(curGlob < 16, NV_ERR_INVALID_ARGUMENT); 1752 1753 // Per Matt's recommendation, only support glob type "OP" for now. 1754 if (globTypeWanted != NBSI_OPTIMUS_PLAT) 1755 { 1756 return NV_ERR_NOT_SUPPORTED; 1757 } 1758 1759 // Change 000 in variable name to glob type and instance hex digit. 1760 uefiVariableName[10] = (globTypeWanted & 0xFF00) >> 8; 1761 uefiVariableName[11] = globTypeWanted & 0xFF; 1762 uefiVariableName[12] = curGlob + (curGlob < 10 ? '0' : 'A' - 10); 1763 1764 status = pGpu->pOS->osGetUefiVariable(pGpu, 1765 uefiVariableName, 1766 (LPGUID)&NV_GUID_UEFI_VARIABLE, 1767 inOutData, 1768 &uefiRtnSize, 1769 NULL); 1770 1771 if (status == NV_OK) 1772 { 1773 portMemCopy(outBuffer, uefiRtnSize, inOutData, uefiRtnSize); 1774 *sizeToRead = uefiRtnSize; 1775 } 1776 return status; 1777 } 1778 1779 //---------------------------------------------------------------------------- 1780 // NV_STATUS getTableDataUsingObjTypeCall(pGpu, 1781 // curDir, acpiFunction, 1782 // inOutData, inOutDataSz, 1783 // outBuffer, outBufferSz, globTypeWanted, 1784 // curGlob, * sizeToRead) 1785 // 1786 // This function retrieves an ACPI based object. 1787 // With RID 61791, also supports objects as UEFI runtime variables. 1788 // 1789 // Input parameters: 1790 // pGpu Current pGpu object 1791 // curDir table source (acpi vs uefi) 1792 // acpiFunction selector for acpi function (nbsi vs hybrid) 1793 // inOutData ACPI inout buffer 1794 // inOutDataSz ACPI inout buffer size 1795 // outBuffer output buffer 1796 // outBufferSz output buffer size 1797 // globTypeWanted desired object Type 1798 // curGlob glob index 1799 // *sizeToRead size to read 1800 // 1801 // Output parameters: 1802 // NV_STATUS: NV_OK if there were no operational issues 1803 // Such as bad parameters or failed read. 1804 // rtnSize set to amount read (always set to inOutDataSz) 1805 // 1806 //---------------------------------------------------------------------------- 1807 static NV_STATUS getTableDataUsingObjTypeCall 1808 ( 1809 OBJGPU *pGpu, 1810 NvU16 curDir, 1811 ACPI_DSM_FUNCTION acpiFunction, 1812 NvU8 * inOutData, 1813 NvU32 inOutDataSz, 1814 NvU8 * outBuffer, 1815 NvU32 outBufferSz, 1816 NBSI_GLOB_TYPE globTypeWanted, 1817 NvU8 curGlob, 1818 NvU32 * sizeToRead 1819 ) 1820 { 1821 NV_STATUS status = NV_OK; 1822 1823 NV_ASSERT(inOutData); 1824 NV_ASSERT(outBuffer); 1825 NV_ASSERT(sizeToRead); 1826 NV_ASSERT(!(*sizeToRead > outBufferSz)); 1827 1828 if (*sizeToRead > outBufferSz) 1829 { 1830 return NV_ERR_GENERIC; 1831 } 1832 1833 if (curDir == NBSI_TBL_SOURCE_ACPI) 1834 { 1835 status = nbsiObjTypeCallAcpi(pGpu, 1836 acpiFunction, 1837 inOutData, 1838 inOutDataSz, 1839 outBuffer, 1840 outBufferSz, 1841 globTypeWanted, 1842 curGlob, 1843 sizeToRead); 1844 } 1845 else if (curDir == NBSI_TBL_SOURCE_UEFI) 1846 { 1847 status = nbsiObjTypeCallUefi(pGpu, 1848 inOutData, 1849 inOutDataSz, 1850 outBuffer, 1851 outBufferSz, 1852 globTypeWanted, 1853 curGlob, 1854 sizeToRead); 1855 } 1856 else 1857 { 1858 status = NV_ERR_INVALID_ARGUMENT; 1859 } 1860 return status; 1861 } 1862 1863 //---------------------------------------------------------------------------- 1864 // NV_STATUS getTableUsingObjTypeCall(pGpu, idx, 1865 // curDir, 1866 // acpiFunction, validationOption, 1867 // wantedGlobType, pActualGlobIdx, 1868 // inOutData, inOutDataSz, tmpBuffer, tmpBufferSz) 1869 // 1870 // This function queries for the ACPI based NBSI table and checks the headers. 1871 // With RID 67191, also supports querying via UEFI runtime variables. 1872 // 1873 // Input parameters: 1874 // pGpu Current pGpu object 1875 // idx index to current gpu 1876 // curDir table source (acpi vs uefi) 1877 // acpiFunction selector for acpi function (nbsi vs hybrid) 1878 // validationOption test validation option 1879 // wantedGlobType glob type wanted 1880 // wantedGlobIdx glob type index wanted 1881 // pActualGlobIdx pointer to actual index found 1882 // inOutData acpi inout buffer for reads 1883 // inOutDataSz size of acpi inout buffer 1884 // tmpBuffer temporary buffer for data manipulation 1885 // (should be equal to inOutDataSz) 1886 // tmpBufferSz size of temporary buffer 1887 // 1888 // Output parameters: 1889 // pRtnObj pointer to return object 1890 // pRtnObjSize pointer to return object size 1891 // pbFound pointer to NvBool indicating object was found 1892 // status == NV_OK no issues in looking for object (although 1893 // object may or may not be present... see 1894 // pbFound) 1895 // status != NV_OK if error occurred while getting the object 1896 // 1897 //---------------------------------------------------------------------------- 1898 1899 static NV_STATUS getTableUsingObjTypeCall 1900 ( 1901 OBJGPU *pGpu, 1902 NvU32 idx, 1903 NvU16 curDir, 1904 ACPI_DSM_FUNCTION acpiFunction, 1905 NBSI_VALIDATE validationOption, 1906 NBSI_GLOB_TYPE wantedGlobType, 1907 NvU8 wantedGlobIdx, 1908 NvU8 * pActualGlobIdx, 1909 PNBSI_GEN_OBJ * pRtnObj, 1910 NvU32 * pRtnObjSize, 1911 NvBool * pbFound, 1912 NvU8 * inOutData, 1913 NvU32 inOutDataSz, 1914 NvU8 * tmpBuffer, 1915 NvU32 tmpBufferSz 1916 ) 1917 { 1918 NV_STATUS status = NV_OK; 1919 PNBSI_DRIVER_OBJ pNbsiDrvrObj; 1920 NBSI_DRIVER_OBJ nbsiDriverObj; 1921 NvU32 drvrObjHdrSize = sizeof(nbsiDriverObj) - 1922 sizeof(nbsiDriverObj.objData); 1923 NvU8 curGlob; 1924 NvU32 curGlobSize; 1925 NvU32 rtnSize; 1926 NvU8 thisScore; 1927 NvBool bMyFound; 1928 NvU8 bestDriverObjectMatchScore = 0; 1929 NvU8 bestDriverObjectMatchGlob = 0; 1930 NvU32 bestDriverObjectMatchSize = 0; 1931 NvU32 driverVersion = 0; 1932 NvU32 bestFitDriverVersion = 0; 1933 NvBool bCheckCRC = NV_TRUE; 1934 1935 NV_ASSERT(pRtnObj); 1936 NV_ASSERT(pRtnObjSize); 1937 NV_ASSERT(pbFound); 1938 NV_ASSERT(pActualGlobIdx); 1939 NV_ASSERT(inOutData); 1940 NV_ASSERT(tmpBuffer); 1941 1942 *pbFound = NV_FALSE; 1943 1944 if (wantedGlobType == (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR) 1945 { 1946 // shouldn't get here... we can't handle this with get obj type call 1947 return NV_ERR_GENERIC; 1948 } 1949 1950 if (wantedGlobIdx) 1951 { 1952 curGlob = wantedGlobIdx; 1953 } 1954 else 1955 { 1956 curGlob = 0; 1957 } 1958 1959 bMyFound = NV_FALSE; 1960 curGlobSize = 0; 1961 while ((status == NV_OK) && !bMyFound) 1962 { 1963 // try to read curGlobHeader for this type 1964 rtnSize = drvrObjHdrSize; 1965 status = getTableDataUsingObjTypeCall(pGpu, 1966 curDir, 1967 acpiFunction, 1968 inOutData, 1969 inOutDataSz, 1970 tmpBuffer, 1971 tmpBufferSz, 1972 wantedGlobType, 1973 curGlob, 1974 &rtnSize); 1975 1976 if (status != NV_OK) 1977 { 1978 // error returned on get, must be no more globs 1979 break; 1980 } 1981 1982 // Confirm this glob header looks okay. 1983 pNbsiDrvrObj = (PNBSI_DRIVER_OBJ) tmpBuffer; 1984 status = testNbsiTable(pGpu, 1985 (PNBSI_GEN_OBJ) pNbsiDrvrObj, 1986 wantedGlobType, 1987 curGlob, 1988 idx, 1989 NBSI_TBL_SOURCE_ACPI_BY_OBJ_TYPE, 1990 tmpBufferSz, 1991 TEST_NBSI_TABLE_SKIP_ALLOC_SIZE_CHECK, 1992 TEST_NBSI_TABLE_SKIP_HASH_CHECK, 1993 TEST_NBSI_TABLE_DO_GLOBTYPE_CHECK); 1994 if (status != NV_OK) 1995 { 1996 // bad table format 1997 // pNbsiObj->nbsiTableState[idx][objt] = NBSI_TABLE_BAD; 1998 return status; 1999 } 2000 2001 // if they wanted a specific glob index we're done 2002 if (wantedGlobIdx || (wantedGlobType != NBSI_DRIVER)) 2003 { 2004 // we've got the header for the glob we want 2005 curGlobSize = pNbsiDrvrObj->objHdr.size; 2006 bMyFound = NV_TRUE; 2007 } 2008 else 2009 { 2010 // we need to find the best fit NBSI_DRIVER 2011 // Check the match score for this table 2012 thisScore = checkUidMatch(pGpu, 2013 (PNBSI_DRIVER_OBJ) pNbsiDrvrObj, 2014 idx, 2015 NBSI_TBL_SOURCE_ACPI_BY_OBJ_TYPE, 2016 curGlob, 2017 &driverVersion); 2018 2019 // Keep track of the best match 2020 if ((thisScore > 0) && 2021 ((thisScore > bestDriverObjectMatchScore) || 2022 ((thisScore == bestDriverObjectMatchScore) && 2023 (driverVersion > bestFitDriverVersion)))) 2024 { 2025 bestDriverObjectMatchGlob = curGlob; 2026 bestDriverObjectMatchScore = thisScore; 2027 bestDriverObjectMatchSize = pNbsiDrvrObj->objHdr.size; 2028 bestFitDriverVersion = driverVersion; 2029 } 2030 } 2031 if (!bMyFound) 2032 { 2033 curGlob++; 2034 } 2035 } 2036 2037 if (bestDriverObjectMatchSize && 2038 (wantedGlobType == NBSI_DRIVER) && 2039 !wantedGlobIdx) 2040 { 2041 // replace last checked with best fit driver glob 2042 curGlob = bestDriverObjectMatchGlob; 2043 curGlobSize = bestDriverObjectMatchSize; 2044 bMyFound = NV_TRUE; 2045 NV_PRINTF(LEVEL_ERROR, 2046 "NBSI Gpu%d Tloc=%d/Glob=%d best fit (score/ver = (%x/%d))\n", 2047 idx, NBSI_TBL_SOURCE_ACPI_BY_OBJ_TYPE, 2048 bestDriverObjectMatchGlob, bestDriverObjectMatchScore, 2049 bestFitDriverVersion); 2050 } 2051 2052 if (bMyFound) 2053 { 2054 // we know which glob number we want to get the entire glob for 2055 // allocate memory to return the entire glob in 2056 pNbsiDrvrObj = portMemAllocNonPaged(curGlobSize); 2057 if (pNbsiDrvrObj == NULL) 2058 { 2059 NV_PRINTF(LEVEL_ERROR, 2060 "Can't alloc 0x%x bytes for ACPI NBSI table.\n", 2061 curGlobSize); 2062 return NV_ERR_GENERIC; 2063 } 2064 2065 // read all of the current glob in 2066 rtnSize = curGlobSize; 2067 status = getTableDataUsingObjTypeCall(pGpu, 2068 curDir, 2069 acpiFunction, 2070 inOutData, 2071 inOutDataSz, 2072 (NvU8 *) pNbsiDrvrObj, 2073 curGlobSize, 2074 wantedGlobType, 2075 curGlob, 2076 &rtnSize); 2077 2078 if (status != NV_OK) 2079 { 2080 // this shouldn't happen since we did this once before 2081 portMemFree(pNbsiDrvrObj); 2082 pNbsiDrvrObj = NULL; 2083 return status; 2084 } 2085 2086 if (validationOption == NBSI_VALIDATE_IGNORE_CRC) 2087 { 2088 bCheckCRC = NV_FALSE; 2089 } 2090 2091 // Confirm this glob header looks okay. 2092 status = testNbsiTable(pGpu, 2093 (PNBSI_GEN_OBJ) pNbsiDrvrObj, 2094 wantedGlobType, 2095 curGlob, 2096 idx, 2097 NBSI_TBL_SOURCE_ACPI_BY_OBJ_TYPE, 2098 curGlobSize, 2099 TEST_NBSI_TABLE_DO_ALLOC_SIZE_CHECK, 2100 bCheckCRC, 2101 TEST_NBSI_TABLE_DO_GLOBTYPE_CHECK); 2102 if (status != NV_OK) 2103 { 2104 // bad table format (most likely hash test failure) 2105 portMemFree(pNbsiDrvrObj); 2106 pNbsiDrvrObj = NULL; 2107 return status; 2108 } 2109 2110 *pRtnObj = (PNBSI_GEN_OBJ) pNbsiDrvrObj; 2111 *pRtnObjSize = pNbsiDrvrObj->objHdr.size; 2112 *pActualGlobIdx = curGlob; 2113 *pbFound = NV_TRUE; 2114 } 2115 return status; 2116 } 2117 2118 //---------------------------------------------------------------------------- 2119 // NV_STATUS getTableDataUsingAllObjectCall(pGpu, acpiFunction, 2120 // inOutData, inOutDataSz, 2121 // outBuffer, outBufferSz, 2122 // curOffset, *sizeToRead) 2123 // 2124 // This function queries for the ACPI based NBSI table. 2125 // 2126 // Input parameters: 2127 // pGpu Current pGpu object 2128 // acpiFunction selector for acpi function (nbsi vs hybrid) 2129 // inOutData ACPI inout buffer 2130 // inOutDataSz ACPI inout buffer size 2131 // outBuffer output buffer 2132 // outBufferSz output buffer size 2133 // *curOffset offset to read from 2134 // *sizeToRead size to read 2135 // 2136 // Output parameters: 2137 // NV_STATUS: NV_OK if there were no operational issues 2138 // Such as bad parameters or failed read. 2139 // curOffset set to original offset plus rtnsize 2140 // rtnSize set to amount read. 2141 // 2142 //---------------------------------------------------------------------------- 2143 2144 static NV_STATUS getTableDataUsingAllObjectCall 2145 ( 2146 OBJGPU *pGpu, 2147 ACPI_DSM_FUNCTION acpiFunction, 2148 NvU8 * inOutData, 2149 NvU32 inOutDataSz, 2150 NvU8 * outBuffer, 2151 NvU32 outBufferSz, 2152 NvU32 curOffset, 2153 NvU32 * sizeToRead 2154 ) 2155 { 2156 NV_STATUS status = NV_OK; 2157 NvU32 leftToRead; 2158 NvU32 bufferOffset; 2159 NvU32 rtnSize = 0; 2160 NvU16 acpiRtnSize = (NvU16) inOutDataSz; 2161 2162 NV_ASSERT(inOutData); 2163 NV_ASSERT(outBuffer); 2164 NV_ASSERT(sizeToRead); 2165 NV_ASSERT(!(*sizeToRead > outBufferSz)); 2166 2167 if (*sizeToRead > outBufferSz) 2168 { 2169 return NV_ERR_GENERIC; 2170 } 2171 2172 leftToRead = *sizeToRead; 2173 *sizeToRead = 0; 2174 while ((status == NV_OK) && (leftToRead)) 2175 { 2176 // get page the data is in. 2177 *(NvU32 *) inOutData = curOffset / inOutDataSz; 2178 status = osCallACPI_DSM(pGpu, 2179 acpiFunction, 2180 NV_ACPI_GENERIC_FUNC_GETALLOBJS, 2181 (NvU32 *)inOutData, 2182 (NvU16 *)&rtnSize); 2183 if ((acpiRtnSize == 0) || 2184 ((status == NV_OK) && 2185 (acpiRtnSize==4) && 2186 ((*(NvU32*)inOutData >= NVHG_ERROR_UNSPECIFIED) && 2187 (*(NvU32*)inOutData <= 0x80000005) ))) 2188 { 2189 status = NV_ERR_GENERIC; 2190 } 2191 2192 if (status == NV_OK) 2193 { 2194 bufferOffset = curOffset % inOutDataSz; 2195 if ((bufferOffset + leftToRead) > acpiRtnSize) 2196 { 2197 rtnSize = acpiRtnSize - bufferOffset; 2198 } 2199 else 2200 { 2201 rtnSize = leftToRead; 2202 } 2203 NV_ASSERT((*sizeToRead+rtnSize)<=outBufferSz); 2204 portMemCopy(&outBuffer[*sizeToRead], rtnSize, &inOutData[curOffset % inOutDataSz], rtnSize); 2205 leftToRead -= rtnSize; 2206 *sizeToRead += rtnSize; 2207 curOffset += rtnSize; 2208 } 2209 } 2210 return status; 2211 } 2212 2213 //---------------------------------------------------------------------------- 2214 // NV_STATUS getTableUsingAllObjectCall(pGpu, idx, 2215 // acpiFunction, validationOption, 2216 // wantedGlobType, wantedGlobIdx, 2217 // *pActualGlobIdx, 2218 // *pRtnObj, *pRtnObjSize, *pbFound, 2219 // inOutData, inOutDataSz, tmpBuffer, 2220 // tmpBufferSz) 2221 // 2222 // This function queries for the ACPI based NBSI table. 2223 // 2224 // Input parameters: 2225 // pGpu Current pGpu object 2226 // idx index to current gpu 2227 // acpiFunction selector for acpi function (nbsi vs hybrid) 2228 // validationOption test validation option 2229 // wantedGlobType desired glob type 2230 // wantedGlobIdx desired glob index 2231 // pActualGlobIdx pointer to actual index wanted object is at 2232 // inOutData acpi inout buffer for reads 2233 // inOutDataSz size of acpi inout buffer 2234 // tmpBuffer temporary buffer for data manipulation 2235 // (should be equal to inOutDataSz) 2236 // tmpBufferSz size of temporary buffer 2237 // 2238 // Output parameters: 2239 // pRtnObj pointer to return object 2240 // pRtnObjSize pointer to return object size 2241 // pbFound pointer to NvBool indicating object was found 2242 // status == NV_OK no issues in looking for object (although 2243 // object may or may not be present... see 2244 // pbFound) 2245 // status != NV_OK if error occurred while getting the object 2246 // 2247 //---------------------------------------------------------------------------- 2248 2249 static NV_STATUS getTableUsingAllObjectCall 2250 ( 2251 OBJGPU *pGpu, 2252 NvU32 idx, 2253 ACPI_DSM_FUNCTION acpiFunction, 2254 NBSI_VALIDATE validationOption, 2255 NBSI_GLOB_TYPE wantedGlobType, 2256 NvU8 wantedGlobIdx, 2257 NvU8 * pActualGlobIdx, 2258 PNBSI_GEN_OBJ * pRtnObj, 2259 NvU32 * pRtnObjSize, 2260 NvBool * pbFound, 2261 NvU8 * inOutData, 2262 NvU32 inOutDataSz, 2263 NvU8 * tmpBuffer, 2264 NvU32 tmpBufferSz 2265 ) 2266 { 2267 NV_STATUS status = NV_OK; 2268 PNBSI_DIRECTORY pNbsiDir; 2269 NvU32 nbsiDirSize; 2270 PNBSI_DRIVER_OBJ pNbsiDrvrObj; 2271 NBSI_DRIVER_OBJ nbsiDrvrObj; 2272 NvU8 numGlobs; 2273 NvU8 curGlob; 2274 NvU32 curGlobSize; 2275 NvU8 cntOfGlobsWithWantedGlobType; 2276 NvU8 cntOfMatchingGlobTypes; 2277 NvU32 rtnSize; 2278 NvU8 thisScore; 2279 NvBool bMyFound; 2280 NvU8 bestDriverObjectMatchScore = 0; 2281 NvU32 bestDriverObjectMatchOffset = 0; 2282 NvU32 bestDriverObjectMatchSize = 0; 2283 NvU8 bestDriverObjectIndex = 0; 2284 NvU32 curOffset; 2285 NvU32 dirContentsSize = 0; 2286 NvU32 driverVersion = 0; 2287 NvU32 bestFitDriverVersion = 0; 2288 NvBool bCheckCRC = NV_TRUE; 2289 2290 NV_ASSERT(pRtnObj); 2291 NV_ASSERT(pRtnObjSize); 2292 NV_ASSERT(pActualGlobIdx); 2293 NV_ASSERT(pbFound); 2294 NV_ASSERT(inOutData); 2295 NV_ASSERT(tmpBuffer); 2296 2297 *pbFound = NV_FALSE; 2298 2299 // read in the directory (assume new format and one globtype entry) 2300 nbsiDirSize = sizeof(pNbsiDir->d); 2301 rtnSize = nbsiDirSize; 2302 curOffset = 0; 2303 status = getTableDataUsingAllObjectCall(pGpu, 2304 acpiFunction, 2305 inOutData, 2306 inOutDataSz, 2307 tmpBuffer, 2308 tmpBufferSz, 2309 curOffset, 2310 &rtnSize); 2311 if (status != NV_OK) 2312 { 2313 // error returned on get, must be no more globs 2314 return status; 2315 } 2316 2317 // determine the size of the directory 2318 pNbsiDir = (PNBSI_DIRECTORY) tmpBuffer; 2319 status = getNbsiDirSize(pGpu, 2320 idx, 2321 pNbsiDir, 2322 &nbsiDirSize, 2323 NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ); 2324 if (status != NV_OK) 2325 { 2326 // error returned on get, must be no more globs 2327 return status; 2328 } 2329 2330 // read all of the directory this time 2331 curOffset = 0; 2332 rtnSize = nbsiDirSize; 2333 status = getTableDataUsingAllObjectCall(pGpu, 2334 acpiFunction, 2335 inOutData, 2336 inOutDataSz, 2337 tmpBuffer, 2338 tmpBufferSz, 2339 curOffset, 2340 &rtnSize); 2341 if (status != NV_OK) 2342 { 2343 // error returned on get, must be no more globs 2344 return status; 2345 } 2346 2347 status = testNbsiDir(pGpu, 2348 idx, 2349 pNbsiDir, 2350 nbsiDirSize, 2351 NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ); 2352 if (status != NV_OK) 2353 { 2354 return status; 2355 } 2356 2357 status = isGlobTypeInNbsiDir(pNbsiDir, 2358 wantedGlobType, 2359 &cntOfMatchingGlobTypes, 2360 &numGlobs); 2361 if (status != NV_OK) 2362 { 2363 return status; 2364 } 2365 2366 if (cntOfMatchingGlobTypes == 0) 2367 { 2368 return NV_OK; 2369 } 2370 2371 // point at the first object in the directory 2372 curOffset += nbsiDirSize; 2373 2374 curGlob = 0; 2375 cntOfGlobsWithWantedGlobType = 0; 2376 curGlobSize = 0; 2377 bMyFound = NV_FALSE; 2378 while ((status == NV_OK) && 2379 !bMyFound && 2380 (curGlob < numGlobs) && 2381 (cntOfGlobsWithWantedGlobType < cntOfMatchingGlobTypes)) 2382 { 2383 // read the generic object so we can test. 2384 rtnSize = sizeof(nbsiDrvrObj) - sizeof(nbsiDrvrObj.objData); 2385 status = getTableDataUsingAllObjectCall(pGpu, 2386 acpiFunction, 2387 inOutData, 2388 inOutDataSz, 2389 tmpBuffer, 2390 tmpBufferSz, 2391 curOffset, 2392 &rtnSize); 2393 if (status != NV_OK) 2394 { 2395 // error returned on get, must be no more globs 2396 break; 2397 } 2398 2399 // Confirm this glob header looks okay. 2400 pNbsiDrvrObj = (PNBSI_DRIVER_OBJ) tmpBuffer; 2401 status = testNbsiTable(pGpu, 2402 (PNBSI_GEN_OBJ) pNbsiDrvrObj, 2403 wantedGlobType, 2404 curGlob, 2405 idx, 2406 NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ, 2407 tmpBufferSz, 2408 TEST_NBSI_TABLE_SKIP_ALLOC_SIZE_CHECK, 2409 TEST_NBSI_TABLE_SKIP_HASH_CHECK, 2410 TEST_NBSI_TABLE_SKIP_GLOBTYPE_CHECK); 2411 if (status != NV_OK) 2412 { 2413 // bad table format 2414 // pNbsiObj->nbsiTableState[idx][objt] = NBSI_TABLE_BAD; 2415 return status; 2416 } 2417 2418 curGlob++; 2419 if (wantedGlobType == (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR) 2420 { 2421 dirContentsSize += pNbsiDrvrObj->objHdr.size; 2422 } 2423 else 2424 { 2425 if (pNbsiDrvrObj->objHdr.globType == wantedGlobType) 2426 { 2427 cntOfGlobsWithWantedGlobType++; 2428 // if want best fit (wantedGlobIdx==0) or we are at real one 2429 if (!wantedGlobIdx || 2430 (cntOfGlobsWithWantedGlobType == wantedGlobIdx)) 2431 { 2432 curGlobSize = pNbsiDrvrObj->objHdr.size; 2433 // if wantedGlobIdx == 0 and driver object use best match 2434 if (!wantedGlobIdx && 2435 (pNbsiDrvrObj->objHdr.globType == NBSI_DRIVER)) 2436 { 2437 // Check the match score for this table 2438 thisScore = 2439 checkUidMatch(pGpu, 2440 (PNBSI_DRIVER_OBJ) pNbsiDrvrObj, 2441 idx, 2442 NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ, 2443 curGlob, 2444 &driverVersion); 2445 2446 // Keep track of the best match 2447 if ((thisScore > 0) && 2448 ((thisScore > bestDriverObjectMatchScore) || 2449 ((thisScore == bestDriverObjectMatchScore) && 2450 (driverVersion > bestFitDriverVersion)))) 2451 { 2452 bestDriverObjectMatchSize = pNbsiDrvrObj->objHdr.size; 2453 bestDriverObjectMatchOffset = curOffset; 2454 bestDriverObjectMatchScore = thisScore; 2455 bestDriverObjectIndex = 2456 cntOfGlobsWithWantedGlobType; 2457 bestFitDriverVersion = driverVersion; 2458 } 2459 } 2460 else 2461 { 2462 bestDriverObjectIndex = cntOfGlobsWithWantedGlobType; 2463 bMyFound = NV_TRUE; 2464 } 2465 } 2466 } 2467 } 2468 2469 // if not found yet move to the next object 2470 if (!bMyFound) 2471 { 2472 curOffset = curOffset + pNbsiDrvrObj->objHdr.size; 2473 } 2474 } 2475 2476 if ((status == NV_OK) && 2477 bestDriverObjectMatchSize && 2478 (wantedGlobType == NBSI_DRIVER) && 2479 !wantedGlobIdx) 2480 { 2481 // replace last checked with best fit driver glob 2482 curOffset = bestDriverObjectMatchOffset; 2483 curGlobSize = bestDriverObjectMatchSize; 2484 bMyFound = NV_TRUE; 2485 NV_PRINTF(LEVEL_ERROR, 2486 "NBSI Gpu%d Tloc=%d/Glob=%d best fit (score/ver = (%x/%d))\n", 2487 idx, NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ, 2488 bestDriverObjectIndex, bestDriverObjectMatchScore, 2489 bestFitDriverVersion); 2490 } 2491 2492 if ((wantedGlobType == (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR) && 2493 ((nbsiDirSize + dirContentsSize) > 0) && 2494 (status == NV_OK)) 2495 { 2496 curOffset = 0; 2497 curGlob = 0; 2498 bestDriverObjectIndex = 0; 2499 curGlobSize = nbsiDirSize + dirContentsSize; 2500 bMyFound = NV_TRUE; 2501 } 2502 2503 if ((status == NV_OK) && bMyFound) 2504 { 2505 // we know which glob number we want to get the entire glob for 2506 // allocate memory to return the entire glob in 2507 pNbsiDrvrObj = portMemAllocNonPaged(curGlobSize); 2508 if (pNbsiDrvrObj == NULL) 2509 { 2510 NV_PRINTF(LEVEL_ERROR, 2511 "Can't alloc 0x%x bytes for ACPI NBSI table.\n", 2512 curGlobSize); 2513 return NV_ERR_GENERIC; 2514 } 2515 2516 // read all of the current glob in 2517 rtnSize = curGlobSize; 2518 status = getTableDataUsingAllObjectCall(pGpu, 2519 acpiFunction, 2520 inOutData, 2521 inOutDataSz, 2522 (NvU8 *) pNbsiDrvrObj, 2523 curGlobSize, 2524 curOffset, 2525 &rtnSize); 2526 if (status != NV_OK) 2527 { 2528 // this shouldn't happen since we did this once before 2529 portMemFree(pNbsiDrvrObj); 2530 pNbsiDrvrObj = NULL; 2531 return status; 2532 } 2533 2534 if (wantedGlobType != (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR) 2535 { 2536 if (validationOption == NBSI_VALIDATE_IGNORE_CRC) 2537 { 2538 bCheckCRC = NV_FALSE; 2539 } 2540 2541 // Confirm this glob header looks okay. 2542 status = testNbsiTable(pGpu, 2543 (PNBSI_GEN_OBJ) pNbsiDrvrObj, 2544 wantedGlobType, 2545 curGlob, 2546 idx, 2547 NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ, 2548 curGlobSize, 2549 TEST_NBSI_TABLE_DO_ALLOC_SIZE_CHECK, 2550 bCheckCRC, 2551 TEST_NBSI_TABLE_DO_GLOBTYPE_CHECK); 2552 if (status != NV_OK) 2553 { 2554 // bad table format (most likely hash test failure) 2555 portMemFree(pNbsiDrvrObj); 2556 pNbsiDrvrObj = NULL; 2557 return status; 2558 } 2559 } 2560 2561 *pRtnObj = (PNBSI_GEN_OBJ) pNbsiDrvrObj; 2562 if (wantedGlobType == (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR) 2563 { 2564 *pRtnObjSize = curGlobSize; 2565 *pActualGlobIdx = curGlob; 2566 } 2567 else 2568 { 2569 *pRtnObjSize = pNbsiDrvrObj->objHdr.size; 2570 *pActualGlobIdx = bestDriverObjectIndex; 2571 } 2572 *pbFound = NV_TRUE; 2573 } 2574 return status; 2575 } 2576 2577 //---------------------------------------------------------------------------- 2578 // NV_STATUS _extractNBSIObjFromACPIDir(pGpu, idx, 2579 // curDir, 2580 // acpiFunction, validationOption, acpiMethod, 2581 // wantedGlobType, wantedGlobIdx, 2582 // pActualGlobIdx, 2583 // *pRtnObj, *pRtnObjSize, *pbFound) 2584 // 2585 // This extracts an NBSI from an ACPI directory. 2586 // With RID 67191, also supports BY_OBJ_TYPE retrieval via UEFI runtime 2587 // variables. 2588 // 2589 // Input parameters: 2590 // pGpu Current pGpu object 2591 // idx GPU instance / index 2592 // curDir table source (acpi or uefi) 2593 // acpiFunction selector for acpi function (nbsi vs hybrid) 2594 // validationOption test validation option 2595 // acpiMethod Acpi method(s) available to access table 2596 // wantedGlobType desired globtype 2597 // wantedGlobIdx desired glob index 2598 // pActualGlobIdx rtn actual index. 2599 // pRtnObj pointer to memory allocated for return object 2600 // (or NULL if pRtnObjSize is 0) 2601 // pRtnObjSize pointer to return object size (use 0 to query 2602 // for object presence and size. (query will cache 2603 // if globIdx is 0 and room is available in cache) 2604 // pbFound pointer to NvBool for return status. 2605 // 2606 // Output parameters: 2607 // NV_STATUS: NV_OK if there were no operational issues 2608 // (such as memory allocation failure) 2609 // looking for the table. 2610 // *pRtnObj pointer to return object (if pbFound=NV_TRUE) 2611 // *pRtnObjSize pointer to return object size. 2612 // *pbFound pointer to NvBool set to NV_TRUE if object was found 2613 // 2614 //---------------------------------------------------------------------------- 2615 2616 static NV_STATUS _extractNBSIObjFromACPIDir 2617 ( 2618 OBJGPU *pGpu, 2619 NvU32 idx, 2620 NvU16 curDir, 2621 ACPI_DSM_FUNCTION acpiFunction, 2622 NBSI_VALIDATE validationOption, 2623 NBSI_ACPI_METHOD acpiMethod, 2624 NBSI_GLOB_TYPE wantedGlobType, 2625 NvU8 wantedGlobIdx, 2626 NvU8 * pActualGlobIdx, 2627 PNBSI_GEN_OBJ * pRtnObj, 2628 NvU32 * pRtnObjSize, 2629 NvBool * pbFound 2630 ) 2631 { 2632 NV_STATUS status = NV_ERR_GENERIC; 2633 void* inOutData = NULL; 2634 NvU32 inOutDataSz = NV_ACPI_DSM_READ_SIZE; 2635 void* tmpBuffer = NULL; 2636 NvU32 tmpBufferSz = NV_ACPI_DSM_READ_SIZE; 2637 2638 NV_ASSERT(pActualGlobIdx); 2639 NV_ASSERT(pRtnObj); 2640 NV_ASSERT(pRtnObjSize); 2641 NV_ASSERT(pbFound); 2642 2643 if ((curDir != NBSI_TBL_SOURCE_ACPI) && 2644 (curDir != NBSI_TBL_SOURCE_UEFI)) 2645 { 2646 // Function only supports ACPI and UEFI sources. 2647 return NV_ERR_INVALID_ARGUMENT; 2648 } 2649 2650 if ((curDir == NBSI_TBL_SOURCE_UEFI) || 2651 (acpiMethod == NBSI_TBL_SOURCE_ACPI_BY_OBJ_TYPE) || 2652 (acpiMethod == NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ) || 2653 (acpiMethod == NBSI_TBL_SOURCE_ACPI_BOTH_METHODS)) 2654 { 2655 // Allocate memory for the ACPI inout parameter buffer 2656 inOutData = portMemAllocNonPaged(inOutDataSz); 2657 if (inOutData == NULL) 2658 { 2659 NV_PRINTF(LEVEL_ERROR, 2660 "Unable to allocate 0x%x bytes for ACPI parm memory.\n", 2661 inOutDataSz); 2662 status = NV_ERR_NO_MEMORY; 2663 goto failed; 2664 } 2665 2666 // Allocate memory for the temporary/local collection buffer 2667 tmpBuffer = portMemAllocNonPaged(tmpBufferSz); 2668 if (tmpBuffer == NULL) 2669 { 2670 NV_PRINTF(LEVEL_ERROR, 2671 "Unable to allocate 0x%x bytes for ACPI parm memory.\n", 2672 tmpBufferSz); 2673 status = NV_ERR_NO_MEMORY; 2674 goto failed; 2675 } 2676 2677 // 2678 // Access types. 2679 // UEFI only supports GetByObjType. 2680 // ACPI supports both GetByObjType and GetAllObjs. 2681 // ACPI requires sub-function support. 2682 // 2683 status = NV_ERR_INVALID_ACCESS_TYPE; 2684 if (((curDir == NBSI_TBL_SOURCE_UEFI) || 2685 (acpiMethod == NBSI_TBL_SOURCE_ACPI_BY_OBJ_TYPE) || 2686 (acpiMethod == NBSI_TBL_SOURCE_ACPI_BOTH_METHODS)) && 2687 (wantedGlobType != (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR)) 2688 { 2689 status = getTableUsingObjTypeCall(pGpu, 2690 idx, 2691 curDir, 2692 acpiFunction, 2693 validationOption, 2694 wantedGlobType, 2695 wantedGlobIdx, 2696 pActualGlobIdx, 2697 pRtnObj, 2698 pRtnObjSize, 2699 pbFound, 2700 inOutData, 2701 inOutDataSz, 2702 tmpBuffer, 2703 tmpBufferSz); 2704 } 2705 else if (curDir == NBSI_TBL_SOURCE_ACPI) 2706 { 2707 if ((acpiMethod == NBSI_TBL_SOURCE_ACPI_BY_ALL_OBJ) || 2708 ((wantedGlobType == (NBSI_GLOB_TYPE) GLOB_TYPE_GET_NBSI_DIR) && 2709 (acpiMethod == NBSI_TBL_SOURCE_ACPI_BOTH_METHODS))) 2710 { 2711 status = getTableUsingAllObjectCall(pGpu, 2712 idx, 2713 acpiFunction, 2714 validationOption, 2715 wantedGlobType, 2716 wantedGlobIdx, 2717 pActualGlobIdx, 2718 pRtnObj, 2719 pRtnObjSize, 2720 pbFound, 2721 inOutData, 2722 inOutDataSz, 2723 tmpBuffer, 2724 tmpBufferSz); 2725 } 2726 } 2727 } 2728 2729 failed: 2730 if (inOutData != NULL) 2731 portMemFree((void*)inOutData); 2732 if (tmpBuffer != NULL) 2733 portMemFree((void*)tmpBuffer); 2734 2735 return status; 2736 } 2737 2738 //---------------------------------------------------------------------------- 2739 // NV_STATUS getNbsiObjByType(pGpu, globType, 2740 // *pWantedGlobIdx, *pWantedGlobSource, 2741 // rtnObjOffset, 2742 // *pRtnObj, *pRtnObjSize, 2743 // *pTotalObjSize, *pRtnGlobStatus, 2744 // acpiFunction, validateOption) 2745 // 2746 // This function gets an object with globType (and wantedGlobIdx) from the 2747 // NBSI table. If wantedGlobIdx is 0, it will cache the object in the nbsi 2748 // cache for future reads. 2749 // If the object exists and will fit in the users memory it returns success 2750 // in pRtnGlobStatus, otherwise it sets this to incomplete 2751 // 2752 // Input parameters: 2753 // pGpu Current pGpu object 2754 // idx GPU instance / index 2755 // globType desired globtype 2756 // wantedGlobIdx desired glob index 2757 // pWantedGlobSource in/out directory source of directory wanted 2758 // rtnObjOffset offset into object to be returned (0=start) 2759 // pRtnObj pointer to memory allocated for return object 2760 // (or NULL if pRtnObjSize is 0) 2761 // pRtnObjSize pointer to return object size (use 0 to query 2762 // for object presence and size. (query will cache 2763 // if globIdx is 0 and room is available in cache) 2764 // pTotalObjSize total size of object being retrieved. 2765 // pRtnGlobStatus pointer to return status 2766 // acpiFunction selector for acpi function (nbsi vs hybrid) 2767 // validationOption object validation option 2768 // 2769 // Output parameters: 2770 // NV_STATUS: NV_OK if there were no operational issues 2771 // (such as memory allocation failure) 2772 // looking for the table. 2773 // *pRtnObj pointer to memory for return object 2774 // *pRtnObjSize pointer to return object size. 2775 // *pRtnGlobStatus 2776 // NV2080_CTRL_BIOS_GET_NBSI_NO_TABLE - no NBSI table found 2777 // NV2080_CTRL_BIOS_GET_NBSI_BAD_TABLE - corrupted NBSI table found 2778 // NV2080_CTRL_BIOS_GET_NBSI_INCOMPLETE - object was found but it's size 2779 // is larger than pRtnObjSize. pRtnObjSize is 2780 // set to actual size of object. 2781 // NV2080_CTRL_BIOS_GET_NBSI_SUCCESS - object found and copied to 2782 // pRtnObj and pRtnObjSize set to actual size 2783 // NV2080_CTRL_BIOS_GET_NBSI_NOT_FOUND - NBSI table present, but object 2784 // was not found matching globType and globTypeIdx 2785 // 2786 //---------------------------------------------------------------------------- 2787 2788 NV_STATUS getNbsiObjByType 2789 ( 2790 OBJGPU *pGpu, 2791 NvU16 globType, 2792 NBSI_SOURCE_LOC * pWantedGlobSource, 2793 NvU8 * pWantedGlobIdx, 2794 NvU32 wantedRtnObjOffset, 2795 NvU8 * pRtnObj, 2796 NvU32 * pRtnObjSize, 2797 NvU32 * pTotalObjSize, 2798 NvU32 * pRtnGlobStatus, 2799 ACPI_DSM_FUNCTION acpiFunction, 2800 NBSI_VALIDATE validationOption 2801 ) 2802 { 2803 NvU32 idx; 2804 NV_STATUS status = NV_ERR_GENERIC; 2805 PNBSI_DIRECTORY pNbsiDir = NULL; 2806 NvU32 nbsiDirSize = 0; 2807 NvBool bFound; 2808 NvBool bFreeDirMemRequired; 2809 NvBool bFreeTestObjRequired; 2810 NBSI_GEN_OBJ *pTestObj; 2811 NvU32 testObjSize; 2812 NvU8 actualGlobIdx = 0; 2813 NvU8 * bufPtr; 2814 NvU16 curDir; 2815 NvU16 dirList; 2816 NvU16 searchDirNdx = 0; 2817 NBSI_SOURCE_LOC nbsiDirLocs[] = {NBSI_TBL_SOURCE_REGISTRY, 2818 NBSI_TBL_SOURCE_VBIOS, 2819 NBSI_TBL_SOURCE_SBIOS, 2820 NBSI_TBL_SOURCE_ACPI, 2821 NBSI_TBL_SOURCE_UEFI, 2822 0}; 2823 NBSI_ACPI_METHOD acpiMethod = NBSI_TBL_SOURCE_ACPI_UNKNOWN; 2824 NBSI_OBJ *pNbsiObj = getNbsiObject(); 2825 2826 NV_ASSERT(pWantedGlobSource); 2827 NV_ASSERT(pWantedGlobIdx); 2828 NV_ASSERT(pTotalObjSize); 2829 NV_ASSERT(pRtnGlobStatus); 2830 NV_ASSERT(!(*pRtnObjSize != 0 && pRtnObj == NULL)); 2831 2832 if (pGpu == NULL) 2833 { 2834 return NV_ERR_GENERIC; 2835 } 2836 2837 idx = gpuGetInstance(pGpu); 2838 if (idx >= NV_MAX_DEVICES) 2839 { 2840 NV_PRINTF(LEVEL_ERROR, 2841 "Invalid gpu index %d. Aborting NBSI get object.\n", 2842 idx); 2843 return NV_ERR_GENERIC; 2844 } 2845 2846 if (globType == GLOB_TYPE_GET_NBSI_ACPI_RAW) 2847 { 2848 // TODO: Add offset arg validation when ACPI calls get support from GSP firmware. 2849 NvU16 rtnSize; 2850 // 2851 // (IN) wantedRtnObjOffset = acpi function, 2852 // (IN/OUT) inoutdata to data (always use 4K!) 2853 // (IN/OUT) pSizeOfData In = size of inoutdata, Out = size returned 2854 // 2855 rtnSize = (NvU16) (*pRtnObjSize & 0xffff); 2856 status = osCallACPI_DSM(pGpu, 2857 acpiFunction, 2858 wantedRtnObjOffset, 2859 (NvU32 *)pRtnObj, 2860 (NvU16 *)&rtnSize); 2861 2862 *pRtnObjSize = rtnSize; 2863 *pWantedGlobSource = (NBSI_SOURCE_LOC) status; 2864 return NV_OK; 2865 } 2866 2867 if ((globType != NBSI_DRIVER) && (*pWantedGlobIdx==1)) 2868 { 2869 // 2870 // object types other than NBSI_DRIVER have best fit index of 1 2871 // So if they ask for best fit (0) or 1 it's the same object. 2872 // If they ask for 0 it gets in the cache as 0 or 1. 2873 // If they ask for 1 first, need to allow 0 as well. 2874 // 2875 *pWantedGlobIdx = 0; 2876 } 2877 2878 // Currently only NBSI and NBCI objects are cached... 2879 if ((acpiFunction == ACPI_DSM_FUNCTION_NBSI) || 2880 (acpiFunction == ACPI_DSM_FUNCTION_NBCI)) 2881 { 2882 status = getNbsiObjFromCache( pGpu, 2883 idx, 2884 globType, 2885 pWantedGlobSource, 2886 pWantedGlobIdx, 2887 wantedRtnObjOffset, 2888 (PNBSI_GEN_OBJ) pRtnObj, 2889 pRtnObjSize, 2890 pTotalObjSize, 2891 pRtnGlobStatus); 2892 if (status != NV_ERR_GENERIC) 2893 { 2894 // It's in the cache, it may or may not fit. 2895 return status; 2896 } 2897 } 2898 2899 // always assume the registry may be present... even if it wasn't before 2900 pNbsiObj->availDirLoc[idx] |= NBSI_TBL_SOURCE_REGISTRY; 2901 2902 // 2903 // Since multiple DSM functions may contain getobject/getallobect subfunctions... 2904 // declaring all ACPI functions as invalid is no longer true. 2905 // So we'll always renable the acpi option. 2906 // Also now that there's generic functions/subfunctions and a cache of dsm 2907 // supported subfunctions this should prevent alot of re-attempts on acpi 2908 // calls that won't work. 2909 // 2910 pNbsiObj->availDirLoc[idx] |= NBSI_TBL_SOURCE_ACPI; 2911 2912 // 2913 // loop through each possible table source until we find the object we're 2914 // looking for 2915 // 2916 if (*pWantedGlobSource == 0) 2917 { 2918 if ((acpiFunction == ACPI_DSM_FUNCTION_NBSI) || 2919 (acpiFunction == ACPI_DSM_FUNCTION_NBCI) || 2920 (acpiFunction == ACPI_DSM_FUNCTION_CURRENT)) 2921 { 2922 dirList = pNbsiObj->availDirLoc[idx]; 2923 } 2924 else 2925 { 2926 dirList = NBSI_TBL_SOURCE_ACPI; 2927 } 2928 } 2929 else 2930 { 2931 if ((acpiFunction == ACPI_DSM_FUNCTION_NBSI) || 2932 (acpiFunction == ACPI_DSM_FUNCTION_NBCI) || 2933 (acpiFunction == ACPI_DSM_FUNCTION_CURRENT)) 2934 { 2935 dirList = *pWantedGlobSource & pNbsiObj->availDirLoc[idx]; 2936 } 2937 else 2938 { 2939 dirList = *pWantedGlobSource; 2940 } 2941 } 2942 2943 bFound = NV_FALSE; 2944 *pRtnGlobStatus = NV2080_CTRL_BIOS_GET_NBSI_NOT_FOUND; 2945 searchDirNdx = 0; 2946 while (!bFound && nbsiDirLocs[searchDirNdx]) 2947 { 2948 curDir = nbsiDirLocs[searchDirNdx] & dirList; 2949 if (curDir == 0) 2950 { 2951 searchDirNdx++; 2952 } 2953 else 2954 { 2955 // Not in the cache so get it from the directory 2956 status = getNbsiDirectory(pGpu, 2957 idx, 2958 &pNbsiDir, 2959 &nbsiDirSize, 2960 curDir, 2961 &bFreeDirMemRequired, 2962 &acpiMethod, 2963 acpiFunction); 2964 2965 if (status != NV_OK) 2966 { 2967 // remove any directories not found. 2968 pNbsiObj->availDirLoc[idx] &= ~curDir; 2969 2970 // bump to next possible. 2971 searchDirNdx++; 2972 // check if searched all directory sources and come up empty. 2973 if (nbsiDirLocs[searchDirNdx] == 0) 2974 { 2975 *pRtnGlobStatus = NV2080_CTRL_BIOS_GET_NBSI_NO_TABLE; 2976 if (bFreeDirMemRequired) 2977 { 2978 portMemFree((void*)pNbsiDir); 2979 } 2980 return status; 2981 } 2982 } 2983 else 2984 { 2985 testObjSize = 0; 2986 pTestObj = NULL; 2987 bFreeTestObjRequired = NV_FALSE; 2988 if ((curDir & NBSI_TBL_SOURCE_ACPI) || 2989 (curDir & NBSI_TBL_SOURCE_UEFI)) 2990 { 2991 status = _extractNBSIObjFromACPIDir(pGpu, 2992 idx, 2993 curDir, 2994 acpiFunction, 2995 validationOption, 2996 acpiMethod, 2997 globType, 2998 *pWantedGlobIdx, 2999 &actualGlobIdx, 3000 &pTestObj, 3001 &testObjSize, 3002 &bFound); 3003 if (pTestObj) 3004 { 3005 // pTestObj was allocated and needs to be released. 3006 bFreeTestObjRequired = NV_TRUE; 3007 } 3008 } 3009 else 3010 { 3011 status = extractNBSIObjFromDir(pGpu, 3012 idx, 3013 pNbsiDir, 3014 nbsiDirSize, 3015 curDir, 3016 globType, 3017 *pWantedGlobIdx, 3018 &actualGlobIdx, 3019 &pTestObj, 3020 &testObjSize, 3021 validationOption, 3022 &bFound); 3023 } 3024 3025 if (bFound == NV_TRUE) 3026 { 3027 NvU32 rtnObjSizeWithOffset; 3028 3029 // Currently only NBSI and NBCI objects are cached... 3030 if ((acpiFunction == ACPI_DSM_FUNCTION_NBSI) || 3031 (acpiFunction == ACPI_DSM_FUNCTION_NBCI)) 3032 { 3033 if ((globType != NBSI_DRIVER) && (actualGlobIdx==1)) 3034 { 3035 // 3036 // object types other than NBSI_DRIVER have best fit 3037 // index of 1. 3038 // So if they ask for best fit (0) or 1 it's the same 3039 // object. 3040 // If they ask for 0 it gets in the cache as 0 or 1. 3041 // If they ask for 1 first, need to allow 0 as well. 3042 // 3043 *pWantedGlobIdx = 0; 3044 } 3045 // Cache everything (until we run out of cache entries) 3046 if (globType != GLOB_TYPE_GET_NBSI_DIR) 3047 { 3048 addNbsiCacheEntry(pGpu, 3049 idx, 3050 pTestObj, 3051 testObjSize, 3052 *pWantedGlobSource, 3053 *pWantedGlobIdx, 3054 curDir, 3055 actualGlobIdx); 3056 } 3057 } 3058 3059 // return the full table size 3060 *pTotalObjSize = testObjSize; 3061 3062 if (!portSafeSubU32(*pTotalObjSize, wantedRtnObjOffset, &rtnObjSizeWithOffset)) 3063 { 3064 // Failed argument validation. 3065 status = NV_ERR_INVALID_OFFSET; 3066 } 3067 else 3068 { 3069 if (*pRtnObjSize >= rtnObjSizeWithOffset) 3070 { 3071 // if rtnsize is larger than remaining part of table, 3072 // then we can return it all this time. 3073 *pRtnObjSize = rtnObjSizeWithOffset; 3074 *pRtnGlobStatus = NV2080_CTRL_BIOS_GET_NBSI_SUCCESS; 3075 } 3076 else 3077 { 3078 // return what we can and indicate incomplete. 3079 *pRtnGlobStatus = NV2080_CTRL_BIOS_GET_NBSI_INCOMPLETE; 3080 } 3081 3082 if (*pRtnObjSize > 0) 3083 { 3084 bufPtr = (NvU8 *) pTestObj; 3085 bufPtr = &bufPtr[wantedRtnObjOffset]; 3086 portMemCopy(pRtnObj, *pRtnObjSize, bufPtr, *pRtnObjSize); 3087 } 3088 } 3089 } 3090 else 3091 { 3092 if (status == NV_ERR_INVALID_DATA) 3093 { 3094 *pRtnGlobStatus = NV2080_CTRL_BIOS_GET_NBSI_BAD_HASH; 3095 } 3096 3097 searchDirNdx++; 3098 // 3099 // check if we've searched all directory sources and 3100 // come up empty. 3101 // 3102 if (nbsiDirLocs[searchDirNdx] == 0) 3103 { 3104 if (*pRtnGlobStatus != NV2080_CTRL_BIOS_GET_NBSI_BAD_HASH) 3105 { 3106 *pRtnGlobStatus = 3107 NV2080_CTRL_BIOS_GET_NBSI_NO_TABLE; 3108 } 3109 3110 // release any memory allocated. 3111 if (bFreeTestObjRequired && pTestObj) 3112 { 3113 portMemFree((void*)pTestObj); 3114 } 3115 3116 // check to released memory temp allocated for the directory 3117 if (bFreeDirMemRequired) 3118 { 3119 portMemFree((void*)pNbsiDir); 3120 } 3121 return status; 3122 } 3123 } 3124 3125 if (bFreeTestObjRequired && pTestObj) 3126 { 3127 portMemFree((void*)pTestObj); 3128 pTestObj = NULL; 3129 } 3130 } 3131 3132 // check to released memory temp allocated for the directory 3133 if (bFreeDirMemRequired) 3134 { 3135 portMemFree((void*)pNbsiDir); 3136 pNbsiDir = NULL; 3137 } 3138 } 3139 } 3140 return status; 3141 } 3142 3143 //---------------------------------------------------------------------------- 3144 // NV_STATUS initNbsiTable(pGpu) 3145 // 3146 // This function finds, allocates and intializes the nbsi table. 3147 // 3148 // Input parameters: 3149 // pGpu pointer to this pGpu object 3150 // none 3151 // 3152 // Output parameters: 3153 // NV_STATUS: NV_OK if there were no operational issues 3154 // (such as memory allocation failure) 3155 // looking for the table. 3156 //---------------------------------------------------------------------------- 3157 3158 NV_STATUS initNbsiTable(OBJGPU *pGpu) 3159 { 3160 NvU32 idx; 3161 NV_STATUS status; 3162 NvU32 globTypeRtnStatus; 3163 NBSI_GEN_OBJ *pNbsiDir = NULL; 3164 NvU32 nbsiDirSize; 3165 NvU32 totalObjSize; 3166 NvU8 curTbl; 3167 NBSI_SOURCE_LOC nbsiDriverSource; 3168 NvU8 nbsiDriverIndex; 3169 NBSI_OBJ *pNbsiObj = getNbsiObject(); 3170 3171 if (pGpu == NULL) 3172 { 3173 return NV_ERR_GENERIC; 3174 } 3175 3176 idx = gpuGetInstance(pGpu); 3177 if (idx >= NV_MAX_DEVICES) 3178 { 3179 NV_PRINTF(LEVEL_ERROR, "Invalid gpu index %d. Aborting NBSI init.\n", idx); 3180 return NV_ERR_GENERIC; 3181 } 3182 3183 if (pNbsiObj->nbsiDrvrTable[idx] != NULL) 3184 { 3185 NV_PRINTF(LEVEL_ERROR, "NBSI table already initialized for GPU index %d. Aborting NBSI init.\n", idx); 3186 return NV_WARN_NOTHING_TO_DO; 3187 } 3188 3189 NV_PRINTF(LEVEL_INFO, "Initializing NBSI tables for gpu %d\n", idx); 3190 3191 status = allocNbsiCache(pGpu, idx, NBSI_INITCACHEENTRYCNT); 3192 if (status != NV_OK) 3193 { 3194 return status; 3195 } 3196 // driver version - filled in in nbsiinit.c 3197 pNbsiObj->DriverVer.OS = 0; // a (7=vista, 6=nt) 3198 pNbsiObj->DriverVer.DX = 0; // bb (15=vista, 14=others) 3199 #ifdef NV_DRIVER_VERSION_NUMBER 3200 pNbsiObj->DriverVer.Rev = NV_DRIVER_VERSION_NUMBER; // cdddd 3201 #else 3202 pNbsiObj->DriverVer.Rev = 0; // cdddd 3203 #endif 3204 3205 if (NVOS_IS_WINDOWS) 3206 { 3207 if (NVCPU_IS_64_BITS) 3208 { 3209 setNbsiOSstring("Vista64",7,2,3); 3210 setNbsiOSstring("Vista",5,1,3); 3211 setNbsiOSstring("",0,0,3); 3212 } 3213 else 3214 { 3215 setNbsiOSstring("Vista",5,1,2); 3216 setNbsiOSstring("",0,0,2); 3217 } 3218 pNbsiObj->DriverVer.OS = 7; 3219 pNbsiObj->DriverVer.DX = 15; 3220 } 3221 else 3222 { 3223 setNbsiOSstring("",0,0,1); 3224 } 3225 3226 // print debug info. 3227 checkUidMatch(pGpu, NULL, idx, 0, 0, NULL); 3228 3229 // By asking how big the NBSI_DRIVER is, it caches it (if found) 3230 nbsiDirSize = 0; 3231 nbsiDriverSource = 0; 3232 nbsiDriverIndex = 0; 3233 status = getNbsiObjByType(pGpu, 3234 NBSI_DRIVER, 3235 &nbsiDriverSource, 3236 &nbsiDriverIndex, 3237 0, // offset 3238 NULL, 3239 &nbsiDirSize, 3240 &totalObjSize, 3241 &globTypeRtnStatus, 3242 ACPI_DSM_FUNCTION_NBCI, 3243 NBSI_VALIDATE_ALL); 3244 3245 // If we didn't find it. 3246 if (status != NV_OK) 3247 { 3248 // if NBCI failed, lets try NBSI... 3249 nbsiDirSize = 0; 3250 nbsiDriverSource = 0; 3251 nbsiDriverIndex = 0; 3252 status = getNbsiObjByType(pGpu, 3253 NBSI_DRIVER, 3254 &nbsiDriverSource, 3255 &nbsiDriverIndex, 3256 0, // offset 3257 NULL, 3258 &nbsiDirSize, 3259 &totalObjSize, 3260 &globTypeRtnStatus, 3261 ACPI_DSM_FUNCTION_NBSI, 3262 NBSI_VALIDATE_ALL); 3263 } 3264 3265 if ((status == NV_OK) && 3266 (globTypeRtnStatus == NV2080_CTRL_BIOS_GET_NBSI_INCOMPLETE)) 3267 { 3268 // Now since it's cached find what memory location it's at and save it. 3269 nbsiDriverSource = 0; 3270 nbsiDriverIndex = 0; 3271 status = getNbsiCacheInfoForGlobType(pGpu, 3272 idx, 3273 NBSI_DRIVER, 3274 &nbsiDriverSource, 3275 &nbsiDriverIndex, 3276 &pNbsiDir, 3277 &nbsiDirSize, 3278 &curTbl); 3279 if (status == NV_OK) 3280 { 3281 // make a copy of the pointer for easy access... no duplicate mem 3282 pNbsiObj->nbsiDrvrTable[idx] = (NvU8 *) pNbsiDir; 3283 } 3284 } 3285 3286 // 3287 // even if the nbsi driver object is not found, the nbsi table could hold 3288 // other objects. So we'll assume success for now. 3289 // 3290 status = NV_OK; 3291 if (nbsiDriverSource == 0) 3292 { 3293 NV_PRINTF(LEVEL_INFO, "No NBSI table for gpu %d found.\n", idx); 3294 } 3295 else if (nbsiDriverSource & NBSI_TBL_SOURCE_REGISTRY) 3296 { 3297 NV_PRINTF(LEVEL_INFO, 3298 "Using NBSI driver object for gpu %d from registry.\n", 3299 idx); 3300 } 3301 else if (nbsiDriverSource & NBSI_TBL_SOURCE_VBIOS) 3302 { 3303 NV_PRINTF(LEVEL_INFO, 3304 "Using NBSI driver object for gpu %d from VBIOS.\n", 3305 idx); 3306 } 3307 else if (nbsiDriverSource & NBSI_TBL_SOURCE_SBIOS) 3308 { 3309 NV_PRINTF(LEVEL_INFO, 3310 "Using NBSI driver object for gpu %d from SBIOS.\n", 3311 idx); 3312 } 3313 else if (nbsiDriverSource & NBSI_TBL_SOURCE_ACPI) 3314 { 3315 NV_PRINTF(LEVEL_INFO, 3316 "Using NBSI driver object for gpu %d from ACPI table.\n", 3317 idx); 3318 } 3319 else 3320 { 3321 NV_PRINTF(LEVEL_INFO, 3322 "Using NBSI driver object for gpu %d from unknown source.\n", 3323 idx); 3324 } 3325 3326 return status; 3327 } 3328 3329 //---------------------------------------------------------------------------- 3330 // NV_STATUS freeNbsiTable(pGpu) 3331 // 3332 // This function frees up the nbsi cache table 3333 // 3334 // Input parameters: 3335 // pGpu pointer to this GPU object 3336 // 3337 // Output parameters: 3338 // none 3339 // 3340 //---------------------------------------------------------------------------- 3341 3342 void freeNbsiTable(OBJGPU *pGpu) 3343 { 3344 NvU32 idx = gpuGetInstance(pGpu); 3345 NBSI_OBJ *pNbsiObj = getNbsiObject(); 3346 3347 if (idx >= NV_MAX_DEVICES) 3348 { 3349 NV_PRINTF(LEVEL_ERROR, 3350 "Invalid gpu index %d. Aborting free NBSI table.\n", 3351 idx); 3352 return; 3353 } 3354 3355 // free up memory used by all cache entries 3356 freeNbsiCache( pGpu, idx); 3357 3358 // Free up the nbsi reg override list. 3359 portMemFree(pNbsiObj->regOverrideList[idx]); 3360 pNbsiObj->regOverrideList[idx] = NULL; 3361 } 3362 3363 void initNbsiObject(NBSI_OBJ *pNbsiObj) 3364 { 3365 NvU32 i; 3366 for (i = 0; i < MAX_NBSI_OS; i++) 3367 { 3368 pNbsiObj->nbsiOSstr[i][0] = 0; 3369 pNbsiObj->nbsiOSstrLen[i] = 0; 3370 pNbsiObj->nbsiOSstrHash[i] = FNV1_32_INIT; 3371 } 3372 pNbsiObj->curMaxNbsiOSes = 1; 3373 3374 // driver version a.bb.1c.dddd 3375 pNbsiObj->DriverVer.OS = 0; // a 3376 pNbsiObj->DriverVer.DX = 0; // bb 3377 pNbsiObj->DriverVer.Rev = 0; // cdddd 3378 3379 for (i = 0; i < NV_MAX_DEVICES; i++) 3380 { 3381 pNbsiObj->availDirLoc[i] = NBSI_TBL_SOURCE_ALL; 3382 pNbsiObj->pTblCache[i] = NULL; 3383 pNbsiObj->nbsiDrvrTable[i] = NULL; 3384 pNbsiObj->regOverrideList[i] = NULL; 3385 } 3386 } 3387 3388 NBSI_OBJ *getNbsiObject(void) 3389 { 3390 OBJSYS *pSys = SYS_GET_INSTANCE(); 3391 OBJPFM *pPfm = SYS_GET_PFM(pSys); 3392 return &pPfm->nbsi; 3393 } 3394