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(&params, 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, &params);
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(&params, 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, &params);
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(&params, 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, &params);
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