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 #define NVOC_KERNEL_GRAPHICS_MANAGER_H_PRIVATE_ACCESS_ALLOWED
25 
26 #include "kernel/gpu/gr/kernel_graphics_manager.h"
27 #include "kernel/gpu/gr/kernel_graphics.h"
28 
29 #include "kernel/gpu/device/device.h"
30 #include "kernel/gpu/fifo/kernel_channel_group_api.h"
31 #include "kernel/gpu/fifo/kernel_channel_group.h"
32 
33 #include "kernel/rmapi/client.h"
34 #include "kernel/rmapi/client_resource.h"
35 #include "nvRmReg.h"
36 
37 // COMPUTE
38 #include "class/clb0c0.h"
39 #include "class/clb1c0.h"
40 #include "class/clc0c0.h"
41 #include "class/clc1c0.h"
42 #include "class/clc3c0.h"
43 #include "class/clc5c0.h"
44 #include "class/clc6c0.h"
45 #include "class/clc7c0.h"
46 #include "class/clc9c0.h"
47 #include "class/clcbc0.h"
48 // GFX
49 #include "class/clb097.h"
50 #include "class/clb197.h"
51 #include "class/clc097.h"
52 #include "class/clc197.h"
53 #include "class/clc397.h"
54 #include "class/clc597.h"
55 #include "class/clc697.h"
56 #include "class/clc797.h"
57 #include "class/clc997.h"
58 #include "class/clcb97.h"
59 // TWOD
60 #include "class/cl902d.h"
61 
62 // MEM2MEM
63 #include "class/cla140.h"
64 
65 static NvBool
66 _kgrmgrGPUInstanceHasComputeInstances
67 (
68     OBJGPU *pGpu,
69     KernelGraphicsManager *pKernelGraphicsManager,
70     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance
71 )
72 {
73     NV_ASSERT_OR_RETURN(pKernelMIGGpuInstance != NULL, NV_FALSE);
74     NvU32 computeInstanceIdx;
75 
76     for (computeInstanceIdx = 0;
77          computeInstanceIdx < NV_ARRAY_ELEMENTS(pKernelMIGGpuInstance->MIGComputeInstance);
78          ++computeInstanceIdx)
79     {
80         if (pKernelMIGGpuInstance->MIGComputeInstance[computeInstanceIdx].bValid)
81             return NV_TRUE;
82     }
83 
84     return NV_FALSE;
85 }
86 
87 /*!
88  * @brief Get GR object type from the class number
89  *
90  * @param[IN]   classNum        external class number
91  * @param[OUT]  pObjectType     GR class subtype
92  */
93 void
94 kgrmgrGetGrObjectType_IMPL
95 (
96     NvU32 classNum,
97     NvU32 *pObjectType
98 )
99 {
100     switch (classNum)
101     {
102         case MAXWELL_COMPUTE_A:
103         case MAXWELL_COMPUTE_B:
104         case PASCAL_COMPUTE_A:
105         case PASCAL_COMPUTE_B:
106         case VOLTA_COMPUTE_A:
107         case TURING_COMPUTE_A:
108         case AMPERE_COMPUTE_A:
109         case AMPERE_COMPUTE_B:
110         case ADA_COMPUTE_A:
111         case HOPPER_COMPUTE_A:
112             *pObjectType = GR_OBJECT_TYPE_COMPUTE;
113             break;
114         case MAXWELL_A:
115         case MAXWELL_B:
116         case PASCAL_A:
117         case PASCAL_B:
118         case VOLTA_A:
119         case TURING_A:
120         case AMPERE_A:
121         case AMPERE_B:
122         case ADA_A:
123         case HOPPER_A:
124             *pObjectType = GR_OBJECT_TYPE_3D;
125             break;
126         case FERMI_TWOD_A:
127             *pObjectType = GR_OBJECT_TYPE_2D;
128             break;
129         case KEPLER_INLINE_TO_MEMORY_B:
130             *pObjectType = GR_OBJECT_TYPE_MEM;
131             break;
132         default:
133             *pObjectType = GR_OBJECT_TYPE_INVALID;
134             break;
135     }
136 }
137 
138 /*!
139  * @brief Is local ctx buffer supported
140  *
141  * @param[IN]   bufId             buffer Id
142  * @param[IN]   bClassSupported2D Is 2D class supported
143  */
144 NvBool
145 kgrmgrIsCtxBufSupported_IMPL
146 (
147     GR_CTX_BUFFER bufId,
148     NvBool bClassSupported2D
149 )
150 {
151     NvBool bSupported = NV_FALSE;
152 
153     NV_ASSERT_OR_RETURN(NV_ENUM_IS(GR_CTX_BUFFER, bufId), NV_FALSE);
154 
155     // All buffers are supported when 2D class is supported
156     if (bClassSupported2D)
157     {
158         return NV_TRUE;
159     }
160 
161     switch (bufId)
162     {
163         case GR_CTX_BUFFER_ZCULL:
164             // fall-through
165         case GR_CTX_BUFFER_PREEMPT:
166             // fall-through
167         case GR_CTX_BUFFER_SPILL:
168             // fall-through
169         case GR_CTX_BUFFER_BETA_CB:
170             // fall-through
171         case GR_CTX_BUFFER_PAGEPOOL:
172             // fall-through
173         case GR_CTX_BUFFER_RTV_CB:
174             bSupported = NV_FALSE;
175             break;
176 
177         case GR_CTX_BUFFER_PM:
178             // fall-through
179         case GR_CTX_BUFFER_MAIN:
180             // fall-through
181         case GR_CTX_BUFFER_PATCH:
182             bSupported = NV_TRUE;
183             break;
184 
185         // No default case - compiler enforces update if enum changes
186     }
187     return bSupported;
188 }
189 
190 /*!
191  * @brief Is globalctx buffer supported
192  *
193  * @param[IN]   bufId             buffer Id
194  * @param[IN]   bClassSupported2D Is 2D class supported
195  */
196 NvBool
197 kgrmgrIsGlobalCtxBufSupported_IMPL
198 (
199     GR_GLOBALCTX_BUFFER bufId,
200     NvBool bClassSupported2D
201 )
202 {
203     NvBool bSupported = NV_FALSE;
204 
205     NV_ASSERT_OR_RETURN(NV_ENUM_IS(GR_GLOBALCTX_BUFFER, bufId), NV_FALSE);
206 
207     // All buffers are supported when 2D class is supported
208     if (bClassSupported2D)
209     {
210         return NV_TRUE;
211     }
212 
213     switch (bufId)
214     {
215         case GR_GLOBALCTX_BUFFER_BUNDLE_CB:
216             // fall-through
217         case GR_GLOBALCTX_BUFFER_PAGEPOOL:
218             // fall-through
219         case GR_GLOBALCTX_BUFFER_ATTRIBUTE_CB:
220             // fall-through
221         case GR_GLOBALCTX_BUFFER_RTV_CB:
222             // fall-through
223         case GR_GLOBALCTX_BUFFER_GFXP_POOL:
224             // fall-through
225         case GR_GLOBALCTX_BUFFER_GFXP_CTRL_BLK:
226             bSupported = NV_FALSE;
227             break;
228 
229         case GR_GLOBALCTX_BUFFER_PRIV_ACCESS_MAP:
230             // fall-through
231         case GR_GLOBALCTX_BUFFER_UNRESTRICTED_PRIV_ACCESS_MAP:
232             // fall-through
233         case GR_GLOBALCTX_BUFFER_FECS_EVENT:
234             // fall-through
235         case GR_GLOBAL_BUFFER_GLOBAL_PRIV_ACCESS_MAP:
236             bSupported = NV_TRUE;
237             break;
238 
239         // No default case - compiler enforces update if enum changes
240     }
241 
242     return bSupported;
243 }
244 
245 /*!
246  * @brief Sets swizzID and engineID on routing info if they don't already exist.
247  *
248  * @param[in]      engID            GR engine ID
249  * @param[in, out] pRouteInfo       Client provided routing info
250  */
251 void
252 kgrmgrCtrlSetEngineID_IMPL
253 (
254     NvU32 engID,
255     NV2080_CTRL_GR_ROUTE_INFO *pRouteInfo
256 )
257 {
258     if (NULL == pRouteInfo)
259     {
260         return;
261     }
262     else if (NV2080_CTRL_GR_ROUTE_INFO_FLAGS_TYPE_NONE ==
263              DRF_VAL(2080_CTRL_GR, _ROUTE_INFO_FLAGS, _TYPE, pRouteInfo->flags))
264     {
265         pRouteInfo->flags = DRF_DEF(2080_CTRL_GR, _ROUTE_INFO_FLAGS, _TYPE, _ENGID);
266         pRouteInfo->route = DRF_NUM64(2080_CTRL_GR, _ROUTE_INFO_DATA, _ENGID, engID);
267     }
268 }
269 
270 /*!
271  * @brief Sets channel handle on routing info if it doesn't already exist.
272  *
273  * @param[in]      hChannel         Channel handle
274  * @param[in, out] pRouteInfo       Client provided routing info
275  */
276 void
277 kgrmgrCtrlSetChannelHandle_IMPL
278 (
279     NvHandle hChannel,
280     NV2080_CTRL_GR_ROUTE_INFO *pRouteInfo
281 )
282 {
283     if (NULL == pRouteInfo)
284     {
285         return;
286     }
287     else if (NV2080_CTRL_GR_ROUTE_INFO_FLAGS_TYPE_NONE ==
288              DRF_VAL(2080_CTRL_GR, _ROUTE_INFO_FLAGS, _TYPE, pRouteInfo->flags))
289     {
290         pRouteInfo->flags = DRF_DEF(2080_CTRL_GR, _ROUTE_INFO_FLAGS, _TYPE, _CHANNEL);
291         pRouteInfo->route = DRF_NUM64(2080_CTRL_GR, _ROUTE_INFO_DATA, _CHANNEL_HANDLE, hChannel);
292     }
293 }
294 
295 static void
296 _kgrmgrInitRegistryOverrides
297 (
298     OBJGPU *pGpu,
299     KernelGraphicsManager *pKernelGraphicsManager
300 )
301 {
302 }
303 
304 NV_STATUS
305 kgrmgrConstructEngine_IMPL
306 (
307     OBJGPU                *pGpu,
308     KernelGraphicsManager *pKernelGraphicsManager,
309     ENGDESCRIPTOR          engDesc
310 )
311 {
312     _kgrmgrInitRegistryOverrides(pGpu, pKernelGraphicsManager);
313 
314     return NV_OK;
315 }
316 
317 void
318 kgrmgrDestruct_IMPL
319 (
320     KernelGraphicsManager *pKernelGraphicsManager
321 )
322 {
323     portMemSet(&pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks, 0,
324                sizeof(pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks));
325     portMemFree(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks);
326     pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks = NULL;
327     portMemFree(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo);
328     pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo = NULL;
329     pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized = NV_FALSE;
330 }
331 
332 /*!
333  * @brief Set legacy Kgraphics Static Info (i.e. state of GR0)
334  */
335 void
336 kgrmgrSetLegacyKgraphicsStaticInfo_IMPL
337 (
338     OBJGPU *pGpu,
339     KernelGraphicsManager *pKernelGraphicsManager,
340     KernelGraphics *pKernelGraphics
341 )
342 {
343     NV_CHECK_OR_RETURN_VOID(LEVEL_INFO, !pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized);
344     NV_ASSERT_OR_RETURN_VOID((pKernelGraphics != NULL) && (kgraphicsGetInstance(pGpu, pKernelGraphics) == 0));
345     const KGRAPHICS_STATIC_INFO *pKernelGraphicsStaticInfo = kgraphicsGetStaticInfo(pGpu, pKernelGraphics);
346     NV_ASSERT_OR_RETURN_VOID(pKernelGraphicsStaticInfo != NULL);
347 
348     portMemCopy(&pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks, sizeof(pKernelGraphicsStaticInfo->floorsweepingMasks),
349                 &pKernelGraphicsStaticInfo->floorsweepingMasks, sizeof(pKernelGraphicsStaticInfo->floorsweepingMasks));
350 
351     if (pKernelGraphicsStaticInfo->pPpcMasks != NULL)
352     {
353         pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks = portMemAllocNonPaged(sizeof(*pKernelGraphicsStaticInfo->pPpcMasks));
354         NV_ASSERT_OR_GOTO(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks != NULL, cleanup);
355 
356         portMemCopy(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks, sizeof(*pKernelGraphicsStaticInfo->pPpcMasks),
357                     pKernelGraphicsStaticInfo->pPpcMasks, sizeof(*pKernelGraphicsStaticInfo->pPpcMasks));
358     }
359 
360     if (pKernelGraphicsStaticInfo->pGrInfo != NULL)
361     {
362         pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo = portMemAllocNonPaged(sizeof(*pKernelGraphicsStaticInfo->pGrInfo));
363         NV_ASSERT_OR_GOTO(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo != NULL, cleanup);
364 
365         portMemCopy(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo, sizeof(*pKernelGraphicsStaticInfo->pGrInfo),
366                     pKernelGraphicsStaticInfo->pGrInfo, sizeof(*pKernelGraphicsStaticInfo->pGrInfo));
367     }
368 
369     pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized = NV_TRUE;
370     return;
371 
372 cleanup:
373     portMemFree(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks);
374     pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks = NULL;
375     portMemFree(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo);
376     pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo = NULL;
377 }
378 
379 /*!
380  * @brief Retrieves associated KernelGraphics engine for given device / route info
381  *
382  * @param[in]  pGpu
383  * @param[in]  pKernelGraphicsManager
384  * @param[in]  pDevice
385  * @param[in]  grRouteInfo                   Client-provided info to direct GR accesses
386  * @param[out] ppKernelGraphics (Optional)   Ptr to store appropriate KernelGraphics *, if desired.
387  */
388 NV_STATUS
389 kgrmgrCtrlRouteKGRWithDevice_IMPL
390 (
391     OBJGPU *pGpu,
392     KernelGraphicsManager *pKernelGraphicsManager,
393     Device *pDevice,
394     const NV2080_CTRL_GR_ROUTE_INFO *pGrRouteInfo,
395     KernelGraphics **ppKernelGraphics
396 )
397 {
398     MIG_INSTANCE_REF ref;
399     KernelGraphics *pKernelGraphics;
400     NvU32 type;
401     NV_STATUS status = NV_OK;
402     NvU32 grIdx;
403     NV2080_CTRL_GR_ROUTE_INFO grRouteInfo = *pGrRouteInfo;
404     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
405     RsClient *pClient;
406 
407     if (!IS_MIG_IN_USE(pGpu))
408     {
409         grIdx = 0;
410         goto done;
411     }
412 
413     pClient = RES_GET_CLIENT(pDevice);
414 
415     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
416         kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager, pDevice, &ref));
417 
418     //
419     // Compute instances always have 1 GR engine, so automatically fill in
420     // the route info when subscribed to a compute instance
421     //
422     if (ref.pMIGComputeInstance != NULL)
423     {
424         portMemSet(&grRouteInfo, 0, sizeof(NV2080_CTRL_GR_ROUTE_INFO));
425         kgrmgrCtrlSetEngineID(0, &grRouteInfo);
426     }
427     else
428     {
429         RmClient *pRmClient = dynamicCast(pClient, RmClient);
430 
431         if (pRmClient == NULL)
432             return NV_ERR_INVALID_OBJECT_HANDLE;
433 
434         RS_PRIV_LEVEL privLevel = rmclientGetCachedPrivilege(pRmClient);
435         if (!rmclientIsAdmin(pRmClient, privLevel) &&
436              _kgrmgrGPUInstanceHasComputeInstances(pGpu, pKernelGraphicsManager, ref.pKernelMIGGpuInstance))
437         {
438             return NV_ERR_INSUFFICIENT_PERMISSIONS;
439         }
440     }
441 
442     type = DRF_VAL(2080_CTRL_GR, _ROUTE_INFO_FLAGS, _TYPE, grRouteInfo.flags);
443     switch (type)
444     {
445         case NV2080_CTRL_GR_ROUTE_INFO_FLAGS_TYPE_NONE:
446             NV_PRINTF(LEVEL_ERROR,
447                       "Cannot give GR Route flag of TYPE_NONE with MIG enabled!\n");
448             return NV_ERR_INVALID_ARGUMENT;
449 
450         case NV2080_CTRL_GR_ROUTE_INFO_FLAGS_TYPE_ENGID:
451         {
452             NvU32 localGrIdx = DRF_VAL64(2080_CTRL_GR, _ROUTE_INFO_DATA,
453                                          _ENGID, grRouteInfo.route);
454             RM_ENGINE_TYPE globalRmEngType;
455 
456             NV_CHECK_OK_OR_RETURN(
457                 LEVEL_ERROR,
458                 kmigmgrGetLocalToGlobalEngineType(pGpu, pKernelMIGManager, ref,
459                                                   RM_ENGINE_TYPE_GR(localGrIdx),
460                                                   &globalRmEngType));
461             NV_ASSERT_OR_RETURN(RM_ENGINE_TYPE_IS_GR(globalRmEngType), NV_ERR_INVALID_STATE);
462             grIdx = RM_ENGINE_TYPE_GR_IDX(globalRmEngType);
463 
464             break;
465         }
466 
467         case NV2080_CTRL_GR_ROUTE_INFO_FLAGS_TYPE_CHANNEL:
468         {
469             KernelChannel *pKernelChannel;
470             RM_ENGINE_TYPE rmEngineType;
471             NvHandle hChannel = DRF_VAL64(2080_CTRL_GR, _ROUTE_INFO_DATA,
472                                           _CHANNEL_HANDLE, grRouteInfo.route);
473 
474             status = CliGetKernelChannel(pClient, hChannel, &pKernelChannel);
475             if (status != NV_OK)
476             {
477                 RsResourceRef         *pChanGrpRef;
478                 KernelChannelGroupApi *pKernelChannelGroupApi = NULL;
479                 KernelChannelGroup    *pKernelChannelGroup    = NULL;
480 
481                 //
482                 // If retrieving a channel with the given hChannel doesn't work,
483                 // try interpreting it as a handle to a channel group instead.
484                 //
485                 status = CliGetChannelGroup(pClient->hClient, hChannel,
486                     &pChanGrpRef, NULL);
487                 if (NV_OK != status)
488                 {
489                     NV_PRINTF(LEVEL_ERROR,
490                               "Failed to find a channel or TSG with given handle 0x%08x associated with hClient=0x%08x\n",
491                               hChannel, pClient->hClient);
492                     return NV_ERR_INVALID_ARGUMENT;
493                 }
494 
495                 pKernelChannelGroupApi = dynamicCast(pChanGrpRef->pResource,
496                                                      KernelChannelGroupApi);
497                 NV_ASSERT_OR_RETURN(
498                     (pKernelChannelGroupApi != NULL &&
499                      pKernelChannelGroupApi->pKernelChannelGroup != NULL),
500                     NV_ERR_INVALID_STATE);
501                 pKernelChannelGroup =
502                     pKernelChannelGroupApi->pKernelChannelGroup;
503 
504                 NV_PRINTF(LEVEL_INFO,
505                           "Found TSG with given handle 0x%08x, using this to determine GR engine ID\n",
506                           hChannel);
507                 rmEngineType = pKernelChannelGroup->engineType;
508             }
509             else
510             {
511                 NV_PRINTF(LEVEL_INFO,
512                           "Found channel with given handle 0x%08x, using this to determine GR engine ID\n",
513                           hChannel);
514                 rmEngineType = kchannelGetEngineType(pKernelChannel);
515             }
516 
517             if (!RM_ENGINE_TYPE_IS_GR(rmEngineType))
518             {
519                 NV_PRINTF(LEVEL_ERROR,
520                           "Failed to route GR using non-GR engine type 0x%x (0x%x)\n",
521                           gpuGetNv2080EngineType(rmEngineType), rmEngineType);
522                 return NV_ERR_INVALID_ARGUMENT;
523             }
524 
525             grIdx = RM_ENGINE_TYPE_GR_IDX(rmEngineType);
526             break;
527         }
528         default:
529             NV_PRINTF(LEVEL_ERROR,
530                       "Unrecognized GR Route flag type 0x%x!\n", type);
531             return NV_ERR_INVALID_ARGUMENT;
532     }
533 
534 done:
535     pKernelGraphics = GPU_GET_KERNEL_GRAPHICS(pGpu, grIdx);
536     NV_ASSERT_OR_RETURN(pKernelGraphics != NULL, NV_ERR_INVALID_STATE);
537 
538     if (ppKernelGraphics != NULL)
539         *ppKernelGraphics = pKernelGraphics;
540 
541     return status;
542 }
543 
544 /*!
545  * @return legacy GPC mask enumerated by this chip
546  */
547 NvU32
548 kgrmgrGetLegacyGpcMask_IMPL
549 (
550     OBJGPU *pGpu,
551     KernelGraphicsManager *pKernelGraphicsManager
552 )
553 {
554     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized, 0);
555 
556     return pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks.gpcMask;
557 }
558 
559 /*!
560  * @return legacy physical GFX GPC mask enumerated by this chip
561  */
562 NvU32
563 kgrmgrGetLegacyPhysGfxGpcMask_IMPL
564 (
565     OBJGPU *pGpu,
566     KernelGraphicsManager *pKernelGraphicsManager
567 )
568 {
569     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized, 0);
570 
571     return pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks.physGfxGpcMask;
572 }
573 
574 /*!
575  * @return legacy TPC mask for certain GPC
576  *
577  * @param[in]  pGpu
578  * @param[in]  KernelGraphicsManager
579  * @param[in]  gpcId                 Indicates logical GPC ID when MIG enabled or physical
580  *                                   GPC ID when MIG disabled
581  */
582 NvU32
583 kgrmgrGetLegacyTpcMask_IMPL
584 (
585     OBJGPU *pGpu,
586     KernelGraphicsManager *pKernelGraphicsManager,
587     NvU32 gpcId
588 )
589 {
590     NvU32 maxNumGpcs;
591 
592     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized, 0);
593     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo != NULL, 0);
594 
595     maxNumGpcs = pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo->infoList[NV2080_CTRL_GR_INFO_INDEX_LITTER_NUM_GPCS].data;
596     NV_CHECK_OR_RETURN(LEVEL_ERROR, (gpcId < maxNumGpcs), 0);
597 
598     return pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks.tpcMask[gpcId];
599 }
600 
601 /*!
602  * @brief Get legacy PPC mask for certain GPC
603  */
604 NV_STATUS
605 kgrmgrGetLegacyPpcMask_IMPL
606 (
607     OBJGPU *pGpu,
608     KernelGraphicsManager *pKernelGraphicsManager,
609     NvU32 physGpcId,
610     NvU32 *pPpcMask
611 )
612 {
613     NvU32 maxNumGpcs;
614 
615     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized, NV_ERR_INVALID_STATE);
616     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo != NULL, NV_ERR_INVALID_STATE);
617     maxNumGpcs = pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo->infoList[NV2080_CTRL_GR_INFO_INDEX_LITTER_NUM_GPCS].data;
618     NV_CHECK_OR_RETURN(LEVEL_ERROR, (physGpcId < maxNumGpcs), NV_ERR_INVALID_ARGUMENT);
619     NV_ASSERT_OR_RETURN((pPpcMask != NULL), NV_ERR_INVALID_ARGUMENT);
620     NV_ASSERT_OR_RETURN((pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks != NULL), NV_ERR_NOT_SUPPORTED);
621 
622     *pPpcMask = pKernelGraphicsManager->legacyKgraphicsStaticInfo.pPpcMasks->mask[physGpcId];
623 
624     return NV_OK;
625 }
626 
627 /*!
628  * @brief Returns legacy zcull mask for specific gpc
629  */
630 NvU32
631 kgrmgrGetLegacyZcullMask_IMPL
632 (
633     OBJGPU *pGpu,
634     KernelGraphicsManager *pKernelGraphicsManager,
635     NvU32 physGpcId
636 )
637 {
638     NvU32 maxNumGpcs;
639 
640     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized, 0);
641     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo != NULL, NV_ERR_INVALID_STATE);
642     maxNumGpcs = pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo->infoList[NV2080_CTRL_GR_INFO_INDEX_LITTER_NUM_GPCS].data;
643     NV_CHECK_OR_RETURN(LEVEL_ERROR, (physGpcId < maxNumGpcs), NV_ERR_INVALID_ARGUMENT);
644 
645     return pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks.zcullMask[physGpcId];
646 }
647 
648 /*!
649  * @brief   Function to Alloc VEIDs for a GR engine
650  *
651  * @param[IN]   pGpu
652  * @param[IN]   pKernelGraphicsManager
653  * @param[IN]   grIdx                  phys gr idx
654  * @param[IN]   veidSpanOffset         Offset of spans localized to a GPU instance to make the VEID request from
655  * @param[IN]   veidCount              Total VEIDs connected to this GR engine
656  * @param[IN]   pKernelMIGGPUInstance
657  */
658 NV_STATUS
659 kgrmgrAllocVeidsForGrIdx_IMPL
660 (
661     OBJGPU *pGpu,
662     KernelGraphicsManager *pKernelGraphicsManager,
663     NvU32 grIdx,
664     NvU32 veidSpanOffset,
665     NvU32 veidCount,
666     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGPUInstance
667 )
668 {
669     NvU32 veidStepSize;
670     NvU32 veidStart = 0;
671     NvU32 veidEnd = 0;
672     NvU32 GPUInstanceVeidEnd;
673     NvU64 GPUInstanceVeidMask;
674     NvU64 GPUInstanceFreeVeidMask;
675     NvU64 reqVeidMask;
676 
677     // This GR should not be already configured to use any VEIDs
678     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->grIdxVeidMask[grIdx] == 0, NV_ERR_INVALID_STATE);
679 
680     NV_ASSERT_OK_OR_RETURN(
681         kgrmgrGetVeidStepSize(pGpu, pKernelGraphicsManager, &veidStepSize));
682 
683     // We statically assign VEIDs to a GR based on the number of GPCs connected to it
684     if (veidCount % veidStepSize != 0)
685     {
686         NV_PRINTF(LEVEL_ERROR, "veidCount %d is not aligned to veidStepSize=%d\n", veidCount, veidStepSize);
687         return NV_ERR_INVALID_ARGUMENT;
688     }
689 
690     NV_ASSERT_OR_RETURN(veidSpanOffset != KMIGMGR_SPAN_OFFSET_INVALID, NV_ERR_INVALID_ARGUMENT);
691 
692     veidStart = (veidSpanOffset * veidStepSize) + pKernelMIGGPUInstance->resourceAllocation.veidOffset;
693     veidEnd = veidStart + veidCount - 1;
694 
695     NV_ASSERT_OR_RETURN(veidStart < veidEnd, NV_ERR_INVALID_STATE);
696     NV_ASSERT_OR_RETURN(veidStart < 64, NV_ERR_INVALID_ARGUMENT);
697     NV_ASSERT_OR_RETURN(veidEnd < 64, NV_ERR_INVALID_ARGUMENT);
698 
699     reqVeidMask = DRF_SHIFTMASK64(veidEnd:veidStart);
700 
701     NV_ASSERT_OR_RETURN(reqVeidMask != 0x0, NV_ERR_INVALID_STATE);
702 
703     // Create a mask for VEIDs associated with this GPU instance
704     GPUInstanceVeidEnd = pKernelMIGGPUInstance->resourceAllocation.veidOffset + pKernelMIGGPUInstance->resourceAllocation.veidCount - 1;
705     GPUInstanceVeidMask = DRF_SHIFTMASK64(GPUInstanceVeidEnd:pKernelMIGGPUInstance->resourceAllocation.veidOffset);
706 
707     NV_ASSERT_OR_RETURN(GPUInstanceVeidMask != 0x0, NV_ERR_INVALID_STATE);
708 
709     GPUInstanceFreeVeidMask = ~(pKernelGraphicsManager->veidInUseMask) & GPUInstanceVeidMask;
710 
711     // VEID range should not overlap with existing VEIDs in use
712     NV_ASSERT_OR_RETURN((pKernelGraphicsManager->veidInUseMask & reqVeidMask) == 0, NV_ERR_STATE_IN_USE);
713 
714     //
715     // For swizzId 0, client can use any range of VEIDs if not used, so we don't
716     // need to do the range check
717     //
718     NV_ASSERT_OR_RETURN(((pKernelMIGGPUInstance->swizzId == 0) ||
719                          ((GPUInstanceFreeVeidMask & reqVeidMask) == reqVeidMask)),
720                         NV_ERR_INSUFFICIENT_RESOURCES);
721 
722     // mark each VEID in the range as "in use"
723     pKernelGraphicsManager->veidInUseMask |= reqVeidMask;
724     pKernelGraphicsManager->grIdxVeidMask[grIdx] |= reqVeidMask;
725 
726     return NV_OK;
727 }
728 
729 /*!
730  * @brief   Function to Clear Gr Engine to VEIDs mapping
731  */
732 void
733 kgrmgrClearVeidsForGrIdx_IMPL
734 (
735     OBJGPU *pGpu,
736     KernelGraphicsManager *pKernelGraphicsManager,
737     NvU32 grIdx
738 )
739 {
740     NvU64 veidMask = pKernelGraphicsManager->grIdxVeidMask[grIdx];
741 
742     // mark all VEIDs of this GR engine as "not in use"
743     NV_ASSERT((pKernelGraphicsManager->veidInUseMask & veidMask) == veidMask);
744     pKernelGraphicsManager->veidInUseMask &= ~veidMask;
745     pKernelGraphicsManager->grIdxVeidMask[grIdx] = 0;
746 }
747 
748 /*!
749  * @brief Get VEID step size
750  */
751 NV_STATUS
752 kgrmgrGetVeidStepSize_IMPL
753 (
754     OBJGPU *pGpu,
755     KernelGraphicsManager *pKernelGraphicsManager,
756     NvU32 *pVeidStepSize
757 )
758 {
759     NV_ASSERT_OR_RETURN(pVeidStepSize != NULL, NV_ERR_INVALID_ARGUMENT);
760     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized, NV_ERR_INVALID_STATE);
761     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo != NULL, NV_ERR_INVALID_STATE);
762 
763     *pVeidStepSize = pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo->infoList[NV0080_CTRL_GR_INFO_INDEX_LITTER_MIN_SUBCTX_PER_SMC_ENG].data;
764 
765     return NV_OK;
766 }
767 
768 /*!
769  * @brief   Function to get starting VEID for a Gr Engine
770  */
771 NV_STATUS
772 kgrmgrGetVeidBaseForGrIdx_IMPL
773 (
774     OBJGPU *pGpu,
775     KernelGraphicsManager *pKernelGraphicsManager,
776     NvU32 grIdx,
777     NvU32 *pVeidStart
778 )
779 {
780     NvU64 veidMask;
781     NV_ASSERT_OR_RETURN(pVeidStart != NULL, NV_ERR_INVALID_ARGUMENT);
782     NV_ASSERT_OR_RETURN(grIdx != KGRMGR_MAX_GR, NV_ERR_INVALID_ARGUMENT);
783 
784     *pVeidStart = 0;
785 
786     veidMask = pKernelGraphicsManager->grIdxVeidMask[grIdx];
787 
788     //
789     // If a GR is not configured, VEID mask for it will be "0" and counting
790     // "0" in a zero-based mask will result in max bit-width size.
791     //
792     if (veidMask != 0x0)
793         *pVeidStart = portUtilCountTrailingZeros64(veidMask);
794 
795     return NV_OK;
796 }
797 
798 /*!
799  * @brief   Function to get GR index for a VEID
800  */
801 NV_STATUS
802 kgrmgrGetGrIdxForVeid_IMPL
803 (
804     OBJGPU *pGpu,
805     KernelGraphicsManager *pKernelGraphicsManager,
806     NvU32 veid,
807     NvU32 *pGrIdx
808 )
809 {
810     NvU32 i;
811     NvU64 veidMask = NVBIT64(veid);
812 
813     NV_ASSERT_OR_RETURN(pGrIdx != NULL, NV_ERR_INVALID_ARGUMENT);
814     for (i = 0; i < KGRMGR_MAX_GR; ++i)
815     {
816         if ((pKernelGraphicsManager->grIdxVeidMask[i] & veidMask) != 0)
817             break;
818     }
819     NV_ASSERT_OR_RETURN(i != KGRMGR_MAX_GR, NV_ERR_OBJECT_NOT_FOUND);
820     *pGrIdx = i;
821     return NV_OK;
822 }
823 
824 /*!
825  * @brief discovers maximum size of local ctx buffers.
826  */
827 NV_STATUS
828 kgrmgrDiscoverMaxLocalCtxBufInfo_IMPL
829 (
830     OBJGPU *pGpu,
831     KernelGraphicsManager *pKernelGraphicsManager,
832     KernelGraphics *pKernelGraphics,
833     NvU32 swizzId
834 )
835 {
836     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
837 
838     //
839     // Most of GR is stub'd so context related things are not needed in AMODEL.
840     // But this function can be called in some MODS test, so return OK directly
841     // to avoid failing the test.
842     //
843     if (IS_MODS_AMODEL(pGpu))
844         return NV_OK;
845 
846     NV_CHECK_OR_RETURN(LEVEL_SILENT,
847         kmigmgrIsMemoryPartitioningNeeded_HAL(pGpu, pKernelMIGManager, swizzId), NV_OK);
848 
849     return kgraphicsDiscoverMaxLocalCtxBufferSize(pGpu, pKernelGraphics);
850 }
851 
852 /*!
853  * @brief Get ctxbufpool info for the global ctx buffer
854  */
855 const CTX_BUF_INFO *
856 kgrmgrGetGlobalCtxBufInfo_IMPL
857 (
858     OBJGPU *pGpu,
859     KernelGraphicsManager *pKernelGraphicsManager,
860     GR_GLOBALCTX_BUFFER buf
861 )
862 {
863     NV_ASSERT_OR_RETURN(NV_ENUM_IS(GR_GLOBALCTX_BUFFER, buf), NULL);
864     return &pKernelGraphicsManager->globalCtxBufInfo[buf];
865 }
866 
867 /*!
868  * @brief Set ctxbufpool parameters for the global ctx buffer
869  */
870 void
871 kgrmgrSetGlobalCtxBufInfo_IMPL
872 (
873     OBJGPU *pGpu,
874     KernelGraphicsManager *pKernelGraphicsManager,
875     GR_GLOBALCTX_BUFFER buf,
876     NvU64 size,
877     NvU64 align,
878     RM_ATTR_PAGE_SIZE attr,
879     NvBool bContiguous
880 )
881 {
882     CTX_BUF_INFO *pInfo;
883     NV_ASSERT_OR_RETURN_VOID(NV_ENUM_IS(GR_GLOBALCTX_BUFFER, buf));
884 
885     pInfo = &pKernelGraphicsManager->globalCtxBufInfo[buf];
886     pInfo->size    = size;
887     pInfo->align   = align;
888     pInfo->attr    = attr;
889     pInfo->bContig = bContiguous;
890 }
891 
892 /*!
893  * @brief Gets maximum size of GR global ctx buffers.
894  *        These are sizes of buffer for GR0 in legacy mode with all GPCs
895  *        connected to GR0.
896  */
897 NV_STATUS
898 kgrmgrDiscoverMaxGlobalCtxBufSizes_IMPL
899 (
900     OBJGPU *pGpu,
901     KernelGraphicsManager *pKernelGraphicsManager,
902     KernelGraphics *pKernelGraphics,
903     NvBool bMemoryPartitioningNeeded
904 )
905 {
906     const KGRAPHICS_STATIC_INFO *pKernelGraphicsStaticInfo;
907     GR_GLOBALCTX_BUFFER bufId;
908 
909     //
910     // Most of GR is stub'd so context related things are not needed in AMODEL.
911     // But this function can be called in some MODS test, so return OK directly
912     // to avoid failing the test.
913     //
914     if (IS_MODS_AMODEL(pGpu))
915         return NV_OK;
916 
917     NV_ASSERT_OR_RETURN(!IS_MIG_IN_USE(pGpu), NV_ERR_INVALID_STATE);
918 
919     //
920     // Bug 2915422: Eventually we expect this check to be replaced by ctxBufPoolIsSupported
921     // we can't use that check today because PDB_PROP_GPU_MOVE_CTX_BUFFERS_TO_PMA is not enabled
922     // when this function is called because
923     // kgraphicsInitializeDeferredStaticData below will eventually lead to
924     // global ctx buffer allocation from ctxBufPools even before these pools are
925     // populated which happens later during GPU instance creation. Once we are
926     // able to rip out global buffer alloc from
927     // kgraphicsInitializeDeferredStaticData, we can enable the above property
928     // early.
929     //
930     NV_CHECK_OR_RETURN(LEVEL_SILENT, bMemoryPartitioningNeeded, NV_OK);
931 
932     // Make sure sizes of all buffers are setup
933     NV_ASSERT_OK_OR_RETURN(
934         kgraphicsInitializeDeferredStaticData(pGpu, pKernelGraphics, NV01_NULL_OBJECT, NV01_NULL_OBJECT));
935 
936     pKernelGraphicsStaticInfo = kgraphicsGetStaticInfo(pGpu, pKernelGraphics);
937     NV_ASSERT_OR_RETURN(pKernelGraphicsStaticInfo != NULL, NV_ERR_INVALID_STATE);
938     NV_ASSERT_OR_RETURN(pKernelGraphicsStaticInfo->pContextBuffersInfo != NULL, NV_ERR_INVALID_STATE);
939 
940     // Get sizes of global ctx buffers
941     FOR_EACH_IN_ENUM(GR_GLOBALCTX_BUFFER, bufId)
942     {
943         NvU32 fifoEngineId;
944         NV_ASSERT_OK_OR_RETURN(
945             kgrctxGlobalCtxBufferToFifoEngineId(bufId, &fifoEngineId));
946 
947         //
948         // contiguity is determined later before reservation as it depends on settings
949         // that take effect after this point.
950         //
951         kgrmgrSetGlobalCtxBufInfo(pGpu, pKernelGraphicsManager, bufId,
952                                   pKernelGraphicsStaticInfo->pContextBuffersInfo->engine[fifoEngineId].size,
953                                   pKernelGraphicsStaticInfo->pContextBuffersInfo->engine[fifoEngineId].alignment,
954                                   RM_ATTR_PAGE_SIZE_4KB, NV_FALSE);
955     }
956     FOR_EACH_IN_ENUM_END;
957 
958     return NV_OK;
959 }
960 
961 /*!
962  * @return legacy TPC count for certain GPC
963  *
964  * @param[in]  pGpu
965  * @param[in]  KernelGraphicsManager
966  * @param[in]  gpcId                 Indicates logical GPC ID
967  */
968 NvU32
969 kgrmgrGetLegacyGpcTpcCount_IMPL
970 (
971     OBJGPU *pGpu,
972     KernelGraphicsManager *pKernelGraphicsManager,
973     NvU32 gpcId
974 )
975 {
976     NvU32 maxNumGpcs;
977 
978     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized, 0);
979     NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo != NULL, 0);
980 
981     maxNumGpcs = nvPopCount32(pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks.gpcMask);
982     NV_CHECK_OR_RETURN(LEVEL_ERROR, (gpcId < maxNumGpcs), 0);
983 
984     return pKernelGraphicsManager->legacyKgraphicsStaticInfo.floorsweepingMasks.tpcCount[gpcId];
985 }
986 
987 /*!
988  * @brief   Function to Alloc VEIDs with either a specific placement or first-fit placement
989  *          depending upon the value passed into pSpanStart
990  *
991  * @param[IN]     pGpu
992  * @param[IN]     pKernelGraphicsManager
993  * @param[IN/OUT] pInUseMask             Mask of VEIDs in-use, updated with newly set VEIDs
994  * @param[IN]     veidCount              Total VEIDs connected to this GR engine
995  * @param[IN/OUT] pSpanStart             GPU Instance local span offset to begin assigning VEIDs from
996  * @param[IN]     pKernelMIGGPUInstance
997  */
998 NV_STATUS
999 kgrmgrCheckVeidsRequest_IMPL
1000 (
1001     OBJGPU *pGpu,
1002     KernelGraphicsManager *pKernelGraphicsManager,
1003     NvU64 *pInUseMask,
1004     NvU32 veidCount,
1005     NvU32 *pSpanStart,
1006     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGPUInstance
1007 )
1008 {
1009     NvU32 veidStepSize;
1010     NvU32 veidStart = 0;
1011     NvU32 veidEnd = 0;
1012     NvU32 GPUInstanceVeidEnd;
1013     NvU64 GPUInstanceVeidMask;
1014     NvU64 GPUInstanceFreeVeidMask;
1015     NvU64 veidMask;
1016 
1017     NV_ASSERT_OK_OR_RETURN(
1018         kgrmgrGetVeidStepSize(pGpu, pKernelGraphicsManager, &veidStepSize));
1019 
1020     NV_ASSERT_OR_RETURN(pSpanStart != NULL, NV_ERR_INVALID_ARGUMENT);
1021     NV_ASSERT_OR_RETURN(pInUseMask != NULL, NV_ERR_INVALID_ARGUMENT);
1022 
1023     // We statically assign VEIDs to a GR based on the number of GPCs connected to it
1024     if (veidCount % veidStepSize != 0)
1025     {
1026         NV_PRINTF(LEVEL_ERROR, "veidCount %d is not aligned to veidStepSize=%d\n", veidCount, veidStepSize);
1027         return NV_ERR_INVALID_ARGUMENT;
1028     }
1029 
1030     // Create a mask for VEIDs associated with this GPU instance
1031     GPUInstanceVeidEnd = pKernelMIGGPUInstance->resourceAllocation.veidOffset + pKernelMIGGPUInstance->resourceAllocation.veidCount - 1;
1032     GPUInstanceVeidMask = DRF_SHIFTMASK64(GPUInstanceVeidEnd:pKernelMIGGPUInstance->resourceAllocation.veidOffset);
1033 
1034     NV_ASSERT_OR_RETURN(GPUInstanceVeidMask != 0x0, NV_ERR_INVALID_STATE);
1035 
1036     GPUInstanceFreeVeidMask = ~(*pInUseMask) & GPUInstanceVeidMask;
1037 
1038     if (*pSpanStart != KMIGMGR_SPAN_OFFSET_INVALID)
1039     {
1040         veidStart = (*pSpanStart * veidStepSize) + pKernelMIGGPUInstance->resourceAllocation.veidOffset;
1041         veidEnd = veidStart + veidCount - 1;
1042 
1043         NV_ASSERT_OR_RETURN(veidStart < veidEnd, NV_ERR_INVALID_STATE);
1044         NV_ASSERT_OR_RETURN(veidStart < 64, NV_ERR_INVALID_ARGUMENT);
1045         NV_ASSERT_OR_RETURN(veidEnd < 64, NV_ERR_INVALID_ARGUMENT);
1046     }
1047     else
1048     {
1049         NvU64 reqVeidMask = DRF_SHIFTMASK64(veidCount - 1:0);
1050         NvU32 i;
1051 
1052         for (i = pKernelMIGGPUInstance->resourceAllocation.veidOffset; i <= GPUInstanceVeidEnd; i += veidStepSize)
1053         {
1054             // See if requested slots are available within this range
1055             if (((GPUInstanceFreeVeidMask >> i) & reqVeidMask) == reqVeidMask)
1056             {
1057                 veidStart = i;
1058                 veidEnd = veidStart + veidCount - 1;
1059                 break;
1060             }
1061         }
1062 
1063         NV_CHECK_OR_RETURN(LEVEL_SILENT, i <= GPUInstanceVeidEnd,
1064                            NV_ERR_INSUFFICIENT_RESOURCES);
1065     }
1066 
1067     veidMask = DRF_SHIFTMASK64(veidEnd:veidStart);
1068     NV_ASSERT_OR_RETURN(veidMask != 0x0, NV_ERR_INVALID_STATE);
1069 
1070     //
1071     // For swizzId 0, client can use any range of VEIDs if not used, so we don't
1072     // need to do the range check
1073     //
1074     NV_CHECK_OR_RETURN(LEVEL_ERROR,
1075                        ((pKernelMIGGPUInstance->swizzId == 0) ||
1076                         (GPUInstanceVeidMask & veidMask) == veidMask),
1077                        NV_ERR_INSUFFICIENT_RESOURCES);
1078 
1079     // VEID range should not overlap with existing VEIDs in use
1080     NV_ASSERT_OR_RETURN((*pInUseMask & veidMask) == 0, NV_ERR_STATE_IN_USE);
1081 
1082     NV_ASSERT(veidStart >= pKernelMIGGPUInstance->resourceAllocation.veidOffset);
1083 
1084     *pSpanStart = (veidStart - pKernelMIGGPUInstance->resourceAllocation.veidOffset) / veidStepSize;
1085     *pInUseMask |= veidMask;
1086     return NV_OK;
1087 }
1088 
1089 /*!
1090  * @brief Atomically set fecs callback scheduled, return NV_TRUE if wasn't scheduled
1091  */
1092 NvBool
1093 kgrmgrSignalFecsCallbackScheduled_IMPL
1094 (
1095     OBJGPU *pGpu,
1096     KernelGraphicsManager *pKernelGraphicsManager
1097 )
1098 {
1099     return portAtomicCompareAndSwapU32(&pKernelGraphicsManager->fecsCallbackScheduled, 1, 0);
1100 }
1101 
1102 /*!
1103  * @brief Atomically clear fecs callback scheduled
1104  */
1105 void
1106 kgrmgrClearFecsCallbackScheduled_IMPL
1107 (
1108     OBJGPU *pGpu,
1109     KernelGraphicsManager *pKernelGraphicsManager
1110 )
1111 {
1112     portAtomicSetU32(&pKernelGraphicsManager->fecsCallbackScheduled, 0);
1113 }
1114