1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-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 #define NVOC_KERNEL_GRAPHICS_OBJECT_H_PRIVATE_ACCESS_ALLOWED
25 
26 #include "kernel/gpu/gr/kernel_graphics_manager.h"
27 #include "kernel/gpu/gr/kernel_graphics.h"
28 #include "kernel/core/locks.h"
29 #include "kernel/gpu/subdevice/subdevice.h"
30 #include "vgpu/rpc.h"
31 #include "kernel/mem_mgr/gpu_vaspace.h"
32 #include "kernel/gpu/mem_mgr/mem_mgr.h"
33 #include "kernel/gpu/fifo/kernel_channel_group.h"
34 #include "kernel/gpu/fifo/kernel_channel_group_api.h"
35 
36 #include "class/cl0020.h"
37 
38 #include "ctrl/ctrl2080/ctrl2080gr.h" // NV2080_CTRL_GR_ROUTE_INFO
39 
40 /*!
41  * This function calls promote context RPC to promote GR buffers.
42  * Each ctx buffer may or may not may not have its PA updated (initialized) in
43  * physical RM, and each ctx buffer should have its VA updated (promoted) in
44  * physical RM at least once per VAS, of which there may be multiple in a TSG.
45  * When UVM is enabled, this function is responsible only for updating the PA of
46  * a given context buffer, and not the VA.
47  */
48 NV_STATUS
49 kgrobjPromoteContext_IMPL
50 (
51     OBJGPU *pGpu,
52     KernelGraphicsObject *pKernelGraphicsObject,
53     KernelGraphics *pKernelGraphics
54 )
55 {
56     NvU32 promoteIds[NV2080_CTRL_GPU_PROMOTE_CONTEXT_MAX_ENTRIES];
57     NvU32 promoteIdsSize;
58     NvBool bAttemptPromote;
59     NvU32 i;
60     NV2080_CTRL_GPU_PROMOTE_CTX_PARAMS params;
61     NvU32 entryCount;
62     RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
63     NV_STATUS status;
64     Device *pDevice = GPU_RES_GET_DEVICE(pKernelGraphicsObject);
65     Subdevice *pSubdevice;
66     ChannelDescendant *pChannelDescendant = staticCast(pKernelGraphicsObject, ChannelDescendant);
67 
68     if (IS_MODS_AMODEL(pGpu))
69         return NV_OK;
70 
71     NV_ASSERT_OK_OR_RETURN(
72         subdeviceGetByDeviceAndGpu(
73             RES_GET_CLIENT(pKernelGraphicsObject),
74             pDevice,
75             pGpu,
76             &pSubdevice));
77 
78     GPU_RES_SET_THREAD_BC_STATE(pSubdevice);
79 
80     kgrobjGetPromoteIds_HAL(pGpu, pKernelGraphicsObject,
81                             NV_ARRAY_ELEMENTS(promoteIds),
82                             promoteIds,
83                             &promoteIdsSize,
84                             &bAttemptPromote);
85 
86     if (promoteIdsSize == 0)
87         return NV_OK;
88 
89     portMemSet(&params, 0, sizeof(params));
90 
91     entryCount = 0;
92     for (i = 0; i < promoteIdsSize; ++i)
93     {
94         NvBool bInitialize;
95         NvBool bPromote = NV_FALSE;
96 
97         // Setup parameters to initialize the PA if necessary
98         NV_ASSERT_OK_OR_RETURN(
99             kgrctxPrepareInitializeCtxBuffer(pGpu,
100                                              pKernelGraphicsObject->pKernelGraphicsContext,
101                                              pKernelGraphics,
102                                              pChannelDescendant->pKernelChannel,
103                                              promoteIds[i],
104                                              &params.promoteEntry[entryCount],
105                                              &bInitialize));
106 
107         if (bAttemptPromote)
108         {
109             // Setup parameters to promote the VA if necessary
110             NV_ASSERT_OK_OR_RETURN(
111                 kgrctxPreparePromoteCtxBuffer(pGpu,
112                                               pKernelGraphicsObject->pKernelGraphicsContext,
113                                               pChannelDescendant->pKernelChannel,
114                                               promoteIds[i],
115                                               &params.promoteEntry[entryCount],
116                                               &bPromote));
117         }
118 
119         // If initialization / promotion was necessary, then move to next index
120         if (bInitialize || bPromote)
121             entryCount++;
122     }
123 
124     // Nothing to promote, so return early
125     if (entryCount == 0)
126         return NV_OK;
127 
128     params.engineType  = NV2080_ENGINE_TYPE_GR(kgraphicsGetInstance(pGpu, pKernelGraphics));
129     params.hChanClient = RES_GET_CLIENT_HANDLE(pChannelDescendant);
130     params.hObject     = RES_GET_PARENT_HANDLE(pChannelDescendant);
131     params.entryCount  = entryCount;
132 
133     status = pRmApi->Control(pRmApi,
134                              RES_GET_CLIENT_HANDLE(pSubdevice),
135                              RES_GET_HANDLE(pSubdevice),
136                              NV2080_CTRL_CMD_GPU_PROMOTE_CTX,
137                              &params,
138                              sizeof(params));
139 
140     if (status == NV_OK)
141     {
142         //
143         // If we successfully promoted the PA, flip a flag to ensure we don't
144         // try to promote it again. The VA_LIST should already track this for
145         // VA, but we can't rely on it for PA due to UVM.
146         //
147         for (i = 0; i < entryCount; ++i)
148         {
149             if (!params.promoteEntry[i].bInitialize)
150                 continue;
151 
152             kgrctxMarkCtxBufferInitialized(pGpu,
153                                            pKernelGraphicsObject->pKernelGraphicsContext,
154                                            pKernelGraphics,
155                                            pChannelDescendant->pKernelChannel,
156                                            params.promoteEntry[i].bufferId);
157         }
158     }
159 
160     return status;
161 }
162 
163 /*!
164  * @brief Construct the Kernel GR object for the given GPU
165  *
166  * @param[in]  pGpu
167  * @param[in]  pKernelGraphics
168  * @param[in]  pKernelGraphicsObject
169  */
170 static NV_STATUS
171 _kgrAlloc
172 (
173     OBJGPU               *pGpu,
174     KernelGraphics       *pKernelGraphics,
175     KernelGraphicsObject *pKernelGraphicsObject
176 )
177 {
178     ChannelDescendant *pChannelDescendant = staticCast(pKernelGraphicsObject, ChannelDescendant);
179     NvU32 numGpcs;
180     NvU32 classNum = pChannelDescendant->resourceDesc.externalClassId;
181     const KGRAPHICS_STATIC_INFO *pKernelGraphicsStaticInfo = kgraphicsGetStaticInfo(pGpu, pKernelGraphics);
182     NvU32 gfid = kchannelGetGfid(pChannelDescendant->pKernelChannel);
183 
184     NV_ASSERT_OR_RETURN(pKernelGraphicsStaticInfo != NULL, NV_ERR_INVALID_STATE);
185 
186     // Prevent ctx creation on sys pipes with 0 GPCs attached
187     if (!IS_MODS_AMODEL(pGpu))
188     {
189         numGpcs = nvPopCount32(pKernelGraphicsStaticInfo->floorsweepingMasks.gpcMask);
190         NV_CHECK_OR_RETURN(LEVEL_ERROR, numGpcs > 0, NV_ERR_INSUFFICIENT_RESOURCES);
191     }
192 
193     // Each object may need to create an Mmio mapping
194     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
195         kgrobjSetComputeMmio_HAL(pGpu, pKernelGraphicsObject));
196 
197     // Ensure that ctx buffer information is initialized
198     if (!IS_MODS_AMODEL(pGpu))
199     {
200         NV_ASSERT_OK_OR_RETURN(
201             kgraphicsInitializeDeferredStaticData(pGpu, pKernelGraphics, NV01_NULL_OBJECT, NV01_NULL_OBJECT));
202     }
203 
204     // Allocate FECS buffer in Guest for SRIOV configs.
205     if (kgrctxShouldManageCtxBuffers_HAL(pGpu, pKernelGraphicsObject->pKernelGraphicsContext, gfid) || IS_VIRTUAL_WITH_SRIOV(pGpu))
206     {
207         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
208             kgraphicsAllocKgraphicsBuffers_HAL(pGpu, pKernelGraphics, pKernelGraphicsObject->pKernelGraphicsContext, pChannelDescendant->pKernelChannel));
209     }
210 
211     if (kgrctxShouldManageCtxBuffers_HAL(pGpu, pKernelGraphicsObject->pKernelGraphicsContext, gfid))
212     {
213         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
214             kgrctxAllocCtxBuffers(pGpu, pKernelGraphicsObject->pKernelGraphicsContext, pKernelGraphics, pKernelGraphicsObject));
215 
216         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
217             kgrctxMapCtxBuffers(pGpu, pKernelGraphicsObject->pKernelGraphicsContext, pKernelGraphics, pKernelGraphicsObject));
218     }
219 
220     kgrctxIncObjectCount_HAL(pGpu, pKernelGraphicsObject->pKernelGraphicsContext, classNum);
221 
222     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
223         kgrobjPromoteContext(pGpu, pKernelGraphicsObject, pKernelGraphics));
224 
225     return NV_OK;
226 }
227 
228 /*!
229  * @brief Destruct the Kernel GR object
230  *
231  * @param[in]  pKernelGraphicsObject
232  * @param[in]  bDestructor              NV_TRUE if called from destructor, used to share
233  *                                       cleanup code with constructor
234  */
235 static void _kgrobjDestruct
236 (
237     KernelGraphicsObject *pKernelGraphicsObject,
238     NvBool bDestructor
239 )
240 {
241     OBJGPU *pGpu = GPU_RES_GET_GPU(pKernelGraphicsObject);
242 
243     SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY | SLI_LOOP_FLAGS_IGNORE_REENTRANCY)
244     {
245         ChannelDescendant *pChannelDescendant = staticCast(pKernelGraphicsObject, ChannelDescendant);
246         NV_STATUS status = NV_OK;
247         KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
248         KernelGraphics *pKernelGraphics;
249         NV2080_CTRL_GR_ROUTE_INFO grRouteInfo = {0};
250         Device *pDevice = GPU_RES_GET_DEVICE(pChannelDescendant);
251         NvHandle hParent = RES_GET_PARENT_HANDLE(pChannelDescendant);
252         NvU32 classNum = pChannelDescendant->resourceDesc.externalClassId;
253 
254         // If MIG is enabled, perform GR instance routing based upon parent channel handle
255         kgrmgrCtrlSetChannelHandle(hParent, &grRouteInfo);
256         NV_ASSERT_OK_OR_CAPTURE_FIRST_ERROR(status,
257             kgrmgrCtrlRouteKGRWithDevice(pGpu, pKernelGraphicsManager, pDevice, &grRouteInfo, &pKernelGraphics));
258 
259         if (status != NV_OK)
260             SLI_LOOP_CONTINUE;
261 
262         // Free Compute Mmio mapping
263         kgrobjFreeComputeMmio_HAL(pGpu, pKernelGraphicsObject);
264 
265         if (bDestructor)
266             kgrctxDecObjectCount_HAL(pGpu, pKernelGraphicsObject->pKernelGraphicsContext, classNum);
267 
268         if (kgrobjShouldCleanup_HAL(pGpu, pKernelGraphicsObject))
269         {
270             kgrctxUnmapCtxBuffers(pGpu,
271                                   pKernelGraphicsObject->pKernelGraphicsContext,
272                                   pKernelGraphicsObject,
273                                   pKernelGraphics,
274                                   bDestructor);
275         }
276     }
277     SLI_LOOP_END;
278 }
279 
280 //
281 // Graphics engine object creation routine.
282 //
283 NV_STATUS
284 kgrobjConstruct_IMPL
285 (
286     KernelGraphicsObject         *pKernelGraphicsObject,
287     CALL_CONTEXT                 *pCallContext,
288     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
289 )
290 {
291     ChannelDescendant *pChannelDescendant = staticCast(pKernelGraphicsObject, ChannelDescendant);
292     KernelChannel     *pKernelChannel = pChannelDescendant->pKernelChannel;
293     NV_STATUS          status = NV_OK;
294     OBJGPU            *pGpu = GPU_RES_GET_GPU(pChannelDescendant);
295     Device            *pDevice = GPU_RES_GET_DEVICE(pKernelGraphicsObject);
296 
297     NV_ASSERT_OR_RETURN(pKernelChannel != NULL, NV_ERR_INVALID_STATE);
298 
299     NV_PRINTF(LEVEL_INFO, "class: 0x%x on channel: 0x%08x\n",
300               pChannelDescendant->resourceDesc.externalClassId, kchannelGetDebugTag(pKernelChannel));
301 
302     //
303     // Legacy code believed this to be possible, but Resource Server should
304     // prevent NV01_NULL_OBJECT from being chosen as a handle.
305     //
306     NV_ASSERT_OR_RETURN(pParams->hResource != NV01_NULL_OBJECT,
307                         NV_ERR_INVALID_STATE);
308 
309     {
310         KernelChannel *pkChannel = pChannelDescendant->pKernelChannel;
311 
312         NV_ASSERT_OR_RETURN(pkChannel != NULL, NV_ERR_INVALID_STATE);
313 
314         if (kgrctxFromKernelChannel(pkChannel, &pKernelGraphicsObject->pKernelGraphicsContext) == NV_OK)
315         {
316             KernelGraphicsContext *pKernelGraphicsContext = pKernelGraphicsObject->pKernelGraphicsContext;
317 
318             //
319             // Add each gr object as a dependant of the context such that all
320             // objects are guaranteed to be torn down before the context
321             //
322             refAddDependant(RES_GET_REF(pKernelGraphicsContext),
323                             RES_GET_REF(pKernelGraphicsObject));
324 
325         }
326     }
327 
328     SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY | SLI_LOOP_FLAGS_IGNORE_REENTRANCY)
329     {
330         KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
331         KernelGraphics *pKernelGraphics;
332         NV2080_CTRL_GR_ROUTE_INFO grRouteInfo = {0};
333 
334         // If MIG is enabled, perform GR instance routing based upon parent channel handle
335         kgrmgrCtrlSetChannelHandle(pParams->hParent, &grRouteInfo);
336         NV_ASSERT_OK_OR_CAPTURE_FIRST_ERROR(status,
337             kgrmgrCtrlRouteKGRWithDevice(pGpu, pKernelGraphicsManager, pDevice, &grRouteInfo, &pKernelGraphics));
338         if (status != NV_OK)
339             SLI_LOOP_BREAK;
340 
341         // Construct the Kernel Object
342         status = _kgrAlloc(pGpu, pKernelGraphics, pKernelGraphicsObject);
343 
344         if (status != NV_OK)
345             SLI_LOOP_BREAK;
346     }
347     SLI_LOOP_END;
348 
349     // failed
350     if (status != NV_OK)
351     {
352         // Destroy the kernel object from the constructor
353         _kgrobjDestruct(pKernelGraphicsObject, NV_FALSE);
354     }
355 
356     return status;
357 }
358 
359 /*!
360  * @brief GR object Destructor
361  *
362  * @param[in]  pKernelGraphicsObject
363  */
364 void
365 kgrobjDestruct_IMPL
366 (
367     KernelGraphicsObject *pKernelGraphicsObject
368 )
369 {
370     // Destroy the kernel object from the destructor
371     _kgrobjDestruct(pKernelGraphicsObject, NV_TRUE);
372 }
373 
374 NV_STATUS
375 kgrobjGetMemInterMapParams_IMPL
376 (
377     KernelGraphicsObject *pKernelGraphicsObject,
378     RMRES_MEM_INTER_MAP_PARAMS *pParams
379 )
380 {
381     MEMORY_DESCRIPTOR *pSrcMemDesc = pKernelGraphicsObject->pMmioMemDesc;
382 
383     if (pParams->bSubdeviceHandleProvided)
384     {
385         NV_PRINTF(LEVEL_ERROR, "Unicast DMA mappings of non-memory objects not supported.\n");
386         return NV_ERR_NOT_SUPPORTED;
387     }
388 
389     if (pSrcMemDesc == NULL)
390         return NV_ERR_INVALID_OBJECT_HANDLE;
391 
392     pParams->pSrcMemDesc = pSrcMemDesc;
393     pParams->pSrcGpu = pSrcMemDesc->pGpu;
394 
395     return NV_OK;
396 }
397 
398 /*!
399  * @brief Set up MMIO memDesc for Compute Object
400  */
401 NV_STATUS
402 kgrobjSetComputeMmio_IMPL
403 (
404     OBJGPU               *pGpu,
405     KernelGraphicsObject *pKernelGraphicsObject
406 )
407 {
408     ChannelDescendant *pChanDes = staticCast(pKernelGraphicsObject, ChannelDescendant);
409     MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
410     NvU32 classNum = pChanDes->resourceDesc.externalClassId;
411     NvU32 objType;
412 
413     kgrmgrGetGrObjectType(classNum, &objType);
414 
415     // Nothing to do for non-compute
416     if (objType != GR_OBJECT_TYPE_COMPUTE)
417         return NV_OK;
418 
419     // This can be called multiple times in SLI, so just skip it if present
420     if (pKernelGraphicsObject->pMmioMemDesc != NULL)
421         return NV_OK;
422 
423     // Set up MMIO memDesc to allow GPU mappings of compute object
424     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
425         memdescCreate(&pKernelGraphicsObject->pMmioMemDesc, pGpu, RM_PAGE_SIZE, 0,
426                       NV_TRUE, ADDR_FBMEM, NV_MEMORY_UNCACHED,
427                       MEMDESC_FLAGS_NONE));
428 
429     //
430     // The address field is completely ignored for these mappings.  We use the
431     // chid as the address strictly for debug purposes.
432     //
433     memdescDescribe(pKernelGraphicsObject->pMmioMemDesc, ADDR_FBMEM /* Ignored */,
434                     RM_PAGE_SIZE * pChanDes->pKernelChannel->ChID,
435                     RM_PAGE_SIZE);
436     memdescSetPteKind(pKernelGraphicsObject->pMmioMemDesc,
437                       memmgrGetMessageKind_HAL(pGpu, pMemoryManager));
438 
439     memmgrSetMemDescPageSize_HAL(pGpu, pMemoryManager, pKernelGraphicsObject->pMmioMemDesc, AT_GPU,
440                                  RM_ATTR_PAGE_SIZE_4KB);
441 
442     return NV_OK;
443 }
444 
445 /*!
446  * @brief Free up MMIO memDesc for Compute Object
447  */
448 void
449 kgrobjFreeComputeMmio_IMPL
450 (
451     OBJGPU               *pGpu,
452     KernelGraphicsObject *pKernelGraphicsObject
453 )
454 {
455     memdescDestroy(pKernelGraphicsObject->pMmioMemDesc);
456     pKernelGraphicsObject->pMmioMemDesc = NULL;
457 }
458 
459 /*!
460  * @brief Should we perform grobj cleanup?
461  * If client RM is not managing the ctx buffers, kernel RM should not unmap ctx buffers
462  */
463 NvBool
464 kgrobjShouldCleanup_KERNEL
465 (
466     OBJGPU *pGpu,
467     KernelGraphicsObject *pKernelGraphicsObject
468 )
469 {
470     ChannelDescendant *pChannelDescendant = staticCast(pKernelGraphicsObject, ChannelDescendant);
471     NvU32              gfid = kchannelGetGfid(pChannelDescendant->pKernelChannel);
472 
473     return gpuIsClientRmAllocatedCtxBufferEnabled(pGpu) && !IS_GFID_VF(gfid);
474 }
475 
476 /*!
477  * @brief Should we perform grobj cleanup?
478  * If client RM is managing the ctx buffers, physical RM should not unmap ctx buffers
479  */
480 NvBool
481 kgrobjShouldCleanup_PHYSICAL
482 (
483     OBJGPU *pGpu,
484     KernelGraphicsObject *pKernelGraphicsObject
485 )
486 {
487     ChannelDescendant *pChannelDescendant = staticCast(pKernelGraphicsObject, ChannelDescendant);
488     NvU32              gfid = kchannelGetGfid(pChannelDescendant->pKernelChannel);
489 
490     return !gpuIsClientRmAllocatedCtxBufferEnabled(pGpu) || (gpuIsSriovEnabled(pGpu) && IS_GFID_PF(gfid));
491 }
492 
493 /*!
494  * @brief Retrieve the IDs of ctx buffers which need to be promoted for this ctx
495  *        This version only serves SRIOV-Heavy, which allocates just the FECS
496  *        event buffer in guest RM and promotes its PA to the host, while the
497  *        rest of the buffers are managed by the host.
498  */
499 void
500 kgrobjGetPromoteIds_VF
501 (
502     OBJGPU *pGpu,
503     KernelGraphicsObject *pKernelGraphicsObject,
504     NvU32 maxPromoteIds,
505     NvU32 *pPromoteIds,
506     NvU32 *pNumEntries,
507     NvBool *pbPromote
508 )
509 {
510     void kgrobjGetPromoteIds_FWCLIENT(OBJGPU *, KernelGraphicsObject *, NvU32, NvU32 *, NvU32 *, NvBool *);
511     NvU32 promoteSriovHeavy[] =
512     {
513         //
514         // For SRIOV Heavy, guest allocates FECS event buffer and informs host
515         // of its address, other buffers are managed by host
516         //
517         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_FECS_EVENT
518     };
519     NvBool bSriovHeavyEnabled = gpuIsWarBug200577889SriovHeavyEnabled(pGpu);
520 
521     if (!bSriovHeavyEnabled)
522     {
523         // Use the same implementation as FWCLIENT
524         kgrobjGetPromoteIds_FWCLIENT(pGpu, pKernelGraphicsObject, maxPromoteIds, pPromoteIds, pNumEntries, pbPromote);
525         return;
526     }
527 
528     *pNumEntries = 0;
529     // SRIOV Heavy only initializes and does not promote the FECS buffer
530     *pbPromote = NV_FALSE;
531 
532     NV_ASSERT_OR_RETURN_VOID(NV_ARRAY_ELEMENTS(promoteSriovHeavy) <= maxPromoteIds);
533     *pNumEntries = NV_ARRAY_ELEMENTS(promoteSriovHeavy);
534     portMemCopy(pPromoteIds, sizeof(promoteSriovHeavy), promoteSriovHeavy, sizeof(promoteSriovHeavy));
535 }
536 
537 /*!
538  * @brief Retrieve the IDs of ctx buffers which need to be promoted for this ctx
539  *        This version serves SRIOV and FWCLIENT, which allocate and map the ctx
540  *        buffers themselves and promote the PA/VA to host RM.
541  */
542 void
543 kgrobjGetPromoteIds_FWCLIENT
544 (
545     OBJGPU *pGpu,
546     KernelGraphicsObject *pKernelGraphicsObject,
547     NvU32 maxPromoteIds,
548     NvU32 *pPromoteIds,
549     NvU32 *pNumEntries,
550     NvBool *pbPromote
551 )
552 {
553     ChannelDescendant *pChannelDescendant = staticCast(pKernelGraphicsObject, ChannelDescendant);
554     NvBool bAcquire3d;
555 
556     // Buffers which need to be promoted if we are not allocating a 3d context
557     NvU32 promoteNon3d[] =
558     {
559         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_MAIN,
560         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PM,
561         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PATCH,
562         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_FECS_EVENT,
563         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PRIV_ACCESS_MAP,
564         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_UNRESTRICTED_PRIV_ACCESS_MAP
565     };
566     // Buffers which need to be promoted if we are allocating a 3d context
567     NvU32 promote3d[] =
568     {
569         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_MAIN,
570         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PM,
571         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PATCH,
572         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_BUFFER_BUNDLE_CB,
573         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PAGEPOOL,
574         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_ATTRIBUTE_CB,
575         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_RTV_CB_GLOBAL,
576         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_GFXP_POOL,
577         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_GFXP_CTRL_BLK,
578         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_FECS_EVENT,
579         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PRIV_ACCESS_MAP,
580         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_UNRESTRICTED_PRIV_ACCESS_MAP
581     };
582 
583     *pNumEntries = 0;
584     *pbPromote = NV_TRUE;
585 
586     if (!gpuIsClientRmAllocatedCtxBufferEnabled(pGpu))
587         return;
588 
589     // Do we need to promote any 3D-specific context buffers?
590     if (pChannelDescendant->pKernelChannel->pKernelChannelGroupApi->pKernelChannelGroup->bLegacyMode)
591     {
592         bAcquire3d = NV_TRUE;
593     }
594     else
595     {
596         NvU32 classNum = pChannelDescendant->resourceDesc.externalClassId;
597         NvU32 objType;
598         kgrmgrGetGrObjectType(classNum, &objType);
599         bAcquire3d = ((objType == GR_OBJECT_TYPE_2D) || (objType == GR_OBJECT_TYPE_3D));
600     }
601 
602     // Determine which set of buffers we need to try to init/promote
603     if (bAcquire3d)
604     {
605         NV_ASSERT_OR_RETURN_VOID(NV_ARRAY_ELEMENTS(promote3d) <= maxPromoteIds);
606         *pNumEntries = NV_ARRAY_ELEMENTS(promote3d);
607         portMemCopy(pPromoteIds, sizeof(promote3d), promote3d, sizeof(promote3d));
608     }
609     else
610     {
611         NV_ASSERT_OR_RETURN_VOID(NV_ARRAY_ELEMENTS(promoteNon3d) <= maxPromoteIds);
612         *pNumEntries = NV_ARRAY_ELEMENTS(promoteNon3d);
613         portMemCopy(pPromoteIds, sizeof(promoteNon3d), promoteNon3d, sizeof(promoteNon3d));
614     }
615 }
616 
617 /*!
618  * @brief Retrieve the IDs of ctx buffers which need to be promoted for this ctx
619  *        This version serves bare metal and GSP when these environments are
620  *        managing the ctx buffers. There is additional physical-only
621  *        initialization required for these buffers on allocation which would
622  *        otherwise be handled when these buffers are promoted from client RM,
623  *        but in absence of above should be called manually by physical RM to
624  *        keep the flow / initialization consistent.
625  */
626 void
627 kgrobjGetPromoteIds_PHYSICAL
628 (
629     OBJGPU *pGpu,
630     KernelGraphicsObject *pKernelGraphicsObject,
631     NvU32 maxPromoteIds,
632     NvU32 *pPromoteIds,
633     NvU32 *pNumEntries,
634     NvBool *pbPromote
635 )
636 {
637     ChannelDescendant *pChannelDescendant = staticCast(pKernelGraphicsObject, ChannelDescendant);
638     NvU32 gfid = kchannelGetGfid(pChannelDescendant->pKernelChannel);
639     NvBool bAcquire3d;
640 
641     // Buffers which need to be promoted if we are not allocating a 3d context
642     NvU32 promoteNon3d[] =
643     {
644         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PATCH,
645         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PRIV_ACCESS_MAP,
646         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_UNRESTRICTED_PRIV_ACCESS_MAP
647     };
648     // Buffers which need to be promoted if we are allocating a 3d context
649     NvU32 promote3d[] =
650     {
651         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PATCH,
652         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_GFXP_CTRL_BLK,
653         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PRIV_ACCESS_MAP,
654         NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_UNRESTRICTED_PRIV_ACCESS_MAP
655     };
656 
657     *pNumEntries = 0;
658     *pbPromote = NV_FALSE;
659 
660     // If client is managing ctx buffers, we expect client to initialize these buffers
661     if (gpuIsClientRmAllocatedCtxBufferEnabled(pGpu) && !(gpuIsSriovEnabled(pGpu) && IS_GFID_PF(gfid)))
662         return;
663 
664     // Do we need to promote any 3D-specific context buffers?
665     if (pChannelDescendant->pKernelChannel->pKernelChannelGroupApi->pKernelChannelGroup->bLegacyMode)
666     {
667         bAcquire3d = NV_TRUE;
668     }
669     else
670     {
671         NvU32 classNum = pChannelDescendant->resourceDesc.externalClassId;
672         NvU32 objType;
673         kgrmgrGetGrObjectType(classNum, &objType);
674         bAcquire3d = ((objType == GR_OBJECT_TYPE_2D) || (objType == GR_OBJECT_TYPE_3D));
675     }
676 
677     // Determine which set of buffers we need to try to init/promote
678     if (bAcquire3d)
679     {
680         NV_ASSERT_OR_RETURN_VOID(NV_ARRAY_ELEMENTS(promote3d) <= maxPromoteIds);
681         *pNumEntries = NV_ARRAY_ELEMENTS(promote3d);
682         portMemCopy(pPromoteIds, sizeof(promote3d), promote3d, sizeof(promote3d));
683     }
684     else
685     {
686         NV_ASSERT_OR_RETURN_VOID(NV_ARRAY_ELEMENTS(promoteNon3d) <= maxPromoteIds);
687         *pNumEntries = NV_ARRAY_ELEMENTS(promoteNon3d);
688         portMemCopy(pPromoteIds, sizeof(promoteNon3d), promoteNon3d, sizeof(promoteNon3d));
689     }
690 }
691 
692