1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2015-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 #define NVOC_RS_SERVER_H_PRIVATE_ACCESS_ALLOWED 25 #include "nvlog_inc.h" 26 #include "resserv/resserv.h" 27 #include "resserv/rs_server.h" 28 #include "resserv/rs_client.h" 29 #include "resserv/rs_resource.h" 30 #include "tls/tls.h" 31 #include "nv_speculation_barrier.h" 32 33 /** 34 * Get the RsClient from a client handle without taking locks 35 * @param[in] pServer 36 * @param[in] hClient The handle to lookup 37 * @param[out] ppClient The RsClient associated with the handle 38 */ 39 static NV_STATUS _serverFindClient(RsServer *pServer, NvHandle hClient, RsClient **ppClient); 40 41 /** 42 * Get the CLIENT_ENTRY from a client handle without taking locks 43 * @param[in] pServer 44 * @param[in] hClient The handle to lookup 45 * @param[in] bFindPartial Include entries that have not finished constructing 46 * @param[out] ppClientEntry The client entry associated with the handle 47 */ 48 static NV_STATUS _serverFindClientEntry(RsServer *pServer, NvHandle hClient, NvBool bFindPartial, CLIENT_ENTRY **ppClientEntry); 49 50 /** 51 * Insert a CLIENT_ENTRY in the server database without taking locks 52 * @param[in] pServer 53 * @param[in] pClientEntry The client entry associated with the handle 54 */ 55 static NV_STATUS _serverInsertClientEntry(RsServer *pServer, CLIENT_ENTRY *pClientEntry, CLIENT_ENTRY **ppClientNext); 56 57 /** 58 * Find the next available client handle in bucket. 59 * @param[in] pServer 60 * @param[in] hClientIn 61 * @param[out] pClientOut 62 */ 63 static NV_STATUS _serverFindNextAvailableClientHandleInBucket(RsServer *pServer, NvHandle hClientIn, NvHandle *phClientOut, CLIENT_ENTRY ***pppClientNext); 64 65 /** 66 * Create a client entry and a client lock for a client that does not exist yet. Used during client 67 * construction. No locks will be taken if this call fails. 68 * @param[in] pServer 69 * @param[in] hClient 70 */ 71 static NV_STATUS _serverCreateEntryAndLockForNewClient(RsServer *pServer, NvHandle *phClient, NvBool bInternalHandle, CLIENT_ENTRY **ppClientEntry, API_SECURITY_INFO *pSecInfo); 72 73 /** 74 * Lock and retrieve the RsClient associated with a client handle. 75 * @param[in] pServer 76 * @param[in] access 77 * @param[in] hClient Handle of client to look-up 78 * @param[out] pClient RsClient associated with the client handle 79 */ 80 static NV_STATUS _serverLockClient(RsServer *pServer, LOCK_ACCESS_TYPE access, NvHandle hClient, RsClient **ppClient); 81 82 /** 83 * Lock and retrieve the RsClient associated with a client handle, and update lock info. 84 * @param[in] pServer 85 * @param[in] access 86 * @param[in] hClient Handle of client to look-up 87 * @param[inout] pLockInfo Lock state 88 * @param[out] pClient RsClient associated with the client handle 89 */ 90 static NV_STATUS _serverLockClientWithLockInfo(RsServer *pServer, LOCK_ACCESS_TYPE access, NvHandle hClient, RS_LOCK_INFO *pLockInfo, NvU32 *pReleaseFlags, RsClient **ppClient); 91 92 /** 93 * Lock and retrieve two RsClient associated with a pair of client handles, and update lock info. 94 * @param[in] pServer 95 * @param[in] access 96 * @param[in] hClient1, hClient2 Handles of clients to look-up and lock 97 * @param[inout] pLockInfo Lock state 98 * @param[out] pClient1, pClient2 RsClient associated with the client handles 99 */ 100 static NV_STATUS _serverLockDualClientWithLockInfo(RsServer *pServer, LOCK_ACCESS_TYPE access, NvHandle hClient1, NvHandle hClient2, RS_LOCK_INFO *pLockInfo, NvU32 *pReleaseFlags, RsClient **ppClient1, RsClient **ppClient2); 101 102 /** 103 * Unlock a client by handle 104 * @param[in] pServer 105 * @param[in] access 106 * @param[in] hClient Handle of the client to unlock 107 */ 108 static NV_STATUS _serverUnlockClient(RsServer *pServer, LOCK_ACCESS_TYPE access, NvHandle hClient); 109 110 /** 111 * Unlock a client by handle, and update lock info. 112 * @param[in] pServer 113 * @param[in] access 114 * @param[in] hClient Handle of the client to unlock 115 * @param[inout] pLockInfo Lock state 116 * @param[inout] pReleaseFlags Flags indicating the locks that need to be released 117 */ 118 static NV_STATUS _serverUnlockClientWithLockInfo(RsServer *pServer, LOCK_ACCESS_TYPE access, NvHandle hClient, RS_LOCK_INFO* pLockInfo, NvU32 *pReleaseFlags); 119 120 /** 121 * Unlock a client by handle, and update lock info. 122 * @param[in] pServer 123 * @param[in] access 124 * @param[in] hClient1, hClient2 Handles of the clients to unlock 125 * @param[inout] pLockInfo Lock state 126 * @param[inout] pReleaseFlags Flags indicating the locks that need to be released 127 */ 128 static NV_STATUS _serverUnlockDualClientWithLockInfo(RsServer *pServer, LOCK_ACCESS_TYPE access, NvHandle hClient1, NvHandle hClient2, RS_LOCK_INFO* pLockInfo, NvU32 *pReleaseFlags); 129 130 NV_STATUS serverFreeResourceTreeUnderLock(RsServer *pServer, RS_RES_FREE_PARAMS *pFreeParams) 131 { 132 NV_STATUS status; 133 RsResourceRef *pResourceRef = pFreeParams->pResourceRef; 134 RS_LOCK_INFO *pLockInfo = pFreeParams->pLockInfo; 135 NvU32 releaseFlags = 0; 136 137 NV_ASSERT_OR_RETURN(pResourceRef != NULL, NV_ERR_INVALID_OBJECT_HANDLE); 138 139 status = serverUpdateLockFlagsForFree(pServer, pFreeParams); 140 if (status != NV_OK) 141 return status; 142 143 status = serverSessionLock_Prologue(LOCK_ACCESS_WRITE, pResourceRef, pLockInfo, &releaseFlags); 144 if (status != NV_OK) 145 return status; 146 147 pLockInfo->flags |= RS_LOCK_FLAGS_FREE_SESSION_LOCK; 148 pLockInfo->traceOp = RS_LOCK_TRACE_FREE; 149 pLockInfo->traceClassId = pResourceRef->externalClassId; 150 status = serverResLock_Prologue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 151 if (status != NV_OK) 152 goto done; 153 154 status = clientFreeResource(pResourceRef->pClient, pServer, pFreeParams); 155 NV_ASSERT(status == NV_OK); 156 157 done: 158 serverResLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 159 160 serverSessionLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 161 162 return status; 163 } 164 165 #if RS_STANDALONE 166 NV_STATUS 167 serverInitFreeParams_Recursive(NvHandle hClient, NvHandle hResource, RS_LOCK_INFO* pLockInfo, RS_RES_FREE_PARAMS *pParams) 168 { 169 portMemSet(pParams, 0, sizeof(*pParams)); 170 pParams->hClient = hClient; 171 pParams->hResource = hResource; 172 pParams->pLockInfo = pLockInfo; 173 return NV_OK; 174 } 175 176 NV_STATUS serverUpdateLockFlagsForCopy(RsServer *pServer, RS_RES_DUP_PARAMS *pParams) 177 { 178 return NV_OK; 179 } 180 181 NV_STATUS serverUpdateLockFlagsForFree(RsServer *pServer, RS_RES_FREE_PARAMS *pParams) 182 { 183 return NV_OK; 184 } 185 186 NV_STATUS serverUpdateLockFlagsForInterAutoUnmap(RsServer *pServer, RS_INTER_UNMAP_PARAMS *pParams) 187 { 188 return NV_OK; 189 } 190 191 NV_STATUS serverFreeResourceRpcUnderLock(RsServer *pServer, RS_RES_FREE_PARAMS *pParams) 192 { 193 return NV_OK; 194 } 195 #endif 196 197 198 // 199 // Client handle format: 200 // 201 // fn [ C[1..3][0..F]] [ *INDEX* ] 202 // bit 31 20 19 0 203 // 204 205 #define RS_CLIENT_HANDLE_DECODE_MASK (RS_CLIENT_HANDLE_MAX - 1) 206 #define CLIENT_DECODEHANDLE(handle) (handle & RS_CLIENT_HANDLE_DECODE_MASK) 207 208 #define CLIENT_ENCODEHANDLE(handleBase, index) (handleBase | index) 209 210 NV_STATUS 211 serverConstruct 212 ( 213 RsServer *pServer, 214 RS_PRIV_LEVEL privilegeLevel, 215 NvU32 maxDomains 216 ) 217 { 218 NvU32 i; 219 PORT_MEM_ALLOCATOR *pAllocator = portMemAllocatorCreateNonPaged(); 220 221 pServer->privilegeLevel = privilegeLevel; 222 pServer->bConstructed = NV_TRUE; 223 pServer->pAllocator = pAllocator; 224 pServer->bDebugFreeList = NV_FALSE; 225 pServer->bRsAccessEnabled = NV_TRUE; 226 pServer->internalHandleBase = RS_CLIENT_INTERNAL_HANDLE_BASE; 227 pServer->clientHandleBase = RS_CLIENT_HANDLE_BASE; 228 pServer->activeClientCount = 0; 229 pServer->activeResourceCount= 0; 230 pServer->roTopLockApiMask = 0; 231 /* pServer->bUnlockedParamCopy is set in _rmapiLockAlloc */ 232 233 pServer->pClientSortedList = PORT_ALLOC(pAllocator, sizeof(RsClientList)*RS_CLIENT_HANDLE_BUCKET_COUNT); 234 if (NULL == pServer->pClientSortedList) 235 goto fail; 236 237 for (i = 0; i < RS_CLIENT_HANDLE_BUCKET_COUNT; i++) 238 { 239 listInit(&pServer->pClientSortedList[i], pAllocator); 240 } 241 pServer->clientCurrentHandleIndex = 0; 242 243 pServer->pClientListLock = portSyncRwLockCreate(pAllocator); 244 if (pServer->pClientListLock == NULL) 245 goto fail; 246 247 #if RS_STANDALONE 248 RS_LOCK_VALIDATOR_INIT(&pServer->topLockVal, LOCK_VAL_LOCK_CLASS_API, 0xdead0000); 249 pServer->pTopLock = portSyncRwLockCreate(pAllocator); 250 if (pServer->pTopLock == NULL) 251 goto fail; 252 253 RS_LOCK_VALIDATOR_INIT(&pServer->resLockVal, LOCK_VAL_LOCK_CLASS_GPU, 0xbeef0000); 254 pServer->pResLock = portSyncRwLockCreate(pAllocator); 255 if (pServer->pResLock == NULL) 256 goto fail; 257 258 pServer->topLockOwnerTid = ~0; 259 #endif 260 261 pServer->pShareMapLock = portSyncSpinlockCreate(pAllocator); 262 263 mapInitIntrusive(&pServer->shareMap); 264 265 listInit(&pServer->defaultInheritedSharePolicyList, pAllocator); 266 listInit(&pServer->globalInternalSharePolicyList, pAllocator); 267 268 if (NV_OK != serverInitGlobalSharePolicies(pServer)) 269 { 270 mapDestroy(&pServer->shareMap); 271 listDestroy(&pServer->defaultInheritedSharePolicyList); 272 listDestroy(&pServer->globalInternalSharePolicyList); 273 goto fail; 274 } 275 276 return NV_OK; 277 fail: 278 279 #if RS_STANDALONE 280 if (pServer->pResLock != NULL) 281 portSyncRwLockDestroy(pServer->pResLock); 282 283 if (pServer->pTopLock != NULL) 284 portSyncRwLockDestroy(pServer->pTopLock); 285 #endif 286 287 if (pServer->pClientListLock != NULL) 288 portSyncRwLockDestroy(pServer->pClientListLock); 289 290 if (pServer->pShareMapLock != NULL) 291 portSyncSpinlockDestroy(pServer->pShareMapLock); 292 293 if (pServer->pClientSortedList != NULL) 294 { 295 for (i = 0; i < RS_CLIENT_HANDLE_BUCKET_COUNT; i++) 296 { 297 listDestroy(&pServer->pClientSortedList[i]); 298 } 299 PORT_FREE(pAllocator, pServer->pClientSortedList); 300 } 301 302 if (pAllocator != NULL) 303 portMemAllocatorRelease(pAllocator); 304 305 return NV_ERR_INSUFFICIENT_RESOURCES; 306 } 307 308 309 NV_STATUS 310 serverDestruct 311 ( 312 RsServer *pServer 313 ) 314 { 315 NvU32 i; 316 RS_LOCK_INFO lockInfo; 317 portMemSet(&lockInfo, 0, sizeof(lockInfo)); 318 319 if (!pServer->bConstructed) 320 return NV_ERR_INVALID_OBJECT; 321 322 for (i = 0; i < RS_CLIENT_HANDLE_BUCKET_COUNT; i++) 323 { 324 CLIENT_ENTRY **ppClientEntry; 325 NvHandle hClient = 0; 326 327 while ((ppClientEntry = listHead(&pServer->pClientSortedList[i])) != NULL) 328 { 329 RS_RES_FREE_PARAMS_INTERNAL freeParams; 330 lockInfo.pClient = (*ppClientEntry)->pClient; 331 hClient = lockInfo.pClient->hClient; 332 serverInitFreeParams_Recursive(hClient, hClient, &lockInfo, &freeParams); 333 serverFreeResourceTree(pServer, &freeParams); 334 } 335 336 listDestroy(&pServer->pClientSortedList[i]); 337 } 338 339 PORT_FREE(pServer->pAllocator, pServer->pClientSortedList); 340 mapDestroy(&pServer->shareMap); 341 listDestroy(&pServer->defaultInheritedSharePolicyList); 342 listDestroy(&pServer->globalInternalSharePolicyList); 343 344 #if RS_STANDALONE 345 portSyncRwLockDestroy(pServer->pResLock); 346 portSyncRwLockDestroy(pServer->pTopLock); 347 #endif 348 349 portSyncSpinlockDestroy(pServer->pShareMapLock); 350 portSyncRwLockDestroy(pServer->pClientListLock); 351 352 portMemAllocatorRelease(pServer->pAllocator); 353 354 pServer->bConstructed = NV_FALSE; 355 356 return NV_OK; 357 } 358 359 NV_STATUS 360 serverSetClientHandleBase 361 ( 362 RsServer *pServer, 363 NvU32 clientHandleBase 364 ) 365 { 366 NvU32 releaseFlags = 0; 367 RS_LOCK_INFO lockInfo; 368 portMemSet(&lockInfo, 0, sizeof(lockInfo)); 369 370 // Grab top level lock before updating the internal state 371 NV_ASSERT_OK_OR_RETURN(serverTopLock_Prologue(pServer, LOCK_ACCESS_WRITE, &lockInfo, &releaseFlags)); 372 373 // Do not allow fixedClientHandle base to be same as internalHandleBase 374 if (clientHandleBase != pServer->internalHandleBase) 375 { 376 pServer->clientHandleBase = clientHandleBase; 377 } 378 else 379 { 380 NV_PRINTF(LEVEL_ERROR, "Error setting fixed Client handle base\n"); 381 } 382 383 serverTopLock_Epilogue(pServer, LOCK_ACCESS_WRITE, &lockInfo, &releaseFlags); 384 385 return NV_OK; 386 } 387 388 static 389 NV_STATUS 390 _serverFreeClient_underlock 391 ( 392 RsServer *pServer, 393 RsClient *pClient 394 ) 395 { 396 CLIENT_ENTRY *pClientEntry = NULL; 397 NvHandle hClient; 398 NV_STATUS status; 399 PORT_RWLOCK *pLock = NULL; 400 401 status =_serverFindClientEntry(pServer, pClient->hClient, NV_FALSE, &pClientEntry); 402 if (status != NV_OK) 403 { 404 return status; 405 } 406 407 NV_ASSERT(pClientEntry->pClient != NULL); 408 409 hClient = pClient->hClient; 410 pClientEntry->pClient = NULL; 411 pClientEntry->hClient = 0; 412 413 clientFreeAccessBackRefs(pClient, pServer); 414 415 objDelete(pClient); 416 417 listRemoveFirstByValue(&pServer->pClientSortedList[hClient & RS_CLIENT_HANDLE_BUCKET_MASK], &pClientEntry); 418 pLock = pClientEntry->pLock; 419 420 RS_RWLOCK_RELEASE_WRITE_EXT(pLock, &pClientEntry->lockVal, NV_TRUE); 421 portSyncRwLockDestroy(pLock); 422 PORT_FREE(pServer->pAllocator, pClientEntry); 423 424 return NV_OK; 425 } 426 427 NV_STATUS 428 serverAllocDomain 429 ( 430 RsServer *pServer, 431 NvU32 hParentDomain, 432 ACCESS_CONTROL *pAccessControl, 433 NvHandle *phDomain 434 ) 435 { 436 return NV_OK; 437 } 438 439 NV_STATUS 440 serverFreeDomain 441 ( 442 RsServer *pServer, 443 NvHandle hDomain 444 ) 445 { 446 NvU32 bucket; 447 for (bucket = 0; bucket < RS_CLIENT_HANDLE_BUCKET_COUNT; bucket ++) 448 { 449 RsClientList *pClientList = &(pServer->pClientSortedList[bucket]); 450 CLIENT_ENTRY **ppClientEntry = listHead(pClientList); 451 while (ppClientEntry != NULL) 452 { 453 CLIENT_ENTRY *pClientEntry = *ppClientEntry; 454 RS_CLIENT_FREE_PARAMS params; 455 456 portMemSet(¶ms, 0, sizeof(params)); 457 if (pClientEntry == NULL) 458 { 459 ppClientEntry = listNext(pClientList, ppClientEntry); 460 continue; 461 } 462 params.hClient = pClientEntry->hClient; 463 464 serverFreeClient(pServer, ¶ms); 465 ppClientEntry = listHead(pClientList); 466 } 467 } 468 return NV_OK; 469 } 470 471 NV_STATUS serverValidate 472 ( 473 RsServer *pServer, 474 NvU32 hDomain, 475 NvHandle hClient 476 ) 477 { 478 return NV_OK; 479 } 480 481 NV_STATUS 482 serverValidateAlloc 483 ( 484 RsServer *pServer, 485 NvU32 hDomain, 486 NvU32 externalClassId 487 ) 488 { 489 // Placeholder for allocation validation 490 return NV_OK; 491 } 492 493 NV_STATUS 494 serverAllocClient 495 ( 496 RsServer *pServer, 497 RS_RES_ALLOC_PARAMS_INTERNAL *pParams 498 ) 499 { 500 NV_STATUS status; 501 NvHandle hClient = 0; 502 RsClient *pClient = NULL; 503 CLIENT_ENTRY *pClientEntry = NULL; 504 NvBool bLockedClient = NV_FALSE; 505 506 if (!pServer->bConstructed) 507 { 508 status = NV_ERR_NOT_READY; 509 goto done; 510 } 511 512 // RS-TODO Assert that the RW top lock is held 513 514 hClient = pParams->hClient; 515 #if !(RS_COMPATABILITY_MODE) 516 if (hClient != 0) 517 { 518 // Fail if the server supplied a client id 519 status = NV_ERR_INVALID_ARGUMENT; 520 goto done; 521 } 522 #endif 523 524 status = _serverCreateEntryAndLockForNewClient(pServer, &hClient, !!(pParams->allocState & ALLOC_STATE_INTERNAL_CLIENT_HANDLE), &pClientEntry, pParams->pSecInfo); 525 526 if (status != NV_OK) 527 { 528 goto done; 529 } 530 pParams->hClient = hClient; 531 pParams->hResource = hClient; 532 bLockedClient = NV_TRUE; 533 534 status = resservClientFactory(pServer->pAllocator, pParams, &pClient); 535 if (NV_OK != status) 536 { 537 status = NV_ERR_INSUFFICIENT_RESOURCES; 538 goto done; 539 } 540 541 pClientEntry->pClient = pClient; 542 543 // Automatically allocate client proxy resource 544 status = clientAllocResource(pClient, pServer, pParams); 545 if (status != NV_OK) 546 goto done; 547 548 // NV_PRINTF(LEVEL_INFO, "Allocated hClient: %x\n", hClient); 549 portAtomicIncrementU32(&pServer->activeClientCount); 550 551 done: 552 if (bLockedClient) 553 _serverUnlockClient(pServer, LOCK_ACCESS_WRITE, pParams->hClient); 554 555 if ((status != NV_OK) && (status != NV_ERR_INSERT_DUPLICATE_NAME) && (hClient != 0)) 556 { 557 if (_serverFindClientEntry(pServer, hClient, NV_TRUE, &pClientEntry) == NV_OK) 558 { 559 listRemoveFirstByValue(&pServer->pClientSortedList[hClient & RS_CLIENT_HANDLE_BUCKET_MASK], &pClientEntry); 560 portSyncRwLockDestroy(pClientEntry->pLock); 561 PORT_FREE(pServer->pAllocator, pClientEntry); 562 } 563 564 objDelete(pClient); 565 } 566 567 return status; 568 } 569 570 static 571 NV_STATUS 572 _serverFreeClient 573 ( 574 RsServer *pServer, 575 RS_CLIENT_FREE_PARAMS *pParams 576 ) 577 { 578 NV_STATUS status; 579 NV_STATUS lockStatus; 580 NvU32 releaseFlags = 0; 581 RsClient *pClient; 582 583 lockStatus = _serverLockClient(pServer, LOCK_ACCESS_WRITE, pParams->hClient, &pClient); 584 if (lockStatus != NV_OK) 585 { 586 status = NV_ERR_INVALID_CLIENT; 587 goto done; 588 } 589 releaseFlags |= RS_LOCK_RELEASE_CLIENT_LOCK; 590 591 status = serverResLock_Prologue(pServer, LOCK_ACCESS_WRITE, pParams->pResFreeParams->pLockInfo, &releaseFlags); 592 if (status != NV_OK) 593 goto done; 594 595 status = _serverFreeClient_underlock(pServer, pClient); 596 if (status != NV_OK) 597 goto done; 598 599 // NV_PRINTF(LEVEL_INFO, "Freeing hClient: %x\n", hClient); 600 portAtomicDecrementU32(&pServer->activeClientCount); 601 602 done: 603 serverResLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pParams->pResFreeParams->pLockInfo, &releaseFlags); 604 605 if (releaseFlags & RS_LOCK_RELEASE_CLIENT_LOCK) 606 _serverUnlockClient(pServer, LOCK_ACCESS_WRITE, pParams->hClient); 607 608 return status; 609 } 610 611 NV_STATUS 612 serverAllocResource 613 ( 614 RsServer *pServer, 615 RS_RES_ALLOC_PARAMS *pParams 616 ) 617 { 618 NV_STATUS status; 619 NvU32 releaseFlags = 0; 620 API_STATE *pApiState; 621 NvBool bClientAlloc = (pParams->externalClassId == NV01_ROOT || 622 pParams->externalClassId == NV01_ROOT_CLIENT || 623 pParams->externalClassId == NV01_ROOT_NON_PRIV); 624 LOCK_ACCESS_TYPE topLockAccess; 625 NvU32 initialLockState; 626 RS_LOCK_INFO *pLockInfo; 627 RsClient *pSecondClient = NULL; 628 NvHandle hSecondClient; 629 630 if (!pServer->bConstructed) 631 return NV_ERR_NOT_READY; 632 633 pLockInfo = pParams->pLockInfo; 634 NV_ASSERT_OR_RETURN(pLockInfo != NULL, NV_ERR_INVALID_ARGUMENT); 635 636 initialLockState = pLockInfo->state; 637 638 status = serverAllocApiCopyIn(pServer, pParams, &pApiState); 639 if (status != NV_OK) 640 return status; 641 642 status = serverAllocResourceLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 643 if (status != NV_OK) 644 goto done; 645 646 if ((status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags)) != NV_OK) 647 goto done; 648 649 if (status == NV_OK) 650 { 651 if (bClientAlloc) 652 { 653 status = serverAllocClient(pServer, pParams); 654 } 655 else 656 { 657 status = serverLookupSecondClient(pParams, &hSecondClient); 658 659 if (status != NV_OK) 660 goto done; 661 662 if (hSecondClient == 0) 663 { 664 status = _serverLockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, 665 pParams->hClient, pLockInfo, 666 &releaseFlags, &pParams->pClient); 667 668 if (status != NV_OK) 669 goto done; 670 671 if (!pParams->pClient->bActive) 672 { 673 status = NV_ERR_INVALID_STATE; 674 goto done; 675 } 676 } 677 else 678 { 679 status = _serverLockDualClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, 680 pParams->hClient, hSecondClient, 681 pLockInfo, &releaseFlags, 682 &pParams->pClient, &pSecondClient); 683 684 if (status != NV_OK) 685 goto done; 686 687 if (!pParams->pClient->bActive || !pSecondClient->bActive) 688 { 689 status = NV_ERR_INVALID_STATE; 690 goto done; 691 } 692 } 693 694 // The second client's usage is class-dependent and should be validated 695 // by the class's constructor 696 status = clientValidate(pParams->pClient, pParams->pSecInfo); 697 698 if (status != NV_OK) 699 goto done; 700 701 status = serverAllocResourceUnderLock(pServer, pParams); 702 } 703 } 704 705 if (status != NV_OK) 706 { 707 NV_PRINTF(LEVEL_INFO, 708 "hParent 0x%08x : hClass 0x%08x allocation failed\n", 709 pParams->hParent, pParams->externalClassId); 710 } 711 712 // RS-TODO: Can this be moved before _ResLock? 713 status = serverAllocEpilogue_WAR(pServer, status, bClientAlloc, pParams); 714 715 done: 716 717 if (!bClientAlloc) 718 { 719 if (pSecondClient != NULL) 720 { 721 _serverUnlockDualClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, 722 pParams->hClient, pSecondClient->hClient, 723 pLockInfo, &releaseFlags); 724 } 725 else 726 { 727 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, 728 pLockInfo, &releaseFlags); 729 } 730 } 731 732 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 733 734 // copyout as needed, being careful not to overwrite a useful status value 735 status = serverAllocApiCopyOut(pServer, status, pApiState); 736 737 NV_ASSERT(pLockInfo->state == initialLockState); 738 739 return status; 740 } 741 742 #if RS_STANDALONE 743 // RS-TODO rename to UnderClientLock 744 NV_STATUS 745 serverAllocResourceUnderLock 746 ( 747 RsServer *pServer, 748 RS_RES_ALLOC_PARAMS *pParams 749 ) 750 { 751 NV_STATUS status; 752 RsClient *pClient = pParams->pClient; 753 NvHandle hResource = pParams->hResource; 754 NvU32 releaseFlags = 0; 755 756 if (!pServer->bConstructed) 757 return NV_ERR_NOT_READY; 758 759 status = serverResLock_Prologue(pServer, LOCK_ACCESS_WRITE, pParams->pLockInfo, &releaseFlags); 760 if (status != NV_OK) 761 goto done; 762 763 status = clientAssignResourceHandle(pClient, &hResource); 764 if (status != NV_OK) 765 goto done; 766 767 pParams->hResource = hResource; 768 pParams->hParent = (pParams->hParent == 0) ? pParams->hClient : pParams->hParent; 769 status = clientAllocResource(pClient, pServer, pParams); 770 if (status != NV_OK) 771 goto done; 772 773 // NV_PRINTF(LEVEL_INFO, "hClient %x: Allocated hResource %x with class %x\n", 774 // pParams->hClient, pParams->hResource, pParams->externalClassId); 775 776 done: 777 serverResLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pParams->pLockInfo, &releaseFlags); 778 return status; 779 } 780 781 NvU32 782 serverAllocClientHandleBase 783 ( 784 RsServer *pServer, 785 NvBool bInternalHandle, 786 API_SECURITY_INFO *pSecInfo 787 ) 788 { 789 return bInternalHandle ? pServer->internalHandleBase : 790 pServer->clientHandleBase; 791 } 792 #endif 793 794 NV_STATUS 795 clientUpdatePendingFreeList_IMPL 796 ( 797 RsClient *pClient, 798 RsResourceRef *pTargetRef, 799 RsResourceRef *pReference, 800 NvBool bMove 801 ) 802 { 803 RsIndexIter it; 804 NvBool bInList = refPendingFree(pTargetRef, pClient); 805 RS_FREE_STACK *pFs = pClient->pFreeStack; 806 if (bMove) 807 { 808 if (pReference != pTargetRef) 809 { 810 // Basic circular dependency check 811 while (pFs != NULL) 812 { 813 RsResourceRef *pFsRef = pFs->pResourceRef; 814 NV_ASSERT_OR_GOTO(pFsRef != pTargetRef, done); 815 816 pFs = pFs->pPrev; 817 } 818 } 819 820 if (bInList) 821 listRemove(&pClient->pendingFreeList, pTargetRef); 822 listPrependExisting(&pClient->pendingFreeList, pTargetRef); 823 } 824 else if (!bInList) 825 { 826 listPrependExisting(&pClient->pendingFreeList, pTargetRef); 827 } 828 829 // 830 // Recursively add children to the pending free list and move 831 // them to the front of the list 832 // 833 it = indexRefIterAll(&pTargetRef->childRefMap); 834 while (indexRefIterNext(&it)) 835 { 836 clientUpdatePendingFreeList(pClient, *it.pValue, pReference, NV_TRUE); 837 } 838 839 // 840 // Recursively add dependencies to the pending free list and 841 // move them to the front of the list 842 // 843 it = indexRefIterAll(&pTargetRef->depRefMap); 844 while (indexRefIterNext(&it)) 845 { 846 clientUpdatePendingFreeList(pClient, *it.pValue, pReference, NV_TRUE); 847 } 848 849 if (pTargetRef->pResource != NULL) 850 { 851 // Allow some objects to add more dependants here 852 resAddAdditionalDependants(pClient, pTargetRef->pResource, pReference); 853 } 854 855 done: 856 return NV_OK; 857 } 858 859 NV_STATUS 860 serverFreeClientList 861 ( 862 RsServer *pServer, 863 NvHandle *phClientList, 864 NvU32 numClients, 865 NvU32 freeState, 866 API_SECURITY_INFO *pSecInfo 867 ) 868 { 869 NvU32 i, j; 870 871 // 872 // Call serverFreeClient twice; first for high priority resources 873 // then again for remaining resources 874 // 875 for (i = 0; i < 2; ++i) 876 { 877 for (j = 0; j < numClients; ++j) 878 { 879 RS_CLIENT_FREE_PARAMS params; 880 portMemSet(¶ms, 0, sizeof(params)); 881 882 if (phClientList[j] == 0) 883 continue; 884 885 params.hClient = phClientList[j]; 886 params.bHiPriOnly = (i == 0); 887 params.state = freeState; 888 params.pSecInfo = pSecInfo; 889 890 serverFreeClient(pServer, ¶ms); 891 } 892 } 893 894 return NV_OK; 895 } 896 897 NV_STATUS 898 serverFreeResourceTree 899 ( 900 RsServer *pServer, 901 RS_RES_FREE_PARAMS *pParams 902 ) 903 { 904 RsClient *pClient = NULL; 905 NV_STATUS status; 906 RsResourceRef *pResourceRef = NULL; 907 RsResourceRef *pTargetRef; 908 RsResourceRef *pFirstLowPriRef; 909 NvBool bHiPriOnly = pParams->bHiPriOnly; 910 NvBool bRecursive = NV_FALSE; 911 RS_FREE_STACK freeStack; 912 NvBool bPopFreeStack = NV_FALSE; 913 RS_LOCK_INFO *pLockInfo; 914 NvU32 initialLockState; 915 NvU32 releaseFlags = 0; 916 LOCK_ACCESS_TYPE topLockAccess; 917 918 if (!pServer->bConstructed) 919 return NV_ERR_NOT_READY; 920 921 pLockInfo = pParams->pLockInfo; 922 NV_ASSERT_OR_RETURN(pLockInfo != NULL, NV_ERR_INVALID_ARGUMENT); 923 924 initialLockState = pLockInfo->state; 925 926 portMemSet(&freeStack, 0, sizeof(freeStack)); 927 928 status = serverFreeResourceLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 929 if (status != NV_OK) 930 goto done; 931 932 status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags); 933 if (status != NV_OK) 934 goto done; 935 936 status = _serverLockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags, &pClient); 937 if (status != NV_OK) 938 goto done; 939 940 status = clientValidate(pClient, pParams->pSecInfo); 941 if (status != NV_OK) 942 goto done; 943 944 if (pClient->pFreeStack != NULL) 945 freeStack.pPrev = pClient->pFreeStack; 946 pClient->pFreeStack = &freeStack; 947 bPopFreeStack = NV_TRUE; 948 949 status = clientGetResourceRef(pClient, pParams->hResource, &pResourceRef); 950 if (status != NV_OK) 951 { 952 NV_PRINTF(LEVEL_ERROR, "hObject 0x%x not found for client 0x%x\n", 953 pParams->hResource, 954 pParams->hClient); 955 #if (RS_COMPATABILITY_MODE) 956 status = NV_OK; 957 #endif 958 goto done; 959 } 960 pParams->pResourceRef = pResourceRef; 961 freeStack.pResourceRef = pResourceRef; 962 963 if (pParams->bInvalidateOnly && pResourceRef->bInvalidated) 964 { 965 status = NV_OK; 966 goto done; 967 } 968 969 bRecursive = (freeStack.pPrev != NULL); 970 status = clientUpdatePendingFreeList(pClient, pResourceRef, pResourceRef, bRecursive); 971 if (status != NV_OK) 972 goto done; 973 974 clientPostProcessPendingFreeList(pClient, &pFirstLowPriRef); 975 976 if (pServer->bDebugFreeList) 977 { 978 NV_PRINTF(LEVEL_INFO, "PENDING FREE LIST START (0x%x)\n", pClient->hClient); 979 NV_PRINTF(LEVEL_INFO, " _HI_PRIORITY_:\n"); 980 pTargetRef = listHead(&pClient->pendingFreeList); 981 while (pTargetRef != NULL) 982 { 983 if (pTargetRef == pFirstLowPriRef) 984 NV_PRINTF(LEVEL_INFO, " _LO_PRIORITY_:\n"); 985 986 NV_PRINTF(LEVEL_INFO, " 0x%08x [%04x]\n", 987 pTargetRef->hResource, 988 pTargetRef->externalClassId); 989 pTargetRef = listNext(&pClient->pendingFreeList, pTargetRef); 990 } 991 NV_PRINTF(LEVEL_INFO, "PENDING FREE LIST END (0x%x)\n", pClient->hClient); 992 } 993 994 while ((pTargetRef = listHead(&pClient->pendingFreeList)) != NULL) 995 { 996 NvBool bInvalidateOnly = NV_TRUE; 997 RS_FREE_STACK *pFs = &freeStack; 998 RS_RES_FREE_PARAMS_INTERNAL freeParams; 999 NvHandle hTarget = pTargetRef->hResource; 1000 1001 if (bHiPriOnly && pTargetRef == pFirstLowPriRef) 1002 goto done; 1003 1004 if (pServer->bDebugFreeList) 1005 { 1006 NV_PRINTF(LEVEL_INFO, "(%08x, %08x)\n", pClient->hClient, hTarget); 1007 } 1008 1009 if (hTarget == pParams->hResource) 1010 { 1011 // Target resource should always be the last one to be freed 1012 NV_ASSERT((listCount(&pClient->pendingFreeList) == 1) || bRecursive); 1013 status = serverFreeResourceTreeUnderLock(pServer, pParams); 1014 break; 1015 } 1016 1017 while (pFs != NULL) 1018 { 1019 RsResourceRef *pFsRef = pFs->pResourceRef; 1020 if (refHasAncestor(pTargetRef, pFsRef)) 1021 { 1022 bInvalidateOnly = pParams->bInvalidateOnly; 1023 break; 1024 } 1025 pFs = pFs->pPrev; 1026 } 1027 1028 serverInitFreeParams_Recursive(pClient->hClient, hTarget, pLockInfo, &freeParams); 1029 freeParams.pResourceRef = pTargetRef; 1030 freeParams.bInvalidateOnly = bInvalidateOnly; 1031 freeParams.pSecInfo = pParams->pSecInfo; 1032 status = serverFreeResourceTreeUnderLock(pServer, &freeParams); 1033 NV_ASSERT(status == NV_OK); 1034 1035 if (pServer->bDebugFreeList) 1036 { 1037 NV_PRINTF(LEVEL_INFO, "(%08x, %08x) status=0x%x\n", 1038 pClient->hClient, 1039 hTarget, 1040 status); 1041 } 1042 } 1043 1044 if (bPopFreeStack) 1045 { 1046 if (pClient != NULL) 1047 pClient->pFreeStack = freeStack.pPrev; 1048 bPopFreeStack = NV_FALSE; 1049 } 1050 1051 if (pParams->hClient == pParams->hResource) 1052 { 1053 pClient->bActive = NV_FALSE; 1054 } 1055 1056 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags); 1057 1058 if (pParams->hClient == pParams->hResource) 1059 { 1060 NvBool bReAcquireLock = (topLockAccess != LOCK_ACCESS_WRITE); 1061 RS_CLIENT_FREE_PARAMS_INTERNAL clientFreeParams; 1062 portMemSet(&clientFreeParams, 0, sizeof(clientFreeParams)); 1063 clientFreeParams.pResFreeParams = pParams; 1064 clientFreeParams.hClient = pParams->hClient; 1065 1066 if (bReAcquireLock) 1067 { 1068 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1069 serverTopLock_Prologue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1070 _serverFreeClient(pServer, &clientFreeParams); 1071 serverTopLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1072 initialLockState &= ~RS_LOCK_STATE_CLIENT_LOCK_ACQUIRED; 1073 } 1074 else 1075 { 1076 _serverFreeClient(pServer, &clientFreeParams); 1077 } 1078 1079 pClient = NULL; 1080 } 1081 1082 done: 1083 if (bPopFreeStack) 1084 { 1085 if (pClient != NULL) 1086 pClient->pFreeStack = freeStack.pPrev; 1087 bPopFreeStack = NV_FALSE; 1088 } 1089 1090 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags); 1091 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1092 1093 // 1094 // Log any changes to lock state, but ignore the ALLOW_RECURSIVE_LOCKS flag 1095 // as that can be set by serverUpdateLockFlagsForFree() when dealing with 1096 // RPCs to GSP; this would have already printed the relevant message. 1097 // 1098 NV_ASSERT((pLockInfo->state == initialLockState) || 1099 (pLockInfo->state == (initialLockState | RS_LOCK_STATE_ALLOW_RECURSIVE_RES_LOCK))); 1100 1101 return status; 1102 } 1103 1104 NV_STATUS 1105 serverControl 1106 ( 1107 RsServer *pServer, 1108 RS_RES_CONTROL_PARAMS *pParams 1109 ) 1110 { 1111 NV_STATUS status; 1112 RsClient *pClient; 1113 RsResourceRef *pResourceRef = NULL; 1114 RS_LOCK_INFO *pLockInfo; 1115 NvU32 releaseFlags = 0; 1116 CALL_CONTEXT callContext; 1117 CALL_CONTEXT *pOldContext = NULL; 1118 LOCK_ACCESS_TYPE access = LOCK_ACCESS_WRITE; 1119 1120 pLockInfo = pParams->pLockInfo; 1121 NV_ASSERT_OR_RETURN(pLockInfo != NULL, NV_ERR_INVALID_ARGUMENT); 1122 1123 status = serverControlLookupLockFlags(pServer, RS_LOCK_TOP, pParams, pParams->pCookie, &access); 1124 if (status != NV_OK) 1125 goto done; 1126 1127 if (pServer->bUnlockedParamCopy) 1128 { 1129 status = serverControlApiCopyIn(pServer, pParams, pParams->pCookie); 1130 if (status != NV_OK) 1131 goto done; 1132 } 1133 1134 status = serverTopLock_Prologue(pServer, access, pLockInfo, &releaseFlags); 1135 if (status != NV_OK) 1136 goto done; 1137 1138 status = _serverLockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags, &pClient); 1139 if (status != NV_OK) 1140 goto done; 1141 1142 if (!pClient->bActive) 1143 { 1144 status = NV_ERR_INVALID_STATE; 1145 goto done; 1146 } 1147 1148 status = clientValidate(pClient, &pParams->secInfo); 1149 if (status != NV_OK) 1150 goto done; 1151 1152 status = clientGetResourceRef(pClient, pParams->hObject, &pResourceRef); 1153 if (status != NV_OK) 1154 goto done; 1155 pParams->pResourceRef = pResourceRef; 1156 1157 if (pResourceRef->bInvalidated || pResourceRef->pResource == NULL) 1158 { 1159 status = NV_ERR_RESOURCE_LOST; 1160 goto done; 1161 } 1162 1163 pLockInfo->flags |= RS_LOCK_FLAGS_NO_DEPENDANT_SESSION_LOCK; 1164 1165 status = serverSessionLock_Prologue(LOCK_ACCESS_WRITE, pResourceRef, 1166 pLockInfo, &releaseFlags); 1167 if (status != NV_OK) 1168 goto done; 1169 1170 if (pResourceRef->pSession != NULL) 1171 { 1172 if (!pResourceRef->pSession->bValid) 1173 { 1174 status = NV_ERR_RESOURCE_LOST; 1175 goto done; 1176 } 1177 } 1178 1179 portMemSet(&callContext, 0, sizeof(callContext)); 1180 callContext.pResourceRef = pResourceRef; 1181 callContext.pClient = pClient; 1182 callContext.secInfo = pParams->secInfo; 1183 callContext.pServer = pServer; 1184 callContext.pControlParams = pParams; 1185 callContext.pLockInfo = pParams->pLockInfo; 1186 1187 // RS-TODO removeme 1188 pParams->pLegacyParams = pParams; 1189 1190 if (pParams->hClient == pParams->hObject) 1191 { 1192 pParams->hParent = pParams->hClient; 1193 } 1194 else 1195 { 1196 pParams->hParent = pResourceRef->pParentRef->hResource; 1197 } 1198 pLockInfo->pContextRef = pResourceRef->pParentRef; 1199 1200 resservSwapTlsCallContext(&pOldContext, &callContext); 1201 status = resControl(pResourceRef->pResource, &callContext, pParams); 1202 resservRestoreTlsCallContext(pOldContext); 1203 1204 done: 1205 1206 serverSessionLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1207 1208 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags); 1209 serverTopLock_Epilogue(pServer, access, pLockInfo, &releaseFlags); 1210 1211 if (pServer->bUnlockedParamCopy) 1212 { 1213 status = serverControlApiCopyOut(pServer, pParams, pParams->pCookie, status); 1214 } 1215 1216 return status; 1217 } 1218 1219 NV_STATUS 1220 serverCopyResource 1221 ( 1222 RsServer *pServer, 1223 RS_RES_DUP_PARAMS *pParams 1224 ) 1225 { 1226 NV_STATUS status; 1227 RS_LOCK_INFO *pLockInfo = pParams->pLockInfo; 1228 NvU32 releaseFlags = 0; 1229 RsClient *pClientSrc; 1230 RsClient *pClientDst; 1231 RsResourceRef *pResourceRefSrc; 1232 LOCK_ACCESS_TYPE topLockAccess; 1233 1234 NvHandle hClientSrc = pParams->hClientSrc; 1235 NvHandle hClientDst = pParams->hClientDst; 1236 1237 if (!pServer->bConstructed) 1238 return NV_ERR_NOT_READY; 1239 1240 NV_ASSERT_OR_RETURN(pLockInfo != NULL, NV_ERR_INVALID_ARGUMENT); 1241 1242 status = serverCopyResourceLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 1243 if (status != NV_OK) 1244 goto done; 1245 1246 status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1247 if (status != NV_OK) 1248 goto done; 1249 1250 status = _serverLockDualClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, 1251 hClientSrc, hClientDst, 1252 pLockInfo, &releaseFlags, 1253 &pClientSrc, &pClientDst); 1254 if (status != NV_OK) 1255 goto done; 1256 1257 if (!pClientSrc->bActive || !pClientDst->bActive) 1258 { 1259 status = NV_ERR_INVALID_STATE; 1260 goto done; 1261 } 1262 1263 status = clientValidate(pClientDst, pParams->pSecInfo); 1264 if (status != NV_OK) 1265 goto done; 1266 1267 status = clientGetResourceRef(pClientSrc, pParams->hResourceSrc, &pResourceRefSrc); 1268 if (status != NV_OK) 1269 goto done; 1270 1271 if (pResourceRefSrc->bInvalidated) 1272 { 1273 status = NV_ERR_RESOURCE_LOST; 1274 goto done; 1275 } 1276 1277 if (!resCanCopy(pResourceRefSrc->pResource)) 1278 { 1279 status = NV_ERR_INVALID_ARGUMENT; 1280 goto done; 1281 } 1282 1283 status = clientAssignResourceHandle(pClientDst, &pParams->hResourceDst); 1284 if (status != NV_OK) 1285 goto done; 1286 1287 pParams->pSrcClient = pClientSrc; 1288 pParams->pSrcRef = pResourceRefSrc; 1289 1290 status = serverUpdateLockFlagsForCopy(pServer, pParams); 1291 if (status != NV_OK) 1292 return status; 1293 1294 status = serverResLock_Prologue(pServer, LOCK_ACCESS_WRITE, pParams->pLockInfo, &releaseFlags); 1295 if (status != NV_OK) 1296 goto done; 1297 1298 status = clientCopyResource(pClientDst, pServer, pParams); 1299 if (status != NV_OK) 1300 goto done; 1301 1302 // NV_PRINTF(LEVEL_INFO, "hClient %x: Copied hResource: %x from hClientSrc: %x hResourceSrc: %x\n", 1303 // hClientDst, hResourceDst, hClientSrc, hResourceSrc); 1304 1305 done: 1306 serverResLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pParams->pLockInfo, &releaseFlags); 1307 1308 _serverUnlockDualClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, 1309 hClientSrc, hClientDst, 1310 pLockInfo, &releaseFlags); 1311 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1312 1313 return status; 1314 } 1315 1316 /** 1317 * Special case of serverShareResourceAccess for sharing with a specific client 1318 * Requires two client locks, so separated into a different function from the normal 1319 * @param[in] pServer 1320 * @param[in] pParams Parameters passed into share function 1321 */ 1322 static NV_STATUS 1323 _serverShareResourceAccessClient 1324 ( 1325 RsServer *pServer, 1326 RS_RES_SHARE_PARAMS *pParams 1327 ) 1328 { 1329 NV_STATUS status; 1330 RS_LOCK_INFO *pLockInfo = pParams->pLockInfo; 1331 NvU32 releaseFlags = 0; 1332 RsClient *pClientOwner; 1333 RsClient *pClientTarget; 1334 RsResourceRef *pResourceRef; 1335 LOCK_ACCESS_TYPE topLockAccess; 1336 1337 NvHandle hClientOwner = pParams->hClient; 1338 NvHandle hClientTarget = pParams->pSharePolicy->target; 1339 1340 CALL_CONTEXT callContext; 1341 CALL_CONTEXT *pOldContext = NULL; 1342 1343 if (!pServer->bConstructed) 1344 return NV_ERR_NOT_READY; 1345 1346 status = serverShareResourceLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 1347 if (status != NV_OK) 1348 goto done; 1349 1350 status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1351 if (status != NV_OK) 1352 goto done; 1353 1354 status = _serverLockDualClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, 1355 hClientOwner, hClientTarget, 1356 pLockInfo, &releaseFlags, 1357 &pClientOwner, &pClientTarget); 1358 if (status != NV_OK) 1359 goto done; 1360 1361 status = clientGetResourceRef(pClientOwner, pParams->hResource, &pResourceRef); 1362 if (status != NV_OK) 1363 goto done; 1364 1365 if (pResourceRef->bInvalidated) 1366 { 1367 status = NV_ERR_RESOURCE_LOST; 1368 goto done; 1369 } 1370 1371 portMemSet(&callContext, 0, sizeof(callContext)); 1372 callContext.pServer = pServer; 1373 callContext.pClient = pClientOwner; 1374 callContext.pResourceRef = pResourceRef; 1375 callContext.secInfo = *pParams->pSecInfo; 1376 callContext.pLockInfo = pParams->pLockInfo; 1377 resservSwapTlsCallContext(&pOldContext, &callContext); 1378 1379 if (hClientOwner == hClientTarget) 1380 { 1381 // 1382 // Special case: RS_SHARE_TYPE_CLIENT with own client 1383 // Allows the caller to directly modify the access map of their object 1384 // 1385 status = clientShareResourceTargetClient(pClientOwner, pResourceRef, pParams->pSharePolicy, &callContext); 1386 if (status != NV_OK) 1387 goto restore_context; 1388 } 1389 1390 // Add backref into pClientTarget to prevent stale client handles 1391 status = clientAddAccessBackRef(pClientTarget, pResourceRef); 1392 if (status != NV_OK) 1393 goto restore_context; 1394 1395 status = clientShareResource(pClientOwner, pResourceRef, pParams->pSharePolicy, &callContext); 1396 if (status != NV_OK) 1397 goto restore_context; 1398 1399 restore_context: 1400 resservRestoreTlsCallContext(pOldContext); 1401 1402 // NV_PRINTF(LEVEL_INFO, "hClientOwner %x: Shared hResource: %x with hClientTarget: %x\n", 1403 // hClientOwner, pParams->hResource, hClientTarget); 1404 1405 done: 1406 _serverUnlockDualClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, 1407 hClientOwner, hClientTarget, 1408 pLockInfo, &releaseFlags); 1409 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1410 1411 return status; 1412 } 1413 1414 1415 NV_STATUS 1416 serverShareResourceAccess 1417 ( 1418 RsServer *pServer, 1419 RS_RES_SHARE_PARAMS *pParams 1420 ) 1421 { 1422 NV_STATUS status; 1423 RS_LOCK_INFO *pLockInfo; 1424 NvU32 releaseFlags = 0; 1425 RsClient *pClient; 1426 RsResourceRef *pResourceRef; 1427 NvU16 shareType; 1428 CALL_CONTEXT callContext; 1429 CALL_CONTEXT *pOldContext = NULL; 1430 LOCK_ACCESS_TYPE topLockAccess; 1431 1432 if (!pServer->bConstructed) 1433 return NV_ERR_NOT_READY; 1434 1435 if (!pServer->bRsAccessEnabled) 1436 return NV_ERR_FEATURE_NOT_ENABLED; 1437 1438 if (pParams->pSharePolicy == NULL) 1439 return NV_ERR_INVALID_ARGUMENT; 1440 1441 shareType = pParams->pSharePolicy->type; 1442 if (shareType >= RS_SHARE_TYPE_MAX) 1443 return NV_ERR_INVALID_ARGUMENT; 1444 1445 pLockInfo = pParams->pLockInfo; 1446 NV_ASSERT_OR_RETURN(pLockInfo != NULL, NV_ERR_INVALID_ARGUMENT); 1447 1448 if (shareType == RS_SHARE_TYPE_CLIENT) 1449 { 1450 // Special case: This requires two locks, so it has its own function 1451 return _serverShareResourceAccessClient(pServer, pParams); 1452 } 1453 1454 status = serverShareResourceLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 1455 if (status != NV_OK) 1456 goto done; 1457 1458 status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1459 if (status != NV_OK) 1460 goto done; 1461 1462 status = _serverLockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags, &pClient); 1463 if (status != NV_OK) 1464 goto done; 1465 1466 status = clientValidate(pClient, pParams->pSecInfo); 1467 if (status != NV_OK) 1468 goto done; 1469 1470 status = clientGetResourceRef(pClient, pParams->hResource, &pResourceRef); 1471 if (status != NV_OK) 1472 goto done; 1473 1474 if (pResourceRef->bInvalidated) 1475 { 1476 status = NV_ERR_RESOURCE_LOST; 1477 goto done; 1478 } 1479 1480 portMemSet(&callContext, 0, sizeof(callContext)); 1481 callContext.pServer = pServer; 1482 callContext.pClient = pClient; 1483 callContext.pResourceRef = pResourceRef; 1484 callContext.secInfo = *pParams->pSecInfo; 1485 callContext.pLockInfo = pParams->pLockInfo; 1486 1487 resservSwapTlsCallContext(&pOldContext, &callContext); 1488 status = clientShareResource(pClient, pResourceRef, pParams->pSharePolicy, &callContext); 1489 resservRestoreTlsCallContext(pOldContext); 1490 if (status != NV_OK) 1491 goto done; 1492 1493 // NV_PRINTF(LEVEL_INFO, "hClient %x: Shared hResource: %x\n", hClient, pParams->hResource); 1494 1495 done: 1496 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags); 1497 1498 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1499 1500 return status; 1501 } 1502 1503 NV_STATUS 1504 serverMap 1505 ( 1506 RsServer *pServer, 1507 NvHandle hClient, 1508 NvHandle hResource, 1509 RS_CPU_MAP_PARAMS *pParams 1510 ) 1511 { 1512 NV_STATUS status = NV_ERR_INVALID_STATE; 1513 CALL_CONTEXT callContext; 1514 CALL_CONTEXT *pOldContext = NULL; 1515 RsClient *pClient; 1516 RsResourceRef *pResourceRef; 1517 RsResourceRef *pContextRef = NULL; 1518 RsResource *pResource; 1519 RsCpuMapping *pCpuMapping = NULL; 1520 RS_LOCK_INFO *pLockInfo; 1521 NvU32 releaseFlags = 0; 1522 LOCK_ACCESS_TYPE topLockAccess = LOCK_ACCESS_WRITE; 1523 1524 pLockInfo = pParams->pLockInfo; 1525 NV_ASSERT_OR_GOTO(pLockInfo != NULL, done); 1526 1527 status = serverMapLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 1528 if (status != NV_OK) 1529 goto done; 1530 1531 status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1532 if (status != NV_OK) 1533 goto done; 1534 1535 status = _serverLockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, hClient, pLockInfo, &releaseFlags, &pClient); 1536 if (status != NV_OK) 1537 goto done; 1538 1539 if (!pClient->bActive) 1540 { 1541 status = NV_ERR_INVALID_STATE; 1542 goto done; 1543 } 1544 1545 status = clientValidate(pClient, pParams->pSecInfo); 1546 if (status != NV_OK) 1547 goto done; 1548 1549 status = clientGetResourceRef(pClient, hResource, &pResourceRef); 1550 if (status != NV_OK) 1551 goto done; 1552 1553 pResource = pResourceRef->pResource; 1554 if (pResource == NULL) 1555 { 1556 status = NV_ERR_NOT_SUPPORTED; 1557 goto done; 1558 } 1559 1560 status = serverMap_Prologue(pServer, pParams); 1561 if (status != NV_OK) 1562 goto done; 1563 1564 status = serverResLock_Prologue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1565 if (status != NV_OK) 1566 goto done; 1567 1568 if (pParams->hContext != 0) 1569 { 1570 status = clientGetResourceRef(pClient, pParams->hContext, &pContextRef); 1571 if (status != NV_OK) 1572 { 1573 NV_PRINTF(LEVEL_INFO, "hClient %x: Cannot find hContext: 0x%x\n", pClient->hClient, pParams->hContext); 1574 goto done; 1575 } 1576 } 1577 1578 status = refAddMapping(pResourceRef, pParams, pContextRef, &pCpuMapping); 1579 if (status != NV_OK) 1580 goto done; 1581 1582 portMemSet(&callContext, 0, sizeof(callContext)); 1583 callContext.pClient = pClient; 1584 callContext.pResourceRef = pResourceRef; 1585 callContext.pLockInfo = pParams->pLockInfo; 1586 1587 // Some MODS tests don't set secInfo. 1588 if (pParams->pSecInfo != NULL) 1589 callContext.secInfo = *pParams->pSecInfo; 1590 1591 resservSwapTlsCallContext(&pOldContext, &callContext); 1592 status = resMap(pResource, &callContext, pParams, pCpuMapping); 1593 resservRestoreTlsCallContext(pOldContext); 1594 1595 if (status != NV_OK) 1596 goto done; 1597 1598 // NV_PRINTF(LEVEL_INFO, "hClient %x: Mapped hResource: 0x%x hContext: %x at addr: " NvP64_fmt "\n", 1599 // hClient, hResource, pParams->hContext, pCpuMapping->pAddress); 1600 1601 if (pParams->ppCpuVirtAddr != NULL) 1602 *pParams->ppCpuVirtAddr = pCpuMapping->pLinearAddress; 1603 1604 done: 1605 if (status != NV_OK) 1606 { 1607 if (pCpuMapping != NULL) 1608 refRemoveMapping(pResourceRef, pCpuMapping); 1609 } 1610 1611 serverResLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1612 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, hClient, pLockInfo, &releaseFlags); 1613 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1614 1615 return status; 1616 } 1617 1618 NV_STATUS 1619 serverUnmap 1620 ( 1621 RsServer *pServer, 1622 NvHandle hClient, 1623 NvHandle hResource, 1624 RS_CPU_UNMAP_PARAMS *pParams 1625 ) 1626 { 1627 NV_STATUS status = NV_ERR_INVALID_STATE; 1628 RsClient *pClient; 1629 RsResourceRef *pResourceRef; 1630 RsResource *pResource; 1631 RsCpuMapping *pCpuMapping; 1632 RS_LOCK_INFO *pLockInfo; 1633 NvU32 releaseFlags = 0; 1634 LOCK_ACCESS_TYPE topLockAccess = LOCK_ACCESS_WRITE; 1635 1636 pLockInfo = pParams->pLockInfo; 1637 NV_ASSERT_OR_GOTO(pLockInfo != NULL, done); 1638 1639 status = serverUnmapLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 1640 if (status != NV_OK) 1641 goto done; 1642 1643 status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1644 if (status != NV_OK) 1645 goto done; 1646 1647 status = _serverLockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, hClient, pLockInfo, &releaseFlags, &pClient); 1648 if (status != NV_OK) 1649 goto done; 1650 1651 status = clientValidate(pClient, pParams->pSecInfo); 1652 if (status != NV_OK) 1653 goto done; 1654 1655 status = clientGetResourceRef(pClient, hResource, &pResourceRef); 1656 if (status != NV_OK) 1657 goto done; 1658 1659 pResource = pResourceRef->pResource; 1660 if (pResource == NULL) 1661 { 1662 status = NV_ERR_NOT_SUPPORTED; 1663 goto done; 1664 } 1665 1666 status = serverUnmap_Prologue(pServer, pParams); 1667 if (status != NV_OK) 1668 goto done; 1669 1670 status = refFindCpuMappingWithFilter(pResourceRef, 1671 pParams->pLinearAddress, 1672 pParams->fnFilter, 1673 &pCpuMapping); 1674 if (status != NV_OK) 1675 goto done; 1676 1677 status = serverResLock_Prologue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1678 if (status != NV_OK) 1679 goto done; 1680 1681 status = clientUnmapMemory(pClient, pResourceRef, pLockInfo, &pCpuMapping, pParams->pSecInfo); 1682 1683 done: 1684 serverUnmap_Epilogue(pServer, pParams); 1685 serverResLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1686 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, hClient, pLockInfo, &releaseFlags); 1687 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1688 1689 return status; 1690 } 1691 1692 NV_STATUS 1693 serverInterMap 1694 ( 1695 RsServer *pServer, 1696 RS_INTER_MAP_PARAMS *pParams 1697 ) 1698 { 1699 RsClient *pClient; 1700 RsResourceRef *pMapperRef; 1701 RsResourceRef *pMappableRef; 1702 RsResourceRef *pContextRef; 1703 RsInterMapping *pMapping = NULL; 1704 LOCK_ACCESS_TYPE topLockAccess; 1705 1706 NV_STATUS status; 1707 RS_LOCK_INFO *pLockInfo = pParams->pLockInfo; 1708 NvU32 releaseFlags = 0; 1709 CALL_CONTEXT callContext; 1710 CALL_CONTEXT *pOldContext = NULL; 1711 NvBool bRestoreCallContext = NV_FALSE; 1712 1713 NV_ASSERT_OR_RETURN(pLockInfo != NULL, NV_ERR_INVALID_ARGUMENT); 1714 1715 if (pParams->length == 0) 1716 return NV_ERR_INVALID_LIMIT; 1717 1718 status = serverInterMapLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 1719 if (status != NV_OK) 1720 goto done; 1721 1722 status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1723 if (status != NV_OK) 1724 goto done; 1725 1726 status = _serverLockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, 1727 pLockInfo, &releaseFlags, &pClient); 1728 if (status != NV_OK) 1729 goto done; 1730 1731 if (!pClient->bActive) 1732 { 1733 status = NV_ERR_INVALID_STATE; 1734 goto done; 1735 } 1736 1737 status = clientValidate(pClient, pParams->pSecInfo); 1738 if (status != NV_OK) 1739 goto done; 1740 1741 status = clientGetResourceRef(pClient, pParams->hMapper, &pMapperRef); 1742 if (status != NV_OK) 1743 goto done; 1744 1745 status = clientGetResourceRef(pClient, pParams->hMappable, &pMappableRef); 1746 if (status != NV_OK) 1747 goto done; 1748 1749 status = clientGetResourceRef(pClient, pParams->hDevice, &pContextRef); 1750 if (status != NV_OK) 1751 goto done; 1752 1753 pLockInfo->pContextRef = pContextRef; 1754 1755 portMemSet(&callContext, 0, sizeof(callContext)); 1756 callContext.pServer = pServer; 1757 callContext.pClient = pClient; 1758 callContext.pResourceRef = pMapperRef; 1759 callContext.pContextRef = pContextRef; 1760 callContext.pLockInfo = pLockInfo; 1761 1762 // Some MODS tests don't set secInfo. 1763 if (pParams->pSecInfo != NULL) 1764 callContext.secInfo = *pParams->pSecInfo; 1765 1766 resservSwapTlsCallContext(&pOldContext, &callContext); 1767 bRestoreCallContext = NV_TRUE; 1768 1769 status = refAddInterMapping(pMapperRef, pMappableRef, pContextRef, &pMapping); 1770 if (status != NV_OK) 1771 goto done; 1772 1773 // serverResLock_Prologue should be called during serverInterMap_Prologue 1774 status = serverInterMap_Prologue(pServer, pMapperRef, pMappableRef, pParams, &releaseFlags); 1775 if (status != NV_OK) 1776 goto done; 1777 1778 status = clientInterMap(pClient, pMapperRef, pMappableRef, pParams); 1779 if (status != NV_OK) 1780 goto done; 1781 1782 pMapping->flags = pParams->flags; 1783 pMapping->dmaOffset = pParams->dmaOffset; 1784 pMapping->pMemDesc = pParams->pMemDesc; 1785 1786 done: 1787 serverInterMap_Epilogue(pServer, pParams, &releaseFlags); 1788 1789 if (bRestoreCallContext) 1790 resservRestoreTlsCallContext(pOldContext); 1791 1792 if (status != NV_OK) 1793 { 1794 if (pMapping != NULL) 1795 refRemoveInterMapping(pMapperRef, pMapping); 1796 } 1797 1798 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags); 1799 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1800 1801 return status; 1802 } 1803 1804 NV_STATUS 1805 serverInterUnmap 1806 ( 1807 RsServer *pServer, 1808 RS_INTER_UNMAP_PARAMS *pParams 1809 ) 1810 { 1811 RsClient *pClient; 1812 RsResourceRef *pMapperRef; 1813 RsResourceRef *pMappableRef; 1814 RsResourceRef *pContextRef; 1815 RsInterMapping *pMapping; 1816 LOCK_ACCESS_TYPE topLockAccess; 1817 1818 NV_STATUS status; 1819 RS_LOCK_INFO *pLockInfo = pParams->pLockInfo; 1820 NvU32 releaseFlags = 0; 1821 CALL_CONTEXT callContext; 1822 CALL_CONTEXT *pOldContext = NULL; 1823 NvBool bRestoreCallContext = NV_FALSE; 1824 1825 NV_ASSERT_OR_RETURN(pLockInfo != NULL, NV_ERR_INVALID_ARGUMENT); 1826 1827 status = serverInterUnmapLookupLockFlags(pServer, RS_LOCK_TOP, pParams, &topLockAccess); 1828 if (status != NV_OK) 1829 goto done; 1830 1831 status = serverTopLock_Prologue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1832 if (status != NV_OK) 1833 goto done; 1834 1835 status = _serverLockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, 1836 pLockInfo, &releaseFlags, &pClient); 1837 if (status != NV_OK) 1838 goto done; 1839 1840 status = clientValidate(pClient, pParams->pSecInfo); 1841 if (status != NV_OK) 1842 goto done; 1843 1844 status = clientGetResourceRef(pClient, pParams->hMapper, &pMapperRef); 1845 if (status != NV_OK) 1846 goto done; 1847 1848 if ((pMapperRef->bInvalidated) && (pMapperRef->pResource == NULL)) 1849 { 1850 // Object has already been freed and unmapped 1851 goto done; 1852 } 1853 1854 status = clientGetResourceRef(pClient, pParams->hMappable, &pMappableRef); 1855 if (status != NV_OK) 1856 goto done; 1857 1858 status = clientGetResourceRef(pClient, pParams->hDevice, &pContextRef); 1859 if (status != NV_OK) 1860 goto done; 1861 1862 status = refFindInterMapping(pMapperRef, pMappableRef, pContextRef, pParams->dmaOffset, &pMapping); 1863 if (status != NV_OK) 1864 goto done; 1865 1866 portMemSet(&callContext, 0, sizeof(callContext)); 1867 callContext.pServer = pServer; 1868 callContext.pClient = pClient; 1869 callContext.pResourceRef = pMapperRef; 1870 callContext.pContextRef = pContextRef; 1871 callContext.pLockInfo = pLockInfo; 1872 1873 // Some MODS tests don't set secInfo. 1874 if (pParams->pSecInfo != NULL) 1875 callContext.secInfo = *pParams->pSecInfo; 1876 1877 if (pLockInfo->pContextRef == NULL) 1878 pLockInfo->pContextRef = pContextRef; 1879 1880 resservSwapTlsCallContext(&pOldContext, &callContext); 1881 bRestoreCallContext = NV_TRUE; 1882 1883 status = serverResLock_Prologue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1884 if (status != NV_OK) 1885 goto done; 1886 1887 status = serverInterUnmap_Prologue(pServer, pParams); 1888 if (status != NV_OK) 1889 goto done; 1890 1891 clientInterUnmap(pClient, pMapperRef, pParams); 1892 1893 refRemoveInterMapping(pMapperRef, pMapping); 1894 1895 done: 1896 serverInterUnmap_Epilogue(pServer, pParams); 1897 1898 serverResLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pLockInfo, &releaseFlags); 1899 1900 if (bRestoreCallContext) 1901 resservRestoreTlsCallContext(pOldContext); 1902 1903 _serverUnlockClientWithLockInfo(pServer, LOCK_ACCESS_WRITE, pParams->hClient, pLockInfo, &releaseFlags); 1904 serverTopLock_Epilogue(pServer, topLockAccess, pLockInfo, &releaseFlags); 1905 1906 return status; 1907 } 1908 1909 NV_STATUS 1910 serverAcquireClient 1911 ( 1912 RsServer *pServer, 1913 NvHandle hClient, 1914 LOCK_ACCESS_TYPE lockAccess, 1915 RsClient **ppClient 1916 ) 1917 { 1918 NV_STATUS status; 1919 RsClient *pClient; 1920 1921 // NV_PRINTF(LEVEL_INFO, "Acquiring hClient %x\n", hClient); 1922 status = _serverLockClient(pServer, lockAccess, hClient, &pClient); 1923 if (status != NV_OK) 1924 return status; 1925 1926 if (ppClient != NULL) 1927 *ppClient = pClient; 1928 1929 return NV_OK; 1930 } 1931 1932 NV_STATUS 1933 serverGetClientUnderLock 1934 ( 1935 RsServer *pServer, 1936 NvHandle hClient, 1937 RsClient **ppClient 1938 ) 1939 { 1940 NV_STATUS status; 1941 RsClient *pClient; 1942 1943 // NV_PRINTF(LEVEL_INFO, "Acquiring hClient %x (without lock)\n", hClient); 1944 status = _serverFindClient(pServer, hClient, &pClient); 1945 if (status != NV_OK) 1946 { 1947 return status; 1948 } 1949 1950 if (ppClient != NULL) 1951 *ppClient = pClient; 1952 1953 return NV_OK; 1954 } 1955 1956 NV_STATUS 1957 serverReleaseClient 1958 ( 1959 RsServer *pServer, 1960 LOCK_ACCESS_TYPE lockAccess, 1961 RsClient *pClient 1962 ) 1963 { 1964 NV_STATUS status; 1965 status = _serverUnlockClient(pServer, lockAccess, pClient->hClient); 1966 return status; 1967 } 1968 1969 static 1970 NV_STATUS 1971 _serverFindClientEntry 1972 ( 1973 RsServer *pServer, 1974 NvHandle hClient, 1975 NvBool bFindPartial, 1976 CLIENT_ENTRY **ppClientEntry 1977 ) 1978 { 1979 RsClientList *pClientList = &(pServer->pClientSortedList[hClient & RS_CLIENT_HANDLE_BUCKET_MASK]); 1980 CLIENT_ENTRY **ppClientEntryLoop = listHead(pClientList); 1981 1982 if (ppClientEntry != NULL) 1983 *ppClientEntry = NULL; 1984 1985 while (ppClientEntryLoop != NULL) 1986 { 1987 CLIENT_ENTRY *pClientEntry = *ppClientEntryLoop; 1988 ppClientEntryLoop = listNext(pClientList, ppClientEntryLoop); 1989 if (pClientEntry == NULL) 1990 { 1991 continue; 1992 } 1993 else if (pClientEntry->hClient == hClient) 1994 { 1995 // Client may not have finished constructing yet 1996 if (pClientEntry->pClient == NULL && !bFindPartial) 1997 return NV_ERR_INVALID_OBJECT_HANDLE; 1998 1999 if (ppClientEntry != NULL) 2000 *ppClientEntry = pClientEntry; 2001 2002 return NV_OK; 2003 } 2004 else if (pClientEntry->hClient > hClient) 2005 { 2006 // Not found in sorted list 2007 return NV_ERR_INVALID_OBJECT; 2008 } 2009 } 2010 2011 return NV_ERR_INVALID_OBJECT_HANDLE; 2012 } 2013 2014 static 2015 NV_STATUS 2016 _serverFindClient 2017 ( 2018 RsServer *pServer, 2019 NvHandle hClient, 2020 RsClient **ppClient 2021 ) 2022 { 2023 CLIENT_ENTRY *pClientEntry; 2024 NV_STATUS status; 2025 status =_serverFindClientEntry(pServer, hClient, NV_FALSE, &pClientEntry); 2026 if (status != NV_OK) 2027 { 2028 return status; 2029 } 2030 2031 *ppClient = pClientEntry->pClient; 2032 return NV_OK; 2033 } 2034 2035 static 2036 NV_STATUS 2037 _serverInsertClientEntry 2038 ( 2039 RsServer *pServer, 2040 CLIENT_ENTRY *pClientEntry, 2041 CLIENT_ENTRY **ppClientNext 2042 ) 2043 { 2044 RsClientList *pClientList; 2045 CLIENT_ENTRY **ppClientEntry; 2046 NvHandle hClient = pClientEntry->hClient; 2047 2048 if (hClient == 0) 2049 { 2050 return NV_ERR_INVALID_OBJECT_HANDLE; 2051 } 2052 2053 pClientList = &(pServer->pClientSortedList[hClient & RS_CLIENT_HANDLE_BUCKET_MASK]); 2054 2055 if (ppClientNext == NULL) 2056 { 2057 ppClientEntry = (CLIENT_ENTRY **)listAppendNew(pClientList); 2058 } 2059 else 2060 { 2061 ppClientEntry = (CLIENT_ENTRY **)listInsertNew(pClientList, ppClientNext); 2062 } 2063 2064 if (ppClientEntry == NULL) 2065 { 2066 return NV_ERR_NO_MEMORY; 2067 } 2068 2069 *ppClientEntry = pClientEntry; 2070 2071 return NV_OK; 2072 } 2073 2074 static 2075 NV_STATUS 2076 _serverFindNextAvailableClientHandleInBucket 2077 ( 2078 RsServer *pServer, 2079 NvHandle hClientIn, 2080 NvHandle *phClientOut, 2081 CLIENT_ENTRY ***pppClientNext 2082 ) 2083 { 2084 NvHandle hPrefixIn, hPrefixOut; 2085 RsClientList *pClientList = &(pServer->pClientSortedList[hClientIn & RS_CLIENT_HANDLE_BUCKET_MASK]); 2086 NvHandle hClientOut = hClientIn; 2087 CLIENT_ENTRY **ppClientEntry = listHead(pClientList); 2088 2089 *pppClientNext = NULL; 2090 if (ppClientEntry == NULL) 2091 { 2092 *phClientOut = hClientOut; 2093 return NV_OK; 2094 } 2095 2096 // 2097 // The list is ordered by increased client handles 2098 // We need to find a value to insert or change the handle 2099 // 2100 while (ppClientEntry != NULL) 2101 { 2102 CLIENT_ENTRY *pClientEntry = *ppClientEntry; 2103 if ((pClientEntry == NULL) || (pClientEntry->hClient < hClientOut)) 2104 { 2105 ppClientEntry = listNext(pClientList, ppClientEntry); 2106 continue; 2107 } 2108 else if (pClientEntry->hClient == hClientOut) 2109 { 2110 // Increase client handle by one unit in same bucket 2111 hClientOut = hClientOut + RS_CLIENT_HANDLE_BUCKET_COUNT; 2112 NV_ASSERT((hClientIn & RS_CLIENT_HANDLE_BUCKET_MASK) == (hClientOut & RS_CLIENT_HANDLE_BUCKET_MASK)); 2113 } 2114 else // last pClientEntry->hClient > hClientOut 2115 { 2116 break; 2117 } 2118 ppClientEntry = listNext(pClientList, ppClientEntry); 2119 } 2120 2121 hPrefixIn = hClientIn & ~RS_CLIENT_HANDLE_DECODE_MASK; 2122 hPrefixOut = hClientOut & ~RS_CLIENT_HANDLE_DECODE_MASK; 2123 if (hPrefixIn != hPrefixOut) 2124 return NV_ERR_INSUFFICIENT_RESOURCES; 2125 2126 *phClientOut = hClientOut; 2127 if (ppClientEntry != NULL) 2128 { 2129 *pppClientNext = ppClientEntry; 2130 } 2131 return NV_OK; 2132 } 2133 2134 static 2135 NV_STATUS 2136 _serverCreateEntryAndLockForNewClient 2137 ( 2138 RsServer *pServer, 2139 NvHandle *phClient, 2140 NvBool bInternalHandle, 2141 CLIENT_ENTRY **ppClientEntry, 2142 API_SECURITY_INFO *pSecInfo 2143 ) 2144 { 2145 CLIENT_ENTRY *pClientEntry; 2146 NV_STATUS status = NV_OK; 2147 NvHandle hClient = *phClient; 2148 CLIENT_ENTRY **ppClientNext = 0; 2149 PORT_RWLOCK *pLock = NULL; 2150 NvU32 handleBase = serverAllocClientHandleBase(pServer, bInternalHandle, pSecInfo); 2151 2152 if (hClient == 0) 2153 { 2154 NvU32 clientHandleIndex = pServer->clientCurrentHandleIndex; 2155 NvU16 clientHandleBucketInit = clientHandleIndex & RS_CLIENT_HANDLE_BUCKET_MASK; 2156 do 2157 { 2158 hClient = CLIENT_ENCODEHANDLE(handleBase, clientHandleIndex); 2159 clientHandleIndex++; 2160 if (clientHandleIndex > RS_CLIENT_HANDLE_DECODE_MASK) 2161 { 2162 // We will override the client base, loop over 2163 clientHandleIndex = 0; 2164 } 2165 if (clientHandleBucketInit == (clientHandleIndex & RS_CLIENT_HANDLE_BUCKET_MASK)) 2166 { 2167 // We looked through all buckets and we did not find any available client (very unlikely) 2168 status = NV_ERR_INSUFFICIENT_RESOURCES; 2169 goto _serverCreateEntryAndLockForNewClient_exit; 2170 } 2171 } 2172 while (_serverFindNextAvailableClientHandleInBucket(pServer, hClient, &hClient, &ppClientNext) != NV_OK); 2173 2174 pServer->clientCurrentHandleIndex = clientHandleIndex; 2175 } 2176 else 2177 { 2178 NvHandle hClientOut = 0; 2179 2180 #if !(RS_COMPATABILITY_MODE) 2181 // Re-encode handle so it matches expected format 2182 NvU32 clientIndex = CLIENT_DECODEHANDLE(hClient); 2183 hClient = CLIENT_ENCODEHANDLE(handleBase, clientIndex); 2184 #endif 2185 2186 if (_serverFindClientEntry(pServer, hClient, NV_FALSE, NULL) == NV_OK) 2187 { 2188 // The handle already exists 2189 status = NV_ERR_INSERT_DUPLICATE_NAME; 2190 goto _serverCreateEntryAndLockForNewClient_exit; 2191 } 2192 status = _serverFindNextAvailableClientHandleInBucket(pServer, hClient, &hClientOut, &ppClientNext); 2193 if (status != NV_OK) 2194 { 2195 goto _serverCreateEntryAndLockForNewClient_exit; 2196 } 2197 if (hClient != hClientOut) 2198 { 2199 // This should not happen as we checked for duplicates already 2200 NV_PRINTF(LEVEL_ERROR, "Client handle mismatch: %x != %x.\n", hClient, hClientOut); 2201 status = NV_ERR_INVALID_STATE; 2202 goto _serverCreateEntryAndLockForNewClient_exit; 2203 } 2204 } 2205 2206 pLock = portSyncRwLockCreate(pServer->pAllocator); 2207 if (pLock == NULL) 2208 { 2209 status = NV_ERR_INSUFFICIENT_RESOURCES; 2210 goto _serverCreateEntryAndLockForNewClient_exit; 2211 } 2212 2213 // At this point we have a hClient, we know in which bucket and where in the bucket to insert the entry. 2214 pClientEntry = (CLIENT_ENTRY *)PORT_ALLOC(pServer->pAllocator, sizeof(CLIENT_ENTRY)); 2215 if (pClientEntry == NULL) 2216 { 2217 status = NV_ERR_INSUFFICIENT_RESOURCES; 2218 goto _serverCreateEntryAndLockForNewClient_exit; 2219 } 2220 portMemSet(pClientEntry, 0, sizeof(*pClientEntry)); 2221 2222 pClientEntry->hClient = hClient; 2223 pClientEntry->pLock = pLock; 2224 2225 2226 RS_LOCK_VALIDATOR_INIT(&pClientEntry->lockVal, 2227 bInternalHandle ? LOCK_VAL_LOCK_CLASS_CLIENT_INTERNAL : LOCK_VAL_LOCK_CLASS_CLIENT, 2228 hClient); 2229 2230 status = _serverInsertClientEntry(pServer, pClientEntry, ppClientNext); 2231 if (status != NV_OK) 2232 { 2233 PORT_FREE(pServer->pAllocator, pClientEntry); 2234 goto _serverCreateEntryAndLockForNewClient_exit; 2235 } 2236 2237 RS_RWLOCK_ACQUIRE_WRITE(pClientEntry->pLock, &pClientEntry->lockVal); 2238 pClientEntry->lockOwnerTid = portThreadGetCurrentThreadId(); 2239 2240 *phClient = hClient; 2241 *ppClientEntry = pClientEntry; 2242 2243 _serverCreateEntryAndLockForNewClient_exit: 2244 if (status != NV_OK && pLock != NULL) 2245 portSyncRwLockDestroy(pLock); 2246 2247 return status; 2248 } 2249 2250 2251 static 2252 NV_STATUS 2253 _serverLockClient 2254 ( 2255 RsServer *pServer, 2256 LOCK_ACCESS_TYPE access, 2257 NvHandle hClient, 2258 RsClient **ppClient 2259 ) 2260 { 2261 RsClient *pClient; 2262 CLIENT_ENTRY *pClientEntry = NULL; 2263 NV_STATUS status = NV_OK; 2264 2265 status =_serverFindClientEntry(pServer, hClient, NV_FALSE, &pClientEntry); 2266 if (status != NV_OK) 2267 { 2268 return status; 2269 } 2270 2271 nv_speculation_barrier(); 2272 2273 if (pClientEntry->pLock == NULL) 2274 { 2275 return NV_ERR_INVALID_OBJECT_HANDLE; 2276 } 2277 2278 if (access == LOCK_ACCESS_READ) 2279 { 2280 RS_RWLOCK_ACQUIRE_READ(pClientEntry->pLock, &pClientEntry->lockVal); 2281 } 2282 else 2283 { 2284 RS_RWLOCK_ACQUIRE_WRITE(pClientEntry->pLock, &pClientEntry->lockVal); 2285 pClientEntry->lockOwnerTid = portThreadGetCurrentThreadId(); 2286 } 2287 2288 pClient = pClientEntry->pClient; 2289 NV_ASSERT(pClient->hClient == pClientEntry->hClient); 2290 2291 if ((pClient == NULL) || (pClient->hClient != hClient)) 2292 { 2293 if (access == LOCK_ACCESS_READ) 2294 RS_RWLOCK_RELEASE_READ(pClientEntry->pLock, &pClientEntry->lockVal); 2295 else 2296 RS_RWLOCK_RELEASE_WRITE(pClientEntry->pLock, &pClientEntry->lockVal); 2297 2298 return NV_ERR_INVALID_OBJECT; 2299 } 2300 2301 if (ppClient != NULL) 2302 *ppClient = pClient; 2303 2304 return NV_OK; 2305 } 2306 2307 static 2308 NV_STATUS 2309 _serverLockClientWithLockInfo 2310 ( 2311 RsServer *pServer, 2312 LOCK_ACCESS_TYPE access, 2313 NvHandle hClient, 2314 RS_LOCK_INFO *pLockInfo, 2315 NvU32 *pReleaseFlags, 2316 RsClient **ppClient 2317 ) 2318 { 2319 NV_STATUS status; 2320 if ((pLockInfo->flags & RS_LOCK_FLAGS_NO_CLIENT_LOCK)) 2321 { 2322 status = _serverFindClient(pServer, hClient, ppClient); 2323 return status; 2324 } 2325 2326 if ((pLockInfo->state & RS_LOCK_STATE_CLIENT_LOCK_ACQUIRED)) 2327 { 2328 CLIENT_ENTRY *pClientEntry; 2329 NV_ASSERT_OK_OR_RETURN(_serverFindClientEntry(pServer, hClient, NV_FALSE, &pClientEntry)); 2330 NV_ASSERT_OR_RETURN(pLockInfo->pClient != NULL, NV_ERR_INVALID_STATE); 2331 NV_ASSERT_OR_RETURN(pLockInfo->pClient == pClientEntry->pClient, NV_ERR_INVALID_STATE); 2332 NV_ASSERT_OR_RETURN(pClientEntry->lockOwnerTid == portThreadGetCurrentThreadId(), NV_ERR_INVALID_STATE); 2333 2334 *ppClient = pLockInfo->pClient; 2335 return NV_OK; 2336 } 2337 2338 status = _serverLockClient(pServer, access, hClient, ppClient); 2339 if (status != NV_OK) 2340 return status; 2341 2342 pLockInfo->state |= RS_LOCK_STATE_CLIENT_LOCK_ACQUIRED; 2343 pLockInfo->pClient = *ppClient; 2344 *pReleaseFlags |= RS_LOCK_RELEASE_CLIENT_LOCK; 2345 2346 return NV_OK; 2347 } 2348 2349 static 2350 NV_STATUS 2351 _serverLockDualClientWithLockInfo 2352 ( 2353 RsServer *pServer, 2354 LOCK_ACCESS_TYPE access, 2355 NvHandle hClient1, 2356 NvHandle hClient2, 2357 RS_LOCK_INFO *pLockInfo, 2358 NvU32 *pReleaseFlags, 2359 RsClient **ppClient1, 2360 RsClient **ppClient2 2361 ) 2362 { 2363 NV_STATUS status; 2364 2365 // 1st and 2nd in handle order, as opposed to fixed 1 and 2 2366 NvHandle hClient1st; 2367 NvHandle hClient2nd; 2368 RsClient **ppClient1st; 2369 RsClient **ppClient2nd; 2370 2371 *ppClient1 = NULL; 2372 *ppClient2 = NULL; 2373 2374 if ((pLockInfo->flags & RS_LOCK_FLAGS_NO_CLIENT_LOCK)) 2375 { 2376 status = _serverFindClient(pServer, hClient1, ppClient1); 2377 if (status != NV_OK) 2378 return status; 2379 2380 if (hClient1 == hClient2) 2381 { 2382 *ppClient2 = *ppClient1; 2383 } 2384 else 2385 { 2386 status = _serverFindClient(pServer, hClient2, ppClient2); 2387 } 2388 2389 return status; 2390 } 2391 2392 if (hClient1 <= hClient2) 2393 { 2394 hClient1st = hClient1; 2395 ppClient1st = ppClient1; 2396 2397 hClient2nd = hClient2; 2398 ppClient2nd = ppClient2; 2399 } 2400 else 2401 { 2402 hClient1st = hClient2; 2403 ppClient1st = ppClient2; 2404 2405 hClient2nd = hClient1; 2406 ppClient2nd = ppClient1; 2407 } 2408 2409 if ((pLockInfo->state & RS_LOCK_STATE_CLIENT_LOCK_ACQUIRED)) 2410 { 2411 CLIENT_ENTRY *pClientEntry, *pSecondClientEntry; 2412 2413 NV_ASSERT_OR_RETURN(pLockInfo->pSecondClient != NULL, NV_ERR_INVALID_STATE); 2414 NV_ASSERT_OR_RETURN(pLockInfo->pClient->hClient == hClient1st, NV_ERR_INVALID_STATE); 2415 NV_ASSERT_OR_RETURN(pLockInfo->pSecondClient->hClient == hClient2nd, NV_ERR_INVALID_STATE); 2416 2417 NV_ASSERT_OK_OR_RETURN(_serverFindClientEntry(pServer, hClient1st, NV_FALSE, &pClientEntry)); 2418 NV_ASSERT_OR_RETURN(pClientEntry->pClient == pLockInfo->pClient, NV_ERR_INVALID_STATE); 2419 NV_ASSERT_OR_RETURN(pClientEntry->lockOwnerTid == portThreadGetCurrentThreadId(), NV_ERR_INVALID_STATE); 2420 2421 NV_ASSERT_OK_OR_RETURN(_serverFindClientEntry(pServer, hClient2nd, NV_FALSE, &pSecondClientEntry)); 2422 NV_ASSERT_OR_RETURN(pSecondClientEntry->pClient == pLockInfo->pSecondClient, NV_ERR_INVALID_STATE); 2423 NV_ASSERT_OR_RETURN(pSecondClientEntry->lockOwnerTid == pClientEntry->lockOwnerTid, NV_ERR_INVALID_STATE); 2424 2425 *ppClient1st = pLockInfo->pClient; 2426 *ppClient2nd = pLockInfo->pSecondClient; 2427 return NV_OK; 2428 } 2429 2430 status = _serverLockClient(pServer, access, hClient1st, ppClient1st); 2431 if (status != NV_OK) 2432 return status; 2433 2434 if (hClient1 == hClient2) 2435 { 2436 *ppClient2nd = *ppClient1st; 2437 } 2438 else 2439 { 2440 status = _serverLockClient(pServer, access, hClient2nd, ppClient2nd); 2441 if (status != NV_OK) 2442 { 2443 _serverUnlockClient(pServer, access, hClient1st); 2444 return status; 2445 } 2446 } 2447 2448 pLockInfo->state |= RS_LOCK_STATE_CLIENT_LOCK_ACQUIRED; 2449 pLockInfo->pClient = *ppClient1st; 2450 pLockInfo->pSecondClient = *ppClient2nd; 2451 *pReleaseFlags |= RS_LOCK_RELEASE_CLIENT_LOCK; 2452 2453 return NV_OK; 2454 } 2455 2456 static 2457 NV_STATUS 2458 _serverUnlockClient 2459 ( 2460 RsServer *pServer, 2461 LOCK_ACCESS_TYPE access, 2462 NvHandle hClient 2463 ) 2464 { 2465 CLIENT_ENTRY *pClientEntry = NULL; 2466 NV_STATUS status = NV_OK; 2467 2468 status =_serverFindClientEntry(pServer, hClient, NV_TRUE, &pClientEntry); 2469 if (status != NV_OK) 2470 { 2471 return status; 2472 } 2473 2474 if (access == LOCK_ACCESS_READ) 2475 { 2476 RS_RWLOCK_RELEASE_READ(pClientEntry->pLock, &pClientEntry->lockVal); 2477 } 2478 else 2479 { 2480 pClientEntry->lockOwnerTid = ~0; 2481 RS_RWLOCK_RELEASE_WRITE(pClientEntry->pLock, &pClientEntry->lockVal); 2482 } 2483 2484 return NV_OK; 2485 } 2486 2487 static 2488 NV_STATUS 2489 _serverUnlockClientWithLockInfo 2490 ( 2491 RsServer *pServer, 2492 LOCK_ACCESS_TYPE access, 2493 NvHandle hClient, 2494 RS_LOCK_INFO *pLockInfo, 2495 NvU32 *pReleaseFlags 2496 ) 2497 { 2498 NV_STATUS status; 2499 if (*pReleaseFlags & RS_LOCK_RELEASE_CLIENT_LOCK) 2500 { 2501 status = _serverUnlockClient(pServer, access, hClient); 2502 if (status != NV_OK) 2503 return status; 2504 2505 pLockInfo->state &= ~RS_LOCK_STATE_CLIENT_LOCK_ACQUIRED; 2506 pLockInfo->pClient = NULL; 2507 *pReleaseFlags &= ~RS_LOCK_RELEASE_CLIENT_LOCK; 2508 } 2509 return NV_OK; 2510 } 2511 2512 static 2513 NV_STATUS 2514 _serverUnlockDualClientWithLockInfo 2515 ( 2516 RsServer *pServer, 2517 LOCK_ACCESS_TYPE access, 2518 NvHandle hClient1, 2519 NvHandle hClient2, 2520 RS_LOCK_INFO *pLockInfo, 2521 NvU32 *pReleaseFlags 2522 ) 2523 { 2524 // 1st and 2nd in handle order, as opposed to fixed 1 and 2 2525 NvHandle hClient1st = NV_MIN(hClient1, hClient2); 2526 NvHandle hClient2nd = NV_MAX(hClient1, hClient2); 2527 2528 if (*pReleaseFlags & RS_LOCK_RELEASE_CLIENT_LOCK) 2529 { 2530 // Try to unlock both, even if one fails 2531 NV_ASSERT_OK(_serverUnlockClient(pServer, access, hClient2nd)); 2532 if (hClient1 != hClient2) 2533 NV_ASSERT_OK(_serverUnlockClient(pServer, access, hClient1st)); 2534 2535 pLockInfo->state &= ~RS_LOCK_STATE_CLIENT_LOCK_ACQUIRED; 2536 pLockInfo->pClient = NULL; 2537 pLockInfo->pSecondClient = NULL; 2538 *pReleaseFlags &= ~RS_LOCK_RELEASE_CLIENT_LOCK; 2539 } 2540 2541 return NV_OK; 2542 } 2543 2544 NvU32 2545 serverGetClientCount(RsServer *pServer) 2546 { 2547 return pServer->activeClientCount; 2548 } 2549 2550 NvU64 2551 serverGetResourceCount(RsServer *pServer) 2552 { 2553 return pServer->activeResourceCount; 2554 } 2555 2556 NV_STATUS 2557 resservSwapTlsCallContext 2558 ( 2559 CALL_CONTEXT **ppOldCallContext, 2560 CALL_CONTEXT *pNewCallContext 2561 ) 2562 { 2563 CALL_CONTEXT **ppTlsCallContext; 2564 2565 if (ppOldCallContext == NULL) 2566 return NV_ERR_INVALID_ARGUMENT; 2567 2568 ppTlsCallContext = (CALL_CONTEXT**)tlsEntryAcquire(TLS_ENTRY_ID_RESSERV_CALL_CONTEXT); 2569 if (ppTlsCallContext == NULL) 2570 return NV_ERR_INVALID_STATE; 2571 2572 *ppOldCallContext = *ppTlsCallContext; 2573 *ppTlsCallContext = pNewCallContext; 2574 2575 // New call contexts inherit the bDeferredApi flag from the old 2576 if ((*ppOldCallContext != NULL) && (pNewCallContext != NULL) && 2577 (pNewCallContext->pControlParams != NULL) && 2578 ((*ppOldCallContext)->pControlParams != NULL)) 2579 { 2580 pNewCallContext->pControlParams->bDeferredApi |= 2581 (*ppOldCallContext)->pControlParams->bDeferredApi; 2582 } 2583 2584 return NV_OK; 2585 } 2586 2587 CALL_CONTEXT * 2588 resservGetTlsCallContext(void) 2589 { 2590 CALL_CONTEXT *pTlsCallContext = NvP64_VALUE(tlsEntryGet(TLS_ENTRY_ID_RESSERV_CALL_CONTEXT)); 2591 return pTlsCallContext; 2592 } 2593 2594 NV_STATUS 2595 resservRestoreTlsCallContext 2596 ( 2597 CALL_CONTEXT *pOldCallContext 2598 ) 2599 { 2600 CALL_CONTEXT **ppTlsCallContext = (CALL_CONTEXT**)tlsEntryAcquire(TLS_ENTRY_ID_RESSERV_CALL_CONTEXT); 2601 if (ppTlsCallContext == NULL) 2602 return NV_ERR_INVALID_ARGUMENT; 2603 2604 *ppTlsCallContext = pOldCallContext; 2605 tlsEntryRelease(TLS_ENTRY_ID_RESSERV_CALL_CONTEXT); 2606 tlsEntryRelease(TLS_ENTRY_ID_RESSERV_CALL_CONTEXT); 2607 2608 return NV_OK; 2609 } 2610 2611 RsResourceRef * 2612 resservGetContextRefByType(NvU32 internalClassId, NvBool bSearchAncestors) 2613 { 2614 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 2615 RsResourceRef *pContextRef = NULL; 2616 2617 if (pCallContext == NULL) 2618 return NULL; 2619 2620 if (pCallContext->pResourceRef != NULL) 2621 { 2622 if (pCallContext->pResourceRef->internalClassId == internalClassId) 2623 { 2624 return pCallContext->pResourceRef; 2625 } 2626 else if (bSearchAncestors && 2627 (refFindAncestorOfType(pCallContext->pResourceRef, internalClassId, &pContextRef) == NV_OK)) 2628 { 2629 return pContextRef; 2630 } 2631 } 2632 2633 if (pCallContext->pContextRef != NULL) 2634 { 2635 if (pCallContext->pContextRef->internalClassId == internalClassId) 2636 { 2637 return pCallContext->pContextRef; 2638 } 2639 else if (bSearchAncestors && 2640 (refFindAncestorOfType(pCallContext->pContextRef, internalClassId, &pContextRef) == NV_OK)) 2641 { 2642 return pContextRef; 2643 } 2644 } 2645 2646 return NULL; 2647 } 2648 2649 NV_STATUS serverFreeClient(RsServer *pServer, RS_CLIENT_FREE_PARAMS* pParams) 2650 { 2651 RS_RES_FREE_PARAMS params; 2652 RS_LOCK_INFO lockInfo; 2653 2654 portMemSet(&lockInfo, 0, sizeof(lockInfo)); 2655 portMemSet(¶ms, 0, sizeof(params)); 2656 params.hClient = pParams->hClient; 2657 params.hResource = pParams->hClient; 2658 params.bHiPriOnly = pParams->bHiPriOnly; 2659 lockInfo.state = pParams->state; 2660 params.pLockInfo = &lockInfo; 2661 params.pSecInfo = pParams->pSecInfo; 2662 2663 return serverFreeResourceTree(pServer, ¶ms); 2664 } 2665 2666 NV_STATUS 2667 shrConstruct_IMPL 2668 ( 2669 RsShared *pShare 2670 ) 2671 { 2672 return NV_OK; 2673 } 2674 2675 void 2676 shrDestruct_IMPL 2677 ( 2678 RsShared *pShare 2679 ) 2680 { 2681 } 2682 2683 NV_STATUS 2684 sessionConstruct_IMPL 2685 ( 2686 RsSession *pSession 2687 ) 2688 { 2689 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 2690 2691 pSession->bValid = NV_TRUE; 2692 listInit(&pSession->dependencies, pCallContext->pServer->pAllocator); 2693 listInit(&pSession->dependants, pCallContext->pServer->pAllocator); 2694 pSession->pLock = portSyncRwLockCreate(pCallContext->pServer->pAllocator); 2695 2696 RS_LOCK_VALIDATOR_INIT(&pSession->lockVal, LOCK_VAL_LOCK_CLASS_SESSION, LOCK_VAL_LOCK_GENERATE); 2697 return NV_OK; 2698 } 2699 2700 void 2701 sessionDestruct_IMPL 2702 ( 2703 RsSession *pSession 2704 ) 2705 { 2706 NV_ASSERT(listCount(&pSession->dependencies) == 0); 2707 NV_ASSERT(listCount(&pSession->dependants) == 0); 2708 listDestroy(&pSession->dependencies); 2709 listDestroy(&pSession->dependants); 2710 pSession->pLock = NULL; 2711 } 2712 2713 NV_STATUS 2714 sessionAddDependant_IMPL 2715 ( 2716 RsSession *pSession, 2717 RsResourceRef *pResourceRef 2718 ) 2719 { 2720 NV_STATUS status; 2721 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 2722 2723 status = sessionCheckLocksForAdd(pSession, pResourceRef); 2724 2725 if (status != NV_OK) 2726 return status; 2727 2728 if (pResourceRef->pSession == pSession) 2729 return NV_OK; 2730 2731 NV_ASSERT_OR_RETURN(pResourceRef->pSession == NULL, NV_ERR_INVALID_ARGUMENT); 2732 2733 if (listAppendValue(&pSession->dependants, &pResourceRef) == NULL) 2734 return NV_ERR_INSUFFICIENT_RESOURCES; 2735 2736 serverRefShare(pCallContext->pServer, staticCast(pSession, RsShared)); 2737 2738 pResourceRef->pSession = pSession; 2739 2740 return NV_OK; 2741 } 2742 2743 NV_STATUS 2744 sessionAddDependency_IMPL 2745 ( 2746 RsSession *pSession, 2747 RsResourceRef *pResourceRef 2748 ) 2749 { 2750 NV_STATUS status; 2751 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 2752 2753 status = sessionCheckLocksForAdd(pSession, pResourceRef); 2754 2755 if (status != NV_OK) 2756 return status; 2757 2758 if (pResourceRef->pDependantSession == pSession) 2759 return NV_OK; 2760 2761 NV_ASSERT_OR_RETURN(pResourceRef->pDependantSession == NULL, NV_ERR_INVALID_ARGUMENT); 2762 2763 if (listAppendValue(&pSession->dependencies, &pResourceRef) == NULL) 2764 return NV_ERR_INSUFFICIENT_RESOURCES; 2765 2766 serverRefShare(pCallContext->pServer, staticCast(pSession, RsShared)); 2767 2768 pResourceRef->pDependantSession = pSession; 2769 2770 return NV_OK; 2771 } 2772 2773 void 2774 sessionRemoveDependant_IMPL 2775 ( 2776 RsSession *pSession, 2777 RsResourceRef *pResourceRef 2778 ) 2779 { 2780 listRemoveFirstByValue(&pSession->dependants, &pResourceRef); 2781 sessionCheckLocksForRemove(pSession, pResourceRef); 2782 pResourceRef->pSession = NULL; 2783 } 2784 2785 void 2786 sessionRemoveDependency_IMPL 2787 ( 2788 RsSession *pSession, 2789 RsResourceRef *pResourceRef 2790 ) 2791 { 2792 listRemoveFirstByValue(&pSession->dependencies, &pResourceRef); 2793 pSession->bValid = NV_FALSE; 2794 sessionCheckLocksForRemove(pSession, pResourceRef); 2795 pResourceRef->pDependantSession = NULL; 2796 } 2797 2798 NV_STATUS sessionCheckLocksForAdd_IMPL(RsSession *pSession, RsResourceRef *pResourceRef) 2799 { 2800 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 2801 RS_LOCK_INFO *pLockInfo; 2802 2803 NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE); 2804 pLockInfo = pCallContext->pLockInfo; 2805 2806 NV_ASSERT_OR_RETURN((pLockInfo != NULL), NV_ERR_INVALID_STATE); 2807 2808 if (!serverRwApiLockIsOwner(pCallContext->pServer)) 2809 { 2810 // Assert clients locked or RW lock 2811 if (pLockInfo->state & RS_LOCK_STATE_CLIENT_LOCK_ACQUIRED) 2812 { 2813 NV_ASSERT_OR_RETURN((pLockInfo->pClient == pResourceRef->pClient) || 2814 (pLockInfo->pSecondClient == pResourceRef->pClient), 2815 NV_ERR_INVALID_ARGUMENT); 2816 } 2817 else if (pLockInfo->state & RS_LOCK_STATE_TOP_LOCK_ACQUIRED) 2818 { 2819 NV_ASSERT_OR_RETURN((pLockInfo->pClient == NULL) && (pLockInfo->pSecondClient == NULL), NV_ERR_INVALID_ARGUMENT); 2820 } 2821 else 2822 { 2823 NV_ASSERT_FAILED("Incorrect locks taken"); 2824 return NV_ERR_INVALID_LOCK_STATE; 2825 } 2826 } 2827 2828 return NV_OK; 2829 } 2830 2831 void sessionCheckLocksForRemove_IMPL(RsSession *pSession, RsResourceRef *pResourceRef) 2832 { 2833 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 2834 RS_LOCK_INFO *pLockInfo; 2835 2836 NV_ASSERT(pCallContext != NULL); 2837 pLockInfo = pCallContext->pLockInfo; 2838 2839 NV_ASSERT(pLockInfo != NULL); 2840 2841 if (pLockInfo->flags & RS_LOCK_FLAGS_FREE_SESSION_LOCK) 2842 { 2843 RsShared *pShared = staticCast(pSession, RsShared); 2844 PORT_RWLOCK *pSessionLock = pSession->pLock; 2845 NvBool bDestroy = (pShared->refCount == 1); 2846 2847 if (!(pLockInfo->state & RS_LOCK_STATE_SESSION_LOCK_ACQUIRED) || !bDestroy) 2848 { 2849 serverFreeShare(pCallContext->pServer, pShared); 2850 pLockInfo->flags &= ~RS_LOCK_FLAGS_FREE_SESSION_LOCK; 2851 } 2852 2853 if (!(pLockInfo->state & RS_LOCK_STATE_SESSION_LOCK_ACQUIRED) && bDestroy) 2854 portSyncRwLockDestroy(pSessionLock); 2855 } 2856 } 2857 2858 NV_STATUS 2859 serverAllocShareWithHalspecParent 2860 ( 2861 RsServer *pServer, 2862 const NVOC_CLASS_INFO *pClassInfo, 2863 RsShared **ppShare, 2864 Object *pHalspecParent 2865 ) 2866 { 2867 RsShared *pShare; 2868 NV_STATUS status; 2869 Dynamic *pDynamic = NULL; 2870 NvU32 flags = NVOC_OBJ_CREATE_FLAGS_NONE; 2871 2872 if (pClassInfo == NULL) 2873 return NV_ERR_INVALID_CLASS; 2874 2875 if (pHalspecParent != NULL) 2876 flags |= NVOC_OBJ_CREATE_FLAGS_PARENT_HALSPEC_ONLY; 2877 2878 status = objCreateDynamicWithFlags(&pDynamic, 2879 pHalspecParent, 2880 (const NVOC_CLASS_INFO*)(const void*)pClassInfo, 2881 flags); 2882 if (status != NV_OK) 2883 return status; 2884 2885 if (pDynamic == NULL) 2886 return NV_ERR_INSUFFICIENT_RESOURCES; 2887 2888 pShare = dynamicCast(pDynamic, RsShared); 2889 if (pShare == NULL) 2890 { 2891 status = NV_ERR_INVALID_CLASS; 2892 goto fail; 2893 } 2894 2895 pShare->refCount = 1; 2896 2897 portSyncSpinlockAcquire(pServer->pShareMapLock); 2898 if (mapInsertExisting(&pServer->shareMap, (NvUPtr)pShare, pShare) != NV_TRUE) 2899 { 2900 status = NV_ERR_INSUFFICIENT_RESOURCES; 2901 portSyncSpinlockRelease(pServer->pShareMapLock); 2902 goto fail; 2903 } 2904 portSyncSpinlockRelease(pServer->pShareMapLock); 2905 2906 if (ppShare != NULL) 2907 *ppShare = pShare; 2908 2909 return NV_OK; 2910 2911 fail: 2912 objDelete(pShare); 2913 2914 return status; 2915 } 2916 2917 NV_STATUS 2918 serverAllocShare 2919 ( 2920 RsServer *pServer, 2921 const NVOC_CLASS_INFO *pClassInfo, 2922 RsShared **ppShare 2923 ) 2924 { 2925 return serverAllocShareWithHalspecParent(pServer, pClassInfo, ppShare, NULL); 2926 } 2927 2928 NvS32 2929 serverGetShareRefCount 2930 ( 2931 RsServer *pServer, 2932 RsShared *pShare 2933 ) 2934 { 2935 return pShare->refCount; 2936 } 2937 2938 NV_STATUS 2939 serverRefShare 2940 ( 2941 RsServer *pServer, 2942 RsShared *pShare 2943 ) 2944 { 2945 portAtomicIncrementS32(&pShare->refCount); 2946 return NV_OK; 2947 } 2948 2949 NV_STATUS 2950 serverFreeShare 2951 ( 2952 RsServer *pServer, 2953 RsShared *pShare 2954 ) 2955 { 2956 if (portAtomicDecrementS32(&pShare->refCount) == 0) 2957 { 2958 portSyncSpinlockAcquire(pServer->pShareMapLock); 2959 mapRemove(&pServer->shareMap, pShare); 2960 portSyncSpinlockRelease(pServer->pShareMapLock); 2961 2962 objDelete(pShare); 2963 } 2964 return NV_OK; 2965 } 2966 2967 RS_SHARE_ITERATOR 2968 serverShareIter 2969 ( 2970 RsServer *pServer, 2971 NvU32 internalClassId 2972 ) 2973 { 2974 RS_SHARE_ITERATOR it; 2975 portMemSet(&it, 0, sizeof(it)); 2976 it.internalClassId = internalClassId; 2977 it.mapIt = mapIterAll(&pServer->shareMap); 2978 2979 return it; 2980 } 2981 2982 NvBool 2983 serverShareIterNext 2984 ( 2985 RS_SHARE_ITERATOR* pIt 2986 ) 2987 { 2988 NvBool bLoop = NV_TRUE; 2989 if (pIt == NULL) 2990 return NV_FALSE; 2991 2992 pIt->pShared = NULL; 2993 bLoop = mapIterNext(&pIt->mapIt); 2994 while(bLoop) 2995 { 2996 RsShared *pShared = pIt->mapIt.pValue; 2997 if ((pIt->internalClassId == 0) || (objDynamicCastById(pShared, pIt->internalClassId) != NULL)) 2998 { 2999 pIt->pShared = pShared; 3000 return NV_TRUE; 3001 } 3002 bLoop = mapIterNext(&pIt->mapIt); 3003 } 3004 3005 return NV_FALSE; 3006 } 3007 3008 #if (RS_PROVIDES_API_STATE) 3009 NV_STATUS 3010 serverAllocApiCopyIn 3011 ( 3012 RsServer *pServer, 3013 RS_RES_ALLOC_PARAMS_INTERNAL *pAllocParams, 3014 API_STATE **ppApiState 3015 ) 3016 { 3017 if (ppApiState != NULL) 3018 *ppApiState = NULL; 3019 3020 return NV_OK; 3021 } 3022 3023 NV_STATUS 3024 serverAllocApiCopyOut 3025 ( 3026 RsServer *pServer, 3027 NV_STATUS status, 3028 API_STATE *pApiState 3029 ) 3030 { 3031 return status; 3032 } 3033 #endif 3034 3035 #if (RS_STANDALONE) 3036 NV_STATUS 3037 serverAllocEpilogue_WAR 3038 ( 3039 RsServer *pServer, 3040 NV_STATUS status, 3041 NvBool bClientAlloc, 3042 RS_RES_ALLOC_PARAMS_INTERNAL *pAllocParams 3043 ) 3044 { 3045 return status; 3046 } 3047 3048 NV_STATUS 3049 serverLookupSecondClient 3050 ( 3051 RS_RES_ALLOC_PARAMS_INTERNAL *pParams, 3052 NvHandle *phClient 3053 ) 3054 { 3055 *phClient = 0; 3056 3057 return NV_OK; 3058 } 3059 3060 NV_STATUS serverTopLock_Prologue 3061 ( 3062 RsServer *pServer, 3063 LOCK_ACCESS_TYPE access, 3064 RS_LOCK_INFO *pLockInfo, 3065 NvU32 *pReleaseFlags 3066 ) 3067 { 3068 if ((pLockInfo->flags & RS_LOCK_FLAGS_NO_TOP_LOCK)) 3069 return NV_OK; 3070 3071 if (!(pLockInfo->state & RS_LOCK_STATE_TOP_LOCK_ACQUIRED)) 3072 { 3073 if (access == LOCK_ACCESS_READ) 3074 { 3075 RS_RWLOCK_ACQUIRE_READ(pServer->pTopLock, &pServer->topLockVal); 3076 } 3077 else 3078 { 3079 RS_RWLOCK_ACQUIRE_WRITE(pServer->pTopLock, &pServer->topLockVal); 3080 pServer->topLockOwnerTid = portThreadGetCurrentThreadId(); 3081 } 3082 3083 pLockInfo->state |= RS_LOCK_STATE_TOP_LOCK_ACQUIRED; 3084 *pReleaseFlags |= RS_LOCK_RELEASE_TOP_LOCK; 3085 } 3086 else if (access == LOCK_ACCESS_WRITE) 3087 { 3088 NV_ASSERT_OR_RETURN(pServer->topLockOwnerTid == portThreadGetCurrentThreadId(), 3089 NV_ERR_INVALID_LOCK_STATE); 3090 } 3091 3092 return NV_OK; 3093 } 3094 3095 void 3096 serverTopLock_Epilogue 3097 ( 3098 RsServer *pServer, 3099 LOCK_ACCESS_TYPE access, 3100 RS_LOCK_INFO *pLockInfo, 3101 NvU32 *pReleaseFlags 3102 ) 3103 { 3104 if (*pReleaseFlags & RS_LOCK_RELEASE_TOP_LOCK) 3105 { 3106 if (access == LOCK_ACCESS_READ) 3107 RS_RWLOCK_RELEASE_READ(pServer->pTopLock, &pServer->topLockVal); 3108 else 3109 { 3110 pServer->topLockOwnerTid = ~0; 3111 RS_RWLOCK_RELEASE_WRITE(pServer->pTopLock, &pServer->topLockVal); 3112 } 3113 3114 pLockInfo->state &= ~RS_LOCK_STATE_TOP_LOCK_ACQUIRED; 3115 *pReleaseFlags &= ~RS_LOCK_RELEASE_TOP_LOCK; 3116 } 3117 } 3118 3119 NV_STATUS 3120 serverResLock_Prologue 3121 ( 3122 RsServer *pServer, 3123 LOCK_ACCESS_TYPE access, 3124 RS_LOCK_INFO *pLockInfo, 3125 NvU32 *pReleaseFlags 3126 ) 3127 { 3128 if (!(pLockInfo->state & RS_LOCK_STATE_CUSTOM_LOCK_1_ACQUIRED)) 3129 { 3130 if (access == LOCK_ACCESS_READ) 3131 RS_RWLOCK_ACQUIRE_READ(pServer->pResLock, &pServer->resLockVal); 3132 else 3133 RS_RWLOCK_ACQUIRE_WRITE(pServer->pResLock, &pServer->resLockVal); 3134 3135 pLockInfo->state |= RS_LOCK_STATE_CUSTOM_LOCK_1_ACQUIRED; 3136 *pReleaseFlags |= RS_LOCK_RELEASE_CUSTOM_LOCK_1; 3137 } 3138 3139 return NV_OK; 3140 } 3141 3142 void 3143 serverResLock_Epilogue 3144 ( 3145 RsServer *pServer, 3146 LOCK_ACCESS_TYPE access, 3147 RS_LOCK_INFO *pLockInfo, 3148 NvU32 *pReleaseFlags 3149 ) 3150 { 3151 if (*pReleaseFlags & RS_LOCK_RELEASE_CUSTOM_LOCK_1) 3152 { 3153 if (access == LOCK_ACCESS_READ) 3154 RS_RWLOCK_RELEASE_READ(pServer->pResLock, &pServer->resLockVal); 3155 else 3156 RS_RWLOCK_RELEASE_WRITE(pServer->pResLock, &pServer->resLockVal); 3157 3158 pLockInfo->state &= ~RS_LOCK_STATE_CUSTOM_LOCK_1_ACQUIRED; 3159 *pReleaseFlags &= ~RS_LOCK_RELEASE_CUSTOM_LOCK_1; 3160 } 3161 } 3162 3163 #if !(RS_STANDALONE_TEST) 3164 NV_STATUS 3165 serverMap_Prologue 3166 ( 3167 RsServer *pServer, 3168 RS_CPU_MAP_PARAMS *pMapParams 3169 ) 3170 { 3171 return NV_OK; 3172 } 3173 #endif /* !RS_STANDALONE_TEST */ 3174 3175 void 3176 serverMap_Epilogue 3177 ( 3178 RsServer *pServer, 3179 RS_CPU_MAP_PARAMS *pMapParams 3180 ) 3181 { 3182 } 3183 3184 #if !(RS_STANDALONE_TEST) 3185 NV_STATUS 3186 serverUnmap_Prologue 3187 ( 3188 RsServer *pServer, 3189 RS_CPU_UNMAP_PARAMS *pUnmapParams 3190 ) 3191 { 3192 return NV_OK; 3193 } 3194 #endif /* !RS_STANDALONE_TEST */ 3195 3196 void 3197 serverUnmap_Epilogue 3198 ( 3199 RsServer *pServer, 3200 RS_CPU_UNMAP_PARAMS *pUnmapParams 3201 ) 3202 { 3203 } 3204 3205 void 3206 serverControl_InitCookie 3207 ( 3208 const struct NVOC_EXPORTED_METHOD_DEF *pExportedEntry, 3209 RS_CONTROL_COOKIE *pCookie 3210 ) 3211 { 3212 } 3213 3214 NV_STATUS 3215 serverInterMap_Prologue 3216 ( 3217 RsServer *pServer, 3218 RsResourceRef *pMapperRef, 3219 RsResourceRef *pMappableRef, 3220 RS_INTER_MAP_PARAMS *pMapParams, 3221 NvU32 *pReleaseFlags 3222 ) 3223 { 3224 NV_STATUS status; 3225 3226 status = serverResLock_Prologue(pServer, LOCK_ACCESS_WRITE, pMapParams->pLockInfo, pReleaseFlags); 3227 3228 return status; 3229 } 3230 3231 void 3232 serverInterMap_Epilogue 3233 ( 3234 RsServer *pServer, 3235 RS_INTER_MAP_PARAMS *pMapParams, 3236 NvU32 *pReleaseFlags 3237 ) 3238 { 3239 serverResLock_Epilogue(pServer, LOCK_ACCESS_WRITE, pMapParams->pLockInfo, pReleaseFlags); 3240 } 3241 3242 NV_STATUS 3243 serverInterUnmap_Prologue 3244 ( 3245 RsServer *pServer, 3246 RS_INTER_UNMAP_PARAMS *pUnmapParams 3247 ) 3248 { 3249 return NV_OK; 3250 } 3251 3252 void 3253 serverInterUnmap_Epilogue 3254 ( 3255 RsServer *pServer, 3256 RS_INTER_UNMAP_PARAMS *pUnmapParams 3257 ) 3258 { 3259 } 3260 3261 NvBool 3262 serverRwApiLockIsOwner 3263 ( 3264 RsServer *pServer 3265 ) 3266 { 3267 return (pServer->topLockOwnerTid == portThreadGetCurrentThreadId()); 3268 } 3269 3270 NV_STATUS 3271 serverAllocResourceLookupLockFlags 3272 ( 3273 RsServer *pServer, 3274 RS_LOCK_ENUM lock, 3275 RS_RES_ALLOC_PARAMS_INTERNAL *pParams, 3276 LOCK_ACCESS_TYPE *pAccess 3277 ) 3278 { 3279 if (lock == RS_LOCK_TOP) 3280 { 3281 NvBool bClientAlloc = (pParams->externalClassId == NV01_ROOT || 3282 pParams->externalClassId == NV01_ROOT_CLIENT || 3283 pParams->externalClassId == NV01_ROOT_NON_PRIV); 3284 3285 if (bClientAlloc) 3286 { 3287 *pAccess = LOCK_ACCESS_WRITE; 3288 return NV_OK; 3289 } 3290 } 3291 3292 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_ALLOC_RESOURCE)) 3293 ? LOCK_ACCESS_READ 3294 : LOCK_ACCESS_WRITE; 3295 3296 return NV_OK; 3297 } 3298 3299 NV_STATUS 3300 serverFreeResourceLookupLockFlags 3301 ( 3302 RsServer *pServer, 3303 RS_LOCK_ENUM lock, 3304 RS_RES_FREE_PARAMS_INTERNAL *pParams, 3305 LOCK_ACCESS_TYPE *pAccess 3306 ) 3307 { 3308 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_FREE_RESOURCE)) 3309 ? LOCK_ACCESS_READ 3310 : LOCK_ACCESS_WRITE; 3311 return NV_OK; 3312 } 3313 3314 NV_STATUS 3315 serverCopyResourceLookupLockFlags 3316 ( 3317 RsServer *pServer, 3318 RS_LOCK_ENUM lock, 3319 RS_RES_DUP_PARAMS *pParams, 3320 LOCK_ACCESS_TYPE *pAccess 3321 ) 3322 { 3323 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_COPY)) 3324 ? LOCK_ACCESS_READ 3325 : LOCK_ACCESS_WRITE; 3326 return NV_OK; 3327 } 3328 3329 NV_STATUS 3330 serverShareResourceLookupLockFlags 3331 ( 3332 RsServer *pServer, 3333 RS_LOCK_ENUM lock, 3334 RS_RES_SHARE_PARAMS *pParams, 3335 LOCK_ACCESS_TYPE *pAccess 3336 ) 3337 { 3338 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_SHARE)) 3339 ? LOCK_ACCESS_READ 3340 : LOCK_ACCESS_WRITE; 3341 3342 return NV_OK; 3343 } 3344 3345 #if !(RS_STANDALONE_TEST) 3346 NV_STATUS 3347 serverControlLookupLockFlags 3348 ( 3349 RsServer *pServer, 3350 RS_LOCK_ENUM lock, 3351 RS_RES_CONTROL_PARAMS_INTERNAL *pParams, 3352 RS_CONTROL_COOKIE *pCookie, 3353 LOCK_ACCESS_TYPE *pAccess 3354 ) 3355 { 3356 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_CTRL)) 3357 ? LOCK_ACCESS_READ 3358 : LOCK_ACCESS_WRITE; 3359 3360 return NV_OK; 3361 } 3362 #endif 3363 3364 NV_STATUS 3365 serverMapLookupLockFlags 3366 ( 3367 RsServer *pServer, 3368 RS_LOCK_ENUM lock, 3369 RS_CPU_MAP_PARAMS *pParams, 3370 LOCK_ACCESS_TYPE *pAccess 3371 ) 3372 { 3373 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_MAP)) 3374 ? LOCK_ACCESS_READ 3375 : LOCK_ACCESS_WRITE; 3376 return NV_OK; 3377 } 3378 3379 NV_STATUS 3380 serverUnmapLookupLockFlags 3381 ( 3382 RsServer *pServer, 3383 RS_LOCK_ENUM lock, 3384 RS_CPU_UNMAP_PARAMS *pParams, 3385 LOCK_ACCESS_TYPE *pAccess 3386 ) 3387 { 3388 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_UNMAP)) 3389 ? LOCK_ACCESS_READ 3390 : LOCK_ACCESS_WRITE; 3391 3392 return NV_OK; 3393 } 3394 3395 NV_STATUS 3396 serverInterMapLookupLockFlags 3397 ( 3398 RsServer *pServer, 3399 RS_LOCK_ENUM lock, 3400 RS_INTER_MAP_PARAMS *pParams, 3401 LOCK_ACCESS_TYPE *pAccess 3402 ) 3403 { 3404 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_INTER_MAP)) 3405 ? LOCK_ACCESS_READ 3406 : LOCK_ACCESS_WRITE; 3407 3408 return NV_OK; 3409 } 3410 3411 NV_STATUS 3412 serverInterUnmapLookupLockFlags 3413 ( 3414 RsServer *pServer, 3415 RS_LOCK_ENUM lock, 3416 RS_INTER_UNMAP_PARAMS *pParams, 3417 LOCK_ACCESS_TYPE *pAccess 3418 ) 3419 { 3420 *pAccess = (serverSupportsReadOnlyLock(pServer, lock, RS_API_INTER_UNMAP)) 3421 ? LOCK_ACCESS_READ 3422 : LOCK_ACCESS_WRITE; 3423 3424 return NV_OK; 3425 } 3426 3427 NV_STATUS 3428 serverControl_ValidateCookie 3429 ( 3430 RS_RES_CONTROL_PARAMS_INTERNAL *pParams, 3431 RS_CONTROL_COOKIE *pCookie 3432 ) 3433 { 3434 return NV_OK; 3435 } 3436 3437 NV_STATUS 3438 serverControlApiCopyIn 3439 ( 3440 RsServer *pServer, 3441 RS_RES_CONTROL_PARAMS_INTERNAL *pParams, 3442 RS_CONTROL_COOKIE *pCookie 3443 ) 3444 { 3445 return NV_OK; 3446 } 3447 3448 NV_STATUS 3449 serverControlApiCopyOut 3450 ( 3451 RsServer *pServer, 3452 RS_RES_CONTROL_PARAMS_INTERNAL *pParams, 3453 RS_CONTROL_COOKIE *pCookie, 3454 NV_STATUS rmStatus 3455 ) 3456 { 3457 return NV_OK; 3458 } 3459 3460 NV_STATUS 3461 serverInitGlobalSharePolicies 3462 ( 3463 RsServer *pServer 3464 ) 3465 { 3466 return NV_OK; 3467 } 3468 #endif 3469 3470 NV_STATUS 3471 serverSessionLock_Prologue 3472 ( 3473 LOCK_ACCESS_TYPE access, 3474 RsResourceRef *pResourceRef, 3475 RS_LOCK_INFO *pLockInfo, 3476 NvU32 *pReleaseFlags 3477 ) 3478 { 3479 RsSession *pSession = pResourceRef->pSession; 3480 RsSession *pDependantSession = pResourceRef->pDependantSession; 3481 3482 if (!(pLockInfo->state & RS_LOCK_STATE_SESSION_LOCK_ACQUIRED)) 3483 { 3484 if (pSession != NULL) 3485 { 3486 if (access == LOCK_ACCESS_READ) 3487 RS_RWLOCK_ACQUIRE_READ(pSession->pLock, &pSession->lockVal); 3488 else 3489 RS_RWLOCK_ACQUIRE_WRITE(pSession->pLock, &pSession->lockVal); 3490 pLockInfo->state |= RS_LOCK_STATE_SESSION_LOCK_ACQUIRED; 3491 *pReleaseFlags |= RS_LOCK_RELEASE_SESSION_LOCK; 3492 3493 pLockInfo->pSession = pSession; 3494 } 3495 } 3496 else 3497 { 3498 NV_ASSERT_OR_RETURN(pLockInfo->pSession == pSession, NV_ERR_INVALID_LOCK_STATE); 3499 } 3500 3501 if (!(pLockInfo->flags & RS_LOCK_FLAGS_NO_DEPENDANT_SESSION_LOCK) && 3502 (pDependantSession != NULL)) 3503 { 3504 if (!(pLockInfo->state & RS_LOCK_STATE_SESSION_LOCK_ACQUIRED)) 3505 { 3506 // 3507 // The only reason we lock the back reference session is if we're freeing the 3508 // resource so take the write lock in all cases 3509 // 3510 RS_RWLOCK_ACQUIRE_WRITE(pDependantSession->pLock, &pDependantSession->lockVal); 3511 3512 pLockInfo->state |= RS_LOCK_STATE_SESSION_LOCK_ACQUIRED; 3513 *pReleaseFlags |= RS_LOCK_RELEASE_SESSION_LOCK; 3514 3515 pLockInfo->pSession = pDependantSession; 3516 } 3517 else 3518 { 3519 // 3520 // For now, don't allow a resource to be both depended on and depending on a 3521 // session to keep this locking code simpler. We'll have to revisit if that 3522 // becomes necessary. 3523 // 3524 NV_ASSERT_OR_RETURN(pLockInfo->pSession == pDependantSession, NV_ERR_INVALID_LOCK_STATE); 3525 } 3526 } 3527 3528 pLockInfo->flags &= ~RS_LOCK_FLAGS_NO_DEPENDANT_SESSION_LOCK; 3529 3530 return NV_OK; 3531 } 3532 3533 void 3534 serverSessionLock_Epilogue 3535 ( 3536 RsServer *pServer, 3537 LOCK_ACCESS_TYPE access, 3538 RS_LOCK_INFO *pLockInfo, 3539 NvU32 *pReleaseFlags 3540 ) 3541 { 3542 RsSession *pSession = pLockInfo->pSession; 3543 3544 if ((pSession != NULL) && (*pReleaseFlags & RS_LOCK_RELEASE_SESSION_LOCK)) 3545 { 3546 if (access == LOCK_ACCESS_READ) 3547 RS_RWLOCK_RELEASE_READ(pSession->pLock, &pSession->lockVal); 3548 else 3549 RS_RWLOCK_RELEASE_WRITE(pSession->pLock, &pSession->lockVal); 3550 3551 pLockInfo->state &= ~RS_LOCK_STATE_SESSION_LOCK_ACQUIRED; 3552 *pReleaseFlags &= ~RS_LOCK_RELEASE_SESSION_LOCK; 3553 3554 if (pLockInfo->flags & RS_LOCK_FLAGS_FREE_SESSION_LOCK) 3555 { 3556 RsShared *pShared = staticCast(pSession, RsShared); 3557 PORT_RWLOCK *pSessionLock = pSession->pLock; 3558 3559 serverFreeShare(pServer, pShared); 3560 portSyncRwLockDestroy(pSessionLock); 3561 } 3562 3563 pLockInfo->pSession = NULL; 3564 } 3565 3566 pLockInfo->flags &= ~RS_LOCK_FLAGS_FREE_SESSION_LOCK; 3567 } 3568 3569 NV_STATUS serverControl_Prologue 3570 ( 3571 RsServer *pServer, 3572 RS_RES_CONTROL_PARAMS_INTERNAL *pParams, 3573 LOCK_ACCESS_TYPE *pAccess, 3574 NvU32* pReleaseFlags 3575 ) 3576 { 3577 NV_STATUS status; 3578 RS_LOCK_INFO *pLockInfo = pParams->pLockInfo; 3579 3580 status = serverControl_ValidateCookie(pParams, pParams->pCookie); 3581 if (status != NV_OK) 3582 return status; 3583 3584 serverControlLookupLockFlags(pServer, RS_LOCK_RESOURCE, pParams, pParams->pCookie, pAccess); 3585 if (status != NV_OK) 3586 return status; 3587 3588 if (!pServer->bUnlockedParamCopy) 3589 { 3590 status = serverControlApiCopyIn(pServer, pParams, pParams->pCookie); 3591 if (status != NV_OK) 3592 return status; 3593 } 3594 3595 pLockInfo->traceOp = RS_LOCK_TRACE_CTRL; 3596 pLockInfo->traceClassId = pParams->cmd; 3597 status = serverResLock_Prologue(pServer, *pAccess, pParams->pLockInfo, pReleaseFlags); 3598 if (status != NV_OK) 3599 return status; 3600 3601 return NV_OK; 3602 } 3603 3604 NV_STATUS 3605 serverControl_Epilogue 3606 ( 3607 RsServer *pServer, 3608 RS_RES_CONTROL_PARAMS_INTERNAL *pParams, 3609 LOCK_ACCESS_TYPE access, 3610 NvU32 *pReleaseFlags, 3611 NV_STATUS status 3612 ) 3613 { 3614 serverResLock_Epilogue(pServer, access, pParams->pLockInfo, pReleaseFlags); 3615 3616 if (!pServer->bUnlockedParamCopy) 3617 { 3618 status = serverControlApiCopyOut(pServer, pParams, pParams->pCookie, status); 3619 } 3620 3621 return status; 3622 } 3623 3624 NvBool 3625 serverSupportsReadOnlyLock 3626 ( 3627 RsServer *pServer, 3628 RS_LOCK_ENUM lock, 3629 RS_API_ENUM api 3630 ) 3631 { 3632 NV_ASSERT(api < RS_API_MAX); 3633 if (lock == RS_LOCK_TOP) 3634 { 3635 return (!!(pServer->roTopLockApiMask & NVBIT(api))); 3636 } 3637 3638 return NV_FALSE; 3639 } 3640