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