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