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(¶ms, 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 ¶ms,
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