1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2021-2023 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  * KernelGsp functions and helpers for executing FWSEC ucode for FRTS.
26  *
27  * Note: Other than those suffixed by a chip name, functions here
28  *       do not actually need to be HAL'd; we are simply keeping them all in
29  *       one file to try to keep it self-contained.
30  */
31 
32 #include "gpu/gsp/kernel_gsp.h"
33 
34 #include "gpu/gpu.h"
35 #include "gpu/mem_mgr/mem_mgr.h"
36 
37 #include "published/turing/tu102/dev_bus.h" // for NV_PBUS_VBIOS_SCRATCH
38 #include "published/turing/tu102/dev_fb.h"  // for NV_PFB_PRI_MMU_WPR2_ADDR_HI
39 #include "published/turing/tu102/dev_gc6_island.h"
40 #include "published/turing/tu102/dev_gc6_island_addendum.h"
41 
42 /*!
43  * Get size of FRTS data.
44  *
45  * Currently, FRTS data size is hard-coded to be 1MB
46  * (if FRTS exists for the chip).
47  */
48 NvU32
kgspGetFrtsSize_TU102(OBJGPU * pGpu,KernelGsp * pKernelGsp)49 kgspGetFrtsSize_TU102
50 (
51     OBJGPU *pGpu,
52     KernelGsp *pKernelGsp
53 )
54 {
55     NvU32 sizeIn4k = NV_PGC6_AON_FRTS_INPUT_WPR_SIZE_SECURE_SCRATCH_GROUP_03_0_WPR_SIZE_1MB_IN_4K;
56     return sizeIn4k * 0x1000;
57 }
58 
59 
60 // ---------------------------------------------------------------------------
61 // Structures and defines for FWSEC commands
62 // ---------------------------------------------------------------------------
63 
64 typedef struct
65 {
66     NvU8 version;
67     NvU8 headerSize;
68     NvU8 entrySize;
69     NvU8 entryCount;
70 } FALCON_APPLICATION_INTERFACE_HEADER_V1;
71 
72 typedef struct
73 {
74     NvU32 id;
75     NvU32 dmemOffset;
76 } FALCON_APPLICATION_INTERFACE_ENTRY_V1;
77 
78 #define FALCON_APPLICATION_INTERFACE_ENTRY_ID_DMEMMAPPER     (0x4)
79 
80 typedef struct
81 {
82     NvU32 signature;
83     NvU16 version;
84     NvU16 size;
85     NvU32 cmd_in_buffer_offset;
86     NvU32 cmd_in_buffer_size;
87     NvU32 cmd_out_buffer_offset;
88     NvU32 cmd_out_buffer_size;
89     NvU32 nvf_img_data_buffer_offset;
90     NvU32 nvf_img_data_buffer_size;
91     NvU32 printfBufferHdr;
92     NvU32 ucode_build_time_stamp;
93     NvU32 ucode_signature;
94     NvU32 init_cmd;
95     NvU32 ucode_feature;
96     NvU32 ucode_cmd_mask0;
97     NvU32 ucode_cmd_mask1;
98     NvU32 multiTgtTbl;
99 } FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3;
100 
101 #define FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_FRTS (0x15)
102 #define FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_SB   (0x19)
103 
104 typedef struct
105 {
106     NvU32 version;
107     NvU32 size;
108     NvU64 gfwImageOffset;
109     NvU32 gfwImageSize;
110     NvU32 flags;
111 } FWSECLIC_READ_VBIOS_DESC;
112 
113 #define FWSECLIC_READ_VBIOS_STRUCT_FLAGS (2)
114 
115 typedef struct
116 {
117     NvU32 version;
118     NvU32 size;
119     NvU32 frtsRegionOffset4K;
120     NvU32 frtsRegionSize;
121     NvU32 frtsRegionMediaType;
122 } FWSECLIC_FRTS_REGION_DESC;
123 
124 #define FWSECLIC_FRTS_REGION_MEDIA_FB (2)
125 #define FWSECLIC_FRTS_REGION_SIZE_1MB_IN_4K (0x100)
126 
127 typedef struct
128 {
129     FWSECLIC_READ_VBIOS_DESC readVbiosDesc;
130     FWSECLIC_FRTS_REGION_DESC frtsRegionDesc;
131 } FWSECLIC_FRTS_CMD;
132 
133 #define NV_VBIOS_FWSECLIC_SCRATCH_INDEX_0E      0x0E
134 #define NV_VBIOS_FWSECLIC_FRTS_ERR_CODE         31:16
135 #define NV_VBIOS_FWSECLIC_FRTS_ERR_CODE_NONE    0x00000000
136 
137 #define NV_VBIOS_FWSECLIC_SCRATCH_INDEX_15      0x15
138 #define NV_VBIOS_FWSECLIC_SB_ERR_CODE           15:0
139 #define NV_VBIOS_FWSECLIC_SB_ERR_CODE_NONE      0x00000000
140 
141 
142 // ---------------------------------------------------------------------------
143 // Functions for preparing and executing FWSEC commands
144 // ---------------------------------------------------------------------------
145 
146 /*!
147  * Patch DMEM of FWSEC for a given command
148  *
149  * @param[inout]  pMappedData      Pointer to mapped DMEM of FWSEC
150  * @param[in]     mappedDataSize   Number of bytes valid under pMappedData
151  * @param[in]     cmd              FWSEC command to invoke
152  * @param[in]     pCmdBuffer       Buffer containing command arguments to patch in
153  * @param[in]     cmdBufferSize    Size of buffer pointed by pCmdBuffer
154  * @param[in]     interfaceOffset  Interface offset given by VBIOS for FWSEC
155  */
156 static NV_STATUS
s_vbiosPatchInterfaceData(NvU8 * pMappedData,const NvU32 mappedDataSize,const NvU32 cmd,const void * pCmdBuffer,const NvU32 cmdBufferSize,const NvU32 interfaceOffset)157 s_vbiosPatchInterfaceData
158 (
159     NvU8 *pMappedData,  // inout
160     const NvU32 mappedDataSize,
161     const NvU32 cmd,
162     const void *pCmdBuffer,
163     const NvU32 cmdBufferSize,
164     const NvU32 interfaceOffset
165 )
166 {
167     FALCON_APPLICATION_INTERFACE_HEADER_V1 *pIntFaceHdr = NULL;
168     FALCON_APPLICATION_INTERFACE_ENTRY_V1 *pIntFaceEntry = NULL;
169     FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3 *pDmemMapper = NULL;
170 
171     NvBool bSafe;
172     NvU32 index;
173 
174     NvU32 curOffset;
175     NvU32 nextOffset;
176 
177     if (interfaceOffset >= mappedDataSize)
178     {
179         return NV_ERR_INVALID_OFFSET;
180     }
181 
182     bSafe = portSafeAddU32(interfaceOffset, sizeof(*pIntFaceHdr), &nextOffset);
183     if (!bSafe || nextOffset > mappedDataSize)
184     {
185         return NV_ERR_INVALID_OFFSET;
186     }
187 
188     pIntFaceHdr = (FALCON_APPLICATION_INTERFACE_HEADER_V1 *) (pMappedData + interfaceOffset);
189     if (pIntFaceHdr->entryCount < 2)
190     {
191         NV_PRINTF(LEVEL_ERROR, "too few interface entires found for FWSEC cmd 0x%x\n", cmd);
192         return NV_ERR_INVALID_DATA;
193     }
194 
195     curOffset = nextOffset;
196     for (index = 0; index < pIntFaceHdr->entryCount; index++)
197     {
198         if (curOffset >= mappedDataSize)
199         {
200             return NV_ERR_INVALID_OFFSET;
201         }
202 
203         bSafe = portSafeAddU32(curOffset, sizeof(*pIntFaceEntry), &nextOffset);
204         if (!bSafe || nextOffset > mappedDataSize)
205         {
206             return NV_ERR_INVALID_OFFSET;
207         }
208 
209         pIntFaceEntry = (FALCON_APPLICATION_INTERFACE_ENTRY_V1 *) (pMappedData + curOffset);
210         curOffset = nextOffset;
211 
212         if (pIntFaceEntry->id == FALCON_APPLICATION_INTERFACE_ENTRY_ID_DMEMMAPPER)
213         {
214             NvU32 dmemMapperMaxOffset;
215 
216             if (pIntFaceEntry->dmemOffset >= mappedDataSize)
217             {
218                 return NV_ERR_INVALID_OFFSET;
219             }
220 
221             bSafe = portSafeAddU32(pIntFaceEntry->dmemOffset, sizeof(*pDmemMapper),
222                                    &dmemMapperMaxOffset);
223             if (!bSafe || dmemMapperMaxOffset > mappedDataSize)
224             {
225                 return NV_ERR_INVALID_OFFSET;
226             }
227 
228             pDmemMapper = (FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3 *)
229                                 (pMappedData + pIntFaceEntry->dmemOffset);
230         }
231     }
232 
233     if (!pDmemMapper)
234     {
235         NV_PRINTF(LEVEL_ERROR, "failed to find required interface entry for FWSEC cmd 0x%x\n", cmd);
236         return NV_ERR_INVALID_DATA;
237     }
238 
239     pDmemMapper->init_cmd = cmd;
240 
241     if (pDmemMapper->cmd_in_buffer_size < cmdBufferSize)
242     {
243         NV_PRINTF(LEVEL_ERROR, "insufficient cmd buffer for FWSEC interface cmd 0x%x\n", cmd);
244     }
245 
246     if (pDmemMapper->cmd_in_buffer_offset >= mappedDataSize)
247     {
248         return NV_ERR_INVALID_OFFSET;
249     }
250 
251     bSafe = portSafeAddU32(pIntFaceEntry->dmemOffset, cmdBufferSize, &nextOffset);
252     if (!bSafe || nextOffset > mappedDataSize)
253     {
254         return NV_ERR_INVALID_OFFSET;
255     }
256 
257     portMemCopy(pMappedData + pDmemMapper->cmd_in_buffer_offset, cmdBufferSize,
258                 pCmdBuffer, cmdBufferSize);
259 
260     return NV_OK;
261 }
262 
263 /*!
264  * Prepare to execute a given FWSEC cmd.
265  *
266  * @param[in]   pGpu           OBJGPU pointer
267  * @param[in]   pKernelGsp     KernelGsp pointer
268  * @param[in]   pFwsecUcode    KernelGspFlcnUcode structure of FWSEC ucode
269  * @param[in]   cmd            FWSEC cmd (FRTS or SB)
270  * @param[in]   frtsOffset     (if cmd is FRTS) desired FB offset of FRTS data
271  * @param[out]  pPreparedCmd   Prepared command state to pass to kgspExecuteFwsec_TU102
272  */
273 static NV_STATUS
s_prepareForFwsec_TU102(OBJGPU * pGpu,KernelGsp * pKernelGsp,KernelGspFlcnUcode * pFwsecUcode,const NvU32 cmd,const NvU64 frtsOffset,KernelGspPreparedFwsecCmd * pPreparedCmd)274 s_prepareForFwsec_TU102
275 (
276     OBJGPU *pGpu,
277     KernelGsp *pKernelGsp,
278     KernelGspFlcnUcode *pFwsecUcode,
279     const NvU32 cmd,
280     const NvU64 frtsOffset,
281     KernelGspPreparedFwsecCmd *pPreparedCmd
282 )
283 {
284     NV_STATUS status;
285 
286     FWSECLIC_READ_VBIOS_DESC readVbiosDesc;
287     FWSECLIC_FRTS_CMD frtsCmd;
288 
289     void *pCmdBuffer;
290     NvU32 cmdBufferSize;
291 
292     NV_ASSERT_OR_RETURN(!IS_VIRTUAL(pGpu), NV_ERR_NOT_SUPPORTED);
293     NV_ASSERT_OR_RETURN(IS_GSP_CLIENT(pGpu), NV_ERR_NOT_SUPPORTED);
294 
295     NV_ASSERT_OR_RETURN(pFwsecUcode != NULL, NV_ERR_INVALID_ARGUMENT);
296     NV_ASSERT_OR_RETURN(pPreparedCmd != NULL, NV_ERR_INVALID_ARGUMENT);
297     NV_ASSERT_OR_RETURN((cmd != FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_FRTS) ||
298                         (frtsOffset > 0), NV_ERR_INVALID_ARGUMENT);
299 
300     if ((cmd != FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_FRTS) &&
301         (cmd != FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_SB))
302     {
303         NV_ASSERT(0);
304         return NV_ERR_INVALID_ARGUMENT;
305     }
306 
307     pPreparedCmd->pFwsecUcode = pFwsecUcode;
308     pPreparedCmd->cmd = cmd;
309     pPreparedCmd->frtsOffset = frtsOffset;
310 
311     readVbiosDesc.version = 1;
312     readVbiosDesc.size = sizeof(readVbiosDesc);
313     readVbiosDesc.gfwImageOffset = 0;
314     readVbiosDesc.gfwImageSize = 0;
315     readVbiosDesc.flags = FWSECLIC_READ_VBIOS_STRUCT_FLAGS;
316 
317     if (cmd == FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_FRTS)
318     {
319         // FRTS takes an FRTS_CMD, here we build that up
320         NvU32 blockSizeIn4K = NV_PGC6_AON_FRTS_INPUT_WPR_SIZE_SECURE_SCRATCH_GROUP_03_0_WPR_SIZE_1MB_IN_4K;
321 
322         frtsCmd.frtsRegionDesc.version = 1;
323         frtsCmd.frtsRegionDesc.size = sizeof(frtsCmd.frtsRegionDesc);
324         frtsCmd.frtsRegionDesc.frtsRegionOffset4K = (NvU32) (frtsOffset >> 12);
325         frtsCmd.frtsRegionDesc.frtsRegionSize = blockSizeIn4K;
326         frtsCmd.frtsRegionDesc.frtsRegionMediaType = FWSECLIC_FRTS_REGION_MEDIA_FB;
327 
328         frtsCmd.readVbiosDesc = readVbiosDesc;
329 
330         pCmdBuffer = &frtsCmd;
331         cmdBufferSize = sizeof(frtsCmd);
332 
333     }
334     else  // i.e. FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_SB
335     {
336         // SB takes READ_VBIOS_DESC directly
337         pCmdBuffer = &readVbiosDesc;
338         cmdBufferSize = sizeof(readVbiosDesc);
339     }
340 
341     if (pFwsecUcode->bootType == KGSP_FLCN_UCODE_BOOT_FROM_HS)
342     {
343         KernelGspFlcnUcodeBootFromHs *pUcode = &pFwsecUcode->ucodeBootFromHs;
344         NvU8 *pMappedImage;
345         NvU8 *pMappedData;
346 
347         NvBool bSafe;
348 
349         NvU32 ucodeVersionVal;
350         NvU32 hsSigVersions;
351         NvU32 sigOffset;
352         NvU32 sigMaxOffset;
353 
354         NV_ASSERT_OR_RETURN(pUcode->pUcodeMemDesc != NULL, NV_ERR_INVALID_ARGUMENT);
355         NV_ASSERT_OR_RETURN(pUcode->pSignatures != NULL, NV_ERR_INVALID_ARGUMENT);
356 
357         ucodeVersionVal = kgspReadUcodeFuseVersion_HAL(pGpu, pKernelGsp, pUcode->ucodeId);
358 
359         ucodeVersionVal = 1 << ucodeVersionVal;
360         hsSigVersions = pUcode->vbiosSigVersions;
361 
362         if ((ucodeVersionVal & hsSigVersions) == 0)
363         {
364             return NV_ERR_NOT_SUPPORTED;;
365         }
366 
367         sigOffset = 0;
368         while ((ucodeVersionVal & hsSigVersions & 1) == 0)
369         {
370             sigOffset += (hsSigVersions & 1) * pUcode->sigSize;
371             hsSigVersions >>= 1;
372             ucodeVersionVal >>= 1;
373         }
374 
375         if (sigOffset >= pUcode->signaturesTotalSize)
376         {
377             return NV_ERR_INVALID_OFFSET;
378         }
379 
380         bSafe = portSafeAddU32(sigOffset, pUcode->sigSize, &sigMaxOffset);
381         if (!bSafe || sigMaxOffset > pUcode->signaturesTotalSize)
382         {
383             return NV_ERR_INVALID_OFFSET;
384         }
385 
386         pMappedImage = memdescMapInternal(pGpu, pUcode->pUcodeMemDesc, TRANSFER_FLAGS_NONE);
387         if (pMappedImage == NULL)
388         {
389             return NV_ERR_INSUFFICIENT_RESOURCES;
390         }
391         pMappedData = pMappedImage + pUcode->dataOffset;
392 
393         status = s_vbiosPatchInterfaceData(pMappedData, pUcode->dmemSize, cmd,
394                                            pCmdBuffer, cmdBufferSize, pUcode->interfaceOffset);
395 
396         portMemCopy(pMappedData + pUcode->hsSigDmemAddr, pUcode->sigSize,
397                     ((NvU8 *) pUcode->pSignatures) + sigOffset, pUcode->sigSize);
398 
399         memdescUnmapInternal(pGpu, pUcode->pUcodeMemDesc,
400                              TRANSFER_FLAGS_DESTROY_MAPPING);
401         pMappedImage = NULL;
402         pMappedData = NULL;
403 
404         if (status != NV_OK)
405         {
406             NV_PRINTF(LEVEL_ERROR, "failed to prepare interface data for FWSEC cmd 0x%x: 0x%x\n",
407                       cmd, status);
408             goto out;
409         }
410     }
411     else if (pFwsecUcode->bootType == KGSP_FLCN_UCODE_BOOT_WITH_LOADER)
412     {
413         KernelGspFlcnUcodeBootWithLoader *pUcode = &pFwsecUcode->ucodeBootWithLoader;
414         NvU8 *pMappedData;
415 
416         NV_ASSERT_OR_RETURN(pUcode->pCodeMemDesc != NULL, NV_ERR_INVALID_ARGUMENT);
417         NV_ASSERT_OR_RETURN(pUcode->pDataMemDesc != NULL, NV_ERR_INVALID_ARGUMENT);
418 
419         pMappedData = memdescMapInternal(pGpu, pUcode->pDataMemDesc, TRANSFER_FLAGS_NONE);
420         if (pMappedData == NULL)
421         {
422             return NV_ERR_INSUFFICIENT_RESOURCES;
423         }
424 
425         status = s_vbiosPatchInterfaceData(pMappedData, pUcode->dmemSize, cmd,
426                                            pCmdBuffer, cmdBufferSize, pUcode->interfaceOffset);
427 
428         memdescUnmapInternal(pGpu, pUcode->pDataMemDesc,
429                             TRANSFER_FLAGS_DESTROY_MAPPING);
430         pMappedData = NULL;
431 
432         if (status != NV_OK)
433         {
434             NV_PRINTF(LEVEL_ERROR, "failed to prepare interface data for FWSEC cmd 0x%x: 0x%x\n",
435                       cmd, status);
436             goto out;
437         }
438     }
439     else
440     {
441         return NV_ERR_NOT_SUPPORTED;
442     }
443 
444 out:
445     if (status != NV_OK)
446     {
447         NV_PRINTF(LEVEL_ERROR, "(note: VBIOS version %s)\n", pKernelGsp->vbiosVersionStr);
448     }
449 
450     return status;
451 }
452 
453 /*!
454  * Execute a given FWSEC cmd and wait for completion.
455  * KernelGspPreparedFwsecCmd should be set by s_prepareForFwsec_TU102 and
456  * not filled in manually
457  *
458  * @param[in]   pGpu           OBJGPU pointer
459  * @param[in]   pKernelGsp     KernelGsp pointer
460  * @param[in]   pPreparedCmd   Prepared command state from s_prepareForFwsec_TU102
461  */
462 NV_STATUS
kgspExecuteFwsec_TU102(OBJGPU * pGpu,KernelGsp * pKernelGsp,KernelGspPreparedFwsecCmd * pPreparedCmd)463 kgspExecuteFwsec_TU102
464 (
465     OBJGPU *pGpu,
466     KernelGsp *pKernelGsp,
467     KernelGspPreparedFwsecCmd *pPreparedCmd
468 )
469 {
470     NV_STATUS status;
471 
472     NV_ASSERT_OR_RETURN(!IS_VIRTUAL(pGpu), NV_ERR_NOT_SUPPORTED);
473     NV_ASSERT_OR_RETURN(IS_GSP_CLIENT(pGpu), NV_ERR_NOT_SUPPORTED);
474 
475     NV_ASSERT_OR_RETURN(pPreparedCmd != NULL, NV_ERR_INVALID_ARGUMENT);
476 
477     status = kgspExecuteHsFalcon_HAL(pGpu, pKernelGsp, pPreparedCmd->pFwsecUcode,
478                                      staticCast(pKernelGsp, KernelFalcon), NULL, NULL);
479 
480     if (status != NV_OK)
481     {
482         NV_PRINTF(LEVEL_ERROR, "failed to execute FWSEC cmd 0x%x: status 0x%x\n", pPreparedCmd->cmd, status);
483         goto out;
484     }
485 
486     if (pPreparedCmd->cmd == FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_FRTS)
487     {
488         NvU32 data;
489         NvU32 frtsErrCode;
490         NvU32 wpr2HiVal;
491         NvU32 wpr2LoVal;
492         NvU32 expectedLoVal;
493 
494         data = GPU_REG_RD32(pGpu, NV_PBUS_VBIOS_SCRATCH(NV_VBIOS_FWSECLIC_SCRATCH_INDEX_0E));
495         frtsErrCode = DRF_VAL(_VBIOS, _FWSECLIC, _FRTS_ERR_CODE, data);
496         if (frtsErrCode != NV_VBIOS_FWSECLIC_FRTS_ERR_CODE_NONE)
497         {
498             NV_PRINTF(LEVEL_ERROR, "failed to execute FWSEC for FRTS: FRTS error code 0x%x\n", frtsErrCode);
499             status = NV_ERR_GENERIC;
500             goto out;
501         }
502 
503         data = GPU_REG_RD32(pGpu, NV_PFB_PRI_MMU_WPR2_ADDR_HI);
504         wpr2HiVal = DRF_VAL(_PFB, _PRI_MMU_WPR2_ADDR_HI, _VAL, data);
505         if (wpr2HiVal == 0)
506         {
507             NV_PRINTF(LEVEL_ERROR, "failed to execute FWSEC for FRTS: no initialized WPR2 found\n");
508             status = NV_ERR_GENERIC;
509             goto out;
510         }
511 
512         data = GPU_REG_RD32(pGpu, NV_PFB_PRI_MMU_WPR2_ADDR_LO);
513         wpr2LoVal = DRF_VAL(_PFB, _PRI_MMU_WPR2_ADDR_LO, _VAL, data);
514         expectedLoVal = (NvU32) (pPreparedCmd->frtsOffset >> NV_PFB_PRI_MMU_WPR2_ADDR_LO_ALIGNMENT);
515         if (wpr2LoVal != expectedLoVal)
516         {
517             NV_PRINTF(LEVEL_ERROR,
518                       "failed to execute FWSEC for FRTS: WPR2 initialized at an unexpected location: 0x%08x (expected 0x%08x)\n",
519                       wpr2LoVal, expectedLoVal);
520             status = NV_ERR_GENERIC;
521             goto out;
522         }
523     }
524     else  // i.e. FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_SB
525     {
526         NvU32 data;
527         NvU32 sbErrCode;
528 
529         if (!GPU_FLD_TEST_DRF_DEF(pGpu, _PGC6, _AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK,
530                                   _READ_PROTECTION_LEVEL0, _ENABLE))
531         {
532             NV_PRINTF(LEVEL_ERROR, "failed to execute FWSEC for SB: GFW PLM not lowered\n");
533             status = NV_ERR_GENERIC;
534             goto out;
535         }
536 
537         if (!GPU_FLD_TEST_DRF_DEF(pGpu, _PGC6, _AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT,
538                                   _PROGRESS, _COMPLETED))
539         {
540             NV_PRINTF(LEVEL_ERROR, "failed to execute FWSEC for SB: GFW progress not completed\n");
541             status = NV_ERR_GENERIC;
542             goto out;
543         }
544 
545         data = GPU_REG_RD32(pGpu, NV_PBUS_VBIOS_SCRATCH(NV_VBIOS_FWSECLIC_SCRATCH_INDEX_15));
546         sbErrCode = DRF_VAL(_VBIOS, _FWSECLIC, _SB_ERR_CODE, data);
547         if (sbErrCode != NV_VBIOS_FWSECLIC_SB_ERR_CODE_NONE)
548         {
549             NV_PRINTF(LEVEL_ERROR, "failed to execute FWSEC for SB: SB error code 0x%x\n", sbErrCode);
550             status = NV_ERR_GENERIC;
551             goto out;
552         }
553     }
554 
555 out:
556     if (status != NV_OK)
557     {
558         NV_PRINTF(LEVEL_ERROR, "(note: VBIOS version %s)\n", pKernelGsp->vbiosVersionStr);
559     }
560 
561     return status;
562 }
563 
564 /*!
565  * Prepare to execute FWSEC FRTS ucode to setup FRTS
566  *
567  * @param[in]   pGpu           OBJGPU pointer
568  * @param[in]   pKernelGsp     KernelGsp pointer
569  * @param[in]   pFwsecUcode    KernelGspFlcnUcode structure of FWSEC ucode
570  * @param[in]   frtsOffset     Desired offset in FB of FRTS data and WPR2
571  * @param[out]  pPreparedCmd   Prepared command state to pass to kgspExecuteFwsec_TU102
572  */
573 NV_STATUS
kgspPrepareForFwsecFrts_TU102(OBJGPU * pGpu,KernelGsp * pKernelGsp,KernelGspFlcnUcode * pFwsecUcode,const NvU64 frtsOffset,KernelGspPreparedFwsecCmd * pPreparedCmd)574 kgspPrepareForFwsecFrts_TU102
575 (
576     OBJGPU *pGpu,
577     KernelGsp *pKernelGsp,
578     KernelGspFlcnUcode *pFwsecUcode,
579     const NvU64 frtsOffset,
580     KernelGspPreparedFwsecCmd *pPreparedCmd
581 )
582 {
583     return s_prepareForFwsec_TU102(pGpu, pKernelGsp, pFwsecUcode,
584                                    FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_FRTS,
585                                    frtsOffset, pPreparedCmd);
586 }
587 
588 /*!
589  * Prepare to execute FWSEC SB ucode to setup FRTS
590  *
591  * @param[in]   pGpu           OBJGPU pointer
592  * @param[in]   pKernelGsp     KernelGsp pointer
593  * @param[in]   pFwsecUcode    KernelGspFlcnUcode structure of FWSEC ucode
594  * @param[out]  pPreparedCmd   Prepared command state to pass to kgspExecuteFwsec_TU102
595  */
596 NV_STATUS
kgspPrepareForFwsecSb_TU102(OBJGPU * pGpu,KernelGsp * pKernelGsp,KernelGspFlcnUcode * pFwsecUcode,KernelGspPreparedFwsecCmd * pPreparedCmd)597 kgspPrepareForFwsecSb_TU102
598 (
599     OBJGPU *pGpu,
600     KernelGsp *pKernelGsp,
601     KernelGspFlcnUcode *pFwsecUcode,
602     KernelGspPreparedFwsecCmd *pPreparedCmd
603 )
604 {
605     return s_prepareForFwsec_TU102(pGpu, pKernelGsp, pFwsecUcode,
606                                    FALCON_APPLICATION_INTERFACE_DMEM_MAPPER_V3_CMD_SB,
607                                    0, pPreparedCmd);
608 }