1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2018-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  *
26  *   Description:
27  *       This file contains the functions managing GPU instance subscriptions
28  *
29  *****************************************************************************/
30 
31 #define NVOC_GPU_INSTANCE_SUBSCRIPTION_H_PRIVATE_ACCESS_ALLOWED
32 
33 #include "core/core.h"
34 #include "core/system.h"
35 #include "gpu/gpu.h"
36 #include "os/os.h"
37 #include "gpu/device/device.h"
38 #include "gpu/subdevice/subdevice.h"
39 #include "virtualization/hypervisor/hypervisor.h"
40 
41 #include "kernel/gpu/mig_mgr/gpu_instance_subscription.h"
42 #include "kernel/gpu/mig_mgr/compute_instance_subscription.h"
43 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
44 
45 #include "ctrl/ctrlc637.h"
46 #include "core/locks.h"
47 #include "rmapi/rs_utils.h"
48 #include "gpu/gpu_uuid.h"
49 #include "vgpu/rpc.h"
50 #include "rmapi/control.h"
51 
52 static inline NvBool
_gisubscriptionClientSharesVASCrossPartition(GPUInstanceSubscription * pGPUInstanceSubscription,CALL_CONTEXT * pCallContext,NvU32 targetedSwizzId)53 _gisubscriptionClientSharesVASCrossPartition
54 (
55     GPUInstanceSubscription *pGPUInstanceSubscription,
56     CALL_CONTEXT *pCallContext,
57     NvU32 targetedSwizzId
58 )
59 {
60     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
61     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
62     RsClient *pRsClientShare;
63     RsResourceRef *pDeviceRef;
64     Device *pDevice;
65     MIG_INSTANCE_REF shareRef;
66     RS_ITERATOR it;
67     NvBool bClientShareHasMatchingInstance = NV_FALSE;
68 
69     NV_ASSERT_OR_RETURN(pGPUInstanceSubscription != NULL, NV_TRUE);
70 
71     NV_ASSERT_OK(
72         refFindAncestorOfType(pCallContext->pResourceRef,
73                               classId(Device), &pDeviceRef));
74     pDevice = dynamicCast(pDeviceRef->pResource, Device);
75 
76     if (pDevice->hClientShare == NV01_NULL_OBJECT)
77     {
78         // NULL Client Share : Legacy Global VASpace. This is cross-GPU-instance.
79         return NV_TRUE;
80     }
81     else if (pDevice->hClientShare == pCallContext->pClient->hClient)
82     {
83         // Same Client Share : Self Scoped VASpace. This is not cross-GPU-instance.
84         return NV_FALSE;
85     }
86 
87     //
88     // Different Client Share. Device default VASpace is shared between this
89     // client and hClientShare. The VAS is cross-GPU-instance if the sharing client
90     // is subscribed to a different GPU instance than the subscription request, or
91     // if the sharing client isn't subscribed to any GPU instance.
92     //
93     NV_ASSERT_OK_OR_RETURN(
94         serverGetClientUnderLock(&g_resServ, pDevice->hClientShare, &pRsClientShare));
95 
96     it = clientRefIter(pRsClientShare, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE);
97 
98     while (clientRefIterNext(pRsClientShare, &it))
99     {
100         pDevice = dynamicCast(it.pResourceRef->pResource, Device);
101 
102         if ((pGpu != GPU_RES_GET_GPU(pDevice)) ||
103             (kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager, pDevice,
104                                              &shareRef) != NV_OK))
105         {
106             continue;
107         }
108 
109         if (shareRef.pKernelMIGGpuInstance->swizzId == targetedSwizzId)
110         {
111             bClientShareHasMatchingInstance = NV_TRUE;
112             break;
113         }
114     }
115 
116     return !bClientShareHasMatchingInstance;
117 }
118 
119 NV_STATUS
gisubscriptionConstruct_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,CALL_CONTEXT * pCallContext,RS_RES_ALLOC_PARAMS_INTERNAL * pRmAllocParams)120 gisubscriptionConstruct_IMPL
121 (
122     GPUInstanceSubscription      *pGPUInstanceSubscription,
123     CALL_CONTEXT                 *pCallContext,
124     RS_RES_ALLOC_PARAMS_INTERNAL *pRmAllocParams
125 )
126 {
127     NVC637_ALLOCATION_PARAMETERS *pUserParams = pRmAllocParams->pAllocParams;
128     RsClient *pRsClient = pCallContext->pClient;
129     OBJGPU *pGpu;
130     KernelMIGManager *pKernelMIGManager;
131     NvU32 swizzId;
132     NV_STATUS status;
133 
134     pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
135 
136     osRmCapInitDescriptor(&pGPUInstanceSubscription->dupedCapDescriptor);
137 
138     if (RS_IS_COPY_CTOR(pRmAllocParams))
139         return gisubscriptionCopyConstruct_IMPL(pGPUInstanceSubscription, pCallContext, pRmAllocParams);
140 
141     pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
142     swizzId = pUserParams->swizzId;
143 
144     if (!IS_MIG_ENABLED(pGpu))
145     {
146         NV_ASSERT_FAILED("Subscription failed: MIG not enabled\n");
147         return NV_ERR_NOT_SUPPORTED;
148     }
149 
150     //
151     // Disable RMCTRL Cache before subscribe to GPU instance.
152     // RMCTRL-CACHE-TODO: remove the workaround when CORERM-5016 is done.
153     //
154     rmapiControlCacheSetMode(NV0000_CTRL_SYSTEM_RMCTRL_CACHE_MODE_CTRL_MODE_DISABLE);
155 
156     //
157     // Root-SwizzID is a special swizzID which doesn't have any GPU instance
158     // associated with it. It can be subscribed to even without GPU instances
159     //
160     if (swizzId == NVC637_DEVICE_PROFILING_SWIZZID)
161     {
162         // Check if this is a root-client or un-privileged device profiling is allowed
163         if (gpuIsRmProfilingPrivileged(pGpu) &&
164             !rmclientIsAdminByHandle(pRmAllocParams->hClient, pCallContext->secInfo.privLevel))
165         {
166             return NV_ERR_INSUFFICIENT_PERMISSIONS;
167         }
168 
169         if (kmigmgrIsDeviceProfilingInUse(pGpu, pKernelMIGManager))
170         {
171             // Only one DeviceProfiling session is allowed to be used with-in a system
172             NV_PRINTF(LEVEL_ERROR,
173                       "Subscription failed: Device-Level-Monitoring already in use\n");
174             return NV_ERR_INVALID_STATE;
175         }
176 
177         // Mark the root swizzID in use and return
178         NV_ASSERT_OK_OR_RETURN(kmigmgrSetDeviceProfilingInUse(pGpu, pKernelMIGManager));
179         pGPUInstanceSubscription->bDeviceProfiling = NV_TRUE;
180         goto done;
181     }
182     else
183     {
184         pGPUInstanceSubscription->bDeviceProfiling = NV_FALSE;
185     }
186 
187     if (!IS_MIG_IN_USE(pGpu))
188     {
189         NV_ASSERT_FAILED("Subscription failed: MIG GPU instancing not done\n");
190         return NV_ERR_NOT_SUPPORTED;
191     }
192 
193     if (!kmigmgrIsSwizzIdInUse(pGpu, pKernelMIGManager, swizzId))
194     {
195         NV_PRINTF(LEVEL_ERROR,
196                   "Subscription failed: swizzid 0x%0x doesn't exist!\n",
197                   swizzId);
198         return NV_ERR_INVALID_ARGUMENT;
199     }
200 
201     if (_gisubscriptionClientSharesVASCrossPartition(pGPUInstanceSubscription, pCallContext, swizzId))
202     {
203         NV_PRINTF(LEVEL_ERROR,
204                   "Subscription failed: Client shares VAS with client not subscribed to target GPU instance!\n");
205         return NV_ERR_STATE_IN_USE;
206     }
207 
208     NV_ASSERT_OK_OR_RETURN(
209         kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager, swizzId,
210                                   &pGPUInstanceSubscription->pKernelMIGGpuInstance));
211 
212     // For now skip kernel clients, such as UVM, until Bug 2729768 is fixed.
213     if (pRsClient->type == CLIENT_TYPE_USER)
214     {
215         status = osRmCapAcquire(pGPUInstanceSubscription->pKernelMIGGpuInstance->pOsRmCaps,
216                                 NV_RM_CAP_SMC_PARTITION_ACCESS,
217                                 pUserParams->capDescriptor,
218                                 &pGPUInstanceSubscription->dupedCapDescriptor);
219         if ((status != NV_ERR_NOT_SUPPORTED) && (status != NV_OK))
220         {
221             NV_PRINTF(LEVEL_ERROR,
222                       "Capability validation failed: swizzid 0x%0x!\n",
223                       swizzId);
224             return status;
225         }
226     }
227 
228     status = kmigmgrIncRefCount(pGPUInstanceSubscription->pKernelMIGGpuInstance->pShare);
229     if (status != NV_OK)
230     {
231         NV_PRINTF(LEVEL_ERROR,
232                   "GPU instance ref-counting failed: swizzid 0x%0x!\n",
233                   swizzId);
234         goto cleanup_duped_desc;
235     }
236 
237 done:
238     NV_PRINTF(LEVEL_INFO, "Client 0x%x subscribed to swizzid 0x%0x.\n",
239               pRmAllocParams->hClient, swizzId);
240 
241     return NV_OK;
242 
243 cleanup_duped_desc:
244     osRmCapRelease(pGPUInstanceSubscription->dupedCapDescriptor);
245 
246     return status;
247 }
248 
249 NV_STATUS
gisubscriptionCopyConstruct_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,CALL_CONTEXT * pCallContext,RS_RES_ALLOC_PARAMS_INTERNAL * pParams)250 gisubscriptionCopyConstruct_IMPL
251 (
252     GPUInstanceSubscription *pGPUInstanceSubscription,
253     CALL_CONTEXT *pCallContext,
254     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
255 )
256 {
257     RsResourceRef *pSrcRef = pParams->pSrcRef;
258     GPUInstanceSubscription *pGPUInstanceSubscriptionSrc = dynamicCast(pSrcRef->pResource, GPUInstanceSubscription);
259     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
260 
261     {
262         // non kernel clients are not allowed to dup GPU instances
263         NV_CHECK_OR_RETURN(LEVEL_SILENT, pCallContext->secInfo.privLevel >= RS_PRIV_LEVEL_KERNEL,
264                            NV_ERR_NOT_SUPPORTED);
265     }
266 
267     if (pGPUInstanceSubscriptionSrc->bDeviceProfiling)
268     {
269         // Duping of root-swizzId is not allowed
270         NV_PRINTF(LEVEL_ERROR,
271                       "Subscription failed: Duping not allowed for Device-level-SwizzId\n");
272         return NV_ERR_NOT_SUPPORTED;
273     }
274 
275     if (IS_VIRTUAL_WITH_SRIOV(pGpu) || IS_GSP_CLIENT(pGpu))
276     {
277         RsResourceRef *pDstRef = pCallContext->pResourceRef;
278         NV_STATUS status = NV_OK;
279 
280         NV_RM_RPC_DUP_OBJECT(pGpu,
281             pCallContext->pClient->hClient,
282             pDstRef->pParentRef->hResource,
283             pDstRef->hResource,
284             pParams->pSrcClient->hClient,
285             pSrcRef->hResource,
286             0, NV_TRUE, // Send RPC for object free
287             pDstRef, status);
288         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, status);
289     }
290 
291     pGPUInstanceSubscription->pKernelMIGGpuInstance = pGPUInstanceSubscriptionSrc->pKernelMIGGpuInstance;
292     // TODO XXX tracking this to support CI subscription bypass path for UVM
293     pGPUInstanceSubscription->bIsDuped = NV_TRUE;
294 
295     NV_ASSERT_OK(
296         kmigmgrIncRefCount(pGPUInstanceSubscription->pKernelMIGGpuInstance->pShare));
297 
298     return NV_OK;
299 }
300 
301 void
gisubscriptionDestruct_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription)302 gisubscriptionDestruct_IMPL
303 (
304     GPUInstanceSubscription *pGPUInstanceSubscription
305 )
306 {
307     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
308     CALL_CONTEXT *pCallContext;
309     RS_RES_FREE_PARAMS_INTERNAL *pParams;
310     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
311 
312     resGetFreeParams(staticCast(pGPUInstanceSubscription, RsResource), &pCallContext, &pParams);
313 
314     if (pGPUInstanceSubscription->bDeviceProfiling)
315     {
316         kmigmgrClearDeviceProfilingInUse(pGpu, pKernelMIGManager);
317         pGPUInstanceSubscription->bDeviceProfiling = NV_FALSE;
318         return;
319     }
320 
321     NV_ASSERT_OK(
322         kmigmgrDecRefCount(pGPUInstanceSubscription->pKernelMIGGpuInstance->pShare));
323 
324     osRmCapRelease(pGPUInstanceSubscription->dupedCapDescriptor);
325 
326     gisubscriptionCleanupOnUnsubscribe(pCallContext);
327 
328     NV_PRINTF(LEVEL_INFO, "Client 0x%x unsubscribed from swizzid 0x%0x.\n",
329               RES_GET_CLIENT(pGPUInstanceSubscription)->hClient, pGPUInstanceSubscription->pKernelMIGGpuInstance->swizzId);
330 }
331 
332 NvBool
gisubscriptionIsDuped_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription)333 gisubscriptionIsDuped_IMPL
334 (
335     GPUInstanceSubscription *pGPUInstanceSubscription
336 )
337 {
338     return pGPUInstanceSubscription->bIsDuped;
339 }
340 
341 NV_STATUS
gisubscriptionGetGPUInstanceSubscription_IMPL(RsClient * pClient,NvHandle hParent,GPUInstanceSubscription ** ppGPUInstanceSubscription)342 gisubscriptionGetGPUInstanceSubscription_IMPL
343 (
344     RsClient *pClient,
345     NvHandle  hParent,
346     GPUInstanceSubscription **ppGPUInstanceSubscription
347 )
348 {
349     RsResourceRef *pResourceRef;
350 
351     NV_ASSERT_OR_RETURN(NULL != ppGPUInstanceSubscription, NV_ERR_INVALID_ARGUMENT);
352 
353     pResourceRef = serverutilFindChildRefByType(pClient->hClient,
354                                                 hParent, classId(GPUInstanceSubscription),
355                                                 NV_TRUE);
356     if (pResourceRef == NULL)
357         return NV_ERR_OBJECT_NOT_FOUND;
358 
359     *ppGPUInstanceSubscription = dynamicCast(pResourceRef->pResource, GPUInstanceSubscription);
360 
361     return NV_OK;
362 }
363 
364 NvBool
gisubscriptionCanCopy_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription)365 gisubscriptionCanCopy_IMPL
366 (
367     GPUInstanceSubscription *pGPUInstanceSubscription
368 )
369 {
370     return NV_TRUE;
371 }
372 
373 //
374 // gisubscriptionCtrlCmdExecPartitionsCreate
375 //
376 // Lock Requirements:
377 //      Assert that API and GPUs lock held on entry
378 //
379 NV_STATUS
gisubscriptionCtrlCmdExecPartitionsCreate_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,NVC637_CTRL_EXEC_PARTITIONS_CREATE_PARAMS * pParams)380 gisubscriptionCtrlCmdExecPartitionsCreate_IMPL
381 (
382     GPUInstanceSubscription *pGPUInstanceSubscription,
383     NVC637_CTRL_EXEC_PARTITIONS_CREATE_PARAMS *pParams
384 )
385 {
386     NV_STATUS status = NV_OK;
387     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
388     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
389     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance = pGPUInstanceSubscription->pKernelMIGGpuInstance;
390 
391     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
392 
393 {
394     CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
395 
396     NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE);
397 
398     if (!rmclientIsCapableOrAdminByHandle(RES_GET_CLIENT_HANDLE(pGPUInstanceSubscription),
399                                           NV_RM_CAP_SYS_SMC_CONFIG,
400                                           pCallContext->secInfo.privLevel))
401     {
402         NV_PRINTF(LEVEL_ERROR, "Non-privileged context issued privileged cmd\n");
403         return NV_ERR_INSUFFICIENT_PERMISSIONS;
404     }
405 }
406 
407     NV_ASSERT_OR_RETURN(pGpu->getProperty(pGpu, PDB_PROP_GPU_MIG_SUPPORTED), NV_ERR_NOT_SUPPORTED);
408     NV_ASSERT_OR_RETURN(IS_MIG_IN_USE(pGpu), NV_ERR_INVALID_STATE);
409 
410     NV_CHECK_OR_RETURN(LEVEL_SILENT, (pParams->execPartCount <= NVC637_CTRL_MAX_EXEC_PARTITIONS),
411                      NV_ERR_INVALID_ARGUMENT);
412 
413     // Check for trivial arguments
414     NV_CHECK_OR_RETURN(LEVEL_SILENT, pParams->execPartCount > 0, NV_WARN_NOTHING_TO_DO);
415 
416     if (IS_VIRTUAL(pGpu) || IS_GSP_CLIENT(pGpu))
417     {
418         CALL_CONTEXT *pCallContext  = resservGetTlsCallContext();
419         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
420 
421         NV_RM_RPC_CONTROL(pGpu, pRmCtrlParams->hClient,
422                           pRmCtrlParams->hObject, pRmCtrlParams->cmd,
423                           pRmCtrlParams->pParams,
424                           pRmCtrlParams->paramsSize, status);
425 
426         // Only continue if execution partition creation succeeded in the host
427         NV_ASSERT_OK_OR_RETURN(status);
428     }
429 
430     if (!IS_GSP_CLIENT(pGpu))
431     {
432         KMIGMGR_CREATE_COMPUTE_INSTANCE_PARAMS request =
433         {
434             .type = KMIGMGR_CREATE_COMPUTE_INSTANCE_PARAMS_TYPE_REQUEST,
435             .inst.request.count = pParams->execPartCount,
436             .inst.request.pReqComputeInstanceInfo = pParams->execPartInfo,
437             .inst.request.requestFlags = pParams->flags
438         };
439 
440         if (!hypervisorIsVgxHyper())
441         {
442             request.inst.request.requestFlags = FLD_SET_DRF(C637_CTRL, _DMA_EXEC_PARTITIONS_CREATE_REQUEST, _WITH_PART_ID, _FALSE, request.inst.request.requestFlags);
443         }
444 
445         if (IS_VIRTUAL(pGpu))
446         {
447             status = kmigmgrCreateComputeInstances_HAL(pGpu, pKernelMIGManager, pKernelMIGGpuInstance,
448                                                        pParams->bQuery,
449                                                        request,
450                                                        pParams->execPartId,
451                                                        NV_TRUE /* create MIG compute instance capabilities */);
452         }
453         else
454         {
455             return NV_ERR_NOT_SUPPORTED;
456         }
457 
458         {
459             NvU32 i;
460 
461             for (i = 0; i < pParams->execPartCount; i++)
462             {
463                 gpumgrCacheCreateComputeInstance(pGpu, pKernelMIGGpuInstance->swizzId,
464                                                  pParams->execPartId[i]);
465             }
466         }
467     }
468     else
469     {
470         NvU32 i;
471 
472         for (i = 0; i < pParams->execPartCount; i++)
473         {
474             RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
475             NVC637_CTRL_EXEC_PARTITIONS_IMPORT_EXPORT_PARAMS export;
476             GPUMGR_SAVE_COMPUTE_INSTANCE save;
477             KMIGMGR_CREATE_COMPUTE_INSTANCE_PARAMS restore =
478             {
479                 .type = KMIGMGR_CREATE_COMPUTE_INSTANCE_PARAMS_TYPE_RESTORE,
480                 .inst.restore.pComputeInstanceSave = &save,
481             };
482             portMemSet(&export, 0, sizeof(export));
483             export.id = pParams->execPartId[i];
484 
485             // Retrieve the CI state created by GSP-RM, then restore it to CPU-RM
486             NV_ASSERT_OK_OR_RETURN(
487                 pRmApi->Control(pRmApi,
488                                 pKernelMIGGpuInstance->instanceHandles.hClient,
489                                 pKernelMIGGpuInstance->instanceHandles.hSubscription,
490                                 NVC637_CTRL_CMD_EXEC_PARTITIONS_EXPORT,
491                                 &export,
492                                 sizeof(export)));
493 
494             portMemSet(&save, 0, sizeof(save));
495             save.bValid = NV_TRUE;
496             save.id = pParams->execPartId[i];
497             save.ciInfo = export.info;
498 
499             NV_ASSERT_OK_OR_RETURN(
500                 kmigmgrCreateComputeInstances_HAL(pGpu, pKernelMIGManager, pKernelMIGGpuInstance,
501                                                   NV_FALSE, restore, &pParams->execPartId[i], NV_TRUE));
502 
503             gpumgrCacheCreateComputeInstance(pGpu, pKernelMIGGpuInstance->swizzId,
504                                              pParams->execPartId[i]);
505         }
506     }
507 
508     //
509     // Generate a subdevice event stating something has changed in GPU instance
510     // config. Clients currently do not care about changes and their scope
511     //
512     if (!pParams->bQuery)
513     {
514         gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_SMC_CONFIG_UPDATE, NULL,
515                                 0, 0, 0);
516     }
517 
518     return status;
519 }
520 
521 //
522 // gisubscriptionCtrlCmdExecPartitionsDelete
523 //
524 // Lock Requirements:
525 //      Assert that API and GPUs lock held on entry
526 //
527 NV_STATUS
gisubscriptionCtrlCmdExecPartitionsDelete_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,NVC637_CTRL_EXEC_PARTITIONS_DELETE_PARAMS * pParams)528 gisubscriptionCtrlCmdExecPartitionsDelete_IMPL
529 (
530     GPUInstanceSubscription *pGPUInstanceSubscription,
531     NVC637_CTRL_EXEC_PARTITIONS_DELETE_PARAMS *pParams
532 )
533 {
534     NV_STATUS status = NV_OK;
535     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
536     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance = pGPUInstanceSubscription->pKernelMIGGpuInstance;
537     NvU32 execPartIdx;
538 
539     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
540 
541 {
542     CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
543 
544     NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE);
545 
546     if (!rmclientIsCapableOrAdminByHandle(RES_GET_CLIENT_HANDLE(pGPUInstanceSubscription),
547                                           NV_RM_CAP_SYS_SMC_CONFIG,
548                                           pCallContext->secInfo.privLevel))
549     {
550         NV_PRINTF(LEVEL_ERROR, "Non-privileged context issued privileged cmd\n");
551         return NV_ERR_INSUFFICIENT_PERMISSIONS;
552     }
553 }
554 
555     NV_ASSERT_OR_RETURN(pGpu->getProperty(pGpu, PDB_PROP_GPU_MIG_SUPPORTED),
556                         NV_ERR_NOT_SUPPORTED);
557 
558     NV_ASSERT_OR_RETURN(IS_MIG_IN_USE(pGpu), NV_ERR_INVALID_STATE);
559 
560     NV_CHECK_OR_RETURN(LEVEL_SILENT, pParams->execPartCount <= NVC637_CTRL_MAX_EXEC_PARTITIONS,
561                      NV_ERR_INVALID_ARGUMENT);
562 
563     // Check for trivial arguments
564     NV_CHECK_OR_RETURN(LEVEL_SILENT, pParams->execPartCount > 0, NV_WARN_NOTHING_TO_DO);
565 
566     // Check that the passed indices are valid compute instances
567     for (execPartIdx = 0; execPartIdx < pParams->execPartCount; ++execPartIdx)
568     {
569         NvU32 execPartId = pParams->execPartId[execPartIdx];
570         NV_CHECK_OR_RETURN(LEVEL_ERROR,
571             execPartId < KMIGMGR_MAX_COMPUTE_INSTANCES,
572             NV_ERR_INVALID_ARGUMENT);
573         NV_CHECK_OR_RETURN(LEVEL_ERROR,
574             pKernelMIGGpuInstance->MIGComputeInstance[execPartId].bValid,
575             NV_ERR_INVALID_ARGUMENT);
576     }
577 
578     for (execPartIdx = 0; execPartIdx < pParams->execPartCount; ++execPartIdx)
579     {
580         if (IS_VIRTUAL(pGpu) || IS_GSP_CLIENT(pGpu))
581         {
582             KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
583             NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
584                 kmigmgrDeleteComputeInstance(pGpu, pKernelMIGManager, pKernelMIGGpuInstance,
585                                              pParams->execPartId[execPartIdx],
586                                              NV_FALSE));
587         }
588         else
589         {
590             return NV_ERR_NOT_SUPPORTED;
591         }
592         gpumgrCacheDestroyComputeInstance(pGpu, pKernelMIGGpuInstance->swizzId,
593                                           pParams->execPartId[execPartIdx]);
594     }
595 
596     //
597     // Generate a subdevice event stating something has changed in GPU instance
598     // config. Clients currently do not care about changes and their scope
599     //
600     gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_SMC_CONFIG_UPDATE, NULL, 0, 0, 0);
601 
602     if (IS_VIRTUAL(pGpu) || IS_GSP_CLIENT(pGpu))
603     {
604         CALL_CONTEXT *pCallContext  = resservGetTlsCallContext();
605         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
606 
607         NV_RM_RPC_CONTROL(pGpu, pRmCtrlParams->hClient,
608                           pRmCtrlParams->hObject, pRmCtrlParams->cmd,
609                           pRmCtrlParams->pParams,
610                           pRmCtrlParams->paramsSize, status);
611 
612         NV_ASSERT_OK_OR_RETURN(status);
613     }
614 
615     return status;
616 }
617 
618 //
619 // gisubscriptionCtrlCmdExecPartitionsGet
620 //
621 // Lock Requirements:
622 //      Assert that API and GPUs lock held on entry
623 //
624 NV_STATUS
gisubscriptionCtrlCmdExecPartitionsGet_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,NVC637_CTRL_EXEC_PARTITIONS_GET_PARAMS * pParams)625 gisubscriptionCtrlCmdExecPartitionsGet_IMPL
626 (
627     GPUInstanceSubscription *pGPUInstanceSubscription,
628     NVC637_CTRL_EXEC_PARTITIONS_GET_PARAMS *pParams
629 )
630 {
631     NV_STATUS status = NV_OK;
632     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
633     ComputeInstanceSubscription *pComputeInstanceSubscription = NULL;
634     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance = pGPUInstanceSubscription->pKernelMIGGpuInstance;
635     NvU32 ciIdx;
636     NvHandle hClient = RES_GET_CLIENT_HANDLE(pGPUInstanceSubscription);
637     CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
638     NvBool bEnumerateAll = NV_FALSE;
639 
640     NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE);
641 
642     // Capability checks shouldn't be done on
643     if (!RMCFG_FEATURE_PLATFORM_GSP)
644     {
645         bEnumerateAll = rmclientIsCapableOrAdminByHandle(hClient,
646                                                          NV_RM_CAP_SYS_SMC_CONFIG,
647                                                          pCallContext->secInfo.privLevel);
648     }
649 
650     MIG_COMPUTE_INSTANCE *pTargetComputeInstanceInfo = NULL;
651 
652     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
653 
654     NV_ASSERT_OR_RETURN(pGpu->getProperty(pGpu, PDB_PROP_GPU_MIG_SUPPORTED),
655                         NV_ERR_NOT_SUPPORTED);
656 
657     NV_ASSERT_OR_RETURN(IS_MIG_IN_USE(pGpu), NV_ERR_INVALID_STATE);
658 
659     (void)cisubscriptionGetComputeInstanceSubscription(RES_GET_CLIENT(pGPUInstanceSubscription), RES_GET_HANDLE(pGPUInstanceSubscription), &pComputeInstanceSubscription);
660     if (pComputeInstanceSubscription != NULL)
661     {
662         pTargetComputeInstanceInfo = cisubscriptionGetMIGComputeInstance(pComputeInstanceSubscription);
663     }
664     else if (!bEnumerateAll)
665     {
666         return NV_ERR_INSUFFICIENT_PERMISSIONS;
667     }
668 
669     pParams->execPartCount = 0;
670     for (ciIdx = 0;
671          ciIdx < NV_ARRAY_ELEMENTS(pKernelMIGGpuInstance->MIGComputeInstance);
672          ++ciIdx)
673     {
674         NVC637_CTRL_EXEC_PARTITIONS_INFO *pOutInfo;
675         MIG_COMPUTE_INSTANCE *pMIGComputeInstance =
676             &pKernelMIGGpuInstance->MIGComputeInstance[ciIdx];
677 
678         if (!pMIGComputeInstance->bValid)
679             continue;
680 
681         if (!bEnumerateAll && (pMIGComputeInstance != pTargetComputeInstanceInfo))
682             continue;
683 
684         pParams->execPartId[pParams->execPartCount] = ciIdx;
685         pOutInfo = &pParams->execPartInfo[pParams->execPartCount];
686         ++pParams->execPartCount;
687 
688         pOutInfo->gpcCount = pMIGComputeInstance->resourceAllocation.gpcCount;
689         pOutInfo->gfxGpcCount = pMIGComputeInstance->resourceAllocation.gfxGpcCount;
690         pOutInfo->veidCount = pMIGComputeInstance->resourceAllocation.veidCount;
691         pOutInfo->ceCount = kmigmgrCountEnginesOfType(&pMIGComputeInstance->resourceAllocation.engines,
692                                                       RM_ENGINE_TYPE_COPY(0));
693         pOutInfo->nvEncCount = kmigmgrCountEnginesOfType(&pMIGComputeInstance->resourceAllocation.engines,
694                                                       RM_ENGINE_TYPE_NVENC(0));
695         pOutInfo->nvDecCount = kmigmgrCountEnginesOfType(&pMIGComputeInstance->resourceAllocation.engines,
696                                                       RM_ENGINE_TYPE_NVDEC(0));
697         pOutInfo->nvJpgCount = kmigmgrCountEnginesOfType(&pMIGComputeInstance->resourceAllocation.engines,
698                                                       RM_ENGINE_TYPE_NVJPG);
699         pOutInfo->ofaCount = kmigmgrCountEnginesOfType(&pMIGComputeInstance->resourceAllocation.engines,
700                                                       RM_ENGINE_TYPE_OFA(0));
701         pOutInfo->sharedEngFlag = pMIGComputeInstance->sharedEngFlag;
702         pOutInfo->veidStartOffset = pMIGComputeInstance->resourceAllocation.veidOffset;
703         pOutInfo->smCount = pMIGComputeInstance->resourceAllocation.smCount;
704         pOutInfo->computeSize = pMIGComputeInstance->computeSize;
705         pOutInfo->spanStart = pMIGComputeInstance->spanStart;
706     }
707 
708     return status;
709 }
710 
711 //
712 // gisubscriptionCtrlCmdExecPartitionsGetActiveIds
713 //
714 // Lock Requirements:
715 //      Assert that API and GPUs lock held on entry
716 //
717 NV_STATUS
gisubscriptionCtrlCmdExecPartitionsGetActiveIds_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,NVC637_CTRL_EXEC_PARTITIONS_GET_ACTIVE_IDS_PARAMS * pParams)718 gisubscriptionCtrlCmdExecPartitionsGetActiveIds_IMPL
719 (
720     GPUInstanceSubscription *pGPUInstanceSubscription,
721     NVC637_CTRL_EXEC_PARTITIONS_GET_ACTIVE_IDS_PARAMS *pParams
722 )
723 {
724     NV_STATUS status = NV_OK;
725     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
726     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance = pGPUInstanceSubscription->pKernelMIGGpuInstance;
727     NvU32 ciIdx;
728 
729     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
730 
731     NV_ASSERT_OR_RETURN(pGpu->getProperty(pGpu, PDB_PROP_GPU_MIG_SUPPORTED),
732                         NV_ERR_NOT_SUPPORTED);
733 
734     NV_ASSERT_OR_RETURN(IS_MIG_IN_USE(pGpu), NV_ERR_INVALID_STATE);
735 
736     pParams->execPartCount = 0;
737     for (ciIdx = 0;
738          ciIdx < NV_ARRAY_ELEMENTS(pKernelMIGGpuInstance->MIGComputeInstance);
739          ++ciIdx)
740     {
741         MIG_COMPUTE_INSTANCE *pMIGComputeInstance =
742             &pKernelMIGGpuInstance->MIGComputeInstance[ciIdx];
743 
744         if (!pMIGComputeInstance->bValid)
745             continue;
746 
747         pParams->execPartId[pParams->execPartCount] = ciIdx;
748 
749         ct_assert(NV_UUID_LEN == NVC637_UUID_LEN);
750         ct_assert(NV_UUID_STR_LEN == NVC637_UUID_STR_LEN);
751 
752         nvGetSmcUuidString(&pMIGComputeInstance->uuid,
753                            pParams->execPartUuid[pParams->execPartCount].str);
754 
755         ++pParams->execPartCount;
756     }
757 
758     return status;
759 }
760 
761 NV_STATUS
gisubscriptionCtrlCmdExecPartitionsExport_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,NVC637_CTRL_EXEC_PARTITIONS_IMPORT_EXPORT_PARAMS * pParams)762 gisubscriptionCtrlCmdExecPartitionsExport_IMPL
763 (
764     GPUInstanceSubscription *pGPUInstanceSubscription,
765     NVC637_CTRL_EXEC_PARTITIONS_IMPORT_EXPORT_PARAMS *pParams
766 )
767 {
768     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
769     KERNEL_MIG_GPU_INSTANCE *pGPUInstance = pGPUInstanceSubscription->pKernelMIGGpuInstance;
770     MIG_COMPUTE_INSTANCE *pMIGComputeInstance;
771     NvU32 gpcIdx;
772 
773     // No partitions to export
774     if (!IS_MIG_IN_USE(pGpu))
775         return NV_ERR_NOT_SUPPORTED;
776 
777 {
778     CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
779 
780     NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE);
781 
782     // An unprivileged client has no use case for import/export
783     if (!rmclientIsCapableOrAdminByHandle(RES_GET_CLIENT_HANDLE(pGPUInstanceSubscription),
784                                           NV_RM_CAP_SYS_SMC_CONFIG,
785                                           pCallContext->secInfo.privLevel))
786     {
787         return NV_ERR_INSUFFICIENT_PERMISSIONS;
788     }
789 }
790 
791     if (IS_VIRTUAL(pGpu))
792     {
793         // Guest RM does not support import/export
794         return NV_ERR_NOT_SUPPORTED;
795     }
796 
797     if (IS_GSP_CLIENT(pGpu))
798     {
799         CALL_CONTEXT *pCallContext  = resservGetTlsCallContext();
800         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
801         RM_API       *pRmApi        = GPU_GET_PHYSICAL_RMAPI(pGpu);
802 
803         return pRmApi->Control(pRmApi,
804                                pRmCtrlParams->hClient,
805                                pRmCtrlParams->hObject,
806                                pRmCtrlParams->cmd,
807                                pRmCtrlParams->pParams,
808                                pRmCtrlParams->paramsSize);
809     }
810 
811     if (pParams->id >= NV_ARRAY_ELEMENTS(pGPUInstance->MIGComputeInstance))
812         return NV_ERR_INVALID_ARGUMENT;
813 
814     if (!pGPUInstance->MIGComputeInstance[pParams->id].bValid)
815         return NV_ERR_OBJECT_NOT_FOUND;
816 
817     pMIGComputeInstance = &pGPUInstance->MIGComputeInstance[pParams->id];
818 
819     portMemCopy(pParams->info.uuid, sizeof(pParams->info.uuid),
820                 pMIGComputeInstance->uuid.uuid, sizeof(pMIGComputeInstance->uuid.uuid));
821     pParams->info.sharedEngFlags = pMIGComputeInstance->sharedEngFlag;
822     pParams->info.veidOffset     = pMIGComputeInstance->resourceAllocation.veidOffset;
823     pParams->info.veidCount      = pMIGComputeInstance->resourceAllocation.veidCount;
824     pParams->info.smCount        = pMIGComputeInstance->resourceAllocation.smCount;
825     pParams->info.spanStart      = pMIGComputeInstance->spanStart;
826     pParams->info.computeSize    = pMIGComputeInstance->computeSize;
827 
828     for (gpcIdx = 0; gpcIdx < pMIGComputeInstance->resourceAllocation.gpcCount; ++gpcIdx)
829     {
830          pParams->info.gpcMask |= NVBIT32(pMIGComputeInstance->resourceAllocation.gpcIds[gpcIdx]);
831     }
832     bitVectorToRaw(&pMIGComputeInstance->resourceAllocation.engines,
833                    pParams->info.enginesMask, sizeof(pParams->info.enginesMask));
834 
835     return NV_OK;
836 }
837 
838 NV_STATUS
gisubscriptionCtrlCmdExecPartitionsImport_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,NVC637_CTRL_EXEC_PARTITIONS_IMPORT_EXPORT_PARAMS * pParams)839 gisubscriptionCtrlCmdExecPartitionsImport_IMPL
840 (
841     GPUInstanceSubscription *pGPUInstanceSubscription,
842     NVC637_CTRL_EXEC_PARTITIONS_IMPORT_EXPORT_PARAMS *pParams
843 )
844 {
845     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
846     KERNEL_MIG_GPU_INSTANCE *pGPUInstance = pGPUInstanceSubscription->pKernelMIGGpuInstance;
847     NV_STATUS status = NV_OK;
848 
849     if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_MIG_SUPPORTED))
850         return NV_ERR_NOT_SUPPORTED;
851 
852 {
853     CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
854 
855     NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE);
856 
857     // An unprivileged client has no use case for import/export
858     if (!rmclientIsCapableOrAdminByHandle(RES_GET_CLIENT_HANDLE(pGPUInstanceSubscription),
859                                           NV_RM_CAP_SYS_SMC_CONFIG,
860                                           pCallContext->secInfo.privLevel))
861     {
862         return NV_ERR_INSUFFICIENT_PERMISSIONS;
863     }
864 }
865 
866     if (IS_VIRTUAL(pGpu))
867     {
868         // Guest RM does not support import/export
869         return NV_ERR_NOT_SUPPORTED;
870     }
871 
872     if (IS_GSP_CLIENT(pGpu))
873     {
874         CALL_CONTEXT *pCallContext  = resservGetTlsCallContext();
875         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
876         RM_API       *pRmApi        = GPU_GET_PHYSICAL_RMAPI(pGpu);
877 
878         status = pRmApi->Control(pRmApi,
879                                  pRmCtrlParams->hClient,
880                                  pRmCtrlParams->hObject,
881                                  pRmCtrlParams->cmd,
882                                  pRmCtrlParams->pParams,
883                                  pRmCtrlParams->paramsSize);
884 
885         if (status != NV_OK)
886             return status;
887     }
888 
889     {
890         GPUMGR_SAVE_COMPUTE_INSTANCE save;
891         KMIGMGR_CREATE_COMPUTE_INSTANCE_PARAMS restore =
892         {
893             .type = KMIGMGR_CREATE_COMPUTE_INSTANCE_PARAMS_TYPE_RESTORE,
894             .inst.restore.pComputeInstanceSave = &save,
895         };
896 
897         portMemSet(&save, 0, sizeof(save));
898         save.bValid = NV_TRUE;
899         save.id = pParams->id;
900         save.ciInfo = pParams->info;
901 
902         if (IS_GSP_CLIENT(pGpu))
903         {
904             KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
905             NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR,
906                 kmigmgrCreateComputeInstances_HAL(pGpu, pKernelMIGManager,
907                  pGPUInstance, NV_FALSE, restore, &pParams->id, pParams->bCreateCap),
908                 cleanup_rpc);
909         }
910         else
911         {
912             return NV_ERR_NOT_SUPPORTED;
913         }
914     }
915 
916     return NV_OK;
917 
918 cleanup_rpc:
919     if (IS_GSP_CLIENT(pGpu))
920     {
921         NVC637_CTRL_EXEC_PARTITIONS_DELETE_PARAMS params;
922         RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
923 
924         portMemSet(&params, 0, sizeof(params));
925         params.execPartCount = 1;
926         params.execPartId[0] = pParams->id;
927 
928         NV_ASSERT_OK(
929             pRmApi->Control(pRmApi,
930                             RES_GET_CLIENT_HANDLE(pGPUInstanceSubscription),
931                             RES_GET_HANDLE(pGPUInstanceSubscription),
932                             NVC637_CTRL_CMD_EXEC_PARTITIONS_DELETE,
933                             &params,
934                             sizeof(params)));
935     }
936 
937     return status;
938 }
939 
940 /*!
941  * @brief Determines whether an object of the given class id is affected by
942  * gpu/compute instance subscription and should be automatically freed if a
943  * client unsubscribes from a gpu/compute instance.
944  */
945 NvBool
gisubscriptionShouldClassBeFreedOnUnsubscribe_IMPL(NvU32 internalClassId)946 gisubscriptionShouldClassBeFreedOnUnsubscribe_IMPL
947 (
948     NvU32 internalClassId
949 )
950 {
951     NvBool bShouldFree = NV_TRUE;
952 
953     switch (internalClassId)
954     {
955         case (classId(Device)):
956             // fall-through
957         case (classId(Subdevice)):
958             // fall-through
959         case (classId(GPUInstanceSubscription)):
960             // fall-through
961         case (classId(ComputeInstanceSubscription)):
962             bShouldFree = NV_FALSE;
963             break;
964         default:
965             break;
966     }
967 
968     return bShouldFree;
969 }
970 
971 /*!
972  * @brief Automatically frees client resources which may be affected by
973  * subscription objects. This is intended to be called on unsubscription.
974  *
975  * @see gisubscriptionShouldClassBeFreedOnUnsubscribe
976  *
977  * @param[in] pCallContext         Call context of client to clean up
978  */
979 void
gisubscriptionCleanupOnUnsubscribe_IMPL(CALL_CONTEXT * pCallContext)980 gisubscriptionCleanupOnUnsubscribe_IMPL
981 (
982     CALL_CONTEXT *pCallContext
983 )
984 {
985     RsResourceRef *pDeviceRef;
986     RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
987     RS_ITERATOR iter;
988     NvHandle *pHandles;
989     NvU32 handleCount;
990     NvU32 i;
991 
992     NV_ASSERT_OK(
993         refFindAncestorOfType(pCallContext->pResourceRef, classId(Device), &pDeviceRef));
994 
995     // Determine the number of handles we need to free
996     handleCount = 0;
997     iter = serverutilRefIter(pCallContext->pClient->hClient,
998                              pDeviceRef->hResource,
999                              0,
1000                              RS_ITERATE_DESCENDANTS,
1001                              NV_FALSE);
1002     while (clientRefIterNext(iter.pClient, &iter))
1003     {
1004         RsResourceRef *pResourceRef = iter.pResourceRef;
1005 
1006         if (!gisubscriptionShouldClassBeFreedOnUnsubscribe(pResourceRef->internalClassId))
1007             continue;
1008 
1009         ++handleCount;
1010         NV_PRINTF(LEVEL_INFO,
1011                   "Will be freeing resource class id 0x%x on unsubscription!\n",
1012                   pResourceRef->internalClassId);
1013     }
1014 
1015     // If we have nothing to free then bail early
1016     if (handleCount == 0)
1017         goto done;
1018 
1019     // Allocate an array large enough to store the handles we need to free
1020     pHandles = portMemAllocNonPaged(handleCount * sizeof(*pHandles));
1021     if (NULL == pHandles)
1022     {
1023         NV_ASSERT(0);
1024         goto done;
1025     }
1026 
1027     // Store the handles that we need to free
1028     i = 0;
1029     iter = serverutilRefIter(pCallContext->pClient->hClient,
1030                              pDeviceRef->hResource,
1031                              0,
1032                              RS_ITERATE_DESCENDANTS,
1033                              NV_FALSE);
1034     while (clientRefIterNext(iter.pClient, &iter))
1035     {
1036         RsResourceRef *pResourceRef = iter.pResourceRef;
1037 
1038         if (!gisubscriptionShouldClassBeFreedOnUnsubscribe(pResourceRef->internalClassId))
1039             continue;
1040 
1041         NV_ASSERT_OR_GOTO(i < handleCount, cleanup);
1042         pHandles[i++] = pResourceRef->hResource;
1043     }
1044 
1045     //
1046     // Free all of the handles we flagged for deletion.
1047     // Note - some of these resources will free other dependant resources, so
1048     // some of these free calls will do nothing. That's fine for our purposes.
1049     //
1050     NV_ASSERT_OR_GOTO(i == handleCount, cleanup);
1051     for (i = 0; i < handleCount; ++i)
1052         pRmApi->Free(pRmApi, pCallContext->pClient->hClient, pHandles[i]);
1053 
1054 cleanup:
1055     portMemFree(pHandles);
1056 
1057 done:
1058     return;
1059 }
1060 
1061 NV_STATUS
gisubscriptionCtrlCmdExecPartitionsGetProfileCapacity_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,NVC637_CTRL_EXEC_PARTITIONS_GET_PROFILE_CAPACITY_PARAMS * pParams)1062 gisubscriptionCtrlCmdExecPartitionsGetProfileCapacity_IMPL
1063 (
1064     GPUInstanceSubscription *pGPUInstanceSubscription,
1065     NVC637_CTRL_EXEC_PARTITIONS_GET_PROFILE_CAPACITY_PARAMS *pParams
1066 )
1067 {
1068     OBJGPU *pGpu = GPU_RES_GET_GPU(pGPUInstanceSubscription);
1069     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance = pGPUInstanceSubscription->pKernelMIGGpuInstance;
1070     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1071     NvBool bCtsRequired = kmigmgrIsCTSAlignmentRequired(pGpu, pKernelMIGManager);
1072 
1073     NV_CHECK_OR_RETURN(LEVEL_ERROR,
1074         pParams->computeSize < NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE__SIZE,
1075         NV_ERR_INVALID_ARGUMENT);
1076 
1077     if (bCtsRequired)
1078     {
1079         NV_RANGE totalRange = kmigmgrComputeProfileSizeToCTSIdRange(pParams->computeSize);
1080         NvU32 slotBasisComputeSize = kmigmgrSmallestComputeProfileSize(pGpu, pKernelMIGManager);
1081         NvU64 slotBasisMask;
1082         NvU64 validQueryMask;
1083         NvU64 inUseIdMask;
1084         NvU64 ctsId;
1085         NvU32 totalSpanCount;
1086         NvU32 availableSpanCount;
1087         NV_RANGE slotBasisIdRange;
1088 
1089         NV_CHECK_OR_RETURN(LEVEL_ERROR, slotBasisComputeSize != KMIGMGR_COMPUTE_SIZE_INVALID, NV_ERR_INVALID_STATE);
1090 
1091         slotBasisIdRange = kmigmgrComputeProfileSizeToCTSIdRange(slotBasisComputeSize);
1092 
1093         NV_CHECK_OR_RETURN(LEVEL_ERROR, !rangeIsEmpty(totalRange), NV_ERR_INVALID_ARGUMENT);
1094         NV_CHECK_OR_RETURN(LEVEL_ERROR, !rangeIsEmpty(slotBasisIdRange), NV_ERR_INVALID_ARGUMENT);
1095 
1096         slotBasisMask = DRF_SHIFTMASK64(slotBasisIdRange.hi:slotBasisIdRange.lo);
1097         validQueryMask = DRF_SHIFTMASK64(totalRange.hi:totalRange.lo) & pKernelMIGGpuInstance->pProfile->validCTSIdMask;
1098 
1099         // Find mask of un-usable IDs due to current in-use CTS Ids
1100         inUseIdMask = 0x0;
1101         FOR_EACH_INDEX_IN_MASK(64, ctsId, pKernelMIGGpuInstance->ctsIdsInUseMask)
1102         {
1103             NvU64 invalidMask;
1104 
1105             NV_ASSERT_OK(kmigmgrGetInvalidCTSIdMask(pGpu, pKernelMIGManager, ctsId, &invalidMask));
1106 
1107             inUseIdMask |= invalidMask;
1108         }
1109         FOR_EACH_INDEX_IN_MASK_END;
1110 
1111         //
1112         // The slot basis defines the smallest divison of the GPU instance.
1113         // CTS IDs from this range are used as a means to specify span placements
1114         // for compute profiles.
1115         //
1116         totalSpanCount = 0;
1117         availableSpanCount = 0;
1118 
1119         FOR_EACH_INDEX_IN_MASK(64, ctsId, validQueryMask)
1120         {
1121             NvU64 invalidMask;
1122 
1123             NV_ASSERT_OK(kmigmgrGetInvalidCTSIdMask(pGpu, pKernelMIGManager, ctsId, &invalidMask));
1124 
1125             invalidMask &= slotBasisMask;
1126             pParams->totalSpans[totalSpanCount].lo = portUtilCountTrailingZeros64(invalidMask) - slotBasisIdRange.lo;
1127             pParams->totalSpans[totalSpanCount].hi = nvPopCount64(invalidMask) + pParams->totalSpans[totalSpanCount].lo - 1;
1128 
1129             if (!(NVBIT64(ctsId) & inUseIdMask))
1130             {
1131                 pParams->availableSpans[availableSpanCount].lo = pParams->totalSpans[totalSpanCount].lo;
1132                 pParams->availableSpans[availableSpanCount].hi = pParams->totalSpans[totalSpanCount].hi;
1133                 availableSpanCount++;
1134             }
1135             totalSpanCount++;
1136         }
1137         FOR_EACH_INDEX_IN_MASK_END;
1138 
1139         pParams->totalSpansCount     = totalSpanCount;
1140         pParams->totalProfileCount   = totalSpanCount;
1141         pParams->availableSpansCount = availableSpanCount;
1142         pParams->profileCount        = availableSpanCount;
1143     }
1144     else
1145     {
1146         KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
1147         NV2080_CTRL_INTERNAL_MIGMGR_COMPUTE_PROFILE profile;
1148         NvU64 veidMask;
1149         NvU32 GPUInstanceVeidEnd;
1150         NvU64 GPUInstanceVeidMask;
1151         NvU64 GPUInstanceFreeVeidMask;
1152         NvU64 GPUInstancePseudoMask;
1153         NvU32 availableSpanCount;
1154         NvU32 totalSpanCount;
1155         NvU32 veidStepSize;
1156         NvU32 veidSlotCount;
1157         NvU32 count;
1158         NvU32 i;
1159 
1160         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
1161             kmigmgrGetComputeProfileFromSize(pGpu, pKernelMIGManager, pParams->computeSize, &profile));
1162         NV_ASSERT_OK_OR_RETURN(
1163             kgrmgrGetVeidStepSize(pGpu, pKernelGraphicsManager, &veidStepSize));
1164 
1165         // Create a mask for VEIDs associated with this GPU instance
1166         veidMask = DRF_SHIFTMASK64(profile.veidCount - 1:0);
1167         GPUInstanceVeidEnd = pKernelMIGGpuInstance->resourceAllocation.veidOffset + pKernelMIGGpuInstance->resourceAllocation.veidCount - 1;
1168         GPUInstanceVeidMask = DRF_SHIFTMASK64(GPUInstanceVeidEnd:pKernelMIGGpuInstance->resourceAllocation.veidOffset);
1169         GPUInstanceFreeVeidMask = GPUInstanceVeidMask &~ (kgrmgrGetVeidInUseMask(pGpu, pKernelGraphicsManager));
1170         GPUInstancePseudoMask = GPUInstanceFreeVeidMask;
1171         veidSlotCount = 0;
1172         availableSpanCount = 0;
1173         totalSpanCount = 0;
1174         count = 0;
1175         for (i = pKernelMIGGpuInstance->resourceAllocation.veidOffset; i < GPUInstanceVeidEnd; i += veidStepSize)
1176         {
1177             // Determine max correctly sized VEID segments
1178             if (((GPUInstanceFreeVeidMask >> i) & veidMask) == veidMask)
1179             {
1180                 pParams->availableSpans[availableSpanCount].lo = count;
1181                 pParams->availableSpans[availableSpanCount].hi = count + (profile.veidCount / veidStepSize) - 1;
1182                 availableSpanCount++;
1183             }
1184 
1185             // Determine max correctly sized VEID segments
1186             if (((GPUInstanceVeidMask >> i) & veidMask) == veidMask)
1187             {
1188                 pParams->totalSpans[totalSpanCount].lo = count;
1189                 pParams->totalSpans[totalSpanCount].hi = count + (profile.veidCount / veidStepSize) - 1;
1190                 totalSpanCount++;
1191             }
1192 
1193             // Determine max correctly sized VEID segments
1194             if (((GPUInstancePseudoMask >> i) & veidMask) == veidMask)
1195             {
1196                 veidSlotCount++;
1197                 GPUInstancePseudoMask &= ~(veidMask << i);
1198             }
1199             count++;
1200         }
1201         pParams->totalProfileCount = NV_MIN(pKernelMIGGpuInstance->pProfile->virtualGpcCount / profile.gpcCount,
1202                                                 pKernelMIGGpuInstance->pProfile->veidCount / profile.veidCount);
1203         pParams->totalSpansCount     = totalSpanCount;
1204         pParams->profileCount        = veidSlotCount;
1205         pParams->availableSpansCount = availableSpanCount;
1206     }
1207 
1208     return NV_OK;
1209 }
1210 
1211 NV_STATUS
gisubscriptionCtrlCmdGetUuid_IMPL(GPUInstanceSubscription * pGPUInstanceSubscription,NVC637_CTRL_GET_UUID_PARAMS * pParams)1212 gisubscriptionCtrlCmdGetUuid_IMPL
1213 (
1214     GPUInstanceSubscription *pGPUInstanceSubscription,
1215     NVC637_CTRL_GET_UUID_PARAMS *pParams
1216 )
1217 {
1218     NV_CHECK_OR_RETURN(LEVEL_ERROR, !pGPUInstanceSubscription->bDeviceProfiling,
1219                        NV_ERR_NOT_SUPPORTED);
1220 
1221     portMemCopy(pParams->uuid, sizeof(pParams->uuid),
1222                 pGPUInstanceSubscription->pKernelMIGGpuInstance->uuid.uuid,
1223                 sizeof(pGPUInstanceSubscription->pKernelMIGGpuInstance->uuid.uuid));
1224 
1225     nvGetSmcUuidString((void*)pParams->uuid, pParams->uuidStr);
1226     pParams->uuidStr[1] = 'G';
1227     pParams->uuidStr[2] = 'I';
1228 
1229     return NV_OK;
1230 }
1231