1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 // FIXME XXX 25 #define NVOC_KERNEL_GRAPHICS_MANAGER_H_PRIVATE_ACCESS_ALLOWED 26 27 #include "kernel/gpu/fifo/kernel_fifo.h" 28 #include "kernel/gpu/fifo/kernel_channel.h" 29 #include "kernel/gpu/fifo/kernel_channel_group.h" 30 #include "kernel/gpu/fifo/kernel_channel_group_api.h" 31 #include "kernel/gpu/fifo/kernel_sched_mgr.h" 32 #include "virtualization/kernel_vgpu_mgr.h" 33 #include "rmapi/rs_utils.h" 34 #include "rmapi/client.h" 35 #include "gpu/subdevice/subdevice.h" 36 37 #include "kernel/core/locks.h" 38 #include "lib/base_utils.h" 39 40 #include "gpu/mmu/kern_gmmu.h" 41 #include "vgpu/rpc.h" 42 #include "vgpu/vgpu_events.h" 43 #include "nvRmReg.h" 44 45 #include "class/cl0080.h" 46 #include "class/cl2080.h" 47 #include "class/cl208f.h" 48 #include "class/clc572.h" 49 50 #include "ctrl/ctrl0080/ctrl0080fifo.h" 51 52 #define KFIFO_EHEAP_OWNER NvU32_BUILD('f','i','f','o') 53 54 static EHeapOwnershipComparator _kfifoUserdOwnerComparator; 55 56 static NV_STATUS _kfifoChidMgrAllocChidHeaps(OBJGPU *pGpu, 57 KernelFifo *pKernelFifo, 58 CHID_MGR *pChidMgr); 59 60 static NV_STATUS _kfifoChidMgrAllocVChidHeapPointers(OBJGPU *pGpu, CHID_MGR *pChidMgr); 61 62 static NV_STATUS _kfifoChidMgrInitChannelGroupMgr(OBJGPU *pGpu, CHID_MGR *pChidMgr); 63 64 static void _kfifoChidMgrDestroyChidHeaps(CHID_MGR *pChidMgr); 65 66 static void _kfifoChidMgrDestroyChannelGroupMgr(CHID_MGR *pChidMgr); 67 68 static NV_STATUS _kfifoChidMgrFreeIsolationId(CHID_MGR *pChidMgr, NvU32 ChID); 69 70 71 NvU32 kfifoGetNumEschedDrivenEngines_IMPL 72 ( 73 KernelFifo *pKernelFifo 74 ) 75 { 76 const ENGINE_INFO *pEngineInfo; 77 NV_ASSERT(kfifoGetNumEngines_HAL(ENG_GET_GPU(pKernelFifo), pKernelFifo) > 78 0); 79 pEngineInfo = kfifoGetEngineInfo(pKernelFifo); 80 return pEngineInfo->numRunlists; 81 } 82 83 84 NV_STATUS 85 kfifoChidMgrConstruct_IMPL 86 ( 87 OBJGPU *pGpu, 88 KernelFifo *pKernelFifo 89 ) 90 { 91 NV_STATUS status = NV_OK; 92 NvU32 i; 93 NvU32 numEngines; 94 95 // 96 // Allocate memory for the array of CHID_MGR pointers. Since this is an 97 // array, we allocate memory for pointers unto maxNumRunlists. We will only 98 // allocate objects for the valid ones. 99 // 100 if (kfifoIsPerRunlistChramEnabled(pKernelFifo)) 101 { 102 // 103 // Construct the engine list if it isn't already constructed (internally 104 // checks if it was already constructed) 105 // 106 NV_ASSERT_OK_OR_RETURN(kfifoConstructEngineList_HAL(pGpu, pKernelFifo)); 107 pKernelFifo->numChidMgrs = kfifoGetMaxNumRunlists_HAL(pGpu, pKernelFifo); 108 } 109 else 110 pKernelFifo->numChidMgrs = 1; 111 112 if (pKernelFifo->numChidMgrs > MAX_NUM_RUNLISTS) 113 { 114 // 115 // This only currently defines the size of our bitvector 116 // pKernelFifo->chidMgrValid. Catch this case if HW expands beyond this so we 117 // can increase the size allocated to the bitvector 118 // 119 NV_PRINTF(LEVEL_ERROR, "numChidMgrs 0x%x exceeds MAX_NUM_RUNLISTS\n", 120 pKernelFifo->numChidMgrs); 121 DBG_BREAKPOINT(); 122 return NV_ERR_BUFFER_TOO_SMALL; 123 } 124 125 pKernelFifo->ppChidMgr = portMemAllocNonPaged(sizeof(CHID_MGR *) * pKernelFifo->numChidMgrs); 126 if (pKernelFifo->ppChidMgr == NULL) 127 { 128 status = NV_ERR_NO_MEMORY; 129 pKernelFifo->ppChidMgr = NULL; 130 NV_PRINTF(LEVEL_ERROR, "Failed to allocate pFifo->pChidMgr\n"); 131 DBG_BREAKPOINT(); 132 return status; 133 } 134 portMemSet(pKernelFifo->ppChidMgr, 0, sizeof(CHID_MGR *) * pKernelFifo->numChidMgrs); 135 136 // Initialize the valid mask 137 if (kfifoIsPerRunlistChramEnabled(pKernelFifo)) 138 { 139 numEngines = kfifoGetNumEngines_HAL(pGpu, pKernelFifo); 140 for (i = 0; i < numEngines; i++) 141 { 142 NvU32 runlistId; 143 status = kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, 144 ENGINE_INFO_TYPE_INVALID, i, 145 ENGINE_INFO_TYPE_RUNLIST, &runlistId); 146 if (status == NV_OK) 147 bitVectorSet(&pKernelFifo->chidMgrValid, runlistId); 148 else 149 { 150 NV_PRINTF(LEVEL_ERROR, "Translation to runlistId failed for engine %d\n", i); 151 DBG_BREAKPOINT(); 152 goto fail; 153 } 154 } 155 } 156 else 157 { 158 bitVectorSet(&pKernelFifo->chidMgrValid, 0); // We only have 1 chidmgr 159 } 160 161 // Allocate memory for each CHID_MGR and its members (only the valid ones) 162 for (i = 0; i < pKernelFifo->numChidMgrs; i++) 163 { 164 if (!bitVectorTest(&pKernelFifo->chidMgrValid, i)) 165 continue; 166 167 pKernelFifo->ppChidMgr[i] = portMemAllocNonPaged(sizeof(CHID_MGR)); 168 if (pKernelFifo->ppChidMgr[i] == NULL) 169 { 170 status = NV_ERR_NO_MEMORY; 171 NV_PRINTF(LEVEL_ERROR, "Failed to allocate pFifo->pChidMgr[%d]\n", i); 172 DBG_BREAKPOINT(); 173 goto fail; 174 } 175 portMemSet(pKernelFifo->ppChidMgr[i], 0, sizeof(CHID_MGR)); 176 177 pKernelFifo->ppChidMgr[i]->runlistId = i; 178 179 pKernelFifo->ppChidMgr[i]->pChanGrpTree = portMemAllocNonPaged(sizeof(KernelChannelGroupMap)); 180 mapInitIntrusive(pKernelFifo->ppChidMgr[i]->pChanGrpTree); 181 182 status = _kfifoChidMgrAllocChidHeaps(pGpu, pKernelFifo, pKernelFifo->ppChidMgr[i]); 183 if (status != NV_OK) 184 { 185 NV_PRINTF(LEVEL_ERROR, "Error allocating FifoDataHeap in " 186 "pChidMgr. Status = %s (0x%x)\n", 187 nvstatusToString(status), status); 188 DBG_BREAKPOINT(); 189 goto fail; 190 } 191 192 status = _kfifoChidMgrInitChannelGroupMgr(pGpu, pKernelFifo->ppChidMgr[i]); 193 if (status != NV_OK) 194 goto fail; 195 } 196 197 198 return status; 199 200 fail: 201 kfifoChidMgrDestruct(pKernelFifo); 202 return status; 203 } 204 205 void 206 kfifoChidMgrDestruct_IMPL 207 ( 208 KernelFifo *pKernelFifo 209 ) 210 { 211 NvU32 i; 212 213 for (i = 0; i < pKernelFifo->numChidMgrs; i++) 214 { 215 if (pKernelFifo->ppChidMgr[i] != NULL) 216 { 217 mapDestroy(pKernelFifo->ppChidMgr[i]->pChanGrpTree); 218 portMemFree(pKernelFifo->ppChidMgr[i]->pChanGrpTree); 219 _kfifoChidMgrDestroyChidHeaps(pKernelFifo->ppChidMgr[i]); 220 _kfifoChidMgrDestroyChannelGroupMgr(pKernelFifo->ppChidMgr[i]); 221 portMemFree(pKernelFifo->ppChidMgr[i]); 222 pKernelFifo->ppChidMgr[i] = NULL; 223 } 224 } 225 226 portMemFree(pKernelFifo->ppChidMgr); 227 pKernelFifo->ppChidMgr = NULL; 228 bitVectorClrAll(&pKernelFifo->chidMgrValid); 229 pKernelFifo->numChidMgrs = 0; 230 } 231 232 /* 233 * @brief Allocate and initialize the virtual ChId heap pointers 234 */ 235 static NV_STATUS 236 _kfifoChidMgrAllocVChidHeapPointers 237 ( 238 OBJGPU *pGpu, 239 CHID_MGR *pChidMgr 240 ) 241 { 242 NV_STATUS status = NV_OK; 243 NvU32 i; 244 245 if (IS_VIRTUAL(pGpu)) 246 { 247 return NV_OK; 248 } 249 250 if (gpuIsSriovEnabled(pGpu)) 251 { 252 // 253 // For Virtual Channel Heap 254 // Allocate Memory for Heap Object pointers 255 // 256 pChidMgr->ppVirtualChIDHeap = portMemAllocNonPaged(sizeof(OBJEHEAP *) * (VMMU_MAX_GFID)); 257 if (pChidMgr->ppVirtualChIDHeap == NULL) 258 { 259 NV_PRINTF(LEVEL_ERROR, 260 "Error allocating memory for virtual channel heap pointers\n"); 261 return NV_ERR_NO_MEMORY; 262 } 263 264 // initialize 265 for (i = 0; i < VMMU_MAX_GFID; i++) 266 { 267 pChidMgr->ppVirtualChIDHeap[i] = NULL; 268 } 269 } 270 return status; 271 } 272 273 274 /* 275 * @brief Allocates & initializes ChID heaps 276 */ 277 static NV_STATUS 278 _kfifoChidMgrAllocChidHeaps 279 ( 280 OBJGPU *pGpu, 281 KernelFifo *pKernelFifo, 282 CHID_MGR *pChidMgr 283 ) 284 { 285 NV_STATUS status = NV_OK; 286 287 if (pChidMgr->numChannels == 0) 288 { 289 if (kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr) == 0) 290 { 291 NV_PRINTF(LEVEL_ERROR, "pChidMgr->numChannels is 0\n"); 292 DBG_BREAKPOINT(); 293 return NV_ERR_INVALID_STATE; 294 } 295 } 296 297 pChidMgr->pFifoDataHeap = portMemAllocNonPaged(sizeof(*pChidMgr->pFifoDataHeap)); 298 if (pChidMgr->pFifoDataHeap == NULL) 299 { 300 status = NV_ERR_NO_MEMORY; 301 NV_PRINTF(LEVEL_ERROR, 302 "Error in Allocating memory for pFifoDataHeap! Status = %s (0x%x)\n", 303 nvstatusToString(status), status); 304 return status; 305 } 306 constructObjEHeap(pChidMgr->pFifoDataHeap, 0, pChidMgr->numChannels, 307 sizeof(KernelChannel *), 0); 308 309 if (kfifoIsChidHeapEnabled(pKernelFifo)) 310 { 311 NvU32 userdBar1Size; 312 NvU32 numChannels = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 313 NvU32 subProcessIsolation = 1; 314 315 pChidMgr->pGlobalChIDHeap = portMemAllocNonPaged(sizeof(OBJEHEAP)); 316 if (pChidMgr->pGlobalChIDHeap == NULL) 317 { 318 NV_PRINTF(LEVEL_ERROR, 319 "Error in Allocating memory for global ChID heap!\n"); 320 return NV_ERR_NO_MEMORY; 321 } 322 constructObjEHeap(pChidMgr->pGlobalChIDHeap, 0, numChannels, 323 sizeof(PFIFO_ISOLATIONID), 0); 324 325 // 326 // Enable USERD allocation isolation. USERD allocated by different clients 327 // should not be in the same page 328 // 329 kfifoGetUserdSizeAlign_HAL(pKernelFifo, &userdBar1Size, NULL); 330 NvBool bIsolationEnabled = (pKernelFifo->bUsePerRunlistChram && pKernelFifo->bDisableChidIsolation) ? NV_FALSE : NV_TRUE; 331 pChidMgr->pGlobalChIDHeap->eheapSetOwnerIsolation(pChidMgr->pGlobalChIDHeap, 332 bIsolationEnabled, 333 RM_PAGE_SIZE / userdBar1Size); 334 335 // Disable USERD allocation isolation for guest if disabled from vmioplugin 336 { 337 // In this case subProcessIsolation is always 0 338 if (IS_GSP_CLIENT(pGpu)) 339 { 340 subProcessIsolation = 0; 341 } 342 } 343 if (!subProcessIsolation) 344 { 345 pChidMgr->pGlobalChIDHeap->eheapSetOwnerIsolation( 346 pChidMgr->pGlobalChIDHeap, 347 NV_FALSE, 348 RM_PAGE_SIZE / userdBar1Size); 349 #if (defined(_WIN32) || defined(_WIN64) || defined(NV_UNIX)) && !RMCFG_FEATURE_MODS_FEATURES 350 NV_PRINTF(LEVEL_INFO, 351 "Sub Process channel isolation disabled by vGPU plugin\n"); 352 #endif 353 } 354 355 status = _kfifoChidMgrAllocVChidHeapPointers(pGpu, pChidMgr); 356 } 357 358 return status; 359 } 360 361 static void 362 _kfifoChidMgrDestroyChidHeaps 363 ( 364 CHID_MGR *pChidMgr 365 ) 366 { 367 if (pChidMgr->pFifoDataHeap != NULL) 368 { 369 pChidMgr->pFifoDataHeap->eheapDestruct(pChidMgr->pFifoDataHeap); 370 portMemFree(pChidMgr->pFifoDataHeap); 371 pChidMgr->pFifoDataHeap = NULL; 372 } 373 if (pChidMgr->pGlobalChIDHeap != NULL) 374 { 375 pChidMgr->pGlobalChIDHeap->eheapDestruct(pChidMgr->pGlobalChIDHeap); 376 portMemFree(pChidMgr->pGlobalChIDHeap); 377 pChidMgr->pGlobalChIDHeap = NULL; 378 } 379 380 portMemFree(pChidMgr->ppVirtualChIDHeap); 381 pChidMgr->ppVirtualChIDHeap = NULL; 382 } 383 384 385 static NV_STATUS 386 _kfifoChidMgrInitChannelGroupMgr 387 ( 388 OBJGPU *pGpu, 389 CHID_MGR *pChidMgr 390 ) 391 { 392 KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu); 393 FIFO_HW_ID *pFifoHwID = &pChidMgr->channelGrpMgr; 394 NvU32 allocSize; 395 NvU32 numChannelGroups = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 396 397 if (numChannelGroups == 0) 398 { 399 return NV_OK; 400 } 401 402 // Rounds up to dword alignemnt, then converts bits to bytes. 403 allocSize = RM_ALIGN_UP(numChannelGroups, 32)/8; 404 405 pFifoHwID->pHwIdInUse = portMemAllocNonPaged(allocSize); 406 if (pFifoHwID->pHwIdInUse == NULL) 407 return NV_ERR_NO_MEMORY; 408 409 // bytes to NvU32[] elements 410 pFifoHwID->hwIdInUseSz = allocSize/4; 411 412 portMemSet(pFifoHwID->pHwIdInUse, 0, allocSize); 413 414 // 415 // If numChannelGroups isn't a multiple of 32 we need to set the bits > numChannelGroups to 416 // 1. Otherwise when we allocate IDs starting at the top we'll allocate 417 // ids >numChannelGroups. 418 // 419 if (numChannelGroups % 32 != 0) 420 { 421 pFifoHwID->pHwIdInUse[numChannelGroups/32] |= ~ ((1<<(numChannelGroups%32))-1); 422 } 423 424 return NV_OK; 425 } 426 427 static void 428 _kfifoChidMgrDestroyChannelGroupMgr 429 ( 430 CHID_MGR *pChidMgr 431 ) 432 { 433 if (pChidMgr->channelGrpMgr.pHwIdInUse) 434 { 435 portMemFree(pChidMgr->channelGrpMgr.pHwIdInUse); 436 pChidMgr->channelGrpMgr.pHwIdInUse = NULL; 437 pChidMgr->channelGrpMgr.hwIdInUseSz = 0; 438 } 439 } 440 441 static NV_STATUS 442 _kfifoChidMgrFreeIsolationId 443 ( 444 CHID_MGR *pChidMgr, 445 NvU32 ChID 446 ) 447 { 448 EMEMBLOCK *pIsolationIdBlock = pChidMgr->pGlobalChIDHeap->eheapGetBlock( 449 pChidMgr->pGlobalChIDHeap, 450 ChID, 451 NV_FALSE); 452 453 NV_ASSERT_OR_RETURN(pIsolationIdBlock, NV_ERR_OBJECT_NOT_FOUND); 454 NV_ASSERT(pIsolationIdBlock->refCount > 0); 455 NV_ASSERT(pIsolationIdBlock->pData != NULL); 456 portMemFree(pIsolationIdBlock->pData); 457 458 pIsolationIdBlock->pData = NULL; 459 460 return NV_OK; 461 } 462 463 /*! 464 * @breif Fifo defined call back comparator to compare eheap block ownership ID 465 * 466 * @param[in] pRequesterID Ownership ID constructed by caller 467 * @param[in] pIsolationID 468 * 469 * @return NV_TRUE if two ownership IDs belong to the same owner 470 */ 471 static NvBool 472 _kfifoUserdOwnerComparator 473 ( 474 void *pRequesterID, 475 void *pIsolationID 476 ) 477 { 478 PFIFO_ISOLATIONID pAllocID = (PFIFO_ISOLATIONID)pRequesterID; 479 PFIFO_ISOLATIONID pBlockID = (PFIFO_ISOLATIONID)pIsolationID; 480 481 // 482 // The block's data will be NULL if the channel has been destroyed but there 483 // is still a refcount on the channel ID. In that case no work can be issued 484 // to that channel ID now or in the future, so we can act as though the 485 // channel does not exist. 486 // 487 if (!pBlockID) 488 return NV_TRUE; 489 490 if ((pAllocID->domain != pBlockID->domain) || 491 (pAllocID->processID != pBlockID->processID) || 492 (pAllocID->subProcessID != pBlockID->subProcessID)) 493 { 494 return NV_FALSE; 495 } 496 else 497 { 498 return NV_TRUE; 499 } 500 } 501 502 /* 503 * @brief Returns the number of vGPU plugin channels. 504 * 505 * Depending on whether this code is executed on the CPU RM or the Physical RM, 506 * different structures are used to retrieve the number. 507 * On the CPU RM or the monolithic RM, KERNEL_HOST_VGPU_DEVICE::numPluginChannels is used, 508 * whereas on the physical RM it's HOST_VGPU_DEVICE::numPluginChannels. 509 */ 510 static NV_STATUS 511 _kfifoGetVgpuPluginChannelsCount 512 ( 513 OBJGPU *pGpu, 514 NvU32 *pNumPluginChannels 515 ) 516 { 517 NV_ASSERT_OR_RETURN(pNumPluginChannels != NULL, NV_ERR_INVALID_ARGUMENT); 518 519 if (!RMCFG_FEATURE_PLATFORM_GSP) 520 { 521 KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice = NULL; 522 523 NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextKernelHostVgpuDevice(pGpu, &pKernelHostVgpuDevice)); 524 NV_ASSERT_OR_RETURN(pKernelHostVgpuDevice != NULL, NV_ERR_OBJECT_NOT_FOUND); 525 526 *pNumPluginChannels = pKernelHostVgpuDevice->numPluginChannels; 527 } 528 529 return NV_OK; 530 } 531 532 /*! 533 * @brief Allocates one Channel ID on heap 534 * 535 * @param[in] OBJGPU GPU Object 536 * @param[in] KernelFifo KernelFifo Object 537 * @param[in] CHID_MGR Channel ID manager 538 * @param[in] chFlag NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_DOWN 539 * NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE 540 * NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_UP 541 * @param[in] bForceInternalIdx true if requesting specific index within USERD 542 * page 543 * @param[in] internalIdx requested index within USERD page when 544 * bForceInternalIdx true 545 * @param[in] ChID ChID to assign in case of ADDRESS_ALLOCATE 546 * @param[in,out] pKernelChannel The previously allocated KernelChannel structure 547 * 548 * @return NV_OK if allocation is successful 549 * NV_ERR_NO_FREE_FIFOS: allocated channel ID exceeds MAX channels. 550 */ 551 NV_STATUS 552 kfifoChidMgrAllocChid_IMPL 553 ( 554 OBJGPU *pGpu, 555 KernelFifo *pKernelFifo, 556 CHID_MGR *pChidMgr, 557 NvHandle hClient, 558 CHANNEL_HW_ID_ALLOC_MODE chIdFlag, 559 NvBool bForceInternalIdx, 560 NvU32 internalIdx, 561 NvBool bForceUserdPage, 562 NvU32 userdPageIdx, 563 NvU32 ChID, 564 KernelChannel *pKernelChannel 565 ) 566 { 567 NvU64 chSize; 568 NvU32 chFlag = chIdFlag; 569 NvU64 ChID64 = 0; 570 NvU64 subProcessID = 0; 571 NvU64 processID = 0; 572 NvBool bIsSubProcessDisabled = NV_FALSE; 573 RmClient *pClient; 574 NvU32 offsetAlign = 1; 575 NvU32 gfid; 576 PFIFO_ISOLATIONID pIsolationID = NULL; 577 NV_STATUS status; 578 NvU32 numChannels; 579 580 NV_ASSERT_OR_RETURN(pKernelChannel != NULL, NV_ERR_INVALID_ARGUMENT); 581 582 numChannels = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 583 584 switch (chIdFlag) 585 { 586 case CHANNEL_HW_ID_ALLOC_MODE_GROW_DOWN: 587 chFlag = NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_DOWN; 588 break; 589 case CHANNEL_HW_ID_ALLOC_MODE_GROW_UP: 590 chFlag = NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_UP; 591 break; 592 case CHANNEL_HW_ID_ALLOC_MODE_PROVIDED: 593 ChID64 = ChID; 594 chFlag = NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE; 595 break; 596 default: 597 NV_PRINTF(LEVEL_ERROR, "Invalid channel ID alloc mode %d\n", chFlag); 598 DBG_BREAKPOINT(); 599 return NV_ERR_INVALID_ARGUMENT; 600 } 601 602 // we are allocating only one Channel at a time 603 chSize = 1; 604 605 // Create unique isolation ID for each process 606 pClient = serverutilGetClientUnderLock(hClient); 607 if (pClient == NULL) 608 { 609 NV_PRINTF(LEVEL_ERROR, "Invalid client handle %ux\n", hClient); 610 DBG_BREAKPOINT(); 611 return NV_ERR_INVALID_CLIENT; 612 } 613 614 NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextGfid(pGpu, &gfid)); 615 616 // SRIOV: In guest plugin context allocate the chid. 617 // In guest RM context allocate the same chid as guest 618 if (IS_GFID_VF(gfid)) 619 { 620 NvU32 numPluginChannels; 621 NvU64 rangeLo, rangeHi, base, size; 622 623 NV_ASSERT_OR_RETURN(pChidMgr->ppVirtualChIDHeap[gfid], 624 NV_ERR_INVALID_STATE); 625 626 NV_ASSERT_OK_OR_RETURN(_kfifoGetVgpuPluginChannelsCount(pGpu, &numPluginChannels)); 627 628 pChidMgr->ppVirtualChIDHeap[gfid]->eheapGetBase( 629 pChidMgr->ppVirtualChIDHeap[gfid], 630 &base); 631 pChidMgr->ppVirtualChIDHeap[gfid]->eheapGetSize( 632 pChidMgr->ppVirtualChIDHeap[gfid], 633 &size); 634 635 rangeLo = base; 636 rangeHi = base + size - 1; 637 638 // Route plugin channels to be allocated at the top 639 NV_ASSERT_OR_RETURN(numPluginChannels < size, 640 NV_ERR_INVALID_PARAMETER); 641 if (pKernelChannel->pKernelChannelGroupApi->pKernelChannelGroup->bIsCallingContextVgpuPlugin && 642 numPluginChannels > 0) 643 { 644 rangeLo = rangeHi - numPluginChannels + 1; 645 } 646 else 647 { 648 rangeHi = rangeHi - numPluginChannels; 649 } 650 651 status = pChidMgr->ppVirtualChIDHeap[gfid]->eheapSetAllocRange( 652 pChidMgr->ppVirtualChIDHeap[gfid], 653 rangeLo, 654 rangeHi); 655 656 NV_ASSERT_OK_OR_RETURN(status); 657 658 if (bForceUserdPage) 659 { 660 NV_ASSERT_OR_RETURN(!bForceInternalIdx, NV_ERR_INVALID_STATE); 661 ChID64 = ((NvU64)userdPageIdx) * 662 pChidMgr->ppVirtualChIDHeap[gfid]->ownerGranularity + 663 internalIdx; 664 chFlag |= NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE; 665 } 666 else if (bForceInternalIdx) 667 { 668 chFlag |= NVOS32_ALLOC_FLAGS_FORCE_INTERNAL_INDEX; 669 offsetAlign = internalIdx; 670 } 671 672 if (chFlag & NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE) 673 NV_ASSERT_OR_RETURN((ChID64 <= rangeHi) && (ChID64 >= rangeLo), 674 NV_ERR_INVALID_PARAMETER); 675 676 // We'll allocate from the VirtualChIdHeap for the guest 677 status = pChidMgr->ppVirtualChIDHeap[gfid]->eheapAlloc( 678 pChidMgr->ppVirtualChIDHeap[gfid], // This Heap 679 KFIFO_EHEAP_OWNER, // owner 680 &chFlag, // Alloc Flags 681 &ChID64, // Alloc Offset 682 &chSize, // Size 683 offsetAlign, // offsetAlign 684 1, // sizeAlign 685 NULL, // Allocated mem block 686 NULL, // Isolation ID 687 NULL // Fifo defined ownership comparator 688 ); 689 if (status != NV_OK) 690 { 691 NV_PRINTF(LEVEL_ERROR, 692 "Failed to allocate Channel ID 0x%llx %d on heap \n", 693 ChID64, 694 chIdFlag); 695 DBG_BREAKPOINT(); 696 goto fail; 697 } 698 } 699 else 700 { 701 // 702 // Legacy / SRIOV vGPU Host, SRIOV guest, baremetal CPU RM, GSP FW, GSP 703 // client allocate from global heap 704 // 705 pIsolationID = portMemAllocNonPaged(sizeof(FIFO_ISOLATIONID)); 706 NV_ASSERT_OR_RETURN((pIsolationID != NULL), NV_ERR_NO_MEMORY); 707 portMemSet(pIsolationID, 0, sizeof(FIFO_ISOLATIONID)); 708 709 // 710 // Check if the allocation request is from the guest RM or host RM 711 // 712 processID = pClient->ProcID; 713 subProcessID = pClient->SubProcessID; 714 bIsSubProcessDisabled = pClient->bIsSubProcessDisabled; 715 716 if (RMCFG_FEATURE_PLATFORM_GSP || kchannelCheckIsKernel(pKernelChannel)) 717 { 718 // 719 // If not GSPFW: Allocation request is from host RM kernel 720 // If GSPFW: ChID has already been chosen by CPU-RM, but pClient 721 // doesn't have the true processID, so just allow the whole pool. 722 // 723 pIsolationID->domain = HOST_KERNEL; 724 processID = KERNEL_PID; 725 } 726 else 727 { 728 if (0x0 != subProcessID) 729 { 730 // 731 // Allocation request is from the guest RM 732 // 733 if (KERNEL_PID == subProcessID) 734 { 735 pIsolationID->domain = GUEST_KERNEL; 736 } 737 else 738 { 739 pIsolationID->domain = GUEST_USER; 740 } 741 } 742 else 743 { 744 pIsolationID->domain = HOST_USER; 745 } 746 } 747 748 pIsolationID->processID = processID; 749 pIsolationID->subProcessID = subProcessID; 750 751 // 752 // Overwrite isolation ID if guest USERD isolation is disabled 753 // 754 if ((subProcessID != 0x0) && (bIsSubProcessDisabled)) 755 { 756 pIsolationID->domain = GUEST_INSECURE; 757 pIsolationID->subProcessID = KERNEL_PID; 758 } 759 760 /* Channel USERD manipuliation only supported without GFID */ 761 if (bForceUserdPage) 762 { 763 NV_ASSERT_OR_RETURN(!bForceInternalIdx, NV_ERR_INVALID_STATE); 764 ChID64 = ((NvU64)userdPageIdx) * 765 pChidMgr->pGlobalChIDHeap->ownerGranularity + 766 internalIdx; 767 chFlag |= NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE; 768 } 769 else if (bForceInternalIdx) 770 { 771 chFlag |= NVOS32_ALLOC_FLAGS_FORCE_INTERNAL_INDEX; 772 offsetAlign = internalIdx; 773 } 774 775 status = pChidMgr->pGlobalChIDHeap->eheapAlloc( 776 pChidMgr->pGlobalChIDHeap, // This Heap 777 KFIFO_EHEAP_OWNER, // owner 778 &chFlag, // Alloc Flags 779 &ChID64, // Alloc Offset 780 &chSize, // Size 781 offsetAlign, // offsetAlign 782 1, // sizeAlign 783 NULL, // Allocated mem block 784 pIsolationID, // Isolation ID 785 _kfifoUserdOwnerComparator // Fifo defined ownership comparator 786 ); 787 788 if (status != NV_OK) 789 { 790 NV_PRINTF(LEVEL_ERROR, "Failed to allocate Channel ID on heap\n"); 791 DBG_BREAKPOINT(); 792 goto fail; 793 } 794 } 795 796 // 797 // Now allocate at a fixed offset from the pFifoDataHeap once the previous 798 // ID allocation told us which ID to use. 799 // 800 chFlag = NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE; 801 status = pChidMgr->pFifoDataHeap->eheapAlloc( 802 pChidMgr->pFifoDataHeap, // This Heap 803 KFIFO_EHEAP_OWNER, // owner 804 &chFlag, // Alloc Flags 805 &ChID64, // Alloc Offset 806 &chSize, // Size 807 1, // offsetAlign 808 1, // sizeAlign 809 NULL, // Allocated mem block 810 NULL, // Isolation ID 811 NULL // ownership comparator 812 ); 813 814 if (status != NV_OK) 815 { 816 // 817 // Should never happen since we're mirroring the global chid heap, or 818 // pre-reserving space on the global chid heap for SR-IOV capable 819 // systems. 820 // 821 NV_PRINTF(LEVEL_ERROR, "Failed to allocate Channel on fifo data heap\n"); 822 goto fail; 823 } 824 825 ChID = NvU64_LO32(ChID64); 826 827 if (ChID < numChannels) 828 { 829 PEMEMBLOCK pFifoDataBlock = pChidMgr->pFifoDataHeap->eheapGetBlock( 830 pChidMgr->pFifoDataHeap, 831 ChID, 832 NV_FALSE); 833 PEMEMBLOCK pIsolationIdBlock = pChidMgr->pGlobalChIDHeap->eheapGetBlock( 834 pChidMgr->pGlobalChIDHeap, 835 ChID, 836 NV_FALSE); 837 838 if (IS_GFID_PF(gfid)) 839 pIsolationIdBlock->pData = pIsolationID; 840 841 pFifoDataBlock->pData = pKernelChannel; 842 pKernelChannel->ChID = ChID; 843 } 844 else 845 { 846 NV_PRINTF(LEVEL_WARNING, "No allocatable FIFO available.\n"); 847 status = NV_ERR_NO_FREE_FIFOS; 848 goto fail; 849 } 850 return NV_OK; 851 852 fail: 853 // We already know that pIsolationID is non-NULL here. 854 portMemFree(pIsolationID); 855 return status; 856 } 857 858 /* 859 * Retain a channel ID which has already been allocated by 860 * kfifoChidMgrAllocChid. Until released, the HW channel ID will not be 861 * allocated by any new channels even after kfifoChidMgrFreeChid has been 862 * called. 863 */ 864 NV_STATUS 865 kfifoChidMgrRetainChid_IMPL 866 ( 867 OBJGPU *pGpu, 868 KernelFifo *pKernelFifo, 869 CHID_MGR *pChidMgr, 870 NvU32 ChID 871 ) 872 { 873 NvU32 gfid; 874 PEMEMBLOCK pFifoDataBlock = NULL; 875 876 NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextGfid(pGpu, &gfid)); 877 878 if (IS_GFID_VF(gfid)) 879 { 880 NV_ASSERT_OR_RETURN(pChidMgr->ppVirtualChIDHeap[gfid] != NULL, 881 NV_ERR_INVALID_STATE); 882 PEMEMBLOCK pVirtChIdBlock = pChidMgr->ppVirtualChIDHeap[gfid]->eheapGetBlock( 883 pChidMgr->ppVirtualChIDHeap[gfid], 884 ChID, 885 NV_FALSE); 886 NV_ASSERT_OR_RETURN(pVirtChIdBlock != NULL, NV_ERR_OBJECT_NOT_FOUND); 887 NV_ASSERT(pVirtChIdBlock->refCount > 0); 888 ++pVirtChIdBlock->refCount; 889 } 890 else 891 { 892 NV_ASSERT_OR_RETURN(pChidMgr->pGlobalChIDHeap != NULL, NV_ERR_INVALID_STATE); 893 PEMEMBLOCK pChIdBlock = pChidMgr->pGlobalChIDHeap->eheapGetBlock( 894 pChidMgr->pGlobalChIDHeap, 895 ChID, 896 NV_FALSE); 897 NV_ASSERT_OR_RETURN(pChIdBlock != NULL, NV_ERR_OBJECT_NOT_FOUND); 898 NV_ASSERT(pChIdBlock->refCount > 0); 899 ++pChIdBlock->refCount; 900 } 901 902 NV_ASSERT_OR_RETURN(pChidMgr->pFifoDataHeap != NULL, NV_ERR_INVALID_STATE); 903 pFifoDataBlock = pChidMgr->pFifoDataHeap->eheapGetBlock( 904 pChidMgr->pFifoDataHeap, 905 ChID, 906 NV_FALSE); 907 NV_ASSERT_OR_RETURN(pFifoDataBlock != NULL, NV_ERR_OBJECT_NOT_FOUND); 908 NV_ASSERT(pFifoDataBlock->refCount > 0); 909 ++pFifoDataBlock->refCount; 910 911 return NV_OK; 912 } 913 914 /* 915 * Drop the refcount on the given channel (ID), removing it from pFifo's heap if 916 * its refcount reaches 0. 917 */ 918 NV_STATUS 919 kfifoChidMgrReleaseChid_IMPL 920 ( 921 OBJGPU *pGpu, 922 KernelFifo *pKernelFifo, 923 CHID_MGR *pChidMgr, 924 NvU32 ChID 925 ) 926 { 927 NvU32 gfid; 928 929 NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextGfid(pGpu, &gfid)); 930 931 if (IS_GFID_VF(gfid)) 932 { 933 NV_ASSERT_OR_RETURN(pChidMgr->ppVirtualChIDHeap[gfid] != NULL, NV_ERR_INVALID_STATE); 934 NV_ASSERT_OK(pChidMgr->ppVirtualChIDHeap[gfid]->eheapFree(pChidMgr->ppVirtualChIDHeap[gfid], ChID)); 935 } 936 else 937 { 938 NV_ASSERT_OR_RETURN(pChidMgr->pGlobalChIDHeap != NULL, NV_ERR_INVALID_STATE); 939 NV_ASSERT_OK(pChidMgr->pGlobalChIDHeap->eheapFree(pChidMgr->pGlobalChIDHeap, ChID)); 940 } 941 942 NV_ASSERT_OR_RETURN(pChidMgr->pFifoDataHeap != NULL, NV_ERR_INVALID_STATE); 943 NV_ASSERT_OK_OR_RETURN(pChidMgr->pFifoDataHeap->eheapFree(pChidMgr->pFifoDataHeap, ChID)); 944 945 return NV_OK; 946 } 947 948 /* 949 * Removes the association between pKernelChannel and its channel ID. Note that this 950 * will not remove the channel ID itself from pFifo's heap if 951 * fifoHeapRetainChannelId has been called. 952 */ 953 NV_STATUS 954 kfifoChidMgrFreeChid_IMPL 955 ( 956 OBJGPU *pGpu, 957 KernelFifo *pKernelFifo, 958 CHID_MGR *pChidMgr, 959 NvU32 ChID 960 ) 961 { 962 EMEMBLOCK *pFifoDataBlock; 963 NV_STATUS status; 964 NvU32 gfid; 965 966 // 967 // This channel is going away, so clear its pointer from the channel ID's heap 968 // block. 969 // 970 pFifoDataBlock = pChidMgr->pFifoDataHeap->eheapGetBlock( 971 pChidMgr->pFifoDataHeap, 972 ChID, 973 NV_FALSE); 974 NV_ASSERT_OR_RETURN(pFifoDataBlock != NULL, NV_ERR_OBJECT_NOT_FOUND); 975 NV_ASSERT(pFifoDataBlock->refCount > 0); 976 pFifoDataBlock->pData = NULL; 977 978 NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextGfid(pGpu, &gfid)); 979 980 if (IS_GFID_PF(gfid)) 981 { 982 // 983 // This marks the channel ID as orphaned and causes it to be ignored for 984 // isolation purposes. This only matters if there will still be a reference 985 // on the ID after we release ours below. 986 // 987 status = _kfifoChidMgrFreeIsolationId(pChidMgr, ChID); 988 if(status != NV_OK) 989 { 990 NV_PRINTF(LEVEL_ERROR, 991 "Failed to free IsolationId. Status = 0x%x\n", status); 992 DBG_BREAKPOINT(); 993 return status; 994 } 995 } 996 997 return kfifoChidMgrReleaseChid(pGpu, pKernelFifo, pChidMgr, ChID); 998 } 999 1000 /** 1001 * @brief Reserve a contiguous set of SCHIDs from the end of our CHID heap for 1002 * the given GFID 1003 * 1004 1005 * @param[in] pChidMgr CHID_MGR pointer 1006 * @param[in] numChannels Number of SCHIDs to reserve 1007 * @param[in] pHostVgpuDevice HOST_VGPU_DEVICE 1008 * 1009 * @return NV_OK if success 1010 */ 1011 NV_STATUS 1012 kfifoChidMgrReserveSystemChids_IMPL 1013 ( 1014 OBJGPU *pGpu, 1015 KernelFifo *pKernelFifo, 1016 CHID_MGR *pChidMgr, 1017 NvU32 numChannels, 1018 NvU32 flags, 1019 NvU32 gfid, 1020 NvU32 *pChidOffset, 1021 NvU32 *pChannelCount, 1022 NvHandle hMigClient, 1023 NvU32 engineFifoListNumEntries, 1024 FIFO_ENGINE_LIST *pEngineFifoList 1025 ) 1026 { 1027 NV_STATUS status = NV_OK; 1028 NvU64 chSize; 1029 NvU64 offset = 0; 1030 PFIFO_ISOLATIONID pIsolationID = NULL; 1031 PEMEMBLOCK pIsolationIdBlock; 1032 NvU32 userdBar1Size; 1033 1034 if (IS_VIRTUAL(pGpu)) 1035 { 1036 // Not supported on guest or when SRIOV is disabled 1037 return NV_ERR_NOT_SUPPORTED; 1038 } 1039 1040 pIsolationID = portMemAllocNonPaged(sizeof(FIFO_ISOLATIONID)); 1041 NV_ASSERT_OR_RETURN((pIsolationID != NULL), NV_ERR_NO_MEMORY); 1042 portMemSet(pIsolationID, 0, sizeof(FIFO_ISOLATIONID)); 1043 1044 chSize = numChannels; 1045 1046 status = pChidMgr->pGlobalChIDHeap->eheapAlloc( 1047 pChidMgr->pGlobalChIDHeap, // This Heap 1048 KFIFO_EHEAP_OWNER, // owner 1049 &flags, // Alloc Flags 1050 &offset, // Alloc Offset 1051 &chSize, // Size 1052 1, // offsetAlign 1053 1, // sizeAlign 1054 NULL, // Allocated mem block 1055 pIsolationID, // IsolationID 1056 _kfifoUserdOwnerComparator // Fifo defined ownership comparator 1057 ); 1058 1059 if(status != NV_OK) 1060 { 1061 NV_PRINTF(LEVEL_ERROR, "Failed to reserve channel IDs. Status = 0x%x\n", status); 1062 DBG_BREAKPOINT(); 1063 1064 // 1065 // Free the allocated memory and return early. After this, all failure 1066 // points can goto the common cleanup label 1067 // 1068 portMemFree(pIsolationID); 1069 return status; 1070 } 1071 1072 pIsolationIdBlock = pChidMgr->pGlobalChIDHeap->eheapGetBlock( 1073 pChidMgr->pGlobalChIDHeap, 1074 offset, 1075 NV_FALSE); 1076 if (pIsolationIdBlock == NULL) 1077 { 1078 // Something bad happened. This should not fail if allocation succeeded 1079 NV_PRINTF(LEVEL_ERROR, "Could not fetch block from eheap\n"); 1080 DBG_BREAKPOINT(); 1081 goto cleanup; 1082 } 1083 pIsolationIdBlock->pData = pIsolationID; 1084 1085 status = kfifoSetChidOffset(pGpu, pKernelFifo, pChidMgr, (NvU32)offset, 1086 numChannels, gfid, pChidOffset, pChannelCount, 1087 hMigClient, engineFifoListNumEntries, pEngineFifoList); 1088 1089 if (status != NV_OK) 1090 { 1091 NV_PRINTF(LEVEL_ERROR, 1092 "Failed to program the CHID table\n"); 1093 goto cleanup; 1094 } 1095 1096 pChidMgr->ppVirtualChIDHeap[gfid] = portMemAllocNonPaged(sizeof(OBJEHEAP)); 1097 if (pChidMgr->ppVirtualChIDHeap[gfid] == NULL) 1098 { 1099 status = NV_ERR_NO_MEMORY; 1100 NV_PRINTF(LEVEL_ERROR, "Error allocating memory for virtual " 1101 "channel ID heap\n"); 1102 goto cleanup; 1103 } 1104 portMemSet(pChidMgr->ppVirtualChIDHeap[gfid], 0, sizeof(OBJEHEAP)); 1105 1106 // 1107 // Construct heap using low as offset and size of numChannels. This heap 1108 // will be used for guest channel ID allocations, but will be in the 1109 // system channel ID space, hence it only manages IDs from offset to 1110 // (offset + numChannels). 1111 // 1112 constructObjEHeap(pChidMgr->ppVirtualChIDHeap[gfid], offset, 1113 (offset + numChannels), 0, 0); 1114 1115 kfifoGetUserdSizeAlign_HAL(pKernelFifo, &userdBar1Size, NULL); 1116 pChidMgr->ppVirtualChIDHeap[gfid]->eheapSetOwnerIsolation( 1117 pChidMgr->ppVirtualChIDHeap[gfid], 1118 NV_FALSE, 1119 RM_PAGE_SIZE/userdBar1Size); 1120 1121 return status; 1122 1123 cleanup: 1124 portMemFree(pChidMgr->ppVirtualChIDHeap[gfid]); 1125 NV_ASSERT(kfifoSetChidOffset(pGpu, pKernelFifo, pChidMgr, 0, 0, 1126 gfid, pChidOffset, pChannelCount, hMigClient, 1127 engineFifoListNumEntries, pEngineFifoList) == NV_OK); 1128 NV_ASSERT(pChidMgr->pGlobalChIDHeap->eheapFree(pChidMgr->pGlobalChIDHeap, offset) == NV_OK); 1129 portMemFree(pIsolationID); 1130 return status; 1131 } 1132 1133 /*! Frees a block of contiguous SCHIDs previously reserved for the given GFID */ 1134 NV_STATUS 1135 kfifoChidMgrFreeSystemChids_IMPL 1136 ( 1137 OBJGPU *pGpu, 1138 KernelFifo *pKernelFifo, 1139 CHID_MGR *pChidMgr, 1140 NvU32 gfid, 1141 NvU32 *pChidOffset, 1142 NvU32 *pChannelCount, 1143 NvHandle hMigClient, 1144 NvU32 engineFifoListNumEntries, 1145 FIFO_ENGINE_LIST *pEngineFifoList 1146 ) 1147 { 1148 NV_STATUS status, tmpStatus; 1149 NvU64 chId; 1150 1151 if (IS_VIRTUAL(pGpu)) 1152 { 1153 // Not supported on guest or when SRIOV is disabled 1154 return NV_ERR_NOT_SUPPORTED; 1155 } 1156 1157 // Get the schid base 1158 pChidMgr->ppVirtualChIDHeap[gfid]->eheapGetBase( 1159 pChidMgr->ppVirtualChIDHeap[gfid], 1160 &chId); 1161 1162 status = _kfifoChidMgrFreeIsolationId(pChidMgr, (NvU32)chId); 1163 if(status != NV_OK) 1164 { 1165 NV_PRINTF(LEVEL_ERROR, 1166 "Failed to free IsolationId. Status = 0x%x\n", 1167 status); 1168 DBG_BREAKPOINT(); 1169 return status; 1170 } 1171 1172 status = pChidMgr->pGlobalChIDHeap->eheapFree(pChidMgr->pGlobalChIDHeap, chId); 1173 if(status != NV_OK) 1174 { 1175 NV_PRINTF(LEVEL_ERROR, 1176 "Failed to free channel IDs. Status = 0x%x\n", 1177 status); 1178 DBG_BREAKPOINT(); 1179 1180 // 1181 // March on anyway to program the ChId table. We'll return an error 1182 // if we get here though. 1183 // 1184 } 1185 1186 tmpStatus = kfifoSetChidOffset(pGpu, pKernelFifo, pChidMgr, 0, 0, 1187 gfid, pChidOffset, pChannelCount, hMigClient, 1188 engineFifoListNumEntries, pEngineFifoList); 1189 if (tmpStatus != NV_OK) 1190 { 1191 NV_PRINTF(LEVEL_ERROR, 1192 "Failed to program the CHID table\n"); 1193 DBG_BREAKPOINT(); 1194 return tmpStatus; 1195 } 1196 1197 pChidMgr->ppVirtualChIDHeap[gfid]->eheapDestruct(pChidMgr->ppVirtualChIDHeap[gfid]); 1198 portMemFree(pChidMgr->ppVirtualChIDHeap[gfid]); 1199 pChidMgr->ppVirtualChIDHeap[gfid] = NULL; 1200 1201 return status; 1202 } 1203 1204 NvU32 1205 kfifoChidMgrGetNumChannels_IMPL 1206 ( 1207 OBJGPU *pGpu, 1208 KernelFifo *pKernelFifo, 1209 CHID_MGR *pChidMgr 1210 ) 1211 { 1212 // Cache ChidMgr's numChannels if not set 1213 if (pChidMgr->numChannels == 0) 1214 { 1215 NvU32 numChannels = kfifoRunlistQueryNumChannels_HAL(pGpu, pKernelFifo, 1216 pChidMgr->runlistId); 1217 1218 if (pKernelFifo->bNumChannelsOverride) 1219 { 1220 pChidMgr->numChannels = NV_MIN(pKernelFifo->numChannelsOverride, numChannels); 1221 } 1222 else 1223 { 1224 pChidMgr->numChannels = numChannels; 1225 } 1226 1227 // Once we have set calculated value disable any overrides. 1228 pKernelFifo->bNumChannelsOverride = 0; 1229 } 1230 1231 return pChidMgr->numChannels; 1232 } 1233 1234 NvU32 1235 kfifoRunlistQueryNumChannels_KERNEL 1236 ( 1237 OBJGPU *pGpu, 1238 KernelFifo *pKernelFifo, 1239 NvU32 runlistId 1240 ) 1241 { 1242 NvU32 numChannels = 0; 1243 NvU32 status; 1244 1245 // Do internal control call and set numChannels 1246 if (IS_GSP_CLIENT(pGpu)) 1247 { 1248 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu); 1249 NV2080_CTRL_INTERNAL_FIFO_GET_NUM_CHANNELS_PARAMS numChannelsParams = {0}; 1250 1251 numChannelsParams.runlistId = runlistId; 1252 1253 status = pRmApi->Control(pRmApi, 1254 pGpu->hInternalClient, 1255 pGpu->hInternalSubdevice, 1256 NV2080_CTRL_CMD_INTERNAL_FIFO_GET_NUM_CHANNELS, 1257 &numChannelsParams, 1258 sizeof(NV2080_CTRL_INTERNAL_FIFO_GET_NUM_CHANNELS_PARAMS)); 1259 if (status != NV_OK) 1260 { 1261 DBG_BREAKPOINT(); 1262 return 0; 1263 } 1264 1265 numChannels = numChannelsParams.numChannels; 1266 } 1267 1268 NV_ASSERT(numChannels > 0); 1269 1270 return numChannels; 1271 } 1272 1273 /** 1274 * @brief reserves a hardware channel slot for a channel group 1275 * 1276 * Only responsible for indicating a hardware channel is in use, does not set 1277 * any other software state. 1278 * 1279 * This function is not called in broadcast mode 1280 * 1281 * @param pGpu 1282 * @param pKernelFifo 1283 * @param pChidMgr 1284 * @param[out] grpID 1285 */ 1286 NV_STATUS 1287 kfifoChidMgrAllocChannelGroupHwID_IMPL 1288 ( 1289 OBJGPU *pGpu, 1290 KernelFifo *pKernelFifo, 1291 CHID_MGR *pChidMgr, 1292 NvU32 *pChGrpID 1293 ) 1294 { 1295 NvU32 maxChannelGroups; 1296 1297 if (pChGrpID == NULL) 1298 return NV_ERR_INVALID_ARGUMENT; 1299 1300 maxChannelGroups = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 1301 if (maxChannelGroups == 0) 1302 { 1303 NV_PRINTF(LEVEL_ERROR, "Zero max channel groups!!!\n"); 1304 return NV_ERR_INVALID_ARGUMENT; 1305 } 1306 1307 // Find the least unused grpID 1308 *pChGrpID = nvBitFieldLSZero(pChidMgr->channelGrpMgr.pHwIdInUse, 1309 pChidMgr->channelGrpMgr.hwIdInUseSz); 1310 1311 if (*pChGrpID < maxChannelGroups) 1312 { 1313 nvBitFieldSet(pChidMgr->channelGrpMgr.pHwIdInUse, 1314 pChidMgr->channelGrpMgr.hwIdInUseSz, *pChGrpID, NV_TRUE); 1315 } 1316 else 1317 { 1318 *pChGrpID = maxChannelGroups; 1319 NV_PRINTF(LEVEL_ERROR, "No allocatable FIFO available.\n"); 1320 return NV_ERR_NO_FREE_FIFOS; 1321 } 1322 return NV_OK; 1323 } 1324 1325 1326 /** 1327 * @brief Releases a hardware channel group ID. 1328 * 1329 * Not responsible for freeing any software state beyond that which indicates a 1330 * hardware channel is in use. 1331 * 1332 * This function is not called in broadcast mode 1333 * 1334 * @param pGpu 1335 * @param pFifo 1336 * @param pChidMgr 1337 * @param chGrpID 1338 */ 1339 NV_STATUS 1340 kfifoChidMgrFreeChannelGroupHwID_IMPL 1341 ( 1342 OBJGPU *pGpu, 1343 KernelFifo *pKernelFifo, 1344 CHID_MGR *pChidMgr, 1345 NvU32 chGrpID 1346 ) 1347 { 1348 NvU32 maxChannelGroups; 1349 1350 maxChannelGroups = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 1351 if (maxChannelGroups == 0) 1352 { 1353 NV_PRINTF(LEVEL_ERROR, "Zero max channel groups!!!\n"); 1354 return NV_ERR_INVALID_ARGUMENT; 1355 } 1356 NV_ASSERT_OR_RETURN(chGrpID < maxChannelGroups, NV_ERR_INVALID_ARGUMENT); 1357 1358 // 1359 // Look for the channel group, check to make sure it's InUse bit is set 1360 // and then clear it to indicate the grpID is no longer in use 1361 // 1362 NV_ASSERT(nvBitFieldTest(pChidMgr->channelGrpMgr.pHwIdInUse, 1363 pChidMgr->channelGrpMgr.hwIdInUseSz, chGrpID)); 1364 nvBitFieldSet(pChidMgr->channelGrpMgr.pHwIdInUse, 1365 pChidMgr->channelGrpMgr.hwIdInUseSz, chGrpID, NV_FALSE); 1366 1367 return NV_OK; 1368 } 1369 1370 CHID_MGR * 1371 kfifoGetChidMgr_IMPL 1372 ( 1373 OBJGPU *pGpu, 1374 KernelFifo *pKernelFifo, 1375 NvU32 runlistId 1376 ) 1377 { 1378 if (!kfifoIsPerRunlistChramEnabled(pKernelFifo)) 1379 { 1380 // We only have 1 chidmgr when we don't have a per-runlist channel RAM 1381 if ((pKernelFifo->numChidMgrs != 1) || 1382 (pKernelFifo->ppChidMgr == NULL) || 1383 !bitVectorTest(&pKernelFifo->chidMgrValid, 0)) 1384 { 1385 return NULL; 1386 } 1387 return pKernelFifo->ppChidMgr[0]; 1388 } 1389 else 1390 { 1391 if (runlistId >= pKernelFifo->numChidMgrs) 1392 { 1393 return NULL; 1394 } 1395 // 1396 // It is valid to return a NULL value as long as runlistId is less than 1397 // maxNumRunlists since it is possible that not everything in the range 1398 // [0, numChidMgrs) represents a valid runlistId. The onus is on the 1399 // caller to check for NULL and only then use the CHIDMGR pointer 1400 // 1401 return pKernelFifo->ppChidMgr[runlistId]; 1402 } 1403 } 1404 1405 /*! Gets associated CHIDMGR object for given FIFO_ENGINE_INFO_TYPE and value */ 1406 NV_STATUS 1407 kfifoGetChidMgrFromType_IMPL 1408 ( 1409 OBJGPU *pGpu, 1410 KernelFifo *pKernelFifo, 1411 NvU32 engineInfoType, 1412 NvU32 val, 1413 CHID_MGR **ppChidMgr 1414 ) 1415 { 1416 NV_STATUS status = NV_OK; 1417 NvU32 runlistId; 1418 1419 NV_CHECK_OR_RETURN(LEVEL_INFO, ppChidMgr != NULL, NV_ERR_INVALID_ARGUMENT); 1420 1421 // Initialize the pointer to NULL, in case we fail and return early 1422 *ppChidMgr = NULL; 1423 1424 status = kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, 1425 engineInfoType, val, 1426 ENGINE_INFO_TYPE_RUNLIST, &runlistId); 1427 NV_CHECK_OR_RETURN(LEVEL_INFO, NV_OK == status, status); 1428 1429 *ppChidMgr = kfifoGetChidMgr(pGpu, pKernelFifo, runlistId); 1430 1431 return NV_OK; 1432 } 1433 1434 /*! 1435 * @brief Fetch pKernelChannel based on chidmgr and chid. 1436 * 1437 * This look-up uses the chid heap. It should find the first allocation of the channel, 1438 * which is useful if the handle is duped to another client. 1439 * 1440 * @param[in] pGpu 1441 * @param[in] pKernelFifo 1442 * @param[in] pChidMgr the ChIDMgr (per-runlist) 1443 * @param[in] ChID the ChID 1444 * 1445 * @return the KernelChannel * or NULL 1446 */ 1447 KernelChannel * 1448 kfifoChidMgrGetKernelChannel_IMPL 1449 ( 1450 OBJGPU *pGpu, 1451 KernelFifo *pKernelFifo, 1452 CHID_MGR *pChidMgr, 1453 NvU32 ChID 1454 ) 1455 { 1456 EMEMBLOCK *pFifoDataBlock; 1457 NvU32 numChannels; 1458 1459 NV_ASSERT_OR_RETURN(pChidMgr != NULL, NULL); 1460 // Lite mode channels don't have KernelChannel yet 1461 NV_ASSERT_OR_RETURN(!kfifoIsLiteModeEnabled_HAL(pGpu, pKernelFifo), NULL); 1462 1463 numChannels = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 1464 if (ChID >= numChannels) 1465 { 1466 return NULL; 1467 } 1468 1469 pFifoDataBlock = pChidMgr->pFifoDataHeap->eheapGetBlock( 1470 pChidMgr->pFifoDataHeap, 1471 ChID, 1472 NV_FALSE); 1473 if (pFifoDataBlock != NULL) 1474 { 1475 return (KernelChannel *)pFifoDataBlock->pData; 1476 } 1477 1478 return NULL; 1479 } 1480 1481 /*! Gets channel group data corresponding to grpID */ 1482 KernelChannelGroup * 1483 kfifoChidMgrGetKernelChannelGroup_IMPL 1484 ( 1485 OBJGPU *pGpu, 1486 KernelFifo *pKernelFifo, 1487 CHID_MGR *pChidMgr, 1488 NvU32 grpID 1489 ) 1490 { 1491 KernelChannelGroup *pKernelChannelGroup = NULL; 1492 1493 pKernelChannelGroup = mapFind(pChidMgr->pChanGrpTree, grpID); 1494 if (pKernelChannelGroup == NULL) 1495 { 1496 NV_PRINTF(LEVEL_INFO, "Can't find channel group %d\n", grpID); 1497 } 1498 1499 return pKernelChannelGroup; 1500 } 1501 1502 /*! 1503 * @brief Gets channel group data corresponding to grpID 1504 * 1505 * This function is not called in broadcast mode 1506 * 1507 * @param pGpu 1508 * @param pFifo 1509 * @param[in] grpID 1510 * @param[in] runlistID pass CHIDMGR_RUNLIST_ID_LEGACY if not known 1511 * 1512 * @returns KernelChannelGroup * on success 1513 * NULL if channel group is not found 1514 */ 1515 KernelChannelGroup * 1516 kfifoGetChannelGroup_IMPL 1517 ( 1518 OBJGPU *pGpu, 1519 KernelFifo *pKernelFifo, 1520 NvU32 grpID, 1521 NvU32 runlistID 1522 ) 1523 { 1524 CHID_MGR *pChidMgr = kfifoGetChidMgr(pGpu, pKernelFifo, runlistID); 1525 1526 return kfifoChidMgrGetKernelChannelGroup(pGpu, pKernelFifo, pChidMgr, grpID); 1527 } 1528 1529 /*! Gets total number of channel groups in use */ 1530 NvU32 1531 kfifoGetChannelGroupsInUse_IMPL 1532 ( 1533 OBJGPU *pGpu, 1534 KernelFifo *pKernelFifo 1535 ) 1536 { 1537 NvU32 numChannelGroups = 0; 1538 NvU32 numChannelGroupsInUse = 0; 1539 NvU32 chGrpID, i; 1540 1541 for (i = 0; i < pKernelFifo->numChidMgrs; i++) 1542 { 1543 if (pKernelFifo->ppChidMgr[i] != NULL) 1544 { 1545 numChannelGroups = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, 1546 pKernelFifo->ppChidMgr[i]); 1547 1548 for (chGrpID = 0; chGrpID < numChannelGroups; chGrpID++) 1549 { 1550 if (nvBitFieldTest(pKernelFifo->ppChidMgr[i]->channelGrpMgr.pHwIdInUse, 1551 pKernelFifo->ppChidMgr[i]->channelGrpMgr.hwIdInUseSz, 1552 chGrpID)) 1553 { 1554 numChannelGroupsInUse++; 1555 } 1556 } 1557 } 1558 } 1559 return numChannelGroupsInUse; 1560 } 1561 1562 /*! Gets total number of channel groups in use per engine */ 1563 NvU32 1564 kfifoGetRunlistChannelGroupsInUse_IMPL 1565 ( 1566 OBJGPU *pGpu, 1567 KernelFifo *pKernelFifo, 1568 NvU32 runlistId 1569 ) 1570 { 1571 NvU32 numChannelGroups = 0; 1572 NvU32 numChannelGroupsInUse = 0; 1573 NvU32 chGrpID; 1574 CHID_MGR *pChidMgr = kfifoGetChidMgr(pGpu, pKernelFifo, runlistId); 1575 1576 numChannelGroups = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 1577 for (chGrpID = 0; chGrpID < numChannelGroups; chGrpID++) 1578 { 1579 if (nvBitFieldTest(pChidMgr->channelGrpMgr.pHwIdInUse, 1580 pChidMgr->channelGrpMgr.hwIdInUseSz, 1581 chGrpID)) 1582 { 1583 numChannelGroupsInUse++; 1584 } 1585 } 1586 return numChannelGroupsInUse; 1587 } 1588 1589 /** 1590 * @brief Sets the timeslice for the specified channel group. 1591 * 1592 * @returns NV_OK if success, appropriate error otherwise 1593 */ 1594 NV_STATUS 1595 kfifoChannelGroupSetTimeslice_IMPL 1596 ( 1597 OBJGPU *pGpu, 1598 KernelFifo *pKernelFifo, 1599 KernelChannelGroup *pKernelChannelGroup, 1600 NvU64 timesliceUs, 1601 NvBool bSkipSubmit 1602 ) 1603 { 1604 NV_STATUS status = NV_OK; 1605 1606 NV_PRINTF(LEVEL_INFO, "Setting TSG %d Timeslice to %lldus\n", 1607 pKernelChannelGroup->grpID, timesliceUs); 1608 1609 if (timesliceUs < kfifoRunlistGetMinTimeSlice_HAL(pKernelFifo)) 1610 { 1611 NV_PRINTF(LEVEL_ERROR, 1612 "Setting Timeslice to %lldus not allowed. Min value is %lldus\n", 1613 timesliceUs, kfifoRunlistGetMinTimeSlice_HAL(pKernelFifo)); 1614 return NV_ERR_NOT_SUPPORTED; 1615 } 1616 1617 pKernelChannelGroup->timesliceUs = timesliceUs; 1618 1619 NV_ASSERT_OK_OR_RETURN(kfifoChannelGroupSetTimesliceSched(pGpu, 1620 pKernelFifo, 1621 pKernelChannelGroup, 1622 timesliceUs, 1623 bSkipSubmit)); 1624 1625 return status; 1626 } 1627 1628 void 1629 kfifoFillMemInfo_IMPL 1630 ( 1631 KernelFifo *pKernelFifo, 1632 MEMORY_DESCRIPTOR *pMemDesc, 1633 NV2080_CTRL_FIFO_MEM_INFO *pMemory 1634 ) 1635 { 1636 if (pMemDesc == NULL) 1637 { 1638 pMemory->aperture = NV2080_CTRL_CMD_FIFO_GET_CHANNEL_MEM_APERTURE_INVALID; 1639 NV_PRINTF(LEVEL_ERROR, "kfifoFillMemInfo: pMemDesc = NULL\n"); 1640 } 1641 else 1642 { 1643 if (memdescGetAddressSpace(pMemDesc) == ADDR_FBMEM) 1644 { 1645 pMemory->aperture = NV2080_CTRL_CMD_FIFO_GET_CHANNEL_MEM_APERTURE_VIDMEM; 1646 } 1647 else if (memdescGetAddressSpace(pMemDesc) == ADDR_SYSMEM) 1648 { 1649 if (memdescGetCpuCacheAttrib(pMemDesc) == NV_MEMORY_CACHED) 1650 { 1651 pMemory->aperture = NV2080_CTRL_CMD_FIFO_GET_CHANNEL_MEM_APERTURE_SYSMEM_COH; 1652 } 1653 else if (memdescGetCpuCacheAttrib(pMemDesc) == NV_MEMORY_UNCACHED) 1654 { 1655 pMemory->aperture = NV2080_CTRL_CMD_FIFO_GET_CHANNEL_MEM_APERTURE_SYSMEM_NCOH; 1656 } 1657 else 1658 { 1659 NV_PRINTF(LEVEL_ERROR, 1660 "kfifoFillMemInfo: Unknown cache attribute for sysmem aperture\n"); 1661 NV_ASSERT(NV_FALSE); 1662 } 1663 } 1664 pMemory->base = memdescGetPhysAddr(pMemDesc, AT_GPU, 0); 1665 pMemory->size = pMemDesc->Size; 1666 } 1667 } 1668 1669 void 1670 kfifoGetChannelIterator_IMPL 1671 ( 1672 OBJGPU *pGpu, 1673 KernelFifo *pKernelFifo, 1674 CHANNEL_ITERATOR *pIt 1675 ) 1676 { 1677 portMemSet(pIt, 0, sizeof(*pIt)); 1678 pIt->physicalChannelID = 0; 1679 pIt->pFifoDataBlock = NULL; 1680 pIt->runlistId = 0; 1681 pIt->numRunlists = 1; 1682 if (kfifoIsPerRunlistChramEnabled(pKernelFifo)) 1683 { 1684 pIt->numRunlists = kfifoGetMaxNumRunlists_HAL(pGpu, pKernelFifo); 1685 } 1686 } 1687 1688 /** 1689 * @brief Returns the next KernelChannel from the iterator. 1690 * 1691 * Iterates over runlist IDs and ChIDs and returns the next KernelChannel found 1692 * on the heap, if any. 1693 * 1694 * (error guaranteed if pointer is NULL; non-NULL pointer guaranteed if NV_OK) 1695 * 1696 * @param[in] pGpu 1697 * @param[in] pKernelFifo 1698 * @param[in] pIt the channel iterator 1699 * @param[out] ppKernelChannel returns a KernelChannel * 1700 * 1701 * @return NV_OK if the returned pointer is valid or error 1702 */ 1703 NV_STATUS kfifoGetNextKernelChannel_IMPL 1704 ( 1705 OBJGPU *pGpu, 1706 KernelFifo *pKernelFifo, 1707 CHANNEL_ITERATOR *pIt, 1708 KernelChannel **ppKernelChannel 1709 ) 1710 { 1711 KernelChannel *pKernelChannel; 1712 1713 if (ppKernelChannel == NULL) 1714 return NV_ERR_INVALID_ARGUMENT; 1715 1716 *ppKernelChannel = NULL; 1717 1718 while (pIt->runlistId < pIt->numRunlists) 1719 { 1720 CHID_MGR *pChidMgr = kfifoGetChidMgr(pGpu, pKernelFifo, pIt->runlistId); 1721 1722 if (pChidMgr == NULL) 1723 { 1724 pIt->runlistId++; 1725 continue; 1726 } 1727 1728 pIt->numChannels = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 1729 1730 if (pIt->pFifoDataBlock == NULL) 1731 { 1732 pIt->pFifoDataBlock = pChidMgr->pFifoDataHeap->eheapGetBlock( 1733 pChidMgr->pFifoDataHeap, 1734 pIt->physicalChannelID, 1735 NV_TRUE); 1736 } 1737 1738 while (pIt->physicalChannelID < pIt->numChannels) 1739 { 1740 if (pIt->pFifoDataBlock->owner == NVOS32_BLOCK_TYPE_FREE) 1741 { 1742 pIt->physicalChannelID = pIt->pFifoDataBlock->end + 1; 1743 } 1744 else 1745 { 1746 pIt->physicalChannelID++; 1747 pKernelChannel = (KernelChannel *)pIt->pFifoDataBlock->pData; 1748 1749 // 1750 // This iterator can be used during an interrupt, when a KernelChannel may 1751 // be in the process of being destroyed. If a KernelChannel expects a pChannel 1752 // but does not have one, it means it's being destroyed and we don't want to 1753 // return it. 1754 // 1755 if (pKernelChannel != NULL && kchannelIsValid_HAL(pKernelChannel)) 1756 { 1757 // Prepare iterator to check next block in pChidMgr->pFifoDataHeap 1758 pIt->pFifoDataBlock = pIt->pFifoDataBlock->next; 1759 *ppKernelChannel = pKernelChannel; 1760 return NV_OK; 1761 } 1762 } 1763 1764 // Check next block in pChidMgr->pFifoDataHeap 1765 pIt->pFifoDataBlock = pIt->pFifoDataBlock->next; 1766 } 1767 1768 pIt->runlistId++; 1769 // Reset iterator for next runlist 1770 pIt->physicalChannelID = 0; 1771 pIt->pFifoDataBlock = NULL; 1772 } 1773 1774 return NV_ERR_OBJECT_NOT_FOUND; 1775 } 1776 1777 /*! 1778 * @brief Localize the engine info received from the host 1779 * 1780 * The host and the guest can run in different version of drivers, the guest driver 1781 * can not directly use the raw MC_ENGINE_IDX values from the host. 1782 * RM does not guarantee those values are consistent cross branches. 1783 * 1784 * To keep the compatibility between different version of branches, this function reconstructs 1785 * of RM_ENGINE_TYPE, MC_ENGINE_IDX values based on NV2080_ENGINE_TYPE 1786 * 1787 * @param[in] pGpu OBJGPU pointer 1788 * @param[in] pFifo KernelFifo pointer 1789 * @param[in/out] pEngine Pointer to engine info table to update 1790 * 1791 */ 1792 static void 1793 _kfifoLocalizeGuestEngineData 1794 ( 1795 OBJGPU *pGpu, 1796 KernelFifo *pKernelFifo, 1797 ENGINE_INFO *pEngineInfo 1798 ) 1799 { 1800 const FIFO_GUEST_ENGINE_TABLE *guestEngineTable; 1801 NvU32 guestEngineTableSz; 1802 NvU32 nv2080EngineType; 1803 NvU32 engineIdx; 1804 NvU32 newEngineIdx; 1805 NvU32 guestTableIdx; 1806 1807 // This function should only be called in a vgpu guest RM 1808 NV_ASSERT_OR_RETURN_VOID(IS_VIRTUAL(pGpu)); 1809 1810 guestEngineTable = kfifoGetGuestEngineLookupTable(&guestEngineTableSz); 1811 1812 newEngineIdx = 0; 1813 1814 for (engineIdx = 0; engineIdx < pEngineInfo->engineInfoListSize; engineIdx++) 1815 { 1816 FIFO_ENGINE_LIST *pEngine = &pEngineInfo->engineInfoList[engineIdx]; 1817 1818 // The actual data in engineData[ENGINE_INFO_TYPE_RM_ENGINE_TYPE] is NV2080 ENGINE TYPE. 1819 nv2080EngineType = pEngine->engineData[ENGINE_INFO_TYPE_RM_ENGINE_TYPE]; 1820 1821 for (guestTableIdx = 0; guestTableIdx < guestEngineTableSz; guestTableIdx++) 1822 { 1823 // Find the engine type supported by the guest 1824 if (guestEngineTable[guestTableIdx].nv2080EngineType == nv2080EngineType) 1825 break; 1826 } 1827 1828 if (guestTableIdx < guestEngineTableSz) 1829 { 1830 // Update the MC for the guest 1831 pEngine->engineData[ENGINE_INFO_TYPE_MC] = guestEngineTable[guestTableIdx].mcIdx; 1832 1833 // Update it with correct engine type 1834 pEngine->engineData[ENGINE_INFO_TYPE_RM_ENGINE_TYPE] = gpuGetRmEngineType(nv2080EngineType); 1835 1836 if (newEngineIdx != engineIdx) 1837 { 1838 // 1839 // Move the engine info up to make sure the engine info table only contains data for 1840 // guest supported engine types. 1841 // 1842 portMemCopy(&pEngineInfo->engineInfoList[newEngineIdx], sizeof(FIFO_ENGINE_LIST), 1843 &pEngineInfo->engineInfoList[engineIdx], sizeof(FIFO_ENGINE_LIST)); 1844 } 1845 1846 newEngineIdx++; 1847 } 1848 } 1849 1850 pEngineInfo->engineInfoListSize = newEngineIdx; 1851 } 1852 1853 /*! 1854 * @brief Performs an RPC into Host RM to read its device info table. 1855 * 1856 * This is necessary because in virtual environments, we cannot directly read 1857 * the device info table, and do not have the physical GPU partitioning 1858 * information to determine which engines belong to this guest, so we have Host 1859 * RM do the filtering and send us the filtered table. 1860 * 1861 * @param[in] pGpu 1862 * @param[in] pKernelFifo 1863 * 1864 * @return NV_OK if succcessful, 1865 * NV_ERR_NOT_SUPPORTED if Host RM calls this interface 1866 * NV_ERR_INVALID_STATE if host supplied invalid data 1867 * NV_STATUS supplied by RPC response from Host 1868 */ 1869 1870 NV_STATUS 1871 kfifoGetHostDeviceInfoTable_KERNEL 1872 ( 1873 OBJGPU *pGpu, 1874 KernelFifo *pKernelFifo, 1875 ENGINE_INFO *pEngineInfo, 1876 NvHandle hMigClient 1877 ) 1878 { 1879 NV_STATUS status = NV_OK; 1880 NvHandle hClient = NV01_NULL_OBJECT; 1881 NvHandle hObject = NV01_NULL_OBJECT; 1882 NV2080_CTRL_FIFO_GET_DEVICE_INFO_TABLE_PARAMS *pParams; 1883 NV2080_CTRL_FIFO_DEVICE_ENTRY *pFetchedTable; 1884 NvU32 numEntries; 1885 NvU32 device; 1886 NvU32 entry; 1887 NvU32 numRunlists; 1888 NvU32 maxRunlistId; 1889 NvU32 maxPbdmaId; 1890 NvU32 i; 1891 struct { 1892 NV2080_CTRL_FIFO_GET_DEVICE_INFO_TABLE_PARAMS params; 1893 NV2080_CTRL_FIFO_DEVICE_ENTRY entries[NV2080_CTRL_FIFO_GET_DEVICE_INFO_TABLE_MAX_DEVICES]; 1894 } *pLocals; 1895 1896 1897 NV_ASSERT_OR_RETURN(IS_VIRTUAL(pGpu) || IS_GSP_CLIENT(pGpu), 1898 NV_ERR_NOT_SUPPORTED); 1899 1900 // RPC call for GSP will throw INVALID_CLIENT error with NULL handles 1901 if (IS_GSP_CLIENT(pGpu)) 1902 { 1903 if (!IS_MIG_IN_USE(pGpu)) 1904 { 1905 hClient = pGpu->hInternalClient; 1906 hObject = pGpu->hInternalSubdevice; 1907 } 1908 else 1909 { 1910 RsClient *pClient; 1911 Subdevice *pSubdevice; 1912 1913 hClient = hMigClient; 1914 1915 NV_ASSERT_OK_OR_RETURN( 1916 serverGetClientUnderLock(&g_resServ, hClient, &pClient)); 1917 1918 NV_ASSERT_OK_OR_RETURN(subdeviceGetByGpu(pClient, pGpu, &pSubdevice)); 1919 1920 GPU_RES_SET_THREAD_BC_STATE(pSubdevice); 1921 1922 hObject = RES_GET_HANDLE(pSubdevice); 1923 } 1924 } 1925 1926 // Allocate pFetchedTable and params on the heap to avoid stack overflow 1927 pLocals = portMemAllocNonPaged(sizeof(*pLocals)); 1928 NV_ASSERT_OR_RETURN((pLocals != NULL), NV_ERR_NO_MEMORY); 1929 1930 pParams = &pLocals->params; 1931 pFetchedTable = pLocals->entries; 1932 1933 // 1934 // Read device info table entries from Host RM until Host indicates that 1935 // there are no more valid entries in the table (by setting bMore flag) 1936 // 1937 numEntries = 0; 1938 for (device = 0; 1939 device < NV2080_CTRL_FIFO_GET_DEVICE_INFO_TABLE_MAX_DEVICES; 1940 device += NV2080_CTRL_FIFO_GET_DEVICE_INFO_TABLE_MAX_ENTRIES) 1941 { 1942 portMemSet(pParams, 0x0, sizeof(*pParams)); 1943 pParams->baseIndex = device; 1944 1945 NV_RM_RPC_CONTROL(pGpu, 1946 hClient, 1947 hObject, 1948 NV2080_CTRL_CMD_FIFO_GET_DEVICE_INFO_TABLE, 1949 pParams, 1950 sizeof(*pParams), 1951 status); 1952 1953 if (status != NV_OK) 1954 goto cleanup; 1955 1956 // Assert that host RM didn't tell us an invalid number of entries 1957 if (pParams->numEntries > 1958 NV2080_CTRL_FIFO_GET_DEVICE_INFO_TABLE_MAX_ENTRIES) 1959 { 1960 DBG_BREAKPOINT(); 1961 status = NV_ERR_INVALID_STATE; 1962 goto cleanup; 1963 } 1964 1965 portMemCopy(&pFetchedTable[device], 1966 pParams->numEntries * (sizeof *pFetchedTable), 1967 pParams->entries, 1968 pParams->numEntries * (sizeof *pParams->entries)); 1969 1970 numEntries += pParams->numEntries; 1971 1972 if (!pParams->bMore) 1973 { 1974 break; 1975 } 1976 } 1977 1978 pEngineInfo->engineInfoListSize = numEntries; 1979 pEngineInfo->engineInfoList = portMemAllocNonPaged(sizeof(*pEngineInfo->engineInfoList) * 1980 pEngineInfo->engineInfoListSize); 1981 if (pEngineInfo->engineInfoList == NULL) 1982 { 1983 NV_CHECK(LEVEL_ERROR, pEngineInfo->engineInfoList != NULL); 1984 status = NV_ERR_NO_MEMORY; 1985 goto cleanup; 1986 } 1987 1988 // Copy each entry from the table 1989 numRunlists = 0; 1990 maxRunlistId = 0; 1991 maxPbdmaId = 0; 1992 for (entry = 0; entry < numEntries; ++entry) 1993 { 1994 FIFO_ENGINE_LIST *pLocalEntry = &pEngineInfo->engineInfoList[entry]; 1995 NV2080_CTRL_FIFO_DEVICE_ENTRY *pFetchedEntry = &pFetchedTable[entry]; 1996 1997 ct_assert(sizeof pLocalEntry->engineData <= 1998 sizeof pFetchedEntry->engineData); 1999 portMemCopy(pLocalEntry->engineData, 2000 sizeof pLocalEntry->engineData, 2001 pFetchedEntry->engineData, 2002 NV_ARRAY_ELEMENTS(pLocalEntry->engineData) * 2003 (sizeof *pFetchedEntry->engineData)); 2004 2005 pLocalEntry->numPbdmas = pFetchedEntry->numPbdmas; 2006 NV_ASSERT_TRUE_OR_GOTO(status, 2007 pLocalEntry->numPbdmas <= 2008 NV_ARRAY_ELEMENTS(pLocalEntry->pbdmaIds) && 2009 pLocalEntry->numPbdmas <= 2010 NV_ARRAY_ELEMENTS(pLocalEntry->pbdmaFaultIds), 2011 NV_ERR_INVALID_STATE, 2012 cleanup); 2013 portMemCopy( 2014 pLocalEntry->pbdmaIds, 2015 pLocalEntry->numPbdmas * (sizeof *(pLocalEntry->pbdmaIds)), 2016 pFetchedEntry->pbdmaIds, 2017 pLocalEntry->numPbdmas * (sizeof *(pFetchedEntry->pbdmaIds))); 2018 portMemCopy( 2019 pLocalEntry->pbdmaFaultIds, 2020 pLocalEntry->numPbdmas * (sizeof *(pLocalEntry->pbdmaFaultIds)), 2021 pFetchedEntry->pbdmaFaultIds, 2022 pLocalEntry->numPbdmas * (sizeof *(pFetchedEntry->pbdmaFaultIds))); 2023 2024 portStringCopy(pLocalEntry->engineName, 2025 sizeof pLocalEntry->engineName, 2026 pFetchedEntry->engineName, 2027 sizeof pFetchedEntry->engineName); 2028 2029 if (pLocalEntry->engineData[ENGINE_INFO_TYPE_IS_HOST_DRIVEN_ENGINE] != 0) 2030 { 2031 numRunlists++; 2032 } 2033 maxRunlistId = NV_MAX(maxRunlistId, 2034 pFetchedEntry->engineData[ENGINE_INFO_TYPE_RUNLIST]); 2035 2036 for (i = 0; i < pLocalEntry->numPbdmas; i++) 2037 { 2038 maxPbdmaId = NV_MAX(maxPbdmaId, pLocalEntry->pbdmaIds[i]); 2039 2040 // 2041 // SW engine while being constructed does not populate any PBDMA Fault IDs. 2042 // Hence, skipping it. 2043 // 2044 if (pLocalEntry->engineData[ENGINE_INFO_TYPE_ENG_DESC] != ENG_SW) 2045 { 2046 bitVectorSet(&pEngineInfo->validEngineIdsForPbdmas, pLocalEntry->pbdmaFaultIds[i]); 2047 } 2048 } 2049 } 2050 2051 NV_ASSERT_OK_OR_GOTO(status, 2052 kfifoReservePbdmaFaultIds_HAL(pGpu, pKernelFifo, 2053 pEngineInfo->engineInfoList, 2054 pEngineInfo->engineInfoListSize), 2055 cleanup); 2056 2057 if (IS_VIRTUAL(pGpu)) 2058 { 2059 _kfifoLocalizeGuestEngineData(pGpu, pKernelFifo, pEngineInfo); 2060 } 2061 2062 pEngineInfo->numRunlists = numRunlists; 2063 pEngineInfo->maxNumRunlists = maxRunlistId + 1; 2064 pEngineInfo->maxNumPbdmas = maxPbdmaId + 1; 2065 2066 cleanup: 2067 portMemFree(pLocals); 2068 2069 return status; 2070 } 2071 2072 /*! 2073 * @brief Constructs EngineInfo List 2074 * 2075 * @param[in] pGpu 2076 * @param[in] pKernelFifo 2077 * 2078 * @return NV_OK if succcessful, 2079 * NV_STATUS supplied by HALs called 2080 */ 2081 NV_STATUS 2082 kfifoConstructEngineList_KERNEL 2083 ( 2084 OBJGPU *pGpu, 2085 KernelFifo *pKernelFifo 2086 ) 2087 { 2088 ENGINE_INFO *pEngineInfo = &pKernelFifo->engineInfo; 2089 2090 // Return early if EngineList is already constructed 2091 if (pEngineInfo->engineInfoList != NULL) 2092 return NV_OK; 2093 2094 if (IS_GSP_CLIENT(pGpu)) 2095 { 2096 NV_ASSERT_OK_OR_RETURN(gpuConstructDeviceInfoTable_HAL(pGpu)); 2097 } 2098 2099 NV_ASSERT_OK_OR_RETURN(kfifoGetHostDeviceInfoTable_HAL(pGpu, pKernelFifo, pEngineInfo, 0)); 2100 2101 return NV_OK; 2102 } 2103 2104 /** 2105 * @brief Create a list of channels. 2106 * 2107 * @param pGpu 2108 * @param pKernelFifo 2109 * @param pList 2110 */ 2111 NV_STATUS 2112 kfifoChannelListCreate_IMPL 2113 ( 2114 OBJGPU *pGpu, 2115 KernelFifo *pKernelFifo, 2116 CHANNEL_LIST **ppList 2117 ) 2118 { 2119 if (!ppList) 2120 return NV_ERR_INVALID_ARGUMENT; 2121 2122 *ppList = portMemAllocNonPaged(sizeof(CHANNEL_LIST)); 2123 NV_ASSERT_OR_RETURN((*ppList != NULL), NV_ERR_NO_MEMORY); 2124 2125 (*ppList)->pHead = NULL; 2126 (*ppList)->pTail = NULL; 2127 2128 return NV_OK; 2129 } 2130 2131 /** 2132 * @brief Append a channel to a channel list. 2133 * 2134 * @param pGpu 2135 * @param pKernelFifo 2136 * @param pKernelChannel 2137 * @param pList 2138 */ 2139 2140 NV_STATUS 2141 kfifoChannelListAppend_IMPL 2142 ( 2143 OBJGPU *pGpu, 2144 KernelFifo *pKernel, 2145 KernelChannel *pKernelChannel, 2146 CHANNEL_LIST *pList 2147 ) 2148 { 2149 PCHANNEL_NODE pNewNode = NULL; 2150 2151 if (!pKernelChannel || !pList) 2152 return NV_ERR_INVALID_ARGUMENT; 2153 2154 pNewNode = portMemAllocNonPaged(sizeof(CHANNEL_NODE)); 2155 NV_ASSERT_OR_RETURN((pNewNode != NULL), NV_ERR_NO_MEMORY); 2156 2157 pNewNode->pKernelChannel = pKernelChannel; 2158 pKernelChannel->refCount++; 2159 2160 pNewNode->pNext = NULL; 2161 2162 // Searching based on the ChID 2163 if (pList->pTail) 2164 { 2165 pList->pTail->pNext = pNewNode; 2166 pList->pTail = pNewNode; 2167 } 2168 else 2169 { 2170 pList->pHead = pNewNode; 2171 pList->pTail = pNewNode; 2172 } 2173 2174 return NV_OK; 2175 } 2176 2177 /** 2178 * @brief remove channel from the given channel list 2179 * look for duplicates. 2180 * 2181 * @param pGpu 2182 * @param pKernelFifo 2183 * @param pKernelChannel 2184 * @param pList 2185 */ 2186 NV_STATUS 2187 kfifoChannelListRemove_IMPL 2188 ( 2189 OBJGPU *pGpu, 2190 KernelFifo *pKernelFifo, 2191 KernelChannel *pKernelChannel, 2192 CHANNEL_LIST *pList 2193 ) 2194 { 2195 PCHANNEL_NODE pNewNode = NULL; 2196 PCHANNEL_NODE pPrevNode = NULL; 2197 PCHANNEL_NODE pTempNode = NULL; 2198 NvBool bFoundOnce = NV_FALSE; 2199 NV_STATUS status = NV_OK; 2200 2201 if (!pKernelChannel) 2202 return NV_ERR_INVALID_ARGUMENT; 2203 2204 if (!pList) 2205 return NV_ERR_INVALID_ARGUMENT; 2206 2207 pNewNode = pList->pHead; 2208 pPrevNode = NULL; 2209 2210 while (pNewNode) 2211 { 2212 2213 if (pKernelChannel != pNewNode->pKernelChannel) 2214 { 2215 pPrevNode = pNewNode; 2216 pNewNode = pNewNode->pNext; 2217 continue; 2218 } 2219 2220 // Deleting first node 2221 if (pList->pHead == pNewNode) 2222 { 2223 pList->pHead = pNewNode->pNext; 2224 } 2225 2226 // Deleting tail node 2227 if (pList->pTail == pNewNode) 2228 { 2229 pList->pTail = pPrevNode; 2230 } 2231 2232 // First node does not have previous node. 2233 if (pPrevNode) 2234 { 2235 pPrevNode->pNext = pNewNode->pNext; 2236 } 2237 2238 pTempNode = pNewNode; 2239 pNewNode = pNewNode->pNext; 2240 portMemFree(pTempNode); 2241 2242 bFoundOnce = NV_TRUE; 2243 2244 if (0 == pKernelChannel->refCount) 2245 { 2246 NV_PRINTF(LEVEL_ERROR, "RefCount for channel is not right!!!\n"); 2247 DBG_BREAKPOINT(); 2248 status = NV_ERR_GENERIC; 2249 break; 2250 } 2251 2252 pKernelChannel->refCount--; 2253 } 2254 2255 2256 if (!bFoundOnce) 2257 { 2258 NV_PRINTF(LEVEL_INFO, 2259 "Can't find channel in channelGroupList (Normal during RC Recovery on " 2260 "GK110+ or if software scheduling is enabled).\n"); 2261 2262 status = NV_ERR_INVALID_CHANNEL; 2263 } 2264 2265 return status; 2266 } 2267 2268 /** 2269 * @brief Destroy channel list. 2270 * 2271 * @param pGpu 2272 * @param pKernelFifo 2273 * @param pList 2274 */ 2275 NV_STATUS 2276 kfifoChannelListDestroy_IMPL 2277 ( 2278 OBJGPU *pGpu, 2279 KernelFifo *pKernel, 2280 CHANNEL_LIST *pList 2281 ) 2282 { 2283 PCHANNEL_NODE pTempNode; 2284 2285 if (!pList) 2286 return NV_OK; 2287 2288 while (pList->pHead) 2289 { 2290 pTempNode = pList->pHead; 2291 2292 NV_ASSERT_OR_RETURN(pTempNode->pKernelChannel && pTempNode->pKernelChannel->refCount, NV_ERR_INVALID_STATE); 2293 2294 pTempNode->pKernelChannel->refCount--; 2295 2296 pList->pHead = pTempNode->pNext; 2297 portMemFree(pTempNode); 2298 } 2299 2300 portMemFree(pList); 2301 2302 return NV_OK; 2303 } 2304 2305 /*! 2306 * @brief Determines whether provided engines have any channels/contexts assigned 2307 * 2308 * @param[IN] pGpu OBJGPU 2309 * @param[IN] pKernelFifo KernelFifo 2310 * @param[IN] pEngines Which engines to check (RM_ENGINE_TYPE_***) 2311 * @param[IN] engineCount Number of engines to check 2312 * 2313 * @return Returns NV_TRUE if any provided engines are active 2314 */ 2315 NvBool 2316 kfifoEngineListHasChannel_IMPL 2317 ( 2318 OBJGPU *pGpu, 2319 KernelFifo *pKernelFifo, 2320 RM_ENGINE_TYPE *pEngines, 2321 NvU32 engineCount 2322 ) 2323 { 2324 KernelChannel *pKernelChannel; 2325 CHANNEL_ITERATOR it; 2326 NvU32 i; 2327 2328 NV_ASSERT_OR_RETURN((pEngines != NULL) && (engineCount > 0), NV_TRUE); 2329 2330 // Find any channels or contexts on passed engines 2331 kfifoGetChannelIterator(pGpu, pKernelFifo, &it); 2332 while (kchannelGetNextKernelChannel(pGpu, &it, &pKernelChannel) == NV_OK) 2333 { 2334 NV_ASSERT_OR_ELSE(pKernelChannel != NULL, continue); 2335 2336 // If the client supplied the engine type, directly check it 2337 if (RM_ENGINE_TYPE_IS_VALID(kchannelGetEngineType(pKernelChannel))) 2338 { 2339 for (i = 0; i < engineCount; ++i) 2340 { 2341 if (kchannelGetEngineType(pKernelChannel) == pEngines[i]) 2342 { 2343 NV_PRINTF(LEVEL_ERROR, 2344 "Found channel on engine 0x%x owned by 0x%x\n", 2345 kchannelGetEngineType(pKernelChannel), RES_GET_CLIENT_HANDLE(pKernelChannel)); 2346 2347 return NV_TRUE; 2348 } 2349 } 2350 } 2351 else 2352 { 2353 NvU32 runlistId; 2354 2355 // Ideally valid engine Id should always be set in channel if this property is enabled 2356 NV_ASSERT_OR_RETURN(!kfifoIsPerRunlistChramEnabled(pKernelFifo), NV_TRUE); 2357 2358 // 2359 // If runlist Id for channel is set then check if it matches with any of the engines 2360 // If channel is not associated with any engine then there is a chance 2361 // it can be created on one of the engines we care about. 2362 // 2363 if (kchannelIsRunlistSet(pGpu, pKernelChannel)) 2364 { 2365 for (i = 0; i < engineCount; ++i) 2366 { 2367 NV_ASSERT_OR_RETURN((kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, 2368 ENGINE_INFO_TYPE_RM_ENGINE_TYPE, (NvU32)pEngines[i], 2369 ENGINE_INFO_TYPE_RUNLIST, &runlistId) == NV_OK), NV_TRUE); 2370 if (kchannelGetRunlistId(pKernelChannel) == runlistId) 2371 { 2372 NV_PRINTF(LEVEL_ERROR, 2373 "Found channel on runlistId 0x%x owned by 0x%x\n", 2374 kchannelGetRunlistId(pKernelChannel), RES_GET_CLIENT_HANDLE(pKernelChannel)); 2375 2376 return NV_TRUE; 2377 } 2378 } 2379 } 2380 else 2381 { 2382 NV_PRINTF(LEVEL_ERROR, 2383 "Found channel owned by 0x%x that can be associated to any engine\n", 2384 RES_GET_CLIENT_HANDLE(pKernelChannel)); 2385 2386 return NV_TRUE; 2387 } 2388 } 2389 } 2390 2391 return NV_FALSE; 2392 } 2393 2394 /** 2395 * @brief Maximum number of subcontexts for a non-legacy mode TSG 2396 */ 2397 CTX_BUF_POOL_INFO * 2398 kfifoGetRunlistBufPool_IMPL 2399 ( 2400 OBJGPU *pGpu, 2401 KernelFifo *pKernelFifo, 2402 RM_ENGINE_TYPE rmEngineType 2403 ) 2404 { 2405 return pKernelFifo->pRunlistBufPool[rmEngineType]; 2406 } 2407 2408 /** 2409 * @brief Get size and alignment requirements for runlist buffers 2410 * 2411 * @param[in] pGpu Pointer to OBJGPU 2412 * @param[in] pKernelFifo Pointer to KernelFifo 2413 * @param[in] runlistId Runlist ID 2414 * @param[in] bTsgSupported Is TSG supported 2415 * @param[in] maxRunlistEntries Max entries to be supported in a runlist 2416 * @param[out] pSize Size of runlist buffer 2417 * @param[out] pAlignment Alignment for runlist buffer 2418 */ 2419 NV_STATUS 2420 kfifoGetRunlistBufInfo_IMPL 2421 ( 2422 OBJGPU *pGpu, 2423 KernelFifo *pKernelFifo, 2424 NvU32 runlistId, 2425 NvBool bTsgSupported, 2426 NvU32 maxRunlistEntries, 2427 NvU64 *pSize, 2428 NvU64 *pAlignment 2429 ) 2430 { 2431 NvU32 runlistEntrySize = 0; 2432 NvU32 maxRunlistEntriesSupported = 0; 2433 CHID_MGR *pChidMgr = kfifoGetChidMgr(pGpu, pKernelFifo, runlistId); 2434 2435 NV_ASSERT_OR_RETURN(pSize != NULL, NV_ERR_INVALID_ARGUMENT); 2436 NV_ASSERT_OR_RETURN(pAlignment != NULL, NV_ERR_INVALID_ARGUMENT); 2437 2438 if (kfifoIsPerRunlistChramEnabled(pKernelFifo)) 2439 { 2440 NV_ASSERT_OR_RETURN(pChidMgr != NULL, NV_ERR_INVALID_ARGUMENT); 2441 // 2442 // We assume worst case of one TSG wrapper per channel, and 2443 // the number of TSGs + number of channels is how we get 2444 // the 2 x number of fifos. 2445 // 2446 maxRunlistEntriesSupported = 2 * kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 2447 } 2448 else 2449 { 2450 maxRunlistEntriesSupported = kfifoGetMaxChannelsInSystem(pGpu, pKernelFifo); 2451 maxRunlistEntriesSupported += (bTsgSupported ? 2452 kfifoGetMaxChannelGroupsInSystem(pGpu, pKernelFifo) 2453 : 0); 2454 } 2455 2456 NV_ASSERT_OR_RETURN(maxRunlistEntries <= maxRunlistEntriesSupported, NV_ERR_INVALID_ARGUMENT); 2457 2458 if (maxRunlistEntries == 0) 2459 { 2460 maxRunlistEntries = maxRunlistEntriesSupported; 2461 } 2462 2463 runlistEntrySize = kfifoRunlistGetEntrySize_HAL(pKernelFifo); 2464 *pSize = (NvU64)runlistEntrySize * maxRunlistEntries; 2465 2466 *pAlignment = NVBIT64(kfifoRunlistGetBaseShift_HAL(pKernelFifo)); 2467 return NV_OK; 2468 } 2469 2470 /*! 2471 * @brief Gets total number of channels supported by the system 2472 */ 2473 NvU32 2474 kfifoGetMaxChannelsInSystem_IMPL 2475 ( 2476 OBJGPU *pGpu, 2477 KernelFifo *pKernelFifo 2478 ) 2479 { 2480 NvU32 numChannels = 0; 2481 NvU32 i; 2482 2483 for (i = 0; i < pKernelFifo->numChidMgrs; i++) 2484 { 2485 if (pKernelFifo->ppChidMgr[i] != NULL) 2486 { 2487 numChannels += kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pKernelFifo->ppChidMgr[i]); 2488 } 2489 } 2490 return numChannels; 2491 } 2492 2493 /*! 2494 * @brief Gets total number of channel groups supported by the system 2495 */ 2496 NvU32 2497 kfifoGetMaxChannelGroupsInSystem_IMPL 2498 ( 2499 OBJGPU *pGpu, 2500 KernelFifo *pKernelFifo 2501 ) 2502 { 2503 // Max channel groups is the same as max channels 2504 return kfifoGetMaxChannelsInSystem(pGpu, pKernelFifo); 2505 } 2506 2507 /*! 2508 * @brief Get runlist buffer allocation params 2509 * 2510 * @param[in] pGpu 2511 * @param[out] *pAperture Aperture to use for runlist buffer allocation 2512 * @param[out] *pAttr Attributes to use for runlits buffer allocation 2513 * @param[out] *pAllocFlags Allocation flags to use for runlist buffer allocation 2514 */ 2515 void 2516 kfifoRunlistGetBufAllocParams_IMPL 2517 ( 2518 OBJGPU *pGpu, 2519 NV_ADDRESS_SPACE *pAperture, 2520 NvU32 *pAttr, 2521 NvU64 *pAllocFlags 2522 ) 2523 { 2524 *pAperture = ADDR_FBMEM; 2525 *pAttr = NV_MEMORY_WRITECOMBINED; 2526 2527 memdescOverrideInstLoc(DRF_VAL(_REG_STR_RM, _INST_LOC, _RUNLIST, pGpu->instLocOverrides), 2528 "runlist", pAperture, pAttr); 2529 2530 *pAllocFlags = FLD_TEST_DRF(_REG_STR_RM, _INST_VPR, _RUNLIST, _TRUE, pGpu->instVprOverrides) 2531 ? MEMDESC_ALLOC_FLAGS_PROTECTED : MEMDESC_FLAGS_NONE; 2532 } 2533 2534 /*! 2535 * @brief Allocate Runlist buffers for a single runlistId 2536 * 2537 * @param[in] pGpu 2538 * @param[in] pKernelFifo 2539 * @param[in] bSupportTsg Will this runlist support TSGs? 2540 * @param[in] aperture NV_ADDRESS_SPACE requested 2541 * @param[in] runlistId runlistId to allocate buffer for 2542 * @param[in] attr CPU cacheability requested 2543 * @param[in] allocFlags MEMDESC_FLAGS_* 2544 * @param[in] maxRunlistEntries Can pass zero to determine in function 2545 * @param[in] bHWRL Is this runlist a HW runlist? (verif feature specific) 2546 * @param[out] ppMemDesc memdesc created/allocated by function 2547 */ 2548 NV_STATUS 2549 kfifoRunlistAllocBuffers_IMPL 2550 ( 2551 OBJGPU *pGpu, 2552 KernelFifo *pKernelFifo, 2553 NvBool bSupportTsg, 2554 NV_ADDRESS_SPACE aperture, 2555 NvU32 runlistId, 2556 NvU32 attr, 2557 NvU64 allocFlags, 2558 NvU64 maxRunlistEntries, 2559 NvBool bHWRL, 2560 MEMORY_DESCRIPTOR **ppMemDesc 2561 ) 2562 { 2563 NV_STATUS status = NV_OK; 2564 NvU64 runlistSz = 0; 2565 NvU64 runlistAlign = 0; 2566 NvU32 counter; 2567 2568 status = kfifoGetRunlistBufInfo(pGpu, pKernelFifo, runlistId, bSupportTsg, 2569 maxRunlistEntries, &runlistSz, &runlistAlign); 2570 if (status != NV_OK) 2571 { 2572 NV_PRINTF(LEVEL_ERROR, "failed to get runlist buffer info 0x%08x\n", 2573 status); 2574 DBG_BREAKPOINT(); 2575 goto failed; 2576 } 2577 2578 for (counter = 0; counter < NUM_BUFFERS_PER_RUNLIST; ++counter) 2579 { 2580 ppMemDesc[counter] = NULL; 2581 2582 status = memdescCreate(&ppMemDesc[counter], pGpu, runlistSz, runlistAlign, 2583 NV_TRUE, aperture, attr, allocFlags); 2584 if (status != NV_OK) 2585 { 2586 NV_PRINTF(LEVEL_ERROR, 2587 "Runlist buffer memdesc create failed 0x%08x\n", status); 2588 DBG_BREAKPOINT(); 2589 goto failed; 2590 } 2591 2592 // If flag is set then allocate runlist from ctx buf pool 2593 if (allocFlags & MEMDESC_FLAGS_OWNED_BY_CTX_BUF_POOL) 2594 { 2595 RM_ENGINE_TYPE rmEngineType; 2596 CTX_BUF_POOL_INFO *pCtxBufPool = NULL; 2597 status = kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, ENGINE_INFO_TYPE_RUNLIST, 2598 runlistId, ENGINE_INFO_TYPE_RM_ENGINE_TYPE, (NvU32 *)&rmEngineType); 2599 if (status != NV_OK) 2600 { 2601 NV_PRINTF(LEVEL_ERROR, 2602 "Failed to translate runlistId 0x%x to NV2080 engine type\n", runlistId); 2603 DBG_BREAKPOINT(); 2604 goto failed; 2605 } 2606 status = ctxBufPoolGetGlobalPool(pGpu, CTX_BUF_ID_RUNLIST, rmEngineType, &pCtxBufPool); 2607 if (status != NV_OK) 2608 { 2609 NV_PRINTF(LEVEL_ERROR, 2610 "Failed to get ctx buf pool for engine type 0x%x (0x%x)\n", 2611 gpuGetNv2080EngineType(rmEngineType), rmEngineType); 2612 DBG_BREAKPOINT(); 2613 goto failed; 2614 } 2615 status = memdescSetCtxBufPool(ppMemDesc[counter], pCtxBufPool); 2616 if (status != NV_OK) 2617 { 2618 NV_PRINTF(LEVEL_ERROR, 2619 "Failed to set ctx buf pool for runlistId 0x%x\n", runlistId); 2620 DBG_BREAKPOINT(); 2621 goto failed; 2622 } 2623 } 2624 2625 status = memdescAlloc(ppMemDesc[counter]); 2626 if (status != NV_OK) 2627 { 2628 NV_PRINTF(LEVEL_ERROR, "Runlist buffer mem alloc failed 0x%08x\n", 2629 status); 2630 DBG_BREAKPOINT(); 2631 goto failed; 2632 } 2633 } 2634 2635 return NV_OK; 2636 2637 failed: 2638 for (counter = 0; counter < NUM_BUFFERS_PER_RUNLIST; counter++) 2639 { 2640 if (ppMemDesc[counter]) 2641 { 2642 memdescFree(ppMemDesc[counter]); 2643 memdescDestroy(ppMemDesc[counter]); 2644 ppMemDesc[counter] = NULL; 2645 } 2646 } 2647 return status; 2648 } 2649 2650 NvU32 2651 kfifoGetMaxSubcontextFromGr_KERNEL 2652 ( 2653 OBJGPU *pGpu, 2654 KernelFifo *pKernelFifo 2655 ) 2656 { 2657 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu); 2658 2659 NV_ASSERT_OR_RETURN(pKernelGraphicsManager != NULL, 0); 2660 NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.bInitialized, 0); 2661 NV_ASSERT_OR_RETURN(pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo != NULL, 0); 2662 2663 return pKernelGraphicsManager->legacyKgraphicsStaticInfo.pGrInfo->infoList[NV0080_CTRL_GR_INFO_INDEX_MAX_SUBCONTEXT_COUNT].data; 2664 } 2665 2666 NvU32 2667 kfifoReturnPushbufferCaps_IMPL 2668 ( 2669 OBJGPU *pGpu, 2670 KernelFifo *pKernelFifo 2671 ) 2672 { 2673 NvU32 kfifoBitMask = 0; 2674 2675 // PCI is always supported 2676 kfifoBitMask = PCI_PB_ALLOWED; 2677 2678 if (!gpuIsUnifiedMemorySpaceEnabled(pGpu)) 2679 { 2680 kfifoBitMask |= VID_PB_ALLOWED; 2681 } 2682 2683 return kfifoBitMask; 2684 } 2685 2686 /*! 2687 * @brief kfifoGetDeviceCaps 2688 * 2689 * This routine gets cap bits in unicast. If pbCapsInitialized is passed as 2690 * NV_FALSE, the caps will be copied into pKfifoCaps without OR/ANDING. 2691 * Otherwise, the caps bits for the current GPU will be ORed/ANDed together with 2692 * pKfifoCaps to create a single set of caps that accurately represents the 2693 * functionality of the device. 2694 */ 2695 void kfifoGetDeviceCaps_IMPL 2696 ( 2697 OBJGPU *pGpu, 2698 KernelFifo *pKernelFifo, 2699 NvU8 *pKfifoCaps, 2700 NvBool bCapsInitialized 2701 ) 2702 { 2703 NvU8 tempCaps[NV0080_CTRL_FIFO_CAPS_TBL_SIZE]; 2704 NvU8 temp; 2705 NvU32 kfifoBitMask; 2706 2707 NV_ASSERT(!gpumgrGetBcEnabledStatus(pGpu)); 2708 2709 portMemSet(tempCaps, 0, NV0080_CTRL_FIFO_CAPS_TBL_SIZE); 2710 2711 kfifoBitMask = kfifoReturnPushbufferCaps(pGpu, pKernelFifo); 2712 2713 if (kfifoBitMask & PCI_PB_ALLOWED) 2714 RMCTRL_SET_CAP(tempCaps, NV0080_CTRL_FIFO_CAPS, _SUPPORT_PCI_PB); 2715 if (kfifoBitMask & VID_PB_ALLOWED) 2716 RMCTRL_SET_CAP(tempCaps, NV0080_CTRL_FIFO_CAPS, _SUPPORT_VID_PB); 2717 2718 if ((IS_VIRTUAL(pGpu) || IS_GSP_CLIENT(pGpu)) && 2719 !gpuIsPipelinedPteMemEnabled(pGpu)) 2720 RMCTRL_SET_CAP(tempCaps, NV0080_CTRL_FIFO_CAPS, _NO_PIPELINED_PTE_BLIT); 2721 2722 if (kfifoIsUserdInSystemMemory(pKernelFifo)) 2723 RMCTRL_SET_CAP(tempCaps, NV0080_CTRL_FIFO_CAPS, _USERD_IN_SYSMEM); 2724 2725 if (kfifoIsUserdMapDmaSupported(pKernelFifo)) 2726 RMCTRL_SET_CAP(tempCaps, NV0080_CTRL_FIFO_CAPS, _GPU_MAP_CHANNEL); 2727 2728 if (kfifoHostHasLbOverflow(pKernelFifo)) 2729 RMCTRL_SET_CAP(tempCaps, NV0080_CTRL_FIFO_CAPS, _HAS_HOST_LB_OVERFLOW_BUG_1667921); 2730 2731 if (kfifoIsSubcontextSupported(pKernelFifo)) 2732 RMCTRL_SET_CAP(tempCaps, NV0080_CTRL_FIFO_CAPS, _MULTI_VAS_PER_CHANGRP); 2733 2734 if (kfifoIsWddmInterleavingPolicyEnabled(pKernelFifo)) 2735 RMCTRL_SET_CAP(tempCaps, NV0080_CTRL_FIFO_CAPS, _SUPPORT_WDDM_INTERLEAVING); 2736 2737 // if this is the first GPU in the device, then start with it's caps 2738 if (bCapsInitialized == NV_FALSE) 2739 { 2740 portMemCopy(pKfifoCaps, NV0080_CTRL_FIFO_CAPS_TBL_SIZE, 2741 tempCaps, NV0080_CTRL_FIFO_CAPS_TBL_SIZE); 2742 return; 2743 } 2744 2745 RMCTRL_AND_CAP(pKfifoCaps, tempCaps, temp, 2746 NV0080_CTRL_FIFO_CAPS, _SUPPORT_PCI_PB); 2747 RMCTRL_AND_CAP(pKfifoCaps, tempCaps, temp, 2748 NV0080_CTRL_FIFO_CAPS, _SUPPORT_VID_PB); 2749 RMCTRL_AND_CAP(pKfifoCaps, tempCaps, temp, 2750 NV0080_CTRL_FIFO_CAPS, _GPU_MAP_CHANNEL); 2751 2752 RMCTRL_OR_CAP(pKfifoCaps, tempCaps, temp, 2753 NV0080_CTRL_FIFO_CAPS, _MULTI_VAS_PER_CHANGRP); 2754 2755 RMCTRL_OR_CAP(pKfifoCaps, tempCaps, temp, 2756 NV0080_CTRL_FIFO_CAPS, _HAS_HOST_LB_OVERFLOW_BUG_1667921); 2757 2758 RMCTRL_OR_CAP(pKfifoCaps, tempCaps, temp, 2759 NV0080_CTRL_FIFO_CAPS, _SUPPORT_WDDM_INTERLEAVING); 2760 return; 2761 } 2762 2763 /*! 2764 * @brief Add handlers for scheduling enable and/or disable. 2765 * 2766 * @param[in] pGpu OBJGPU pointer 2767 * @param[in] pKernelFifo KernelFifo pointer 2768 * @param[in] pPostSchedulingEnableHandler No action if NULL 2769 * @param[in] pPostSchedulingEnableHandlerData Data to pass to 2770 * @p pPostSchedulingEnableHandler 2771 * @param[in] pPreSchedulingDisableHandler No action if NULL 2772 * @param[in] pPreSchedulingDisableHandlerData Data to pass to 2773 * @p pPreSchedulingDisableHandler 2774 * 2775 * @returns NV_OK if successfully processed both handlers 2776 * NV_WARN_NOTHING_TO_DO if: - Both handlers are NULL 2777 * - Both handlers are already installed 2778 * NV_ERR_INVALID_STATE if one handler is already installed, but not both 2779 */ 2780 NV_STATUS 2781 kfifoAddSchedulingHandler_IMPL 2782 ( 2783 OBJGPU *pGpu, 2784 KernelFifo *pKernelFifo, 2785 PFifoSchedulingHandler pPostSchedulingEnableHandler, 2786 void *pPostSchedulingEnableHandlerData, 2787 PFifoSchedulingHandler pPreSchedulingDisableHandler, 2788 void *pPreSchedulingDisableHandlerData 2789 ) 2790 { 2791 FifoSchedulingHandlerEntry *pEntry; 2792 NvBool bPostHandlerAlreadyPresent = NV_FALSE; 2793 NvBool bPreHandlerAlreadyPresent = NV_FALSE; 2794 FifoSchedulingHandlerEntry postEntry; 2795 FifoSchedulingHandlerEntry preEntry; 2796 2797 NV_CHECK_OR_RETURN(LEVEL_SILENT, 2798 (pPostSchedulingEnableHandler != NULL) || 2799 (pPreSchedulingDisableHandler != NULL), 2800 NV_WARN_NOTHING_TO_DO); 2801 2802 // Check for already installed handler if non-NULL 2803 if (pPostSchedulingEnableHandler != NULL) 2804 { 2805 for (pEntry = listHead(&pKernelFifo->postSchedulingEnableHandlerList); 2806 pEntry != NULL; 2807 pEntry = listNext(&pKernelFifo->postSchedulingEnableHandlerList, pEntry)) 2808 { 2809 if (pEntry->pCallback == pPostSchedulingEnableHandler && 2810 pEntry->pCallbackParam == pPostSchedulingEnableHandlerData) 2811 { 2812 bPostHandlerAlreadyPresent = NV_TRUE; 2813 break; 2814 } 2815 } 2816 } 2817 2818 // Check for already installed handler if non-NULL 2819 if (pPreSchedulingDisableHandler != NULL) 2820 { 2821 for (pEntry = listHead(&pKernelFifo->preSchedulingDisableHandlerList); 2822 pEntry != NULL; 2823 pEntry = listNext(&pKernelFifo->preSchedulingDisableHandlerList, pEntry)) 2824 { 2825 if (pEntry->pCallback == pPreSchedulingDisableHandler && 2826 pEntry->pCallbackParam == pPreSchedulingDisableHandlerData) 2827 { 2828 bPreHandlerAlreadyPresent = NV_TRUE; 2829 break; 2830 } 2831 } 2832 } 2833 2834 // 2835 // If we are installing both handlers, and one is already present, but not 2836 // the other, we will do nothing, so assert loudly in that case 2837 // 2838 if ((pPostSchedulingEnableHandler != NULL) && (pPreSchedulingDisableHandler != NULL)) 2839 { 2840 NV_ASSERT_OR_RETURN(!(bPostHandlerAlreadyPresent ^ bPreHandlerAlreadyPresent), 2841 NV_ERR_INVALID_STATE); 2842 } 2843 2844 // Return early unless all non-null handlers are not already installed 2845 NV_CHECK_OR_RETURN(LEVEL_SILENT, 2846 !bPostHandlerAlreadyPresent && !bPreHandlerAlreadyPresent, 2847 NV_WARN_NOTHING_TO_DO); 2848 2849 // Add handler entry to list unless NULL 2850 if (pPostSchedulingEnableHandler != NULL) 2851 { 2852 postEntry.pCallback = pPostSchedulingEnableHandler; 2853 postEntry.pCallbackParam = pPostSchedulingEnableHandlerData; 2854 postEntry.bHandled = NV_FALSE; 2855 NV_ASSERT_OR_RETURN(listPrependValue(&pKernelFifo->postSchedulingEnableHandlerList, &postEntry), 2856 NV_ERR_NO_MEMORY); 2857 } 2858 2859 // Add handler entry to list unless NULL 2860 if (pPreSchedulingDisableHandler != NULL) 2861 { 2862 preEntry.pCallback = pPreSchedulingDisableHandler; 2863 preEntry.pCallbackParam = pPreSchedulingDisableHandlerData; 2864 preEntry.bHandled = NV_FALSE; 2865 NV_ASSERT_OR_RETURN(listPrependValue(&pKernelFifo->preSchedulingDisableHandlerList, &preEntry), 2866 NV_ERR_NO_MEMORY); 2867 } 2868 2869 return NV_OK; 2870 } 2871 2872 /*! 2873 * @brief Remove handlers for scheduling enable and/or disable. 2874 * 2875 * @param[in] pGpu OBJGPU pointer 2876 * @param[in] pKernelFifo KernelFifo pointer 2877 * @param[in] pPostSchedulingEnableHandler No action if NULL 2878 * @param[in] pPostSchedulingEnableHandlerData Data argument set for the 2879 * handler. 2880 * @param[in] pPreSchedulingDisableHandler No action if NULL 2881 * @param[in] pPreSchedulingDisableHandlerData Data argument set for the 2882 * handler. 2883 */ 2884 void 2885 kfifoRemoveSchedulingHandler_IMPL 2886 ( 2887 OBJGPU *pGpu, 2888 KernelFifo *pKernelFifo, 2889 PFifoSchedulingHandler pPostSchedulingEnableHandler, 2890 void *pPostSchedulingEnableHandlerData, 2891 PFifoSchedulingHandler pPreSchedulingDisableHandler, 2892 void *pPreSchedulingDisableHandlerData 2893 ) 2894 { 2895 FifoSchedulingHandlerEntry *pEntry; 2896 FifoSchedulingHandlerEntry *pTemp; 2897 2898 // Search for the post handler in the post handler list and remove it if present 2899 pEntry = listHead(&pKernelFifo->postSchedulingEnableHandlerList); 2900 while (pEntry != NULL) 2901 { 2902 pTemp = listNext(&pKernelFifo->postSchedulingEnableHandlerList, pEntry); 2903 2904 if (pEntry->pCallback == pPostSchedulingEnableHandler && 2905 pEntry->pCallbackParam == pPostSchedulingEnableHandlerData) 2906 { 2907 listRemove(&pKernelFifo->postSchedulingEnableHandlerList, pEntry); 2908 } 2909 2910 pEntry = pTemp; 2911 } 2912 2913 // Search for the pre handler in the pre handler list and remove it if present 2914 pEntry = listHead(&pKernelFifo->preSchedulingDisableHandlerList); 2915 while (pEntry != NULL) 2916 { 2917 pTemp = listNext(&pKernelFifo->preSchedulingDisableHandlerList, pEntry); 2918 2919 if (pEntry->pCallback == pPreSchedulingDisableHandler && 2920 pEntry->pCallbackParam == pPreSchedulingDisableHandlerData) 2921 { 2922 listRemove(&pKernelFifo->preSchedulingDisableHandlerList, pEntry); 2923 } 2924 2925 pEntry = pTemp; 2926 } 2927 } 2928 2929 2930 /*! 2931 * @brief Notify handlers that scheduling has been enabled. 2932 * 2933 * @param[in] pGpu OBJGPU pointer 2934 * @param[in] pKernelFifo KernelFifo pointer 2935 * 2936 * @returns NV_STATUS 2937 */ 2938 NV_STATUS 2939 kfifoTriggerPostSchedulingEnableCallback_IMPL 2940 ( 2941 OBJGPU *pGpu, 2942 KernelFifo *pKernelFifo 2943 ) 2944 { 2945 NV_STATUS status = NV_OK; 2946 FifoSchedulingHandlerEntry *pEntry; 2947 NvBool bRetry = NV_FALSE; 2948 2949 for (pEntry = listHead(&pKernelFifo->postSchedulingEnableHandlerList); 2950 pEntry != NULL; 2951 pEntry = listNext(&pKernelFifo->postSchedulingEnableHandlerList, pEntry)) 2952 { 2953 NV_ASSERT_OR_ELSE(pEntry->pCallback != NULL, 2954 status = NV_ERR_INVALID_STATE; break;); 2955 2956 pEntry->bHandled = NV_FALSE; 2957 status = pEntry->pCallback(pGpu, pEntry->pCallbackParam); 2958 2959 // Retry mechanism: Some callbacks depend on other callbacks in this list. 2960 bRetry = bRetry || (status == NV_WARN_MORE_PROCESSING_REQUIRED); 2961 2962 if (status == NV_WARN_MORE_PROCESSING_REQUIRED) 2963 // Quash retry status 2964 status = NV_OK; 2965 else if (status == NV_OK) 2966 // Successfully handled, no need to retry 2967 pEntry->bHandled = NV_TRUE; 2968 else 2969 // Actual error, abort 2970 break; 2971 } 2972 2973 // If we hit an actual error or completed everything successfully, return early. 2974 if ((status != NV_OK) || !bRetry) 2975 return status; 2976 2977 // Second pass, retry anything that asked nicely to be deferred 2978 for (pEntry = listHead(&pKernelFifo->postSchedulingEnableHandlerList); 2979 pEntry != NULL; 2980 pEntry = listNext(&pKernelFifo->postSchedulingEnableHandlerList, pEntry)) 2981 { 2982 NV_ASSERT_OR_ELSE(pEntry->pCallback != NULL, 2983 status = NV_ERR_INVALID_STATE; break;); 2984 2985 // Skip anything that was completed successfully 2986 if (pEntry->bHandled) 2987 continue; 2988 2989 NV_CHECK_OK_OR_ELSE(status, LEVEL_ERROR, 2990 pEntry->pCallback(pGpu, pEntry->pCallbackParam), 2991 break; ); 2992 } 2993 2994 return status; 2995 } 2996 2997 2998 /*! 2999 * @brief Notify handlers that scheduling will soon be disabled. 3000 * 3001 * @param[in] pGpu OBJGPU pointer 3002 * @param[in] pKernelFifo KernelFifo pointer 3003 * 3004 * @returns NV_STATUS 3005 */ 3006 NV_STATUS 3007 kfifoTriggerPreSchedulingDisableCallback_IMPL 3008 ( 3009 OBJGPU *pGpu, 3010 KernelFifo *pKernelFifo 3011 ) 3012 { 3013 NV_STATUS status = NV_OK; 3014 FifoSchedulingHandlerEntry *pEntry; 3015 NvBool bRetry = NV_FALSE; 3016 3017 // First pass 3018 for (pEntry = listHead(&pKernelFifo->preSchedulingDisableHandlerList); 3019 pEntry != NULL; 3020 pEntry = listNext(&pKernelFifo->preSchedulingDisableHandlerList, pEntry)) 3021 { 3022 NV_ASSERT_OR_ELSE(pEntry->pCallback != NULL, 3023 status = NV_ERR_INVALID_STATE; break;); 3024 3025 pEntry->bHandled = NV_FALSE; 3026 status = pEntry->pCallback(pGpu, pEntry->pCallbackParam); 3027 3028 // Retry mechanism: Some callbacks depend on other callbacks in this list. 3029 bRetry = bRetry || (status == NV_WARN_MORE_PROCESSING_REQUIRED); 3030 3031 if (status == NV_WARN_MORE_PROCESSING_REQUIRED) 3032 // Quash retry status 3033 status = NV_OK; 3034 else if (status == NV_OK) 3035 // Successfully handled, no need to retry 3036 pEntry->bHandled = NV_TRUE; 3037 else 3038 // Actual error, abort 3039 break; 3040 } 3041 3042 // If we hit an actual error or completed everything successfully, return early. 3043 if ((status != NV_OK) || !bRetry) 3044 return status; 3045 3046 // Second pass, retry anything that asked nicely to be deferred 3047 for (pEntry = listHead(&pKernelFifo->preSchedulingDisableHandlerList); 3048 pEntry != NULL; 3049 pEntry = listNext(&pKernelFifo->preSchedulingDisableHandlerList, pEntry)) 3050 { 3051 NV_ASSERT_OR_ELSE(pEntry->pCallback != NULL, 3052 status = NV_ERR_INVALID_STATE; break;); 3053 3054 // Skip anything that was completed successfully 3055 if (pEntry->bHandled) 3056 continue; 3057 3058 NV_CHECK_OK_OR_ELSE(status, LEVEL_ERROR, 3059 pEntry->pCallback(pGpu, pEntry->pCallbackParam), 3060 break; ); 3061 } 3062 3063 return status; 3064 } 3065 3066 /** 3067 * @brief Gets vChid corresponding to a sChid 3068 */ 3069 NV_STATUS 3070 kfifoGetVChIdForSChId_FWCLIENT 3071 ( 3072 OBJGPU *pGpu, 3073 KernelFifo *pKernelFifo, 3074 NvU32 sChId, 3075 NvU32 gfid, 3076 NvU32 engineId, 3077 NvU32 *pVChid 3078 ) 3079 { 3080 KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice = NULL; 3081 3082 NV_ASSERT_OR_RETURN(pVChid != NULL, NV_ERR_INVALID_ARGUMENT); 3083 *pVChid = sChId; 3084 3085 NV_CHECK_OR_RETURN(LEVEL_INFO, IS_GFID_VF(gfid), NV_OK); 3086 NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextKernelHostVgpuDevice(pGpu, &pKernelHostVgpuDevice)); 3087 NV_ASSERT_OR_RETURN(pKernelHostVgpuDevice->gfid == gfid, NV_ERR_INVALID_ARGUMENT); 3088 NV_ASSERT_OR_RETURN(engineId < (sizeof(pKernelHostVgpuDevice->chidOffset) / sizeof(pKernelHostVgpuDevice->chidOffset[0])), 3089 NV_ERR_INVALID_STATE); 3090 NV_ASSERT_OR_RETURN(pKernelHostVgpuDevice->chidOffset[engineId] != 0, NV_ERR_INVALID_STATE); 3091 3092 NV_ASSERT_OR_RETURN(sChId >= pKernelHostVgpuDevice->chidOffset[engineId], NV_ERR_INVALID_ARGUMENT); 3093 3094 *pVChid = sChId - pKernelHostVgpuDevice->chidOffset[engineId]; 3095 3096 return NV_OK; 3097 } 3098 3099 /** 3100 * @brief cache vChid <-> sChid offset 3101 */ 3102 NV_STATUS 3103 kfifoSetChidOffset_IMPL 3104 ( 3105 OBJGPU *pGpu, 3106 KernelFifo *pKernelFifo, 3107 CHID_MGR *pChidMgr, 3108 NvU32 offset, 3109 NvU32 numChannels, 3110 NvU32 gfid, 3111 NvU32 *pChidOffset, 3112 NvU32 *pChannelCount, 3113 NvU32 hMigClient, 3114 NvU32 engineFifoListNumEntries, 3115 FIFO_ENGINE_LIST *pEngineFifoList 3116 ) 3117 { 3118 NV_STATUS status = NV_OK; 3119 RM_ENGINE_TYPE *pEngineIds = NULL; 3120 NvU32 maxEngines = kfifoGetNumEngines_HAL(pGpu, pKernelFifo); 3121 NvU32 numEngines, i; 3122 3123 NV_ASSERT_OR_RETURN(pChidMgr != NULL, NV_ERR_INVALID_ARGUMENT); 3124 NV_ASSERT_OR_RETURN(pChidOffset != NULL, NV_ERR_INVALID_ARGUMENT); 3125 3126 pEngineIds = portMemAllocNonPaged(sizeof(RM_ENGINE_TYPE) * maxEngines); 3127 NV_ASSERT_OR_RETURN((pEngineIds != NULL), NV_ERR_NO_MEMORY); 3128 portMemSet(pEngineIds, 0, sizeof(RM_ENGINE_TYPE) * maxEngines); 3129 3130 NV_ASSERT_OK_OR_GOTO(status, kfifoGetEngineListForRunlist(pGpu, pKernelFifo, pChidMgr->runlistId, pEngineIds, &numEngines), cleanup) 3131 3132 for (i = 0; i < numEngines; i++) 3133 { 3134 NV_ASSERT_OR_ELSE(NV2080_ENGINE_TYPE_IS_VALID(pEngineIds[i]), status = NV_ERR_INVALID_STATE; goto cleanup); 3135 pChidOffset[pEngineIds[i]] = offset; 3136 pChannelCount[pEngineIds[i]] = numChannels; 3137 } 3138 3139 NV_ASSERT_OK_OR_GOTO(status, kfifoProgramChIdTable_HAL(pGpu, pKernelFifo, pChidMgr, offset, numChannels, gfid, 3140 hMigClient, engineFifoListNumEntries, pEngineFifoList), cleanup); 3141 3142 cleanup: 3143 3144 portMemFree(pEngineIds); 3145 3146 return status; 3147 } 3148 3149 /* 3150 * @brief Gets a list of engine ids that use this runlist 3151 * 3152 * @param[in] runlistId Runlist id 3153 * @param[out] pOutEngineIds List of engineids 3154 * @param[out] pNumEngines # of entries in pOutEngines 3155 */ 3156 NV_STATUS 3157 kfifoGetEngineListForRunlist_IMPL 3158 ( 3159 OBJGPU *pGpu, 3160 KernelFifo *pKernelFifo, 3161 NvU32 runlistId, 3162 RM_ENGINE_TYPE *pOutEngineIds, 3163 NvU32 *pNumEngines 3164 ) 3165 { 3166 NV_STATUS status = NV_OK; 3167 NvU32 numEngines = kfifoGetNumEngines_HAL(pGpu, pKernelFifo); 3168 NvU32 i; 3169 3170 // Sanity check the input 3171 NV_CHECK_OR_RETURN(LEVEL_ERROR, pOutEngineIds != NULL, NV_ERR_INVALID_ARGUMENT); 3172 NV_CHECK_OR_RETURN(LEVEL_ERROR, pNumEngines != NULL, NV_ERR_INVALID_ARGUMENT); 3173 3174 *pNumEngines = 0; 3175 NV_PRINTF(LEVEL_INFO, "Engine list for runlistId 0x%x:\n", runlistId); 3176 3177 for (i = 0; i < numEngines; i++) 3178 { 3179 RM_ENGINE_TYPE rmEngineType; 3180 NvU32 thisRunlistId; 3181 3182 NV_ASSERT_OK_OR_GOTO(status, 3183 kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, 3184 ENGINE_INFO_TYPE_INVALID, 3185 i, 3186 ENGINE_INFO_TYPE_RUNLIST, 3187 &thisRunlistId), done); 3188 if (runlistId == thisRunlistId) 3189 { 3190 NV_ASSERT_OK_OR_GOTO(status, 3191 kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, 3192 ENGINE_INFO_TYPE_INVALID, 3193 i, 3194 ENGINE_INFO_TYPE_RM_ENGINE_TYPE, 3195 (NvU32 *)&rmEngineType), done); 3196 pOutEngineIds[(*pNumEngines)++] = rmEngineType; 3197 3198 NV_PRINTF(LEVEL_INFO, "Engine name: %s\n", 3199 kfifoGetEngineName_HAL(pKernelFifo, ENGINE_INFO_TYPE_RM_ENGINE_TYPE, 3200 (NvU32)rmEngineType)); 3201 } 3202 } 3203 done: 3204 if ((status != NV_OK) && (*pNumEngines != 0)) 3205 { 3206 portMemSet(pOutEngineIds, 0, sizeof(NvU32) * (*pNumEngines)); 3207 *pNumEngines = 0; 3208 } 3209 return status; 3210 } 3211 3212 /** 3213 * @brief Return bitmask of currently allocated channels for a given runlist 3214 * 3215 * @param[in] bitMaskSize @p pBitMask size in bytes 3216 * 3217 */ 3218 NV_STATUS 3219 kfifoGetAllocatedChannelMask_IMPL 3220 ( 3221 OBJGPU *pGpu, 3222 KernelFifo *pKernelFifo, 3223 NvU32 runlistId, 3224 NvU32 *pBitMask, 3225 NvLength bitMaskSize 3226 ) 3227 { 3228 CHID_MGR *pChidMgr; 3229 NvU32 chId; 3230 NvU32 numChannels; 3231 3232 NV_ASSERT(pBitMask != NULL); 3233 portMemSet(pBitMask, 0, bitMaskSize); 3234 3235 NV_ASSERT_OR_RETURN(bitMaskSize % sizeof(NvU32) == 0, 3236 NV_ERR_INVALID_ARGUMENT); 3237 3238 if (!kfifoIsPerRunlistChramEnabled(pKernelFifo)) 3239 { 3240 if (runlistId > 0) 3241 { 3242 return NV_ERR_OUT_OF_RANGE; 3243 } 3244 else 3245 { 3246 runlistId = CHIDMGR_RUNLIST_ID_LEGACY; 3247 } 3248 } 3249 else 3250 { 3251 if (!(runlistId < kfifoGetMaxNumRunlists_HAL(pGpu, pKernelFifo))) 3252 { 3253 return NV_ERR_OUT_OF_RANGE; 3254 } 3255 } 3256 3257 pChidMgr = kfifoGetChidMgr(pGpu, pKernelFifo, runlistId); 3258 if (pChidMgr == NULL) 3259 { 3260 // 3261 // This runlist is not valid. This is not an error since it might be 3262 // possible for some runlists between [0, maxRunlists) to be invalid. 3263 // Simply return that it has no channels to simplify clients iterating 3264 // over all runlists. 3265 // 3266 numChannels = 0; 3267 } 3268 else 3269 { 3270 numChannels = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pChidMgr); 3271 } 3272 3273 if (((numChannels + 7) / 8) > bitMaskSize) 3274 { 3275 return NV_ERR_BUFFER_TOO_SMALL; 3276 } 3277 3278 for (chId = 0; chId < numChannels; chId++) 3279 { 3280 KernelChannel *pKernelChannel; 3281 pKernelChannel = kfifoChidMgrGetKernelChannel(pGpu, pKernelFifo, 3282 pChidMgr, 3283 chId); 3284 if (pKernelChannel != NULL) 3285 { 3286 NV_BITMASK32_SET(pBitMask, chId); 3287 } 3288 } 3289 3290 return NV_OK; 3291 } 3292 3293 /*! 3294 * Get host channel class 3295 */ 3296 NvU32 3297 kfifoGetChannelClassId_IMPL 3298 ( 3299 OBJGPU *pGpu, 3300 KernelFifo *pKernelFifo 3301 ) 3302 { 3303 NvU32 numClasses; 3304 NvU32 *pClassList = NULL; 3305 CLI_CHANNEL_CLASS_INFO classInfo; 3306 NvU32 i; 3307 NvU32 class = 0; 3308 3309 NV_ASSERT_OR_RETURN(NV_OK == gpuGetClassList(pGpu, &numClasses, NULL, ENG_KERNEL_FIFO), 0); 3310 NV_ASSERT_OR_RETURN(numClasses > 0, 0); 3311 pClassList = portMemAllocNonPaged(sizeof(NvU32) * numClasses); 3312 NV_ASSERT_OR_RETURN((pClassList != NULL), 0); 3313 3314 if (NV_OK == gpuGetClassList(pGpu, &numClasses, pClassList, ENG_KERNEL_FIFO)) 3315 { 3316 for (i = 0; i < numClasses; i++) 3317 { 3318 if (pClassList[i] == PHYSICAL_CHANNEL_GPFIFO) 3319 { 3320 // Skip the physical channel class 3321 continue; 3322 } 3323 CliGetChannelClassInfo(pClassList[i], &classInfo); 3324 if (classInfo.classType == CHANNEL_CLASS_TYPE_GPFIFO) 3325 class = NV_MAX(class, pClassList[i]); 3326 } 3327 } 3328 3329 NV_ASSERT(class); 3330 portMemFree(pClassList); 3331 return class; 3332 } 3333 3334 /** 3335 * @brief Return the FIFO_GUEST_ENGINE_TABLE 3336 * 3337 * @param[out] pEngLookupTblSize To get the table size 3338 * 3339 * @return a pointer to FIFO_GUEST_ENGINE_TABLE 3340 * 3341 */ 3342 const FIFO_GUEST_ENGINE_TABLE * 3343 kfifoGetGuestEngineLookupTable_IMPL 3344 ( 3345 NvU32 *pEngLookupTblSize 3346 ) 3347 { 3348 // 3349 // This table is used for a guest RM to reconstruct the engine list data 3350 // received from the host RM. The host and guest RM can be running on 3351 // different versions. 3352 // 3353 // This table does not need to be HALified. It need to match NV2080_ENGINE_TYPE 3354 // defined in cl2080_notification.h 3355 // 3356 const static FIFO_GUEST_ENGINE_TABLE guestEngineLookupTable[] = 3357 { 3358 // nv2080EngineType mcIdx 3359 {NV2080_ENGINE_TYPE_GR0, MC_ENGINE_IDX_GR0}, 3360 {NV2080_ENGINE_TYPE_GR1, MC_ENGINE_IDX_GR1}, 3361 {NV2080_ENGINE_TYPE_GR2, MC_ENGINE_IDX_GR2}, 3362 {NV2080_ENGINE_TYPE_GR3, MC_ENGINE_IDX_GR3}, 3363 {NV2080_ENGINE_TYPE_GR4, MC_ENGINE_IDX_GR4}, 3364 {NV2080_ENGINE_TYPE_GR5, MC_ENGINE_IDX_GR5}, 3365 {NV2080_ENGINE_TYPE_GR6, MC_ENGINE_IDX_GR6}, 3366 {NV2080_ENGINE_TYPE_GR7, MC_ENGINE_IDX_GR7}, 3367 {NV2080_ENGINE_TYPE_COPY0, MC_ENGINE_IDX_CE0}, 3368 {NV2080_ENGINE_TYPE_COPY1, MC_ENGINE_IDX_CE1}, 3369 {NV2080_ENGINE_TYPE_COPY2, MC_ENGINE_IDX_CE2}, 3370 {NV2080_ENGINE_TYPE_COPY3, MC_ENGINE_IDX_CE3}, 3371 {NV2080_ENGINE_TYPE_COPY4, MC_ENGINE_IDX_CE4}, 3372 {NV2080_ENGINE_TYPE_COPY5, MC_ENGINE_IDX_CE5}, 3373 {NV2080_ENGINE_TYPE_COPY6, MC_ENGINE_IDX_CE6}, 3374 {NV2080_ENGINE_TYPE_COPY7, MC_ENGINE_IDX_CE7}, 3375 {NV2080_ENGINE_TYPE_COPY8, MC_ENGINE_IDX_CE8}, 3376 {NV2080_ENGINE_TYPE_COPY9, MC_ENGINE_IDX_CE9}, 3377 {NV2080_ENGINE_TYPE_NVENC0, MC_ENGINE_IDX_MSENC}, 3378 {NV2080_ENGINE_TYPE_NVENC1, MC_ENGINE_IDX_MSENC1}, 3379 {NV2080_ENGINE_TYPE_NVENC2, MC_ENGINE_IDX_MSENC2}, 3380 {NV2080_ENGINE_TYPE_NVDEC0, MC_ENGINE_IDX_NVDEC0}, 3381 {NV2080_ENGINE_TYPE_NVDEC1, MC_ENGINE_IDX_NVDEC1}, 3382 {NV2080_ENGINE_TYPE_NVDEC2, MC_ENGINE_IDX_NVDEC2}, 3383 {NV2080_ENGINE_TYPE_NVDEC3, MC_ENGINE_IDX_NVDEC3}, 3384 {NV2080_ENGINE_TYPE_NVDEC4, MC_ENGINE_IDX_NVDEC4}, 3385 {NV2080_ENGINE_TYPE_NVDEC5, MC_ENGINE_IDX_NVDEC5}, 3386 {NV2080_ENGINE_TYPE_NVDEC6, MC_ENGINE_IDX_NVDEC6}, 3387 {NV2080_ENGINE_TYPE_NVDEC7, MC_ENGINE_IDX_NVDEC7}, 3388 {NV2080_ENGINE_TYPE_SW, MC_ENGINE_IDX_NULL}, 3389 {NV2080_ENGINE_TYPE_SEC2, MC_ENGINE_IDX_SEC2}, 3390 {NV2080_ENGINE_TYPE_NVJPEG0, MC_ENGINE_IDX_NVJPEG0}, 3391 {NV2080_ENGINE_TYPE_NVJPEG1, MC_ENGINE_IDX_NVJPEG1}, 3392 {NV2080_ENGINE_TYPE_NVJPEG2, MC_ENGINE_IDX_NVJPEG2}, 3393 {NV2080_ENGINE_TYPE_NVJPEG3, MC_ENGINE_IDX_NVJPEG3}, 3394 {NV2080_ENGINE_TYPE_NVJPEG4, MC_ENGINE_IDX_NVJPEG4}, 3395 {NV2080_ENGINE_TYPE_NVJPEG5, MC_ENGINE_IDX_NVJPEG5}, 3396 {NV2080_ENGINE_TYPE_NVJPEG6, MC_ENGINE_IDX_NVJPEG6}, 3397 {NV2080_ENGINE_TYPE_NVJPEG7, MC_ENGINE_IDX_NVJPEG7}, 3398 {NV2080_ENGINE_TYPE_OFA, MC_ENGINE_IDX_OFA0}, 3399 }; 3400 3401 // 3402 // To trap NV2080_ENGINE_TYPE expansions. 3403 // Please update the table guestEngineLookupTable if this assertion is triggered. 3404 // 3405 ct_assert(NV2080_ENGINE_TYPE_LAST == 0x0000003e); 3406 3407 *pEngLookupTblSize = NV_ARRAY_ELEMENTS(guestEngineLookupTable); 3408 3409 return guestEngineLookupTable; 3410 }; 3411 3412 /** 3413 * @brief Fetch the maximum number of secure channels supported by SEC2 3414 * and secure CEs when confidential compute is enabled 3415 * 3416 */ 3417 NV_STATUS 3418 kfifoGetMaxSecureChannels_KERNEL 3419 ( 3420 OBJGPU *pGpu, 3421 KernelFifo *pKernelFifo 3422 ) 3423 { 3424 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu); 3425 NV2080_CTRL_INTERNAL_FIFO_GET_NUM_SECURE_CHANNELS_PARAMS numSecureChannelsParams = {0}; 3426 3427 NV_ASSERT_OK_OR_RETURN( 3428 pRmApi->Control(pRmApi, 3429 pGpu->hInternalClient, 3430 pGpu->hInternalSubdevice, 3431 NV2080_CTRL_CMD_INTERNAL_FIFO_GET_NUM_SECURE_CHANNELS, 3432 &numSecureChannelsParams, 3433 sizeof(numSecureChannelsParams))); 3434 3435 pKernelFifo->maxSec2SecureChannels = numSecureChannelsParams.maxSec2SecureChannels; 3436 pKernelFifo->maxCeSecureChannels = numSecureChannelsParams.maxCeSecureChannels; 3437 3438 return NV_OK; 3439 } 3440