1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 1993-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 25 #include "nvrm_registry.h" 26 #include "rmapi/rmapi.h" 27 #include "entry_points.h" 28 #include "resserv/rs_server.h" 29 #include "rmapi/rs_utils.h" 30 #include "gpu/gpu_resource.h" 31 #include "gpu/device/device.h" 32 #include "core/locks.h" 33 #include "gpu/gpu.h" 34 #include "diagnostics/tracer.h" 35 #include "tls/tls.h" 36 #include "core/thread_state.h" 37 #include "gpu_mgr/gpu_mgr.h" 38 #include "resource_desc.h" 39 40 typedef struct 41 { 42 PORT_RWLOCK * pLock; 43 NvU64 threadId; 44 NvU64 timestamp; 45 LOCK_TRACE_INFO traceInfo; 46 NvU64 tlsEntryId; 47 48 } RMAPI_LOCK; 49 50 RsServer g_resServ; 51 static RM_API g_RmApiList[RMAPI_TYPE_MAX]; 52 static NvBool g_bResServInit = NV_FALSE; 53 static RMAPI_LOCK g_RmApiLock; 54 55 static void _rmapiInitInterface(RM_API *pRmApi, API_SECURITY_INFO *pDefaultSecurityInfo, NvBool bTlsInternal, 56 NvBool bApiLockInternal, NvBool bGpuLockInternal); 57 static NV_STATUS _rmapiLockAlloc(void); 58 static void _rmapiLockFree(void); 59 60 // from rmapi_stubs.c 61 void rmapiInitStubInterface(RM_API *pRmApi); 62 63 NV_STATUS 64 rmapiInitialize 65 ( 66 void 67 ) 68 { 69 NV_STATUS status = NV_OK; 70 API_SECURITY_INFO secInfo = {0}; 71 72 NV_ASSERT(!g_bResServInit); 73 74 status = _rmapiLockAlloc(); 75 76 if (status != NV_OK) 77 { 78 NV_PRINTF(LEVEL_ERROR, "*** Cannot allocate rmapi locks\n"); 79 goto failed; 80 } 81 82 status = rmapiControlCacheInit(); 83 if (status != NV_OK) 84 { 85 NV_PRINTF(LEVEL_ERROR, "*** Cannot initialize rmapi cache\n"); 86 goto failed_free_lock; 87 } 88 89 RsResInfoInitialize(); 90 status = serverConstruct(&g_resServ, RS_PRIV_LEVEL_HOST, 0); 91 92 if (status != NV_OK) 93 { 94 NV_PRINTF(LEVEL_ERROR, "*** Cannot initialize resource server\n"); 95 goto failed_free_cache; 96 } 97 98 serverSetClientHandleBase(&g_resServ, RS_CLIENT_HANDLE_BASE); 99 100 listInit(&g_clientListBehindGpusLock, g_resServ.pAllocator); 101 listInit(&g_userInfoList, g_resServ.pAllocator); 102 multimapInit(&g_osInfoList, g_resServ.pAllocator); 103 104 secInfo.privLevel = RS_PRIV_LEVEL_KERNEL; 105 secInfo.paramLocation = PARAM_LOCATION_KERNEL; 106 107 _rmapiInitInterface(&g_RmApiList[RMAPI_EXTERNAL], NULL, NV_FALSE /* bTlsInternal */, NV_FALSE /* bApiLockInternal */, NV_FALSE /* bGpuLockInternal */); 108 _rmapiInitInterface(&g_RmApiList[RMAPI_EXTERNAL_KERNEL], &secInfo, NV_FALSE /* bTlsInternal */, NV_FALSE /* bApiLockInternal */, NV_FALSE /* bGpuLockInternal */); 109 _rmapiInitInterface(&g_RmApiList[RMAPI_MODS_LOCK_BYPASS], &secInfo, NV_FALSE /* bTlsInternal */, NV_TRUE /* bApiLockInternal */, NV_TRUE /* bGpuLockInternal */); 110 _rmapiInitInterface(&g_RmApiList[RMAPI_API_LOCK_INTERNAL], &secInfo, NV_TRUE /* bTlsInternal */, NV_TRUE /* bApiLockInternal */, NV_FALSE /* bGpuLockInternal */); 111 _rmapiInitInterface(&g_RmApiList[RMAPI_GPU_LOCK_INTERNAL], &secInfo, NV_TRUE /* bTlsInternal */, NV_TRUE /* bApiLockInternal */, NV_TRUE /* bGpuLockInternal */); 112 113 rmapiInitStubInterface(&g_RmApiList[RMAPI_STUBS]); 114 115 g_bResServInit = NV_TRUE; 116 117 return NV_OK; 118 119 failed_free_cache: 120 rmapiControlCacheFree(); 121 failed_free_lock: 122 _rmapiLockFree(); 123 failed: 124 return status; 125 } 126 127 void 128 rmapiShutdown 129 ( 130 void 131 ) 132 { 133 if (!g_bResServInit) 134 return; 135 136 serverFreeDomain(&g_resServ, 0); 137 serverDestruct(&g_resServ); 138 _rmapiLockFree(); 139 140 rmapiControlCacheFree(); 141 142 g_bResServInit = NV_FALSE; 143 } 144 145 static void 146 _rmapiInitInterface 147 ( 148 RM_API *pRmApi, 149 API_SECURITY_INFO *pDefaultSecInfo, 150 NvBool bTlsInternal, 151 NvBool bApiLockInternal, 152 NvBool bGpuLockInternal 153 ) 154 { 155 // 156 // Initialize to all stubs first, so any APIs not explicitly set here 157 // will return NV_ERR_NOT_SUPPORTED if called 158 // 159 rmapiInitStubInterface(pRmApi); 160 161 // 162 // Init members 163 // 164 if (pDefaultSecInfo) 165 pRmApi->defaultSecInfo = *pDefaultSecInfo; 166 167 pRmApi->bHasDefaultSecInfo = !!pDefaultSecInfo; 168 pRmApi->bTlsInternal = bTlsInternal; 169 pRmApi->bApiLockInternal = bApiLockInternal; 170 pRmApi->bRmSemaInternal = bApiLockInternal; 171 pRmApi->bGpuLockInternal = bGpuLockInternal; 172 pRmApi->pPrivateContext = NULL; 173 174 // 175 // Init function pointers 176 // 177 pRmApi->Alloc = rmapiAlloc; 178 pRmApi->AllocWithHandle = rmapiAllocWithHandle; 179 pRmApi->AllocWithSecInfo = pRmApi->bTlsInternal ? rmapiAllocWithSecInfo : rmapiAllocWithSecInfoTls; 180 181 pRmApi->FreeClientList = rmapiFreeClientList; 182 pRmApi->FreeClientListWithSecInfo = pRmApi->bTlsInternal ? rmapiFreeClientListWithSecInfo : rmapiFreeClientListWithSecInfoTls; 183 184 pRmApi->Free = rmapiFree; 185 pRmApi->FreeWithSecInfo = pRmApi->bTlsInternal ? rmapiFreeWithSecInfo : rmapiFreeWithSecInfoTls; 186 187 pRmApi->Control = rmapiControl; 188 pRmApi->ControlWithSecInfo = pRmApi->bTlsInternal ? rmapiControlWithSecInfo : rmapiControlWithSecInfoTls; 189 190 pRmApi->DupObject = rmapiDupObject; 191 pRmApi->DupObjectWithSecInfo = pRmApi->bTlsInternal ? rmapiDupObjectWithSecInfo : rmapiDupObjectWithSecInfoTls; 192 193 pRmApi->Share = rmapiShare; 194 pRmApi->ShareWithSecInfo = pRmApi->bTlsInternal ? rmapiShareWithSecInfo : rmapiShareWithSecInfoTls; 195 196 pRmApi->MapToCpu = rmapiMapToCpu; 197 pRmApi->MapToCpuWithSecInfo = pRmApi->bTlsInternal ? rmapiMapToCpuWithSecInfo : rmapiMapToCpuWithSecInfoTls; 198 pRmApi->MapToCpuWithSecInfoV2 = pRmApi->bTlsInternal ? rmapiMapToCpuWithSecInfoV2 : rmapiMapToCpuWithSecInfoTlsV2; 199 200 pRmApi->UnmapFromCpu = rmapiUnmapFromCpu; 201 pRmApi->UnmapFromCpuWithSecInfo = pRmApi->bTlsInternal ? rmapiUnmapFromCpuWithSecInfo : rmapiUnmapFromCpuWithSecInfoTls; 202 203 pRmApi->Map = rmapiMap; 204 pRmApi->MapWithSecInfo = pRmApi->bTlsInternal ? rmapiMapWithSecInfo : rmapiMapWithSecInfoTls; 205 206 pRmApi->Unmap = rmapiUnmap; 207 pRmApi->UnmapWithSecInfo = pRmApi->bTlsInternal ? rmapiUnmapWithSecInfo : rmapiUnmapWithSecInfoTls; 208 } 209 210 RM_API * 211 rmapiGetInterface 212 ( 213 RMAPI_TYPE rmapiType 214 ) 215 { 216 return &g_RmApiList[rmapiType]; 217 } 218 219 NV_STATUS 220 rmapiPrologue 221 ( 222 RM_API *pRmApi, 223 RM_API_CONTEXT *pContext 224 ) 225 { 226 NV_STATUS status = NV_OK; 227 return status; 228 } 229 230 void 231 rmapiEpilogue 232 ( 233 RM_API *pRmApi, 234 RM_API_CONTEXT *pContext 235 ) 236 { 237 } 238 239 void 240 rmapiInitLockInfo 241 ( 242 RM_API *pRmApi, 243 NvHandle hClient, 244 RS_LOCK_INFO *pLockInfo 245 ) 246 { 247 NV_ASSERT_OR_RETURN_VOID(pLockInfo != NULL); 248 pLockInfo->flags = 0; 249 pLockInfo->state = 0; 250 251 if (hClient != 0) 252 { 253 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 254 if ((pCallContext != NULL) && (pCallContext->pLockInfo != NULL)) 255 { 256 pLockInfo->state = pCallContext->pLockInfo->state; 257 258 if ((pCallContext->pLockInfo->pClient != NULL) && 259 (pCallContext->pLockInfo->pClient->hClient == hClient)) 260 { 261 pLockInfo->pClient = pCallContext->pLockInfo->pClient; 262 } 263 else 264 { 265 pLockInfo->state &= ~RM_LOCK_STATES_CLIENT_LOCK_ACQUIRED; 266 } 267 } 268 } 269 270 if (!pRmApi->bRmSemaInternal) 271 pLockInfo->flags |= RM_LOCK_FLAGS_RM_SEMA; 272 273 if (pRmApi->bApiLockInternal) 274 { 275 pLockInfo->state |= RM_LOCK_STATES_API_LOCK_ACQUIRED; 276 277 // RS-TODO: Assert that API rwlock is taken if no client is locked 278 if (pLockInfo->pClient == NULL) 279 pLockInfo->flags |= RM_LOCK_FLAGS_NO_CLIENT_LOCK; 280 } 281 282 if (pRmApi->bGpuLockInternal) 283 pLockInfo->state |= RM_LOCK_STATES_ALLOW_RECURSIVE_LOCKS; 284 } 285 286 static NV_STATUS 287 _rmapiLockAlloc(void) 288 { 289 // Turn on by default for Linux to get some soak time 290 // bug 2539044, bug 2536036: Enable by default. 291 g_resServ.bUnlockedParamCopy = NV_TRUE; 292 293 NvU32 val = 0; 294 if ((osReadRegistryDword(NULL, 295 NV_REG_STR_RM_PARAM_COPY_NO_LOCK, 296 &val) == NV_OK)) 297 { 298 g_resServ.bUnlockedParamCopy = (val != 0); 299 } 300 301 portMemSet(&g_RmApiLock, 0, sizeof(g_RmApiLock)); 302 g_RmApiLock.threadId = ~((NvU64)(0)); 303 g_RmApiLock.pLock = portSyncRwLockCreate(portMemAllocatorGetGlobalNonPaged()); 304 if (g_RmApiLock.pLock == NULL) 305 return NV_ERR_INSUFFICIENT_RESOURCES; 306 307 g_RmApiLock.tlsEntryId = tlsEntryAlloc(); 308 309 return NV_OK; 310 } 311 312 static void 313 _rmapiLockFree(void) 314 { 315 portSyncRwLockDestroy(g_RmApiLock.pLock); 316 } 317 318 NV_STATUS 319 rmapiLockAcquire(NvU32 flags, NvU32 module) 320 { 321 NV_STATUS rmStatus = NV_OK; 322 NvU64 threadId = portThreadGetCurrentThreadId(); 323 324 NvU64 myPriority = 0; 325 326 LOCK_ASSERT_AND_RETURN(!rmapiLockIsOwner()); 327 328 // 329 // If a read-only lock was requested, check to see if the module is allowed 330 // to take read-only locks 331 // 332 if ((flags & RMAPI_LOCK_FLAGS_READ) && (module != RM_LOCK_MODULES_NONE)) 333 { 334 OBJSYS *pSys = SYS_GET_INSTANCE(); 335 if ((pSys->apiLockModuleMask & RM_LOCK_MODULE_GRP(module)) == 0) 336 { 337 flags &= ~RMAPI_LOCK_FLAGS_READ; 338 } 339 } 340 341 // 342 // For conditional acquires and DISPATCH_LEVEL we want to exit 343 // immediately without waiting. 344 // 345 // If RM Locking V3 Lite is not enabled, *always* acquire the API 346 // lock in WRITE mode to ensure compatibility with Locking model V2 347 // behavior (providing exclusive access to the resource). 348 // 349 flags = osApiLockAcquireConfigureFlags(flags); 350 if (flags & API_LOCK_FLAGS_COND_ACQUIRE) 351 { 352 if ((flags & RMAPI_LOCK_FLAGS_READ)) 353 { 354 if (!portSyncRwLockAcquireReadConditional(g_RmApiLock.pLock)) 355 rmStatus = NV_ERR_TIMEOUT_RETRY; 356 } 357 else 358 { 359 if (portSyncRwLockAcquireWriteConditional(g_RmApiLock.pLock)) 360 { 361 g_RmApiLock.threadId = threadId; 362 } 363 else 364 { 365 rmStatus = NV_ERR_TIMEOUT_RETRY; 366 } 367 } 368 } 369 else 370 { 371 if ((flags & RMAPI_LOCK_FLAGS_READ)) 372 { 373 portSyncRwLockAcquireRead(g_RmApiLock.pLock); 374 } 375 else 376 { 377 378 portSyncRwLockAcquireWrite(g_RmApiLock.pLock); 379 g_RmApiLock.threadId = threadId; 380 } 381 } 382 383 384 if (rmStatus == NV_OK) 385 { 386 NvU64 timestamp; 387 osGetCurrentTick(×tamp); 388 389 if (g_RmApiLock.threadId == threadId) 390 g_RmApiLock.timestamp = timestamp; 391 392 // save off owning thread 393 RMTRACE_RMLOCK(_API_LOCK_ACQUIRE); 394 395 // add api lock trace record 396 INSERT_LOCK_TRACE(&g_RmApiLock.traceInfo, 397 NV_RETURN_ADDRESS(), 398 lockTraceAcquire, 399 flags, module, 400 threadId, 401 !portSyncExSafeToSleep(), 402 myPriority, 403 timestamp); 404 405 // 406 // If enabled, reset the timeout now that we are running and off 407 // the Sleep Queue. 408 // 409 if (threadStateGetSetupFlags() & 410 THREAD_STATE_SETUP_FLAGS_DO_NOT_INCLUDE_SLEEP_TIME_ENABLED) 411 { 412 threadStateResetTimeout(NULL); 413 } 414 } 415 416 NvP64 *pAcquireAddress = tlsEntryAcquire(g_RmApiLock.tlsEntryId); 417 if (pAcquireAddress != NULL) 418 { 419 *pAcquireAddress = (NvP64)(NvUPtr)NV_RETURN_ADDRESS(); 420 } 421 422 return rmStatus; 423 } 424 425 void 426 rmapiLockRelease(void) 427 { 428 NvU64 threadId = portThreadGetCurrentThreadId(); 429 NvU64 timestamp; 430 431 osGetCurrentTick(×tamp); 432 433 RMTRACE_RMLOCK(_API_LOCK_RELEASE); 434 435 // add api lock trace record 436 INSERT_LOCK_TRACE(&g_RmApiLock.traceInfo, 437 NV_RETURN_ADDRESS(), 438 lockTraceRelease, 439 0, 0, 440 threadId, 441 !portSyncExSafeToSleep(), 442 0, 443 timestamp); 444 445 if (g_RmApiLock.threadId == threadId) 446 { 447 // 448 // If the threadId in the global is same as current thread id, then 449 // we know that it was acquired in WRITE mode. 450 // 451 g_RmApiLock.threadId = ~0ull; 452 g_RmApiLock.timestamp = timestamp; 453 portSyncRwLockReleaseWrite(g_RmApiLock.pLock); 454 455 } 456 else 457 { 458 portSyncRwLockReleaseRead(g_RmApiLock.pLock); 459 } 460 461 tlsEntryRelease(g_RmApiLock.tlsEntryId); 462 } 463 464 NvBool 465 rmapiLockIsOwner(void) 466 { 467 return tlsEntryGet(g_RmApiLock.tlsEntryId) != NvP64_NULL; 468 } 469 470 // 471 // Mark for deletion the client resources from the data base, given a GPU mask 472 // 473 void 474 rmapiSetDelPendingClientResourcesFromGpuMask 475 ( 476 NvU32 gpuMask 477 ) 478 { 479 RS_ITERATOR it; 480 RmClient **ppClient; 481 RmClient *pClient; 482 RsClient *pRsClient; 483 Device *pDevice; 484 NvBool bDevicesInMask = NV_FALSE; 485 OBJGPU *pGpu; 486 487 for (ppClient = serverutilGetFirstClientUnderLock(); 488 ppClient; 489 ppClient = serverutilGetNextClientUnderLock(ppClient)) 490 { 491 pClient = *ppClient; 492 pRsClient = staticCast(pClient, RsClient); 493 494 it = clientRefIter(pRsClient, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE); 495 496 // Check that one of the devices is in the GPU mask 497 bDevicesInMask = NV_FALSE; 498 while (clientRefIterNext(it.pClient, &it)) 499 { 500 pDevice = dynamicCast(it.pResourceRef->pResource, Device); 501 502 if (!pDevice) 503 { 504 continue; 505 } 506 507 pGpu = GPU_RES_GET_GPU(pDevice); 508 if ((gpuMask & NVBIT(gpuGetInstance(pGpu))) != 0) 509 { 510 bDevicesInMask = NV_TRUE; 511 break; 512 } 513 } 514 515 if (bDevicesInMask == NV_FALSE) 516 { 517 continue; 518 } 519 520 pClient->Flags |= RMAPI_CLIENT_FLAG_DELETE_PENDING; 521 } 522 } 523 524 void 525 rmapiDelPendingDevices 526 ( 527 NvU32 gpuMask 528 ) 529 { 530 RmClient **ppClient; 531 RmClient *pClient; 532 RsClient *pRsClient; 533 RS_ITERATOR it; 534 RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL); 535 536 ppClient = serverutilGetFirstClientUnderLock(); 537 while (ppClient) 538 { 539 pClient = *ppClient; 540 pRsClient = staticCast(pClient, RsClient); 541 542 if (((pClient->Flags & RMAPI_CLIENT_FLAG_DELETE_PENDING) != 0) && 543 ((pClient->Flags & RMAPI_CLIENT_FLAG_RM_INTERNAL_CLIENT) == 0)) 544 { 545 it = clientRefIter(pRsClient, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE); 546 while(clientRefIterNext(pRsClient, &it)) 547 { 548 RsResourceRef *pDeviceRef = it.pResourceRef; 549 Device *pDevice = dynamicCast(pDeviceRef->pResource, Device); 550 551 if ((gpuMask & NVBIT(gpuGetInstance(GPU_RES_GET_GPU(pDevice)))) != 0) 552 { 553 pRmApi->Free(pRmApi, pRsClient->hClient, pDeviceRef->hResource); 554 555 // Client's resource map has been modified, re-snap iterator 556 it = clientRefIter(pRsClient, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE); 557 } 558 } 559 560 } 561 562 ppClient = serverutilGetNextClientUnderLock(ppClient); 563 } 564 } 565 566 void 567 rmapiReportLeakedDevices 568 ( 569 NvU32 gpuMask 570 ) 571 { 572 RmClient **ppClient; 573 RmClient *pClient; 574 RsClient *pRsClient; 575 RS_ITERATOR it; 576 RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL); 577 578 ppClient = serverutilGetFirstClientUnderLock(); 579 while (ppClient) 580 { 581 pClient = *ppClient; 582 pRsClient = staticCast(pClient, RsClient); 583 584 it = clientRefIter(pRsClient, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE); 585 while(clientRefIterNext(pRsClient, &it)) 586 { 587 RsResourceRef *pDeviceRef = it.pResourceRef; 588 Device *pDevice = dynamicCast(pDeviceRef->pResource, Device); 589 590 if ((gpuMask & NVBIT(gpuGetInstance(GPU_RES_GET_GPU(pDevice)))) != 0) 591 { 592 NV_PRINTF(LEVEL_ERROR, 593 "Device object leak: (0x%x, 0x%x). Please file a bug against RM-core.\n", 594 pRsClient->hClient, pDeviceRef->hResource); 595 NV_ASSERT(0); 596 597 // Delete leaked resource from database 598 pRmApi->Free(pRmApi, pRsClient->hClient, pDeviceRef->hResource); 599 600 // Client's resource map has been modified, re-snap iterator 601 it = clientRefIter(pRsClient, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE); 602 } 603 } 604 605 ppClient = serverutilGetNextClientUnderLock(ppClient); 606 } 607 } 608 609 // 610 // Delete the marked client resources 611 // 612 void 613 rmapiDelPendingClients 614 ( 615 void 616 ) 617 { 618 RmClient **ppClient; 619 RmClient *pClient; 620 RsClient *pRsClient; 621 RS_ITERATOR it; 622 RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL); 623 624 ppClient = serverutilGetFirstClientUnderLock(); 625 while (ppClient) 626 { 627 pClient = *ppClient; 628 pRsClient = staticCast(pClient, RsClient); 629 ppClient = serverutilGetNextClientUnderLock(ppClient); 630 if ((pClient->Flags & RMAPI_CLIENT_FLAG_DELETE_PENDING) != 0) 631 { 632 // Only free clients that have no devices left 633 it = clientRefIter(pRsClient, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE); 634 if (!clientRefIterNext(pRsClient, &it)) 635 pRmApi->Free(pRmApi, pRsClient->hClient, pRsClient->hClient); 636 } 637 } 638 } 639 640 extern OsInfoMap g_osInfoList; 641 642 NV_STATUS 643 rmapiGetClientHandlesFromOSInfo 644 ( 645 void *pOSInfo, 646 NvHandle **ppClientHandleList, 647 NvU32 *pClientHandleListSize 648 ) 649 { 650 OBJSYS *pSys = SYS_GET_INSTANCE(); 651 652 NvHandle *pClientHandleList; 653 NvU32 clientHandleListSize = 0; 654 NvU32 k; 655 656 RmClient **ppClient; 657 RmClient **ppFirstClient; 658 RmClient *pClient; 659 RsClient *pRsClient; 660 661 NvBool clientHandleLookup = pSys->getProperty(pSys, PDB_PROP_SYS_CLIENT_HANDLE_LOOKUP); 662 663 if (!clientHandleLookup) 664 { 665 ppFirstClient = NULL; 666 for (ppClient = serverutilGetFirstClientUnderLock(); 667 ppClient; 668 ppClient = serverutilGetNextClientUnderLock(ppClient)) 669 { 670 pClient = *ppClient; 671 if (pClient->pOSInfo != pOSInfo) 672 { 673 continue; 674 } 675 clientHandleListSize++; 676 677 if (NULL == ppFirstClient) 678 ppFirstClient = ppClient; 679 } 680 681 if (clientHandleListSize == 0) 682 { 683 *pClientHandleListSize = 0; 684 *ppClientHandleList = NULL; 685 return NV_ERR_INVALID_ARGUMENT; 686 } 687 688 pClientHandleList = portMemAllocNonPaged(clientHandleListSize * sizeof(NvU32)); 689 if (pClientHandleList == NULL) 690 { 691 return NV_ERR_NO_MEMORY; 692 } 693 694 *pClientHandleListSize = clientHandleListSize; 695 *ppClientHandleList = pClientHandleList; 696 697 k = 0; 698 for (ppClient = ppFirstClient; 699 ppClient; 700 ppClient = serverutilGetNextClientUnderLock(ppClient)) 701 { 702 pClient = *ppClient; 703 pRsClient = staticCast(pClient, RsClient); 704 if (pClient->pOSInfo != pOSInfo) 705 { 706 continue; 707 } 708 pClientHandleList[k++] = pRsClient->hClient; 709 710 if (clientHandleListSize <= k) 711 break; 712 } 713 } 714 else 715 { 716 OsInfoMapSubmap *pSubmap = NULL; 717 OsInfoMapIter it; 718 NvU64 key1 = (NvUPtr)pOSInfo; 719 pSubmap = multimapFindSubmap(&g_osInfoList, key1); 720 if (pSubmap != NULL) 721 { 722 clientHandleListSize = multimapCountSubmapItems(&g_osInfoList, pSubmap); 723 NV_PRINTF(LEVEL_INFO, "*** Found %d clients for %llx\n", clientHandleListSize, key1); 724 } 725 if (clientHandleListSize == 0) 726 { 727 *pClientHandleListSize = 0; 728 *ppClientHandleList = NULL; 729 return NV_ERR_INVALID_ARGUMENT; 730 } 731 pClientHandleList = portMemAllocNonPaged(clientHandleListSize * sizeof(NvU32)); 732 if (pClientHandleList == NULL) 733 { 734 return NV_ERR_NO_MEMORY; 735 } 736 *pClientHandleListSize = clientHandleListSize; 737 *ppClientHandleList = pClientHandleList; 738 k = 0; 739 it = multimapSubmapIterItems(&g_osInfoList, pSubmap); 740 while(multimapItemIterNext(&it)) 741 { 742 pClient = *it.pValue; 743 pRsClient = staticCast(pClient, RsClient); 744 745 NV_CHECK_OR_ELSE_STR(LEVEL_ERROR, pClient->pOSInfo == pOSInfo, "*** OS info mismatch", continue); 746 747 pClientHandleList[k++] = pRsClient->hClient; 748 NV_PRINTF(LEVEL_INFO, "*** Found: %x\n", pRsClient->hClient); 749 if (clientHandleListSize <= k) 750 break; 751 } 752 } 753 754 return NV_OK; 755 } 756 757