1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2009-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "core/core.h"
25 #include "core/locks.h"
26 #include "gpu/gpu.h"
27 #include "gpu/device/device.h"
28 #include "gpu/subdevice/subdevice.h"
29 #include "gpu/bus/third_party_p2p.h"
30 #include "platform/p2p/p2p_caps.h"
31 #include "gpu/bus/kern_bus.h"
32 #include "mem_mgr/mem.h"
33 #include "rmapi/rs_utils.h"
34 #include "vgpu/rpc.h"
35 #include "os/os.h"
36 
37 #include "class/cl503c.h"
38 
39 //
40 // A monotonic counter as ID that's assigned to every new VidmemInfo.
41 // This is used to get internal VidmemInfo for persistent mappings.
42 //
43 static volatile NvU64 vidmemInfoId = 0;
44 
45 //
46 // A monotonic counter as ID that's assigned to every new 3rd party p2p class.
47 //
48 static volatile NvU64 p2pTokenId = 0;
49 
50 //
51 // We make sure that only one instance of NV50_THIRD_PARTY_P2P can be active at
52 // a time per client per GPU. It simplifies tuple(VA,size) tracking/validation
53 // in SW. For example, detecting duplicate/overlapping tuples.
54 //
55 NV_STATUS
thirdpartyp2pConstruct_IMPL(ThirdPartyP2P * pThirdPartyP2P,CALL_CONTEXT * pCallContext,RS_RES_ALLOC_PARAMS_INTERNAL * pParams)56 thirdpartyp2pConstruct_IMPL
57 (
58     ThirdPartyP2P *pThirdPartyP2P,
59     CALL_CONTEXT *pCallContext,
60     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
61 )
62 {
63     NV503C_ALLOC_PARAMETERS    *pNv503cAllocParams = pParams->pAllocParams;
64     NvHandle                    hClient            = pCallContext->pClient->hClient;
65     NvHandle                    hThirdPartyP2P     = pParams->hResource;
66     NvU32                       flags              = 0;
67     OBJGPU                     *pGpu;
68     CLI_THIRD_PARTY_P2P_TYPE    type;
69     RsResourceRef              *pSubdeviceRef = pCallContext->pResourceRef->pParentRef;
70     Subdevice                  *pSubdevice;
71     NvU64                       p2pToken         = 0;
72     NvU32                       peerIndex        = 0;
73     NvU32                       pidIndex         = 0;
74     NV_STATUS                   status           = NV_OK;
75     NvU32                       pid = osGetCurrentProcess();
76     RsShared                   *pShare;
77     P2PTokenShare              *pP2PTokenShare;
78 
79     pSubdevice = dynamicCast(pSubdeviceRef->pResource, Subdevice);
80     if (pSubdevice == NULL)
81         return NV_ERR_INVALID_OBJECT_PARENT;
82 
83     pGpu = GPU_RES_GET_GPU(pThirdPartyP2P);
84     if (pGpu == NULL)
85         return NV_ERR_INVALID_OBJECT_PARENT;
86 
87     if (gpuIsApmFeatureEnabled(pGpu))
88     {
89         return NV_ERR_NOT_SUPPORTED;
90     }
91 
92     API_GPU_FULL_POWER_SANITY_CHECK(pGpu, NV_TRUE, NV_FALSE);
93 
94     if (pNv503cAllocParams != NULL)
95     {
96         flags              = pNv503cAllocParams->flags;
97     }
98 
99     switch(DRF_VAL(503C, _ALLOC_PARAMETERS_FLAGS, _TYPE, flags))
100     {
101         case NV503C_ALLOC_PARAMETERS_FLAGS_TYPE_BAR1:
102             type = CLI_THIRD_PARTY_P2P_TYPE_BAR1;
103             break;
104         case NV503C_ALLOC_PARAMETERS_FLAGS_TYPE_NVLINK:
105             type = CLI_THIRD_PARTY_P2P_TYPE_NVLINK;
106             break;
107         case NV503C_ALLOC_PARAMETERS_FLAGS_TYPE_PROPRIETARY:
108             type = CLI_THIRD_PARTY_P2P_TYPE_PROPRIETARY;
109             break;
110         default:
111             return NV_ERR_INVALID_ARGUMENT;
112     }
113 
114     if (type == CLI_THIRD_PARTY_P2P_TYPE_BAR1)
115     {
116         if (pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING))
117         {
118             return NV_ERR_INVALID_ARGUMENT;
119         }
120 
121         p2pToken = portAtomicExIncrementU64(&p2pTokenId);;
122     }
123     else if (type == CLI_THIRD_PARTY_P2P_TYPE_NVLINK)
124     {
125         if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING))
126         {
127             return NV_ERR_INVALID_STATE;
128         }
129 
130         p2pToken = portAtomicExIncrementU64(&p2pTokenId);;
131     }
132     else
133     {
134         return NV_ERR_NOT_SUPPORTED;
135     }
136 
137     pThirdPartyP2P->hClient          = hClient;
138     pThirdPartyP2P->hThirdPartyP2P   = hThirdPartyP2P;
139     pThirdPartyP2P->type             = type;
140     pThirdPartyP2P->pSubdevice       = pSubdevice;
141     pThirdPartyP2P->peerIndex        = peerIndex;
142     pThirdPartyP2P->p2pToken         = p2pToken;
143     pThirdPartyP2P->pDestroyCallback = NULL;
144     pThirdPartyP2P->pData            = NULL;
145     pThirdPartyP2P->pAddressRangeTree = NULL;
146     pThirdPartyP2P->Node.keyStart    = hThirdPartyP2P;
147     pThirdPartyP2P->Node.keyEnd      = hThirdPartyP2P;
148     pThirdPartyP2P->Node.Data        = (void*)pThirdPartyP2P;
149     portMemSet(pThirdPartyP2P->pidClientList, 0, sizeof(pThirdPartyP2P->pidClientList));
150     mapInit(&pThirdPartyP2P->vaSpaceInfoMap, portMemAllocatorGetGlobalNonPaged());
151     mapInitIntrusive(&pThirdPartyP2P->vidmemInfoMap);
152 
153     status = NV_ERR_OBJECT_NOT_FOUND;
154     for (pidIndex = 0; pidIndex < CLI_THIRD_PARTY_P2P_MAX_CLIENT; pidIndex++)
155     {
156         if (0 == pThirdPartyP2P->pidClientList[pidIndex].pid)
157         {
158             pThirdPartyP2P->pidClientList[pidIndex].pid = pid;
159             pThirdPartyP2P->pidClientList[pidIndex].hClient = hClient;
160             status = NV_OK;
161             break;
162         }
163     }
164 
165     status = serverAllocShare(&g_resServ, classInfo(P2PTokenShare), &pShare);
166 
167     if (status != NV_OK)
168         return status;
169 
170     pP2PTokenShare = dynamicCast(pShare, P2PTokenShare);
171     pP2PTokenShare->pThirdPartyP2P = pThirdPartyP2P;
172     pThirdPartyP2P->pTokenShare = pP2PTokenShare;
173 
174     NV_ASSERT(status == NV_OK);
175     return status;
176 }
177 
178 static inline
gpuFullPowerSanityCheck(OBJGPU * pGpu,NvBool bGpuAccess)179 NV_STATUS gpuFullPowerSanityCheck(OBJGPU *pGpu, NvBool bGpuAccess)
180 {
181     API_GPU_FULL_POWER_SANITY_CHECK(pGpu, bGpuAccess, NV_FALSE);
182     return NV_OK;
183 }
184 
185 void
thirdpartyp2pDestruct_IMPL(ThirdPartyP2P * pThirdPartyP2P)186 thirdpartyp2pDestruct_IMPL
187 (
188     ThirdPartyP2P *pThirdPartyP2P
189 )
190 {
191     NV_STATUS                               status = NV_OK;
192     OBJGPU                                 *pGpu = GPU_RES_GET_GPU(pThirdPartyP2P);
193     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO        pVidmemInfo;
194     CALL_CONTEXT                           *pCallContext;
195     RS_RES_FREE_PARAMS_INTERNAL            *pParams;
196 
197     resGetFreeParams(staticCast(pThirdPartyP2P, RsResource), &pCallContext, &pParams);
198 
199     if (pThirdPartyP2P->pTokenShare)
200         serverFreeShare(&g_resServ, staticCast(pThirdPartyP2P->pTokenShare, RsShared));
201 
202     pParams->status = gpuFullPowerSanityCheck(pGpu, NV_TRUE);
203     if (pParams->status != NV_OK)
204     {
205         return;
206     }
207 
208     mapDestroy(&pThirdPartyP2P->vaSpaceInfoMap);
209 
210     pVidmemInfo = mapFindGEQ(&pThirdPartyP2P->vidmemInfoMap, 0);
211     while (pVidmemInfo != NULL)
212     {
213         status = CliDelThirdPartyP2PVidmemInfo(pThirdPartyP2P,
214                 pVidmemInfo->hMemory);
215         NV_ASSERT(status == NV_OK);
216         pVidmemInfo = mapFindGEQ(&pThirdPartyP2P->vidmemInfoMap, 0);
217     }
218 
219     //
220     // After destroying all of the vidmem info entries, there shouldn't remain
221     // any entries in the address range tree.
222     //
223     NV_ASSERT(pThirdPartyP2P->pAddressRangeTree == NULL);
224 
225     if (pThirdPartyP2P->pDestroyCallback != NULL)
226     {
227         pThirdPartyP2P->pDestroyCallback(pThirdPartyP2P->pData);
228     }
229 
230     pParams->status = status;
231 }
232 
CliGetThirdPartyP2PInfoFromToken(NvU64 p2pToken,ThirdPartyP2P ** ppThirdPartyP2P)233 NV_STATUS CliGetThirdPartyP2PInfoFromToken
234 (
235     NvU64  p2pToken,
236     ThirdPartyP2P            **ppThirdPartyP2P
237 )
238 {
239     ThirdPartyP2P *pThirdPartyP2P;
240     RS_SHARE_ITERATOR it;
241 
242     NV_ASSERT_OR_RETURN((ppThirdPartyP2P != NULL), NV_ERR_INVALID_ARGUMENT);
243 
244     it = serverutilShareIter(classId(P2PTokenShare));
245 
246     while(serverutilShareIterNext(&it))
247     {
248         RsShared *pShared = it.pShared;
249         P2PTokenShare *pP2PTokenShare = dynamicCast(pShared, P2PTokenShare);
250         if (pP2PTokenShare == NULL)
251             continue;
252         pThirdPartyP2P = pP2PTokenShare->pThirdPartyP2P;
253 
254         if (pThirdPartyP2P->p2pToken == p2pToken)
255         {
256             *ppThirdPartyP2P = pThirdPartyP2P;
257             return NV_OK;
258         }
259     }
260 
261     return NV_ERR_OBJECT_NOT_FOUND;
262 }
263 
264 static
CliGetPlatformDataMatchFromVidMem(PCLI_THIRD_PARTY_P2P_VIDMEM_INFO pVidmemInfo,void * pPlatformData)265 NV_STATUS CliGetPlatformDataMatchFromVidMem
266 (
267     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO pVidmemInfo,
268     void *pPlatformData
269 )
270 {
271     NV_STATUS status;
272     PNODE pNode;
273 
274     status = btreeSearch((NvU64)(NvUPtr)pPlatformData,
275                          &pNode, pVidmemInfo->pMappingInfoList);
276     return status;
277 }
278 
CliGetThirdPartyP2PPlatformData(ThirdPartyP2P * pThirdPartyP2P,void * platformData)279 NV_STATUS CliGetThirdPartyP2PPlatformData
280 (
281     ThirdPartyP2P *pThirdPartyP2P,
282     void *platformData
283 )
284 {
285     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO        pVidmemInfo;
286     CLI_THIRD_PARTY_P2P_VIDMEM_INFO_MAPIter vidMemMapIter = mapIterAll(&pThirdPartyP2P->vidmemInfoMap);
287 
288     while (mapIterNext(&vidMemMapIter))
289     {
290         pVidmemInfo = vidMemMapIter.pValue;
291         if (CliGetPlatformDataMatchFromVidMem(pVidmemInfo, platformData) == NV_OK)
292         {
293             return NV_OK;
294         }
295     }
296 
297     return NV_ERR_OBJECT_NOT_FOUND;
298 }
299 
CliNextThirdPartyP2PInfoWithPid(OBJGPU * pGpu,NvU32 pid,NvHandle hClient,RmClient ** ppClientOut,ThirdPartyP2P ** ppThirdPartyP2P)300 NV_STATUS CliNextThirdPartyP2PInfoWithPid
301 (
302     OBJGPU         *pGpu,
303     NvU32           pid,
304     NvHandle        hClient,
305     RmClient      **ppClientOut,
306     ThirdPartyP2P **ppThirdPartyP2P
307 )
308 {
309     ThirdPartyP2P *pThirdPartyP2P;
310     RS_SHARE_ITERATOR it;
311 
312     it = serverutilShareIter(classId(P2PTokenShare));
313 
314     while(serverutilShareIterNext(&it))
315     {
316         RsShared *pShared = it.pShared;
317         P2PTokenShare *pP2PTokenShare = dynamicCast(pShared, P2PTokenShare);
318         if (pP2PTokenShare == NULL)
319             continue;
320 
321         pThirdPartyP2P = pP2PTokenShare->pThirdPartyP2P;
322 
323         if (NULL == *ppThirdPartyP2P)
324         {
325             if (thirdpartyp2pIsValidClientPid(pThirdPartyP2P, pid, hClient))
326             {
327                 RsClient *pClient = RES_GET_CLIENT(pThirdPartyP2P);
328                 *ppClientOut = dynamicCast(pClient, RmClient);
329                 *ppThirdPartyP2P = pThirdPartyP2P;
330                 return NV_OK;
331             }
332         }
333         else if (pThirdPartyP2P->p2pToken ==
334                                          (*ppThirdPartyP2P)->p2pToken)
335         {
336             *ppClientOut = NULL;
337             *ppThirdPartyP2P = NULL;
338         }
339     }
340 
341     return NV_ERR_OBJECT_NOT_FOUND;
342 }
343 
CliAddThirdPartyP2PVASpace(ThirdPartyP2P * pThirdPartyP2P,NvHandle hVASpace,NvU32 * pVASpaceToken)344 NV_STATUS CliAddThirdPartyP2PVASpace
345 (
346     ThirdPartyP2P *pThirdPartyP2P,
347     NvHandle       hVASpace,
348     NvU32         *pVASpaceToken
349 )
350 {
351     NvHandle hThirdPartyP2P = RES_GET_HANDLE(pThirdPartyP2P);
352     RsClient *pClient = RES_GET_CLIENT(pThirdPartyP2P);
353     CLI_THIRD_PARTY_P2P_VASPACE_INFO vaSpaceInfo;
354     NvU32 vaSpaceToken;
355 
356     NV_ASSERT_OR_RETURN((pVASpaceToken != NULL), NV_ERR_INVALID_ARGUMENT);
357 
358     portMemSet(&vaSpaceInfo, 0, sizeof(CLI_THIRD_PARTY_P2P_VASPACE_INFO));
359 
360     for (vaSpaceToken = 0xfe00; vaSpaceToken < 0xff00; vaSpaceToken++)
361     {
362         if (mapFind(&pThirdPartyP2P->vaSpaceInfoMap, vaSpaceToken) == NULL)
363             break;
364     }
365     if (vaSpaceToken == 0xff00)
366     {
367         return NV_ERR_INSUFFICIENT_RESOURCES;
368     }
369 
370     vaSpaceInfo.hClient = pClient->hClient;
371     vaSpaceInfo.hThirdPartyP2P = hThirdPartyP2P;
372     vaSpaceInfo.hVASpace = hVASpace;
373     vaSpaceInfo.vaSpaceToken = vaSpaceToken;
374 
375     if (mapInsertValue(&pThirdPartyP2P->vaSpaceInfoMap, hVASpace, &vaSpaceInfo) == NULL)
376     {
377         if (mapFind(&pThirdPartyP2P->vaSpaceInfoMap, hVASpace) != NULL)
378         {
379             return NV_ERR_INSERT_DUPLICATE_NAME;
380         }
381         else
382         {
383             return NV_ERR_NO_MEMORY;
384         }
385     }
386 
387     if (hVASpace != 0)
388     {
389         RsResourceRef *pP2PRef;
390         RsResourceRef *pVASpaceRef;
391         if ((clientGetResourceRef(pClient, hThirdPartyP2P, &pP2PRef) == NV_OK) &&
392             (clientGetResourceRef(pClient, hVASpace, &pVASpaceRef) == NV_OK))
393         {
394             refAddDependant(pVASpaceRef, pP2PRef);
395         }
396     }
397 
398     *pVASpaceToken = vaSpaceToken;
399 
400     return NV_OK;
401 }
402 
CliDelThirdPartyP2PVASpace(ThirdPartyP2P * pThirdPartyP2P,NvHandle hVASpace)403 NV_STATUS CliDelThirdPartyP2PVASpace
404 (
405     ThirdPartyP2P *pThirdPartyP2P,
406     NvHandle hVASpace
407 )
408 {
409     PCLI_THIRD_PARTY_P2P_VASPACE_INFO pVASpaceInfo;
410 
411     pVASpaceInfo = mapFind(&pThirdPartyP2P->vaSpaceInfoMap, hVASpace);
412 
413     if (pVASpaceInfo == NULL)
414     {
415         return NV_ERR_OBJECT_NOT_FOUND;
416     }
417 
418     mapRemove(&pThirdPartyP2P->vaSpaceInfoMap, pVASpaceInfo);
419 
420     return NV_OK;
421 }
422 
thirdpartyp2pGetNextVASpaceInfo_IMPL(ThirdPartyP2P * pThirdPartyP2P,PCLI_THIRD_PARTY_P2P_VASPACE_INFO * ppVASpaceInfo)423 NV_STATUS thirdpartyp2pGetNextVASpaceInfo_IMPL
424 (
425     ThirdPartyP2P *pThirdPartyP2P,
426     PCLI_THIRD_PARTY_P2P_VASPACE_INFO *ppVASpaceInfo
427 )
428 {
429     if (*ppVASpaceInfo == NULL)
430     {
431         *ppVASpaceInfo = mapFindGEQ(&pThirdPartyP2P->vaSpaceInfoMap, 0);
432     }
433     else
434     {
435         *ppVASpaceInfo = mapNext(&pThirdPartyP2P->vaSpaceInfoMap, *ppVASpaceInfo);
436     }
437 
438     if (*ppVASpaceInfo == NULL)
439     {
440         return NV_ERR_OBJECT_NOT_FOUND;
441     }
442     else
443     {
444         return NV_OK;
445     }
446 }
447 
thirdpartyp2pGetVASpaceInfoFromToken_IMPL(ThirdPartyP2P * pThirdPartyP2P,NvU32 vaSpaceToken,PCLI_THIRD_PARTY_P2P_VASPACE_INFO * ppVASpaceInfo)448 NV_STATUS thirdpartyp2pGetVASpaceInfoFromToken_IMPL
449 (
450     ThirdPartyP2P                     *pThirdPartyP2P,
451     NvU32                              vaSpaceToken,
452     PCLI_THIRD_PARTY_P2P_VASPACE_INFO *ppVASpaceInfo
453 )
454 {
455     PCLI_THIRD_PARTY_P2P_VASPACE_INFO        pVASpaceInfo;
456     CLI_THIRD_PARTY_P2P_VASPACE_INFO_MAPIter vaSpaceInfoIter = mapIterAll(&pThirdPartyP2P->vaSpaceInfoMap);
457 
458     NV_ASSERT_OR_RETURN((ppVASpaceInfo != NULL), NV_ERR_INVALID_ARGUMENT);
459 
460     while(mapIterNext(&vaSpaceInfoIter))
461     {
462         pVASpaceInfo = vaSpaceInfoIter.pValue;
463 
464         if (pVASpaceInfo->vaSpaceToken == vaSpaceToken)
465         {
466             *ppVASpaceInfo = pVASpaceInfo;
467             return NV_OK;
468         }
469     }
470 
471     return NV_ERR_OBJECT_NOT_FOUND;
472 }
473 
CliAddThirdPartyP2PVidmemInfo(ThirdPartyP2P * pThirdPartyP2P,NvHandle hMemory,NvU64 address,NvU64 size,NvU64 offset,Memory * pMemory)474 NV_STATUS CliAddThirdPartyP2PVidmemInfo
475 (
476     ThirdPartyP2P *pThirdPartyP2P,
477     NvHandle       hMemory,
478     NvU64          address,
479     NvU64          size,
480     NvU64          offset,
481     Memory        *pMemory
482 )
483 {
484     NV_STATUS status;
485     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO pVidmemInfo;
486 
487     NV_ASSERT_OR_RETURN((pMemory != NULL), NV_ERR_INVALID_ARGUMENT);
488 
489     pVidmemInfo = portMemAllocNonPaged(sizeof(CLI_THIRD_PARTY_P2P_VIDMEM_INFO));
490     if (pVidmemInfo == NULL)
491     {
492         return NV_ERR_NO_MEMORY;
493     }
494 
495     portMemSet(pVidmemInfo, 0, sizeof(CLI_THIRD_PARTY_P2P_VIDMEM_INFO));
496 
497     listInitIntrusive(&pVidmemInfo->mappingExtentList);
498 
499     if (!mapInsertExisting(&pThirdPartyP2P->vidmemInfoMap, hMemory, pVidmemInfo))
500     {
501         if (mapFind(&pThirdPartyP2P->vidmemInfoMap, hMemory) != NULL)
502         {
503             status = NV_ERR_INSERT_DUPLICATE_NAME;
504         }
505         else
506         {
507             status = NV_ERR_INVALID_STATE;
508         }
509         portMemFree(pVidmemInfo);
510         return status;
511     }
512 
513     pVidmemInfo->offset = offset;
514 
515     pVidmemInfo->addressRangeNode.keyStart = address;
516     pVidmemInfo->addressRangeNode.keyEnd = address + size - 1;
517     pVidmemInfo->addressRangeNode.Data = pVidmemInfo;
518 
519     status = btreeInsert(&pVidmemInfo->addressRangeNode,
520                          &pThirdPartyP2P->pAddressRangeTree);
521     if (status != NV_OK)
522     {
523         mapRemove(&pThirdPartyP2P->vidmemInfoMap, pVidmemInfo);
524         portMemFree(pVidmemInfo);
525         return status;
526     }
527 
528     pVidmemInfo->hClient = RES_GET_CLIENT_HANDLE(pThirdPartyP2P);
529     pVidmemInfo->hThirdPartyP2P = RES_GET_HANDLE(pThirdPartyP2P);
530     pVidmemInfo->hMemory = hMemory;
531     pVidmemInfo->pMemDesc = pMemory->pMemDesc;
532     pVidmemInfo->id = portAtomicExIncrementU64(&vidmemInfoId);
533 
534     return NV_OK;
535 }
536 
537 // For persistent mappings, free VidmemInfo if it's not used by any clients.
CliDelThirdPartyP2PVidmemInfoPersistent(ThirdPartyP2P * pThirdPartyP2P,CLI_THIRD_PARTY_P2P_VIDMEM_INFO * pVidmemInfo)538 void CliDelThirdPartyP2PVidmemInfoPersistent
539 (
540     ThirdPartyP2P                   *pThirdPartyP2P,
541     CLI_THIRD_PARTY_P2P_VIDMEM_INFO *pVidmemInfo
542 )
543 {
544     RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
545     NODE *pNode = NULL;
546 
547     NV_ASSERT((pVidmemInfo != NULL) && (pThirdPartyP2P != NULL));
548 
549     btreeEnumStart(0, &pNode, pVidmemInfo->pMappingInfoList);
550     if (pNode == NULL)
551     {
552         pRmApi->Free(pRmApi, pThirdPartyP2P->hClient, pVidmemInfo->hMemory);
553     }
554 }
555 
CliDelThirdPartyP2PVidmemInfo(ThirdPartyP2P * pThirdPartyP2P,NvHandle hMemory)556 NV_STATUS CliDelThirdPartyP2PVidmemInfo
557 (
558     ThirdPartyP2P *pThirdPartyP2P,
559     NvHandle hMemory
560 )
561 {
562     NV_STATUS status;
563     PNODE pNode;
564     PCLI_THIRD_PARTY_P2P_MAPPING_INFO pMappingInfo;
565     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO pVidmemInfo;
566     void *pKey;
567     NvBool bPendingMappings = NV_FALSE;
568 
569     pVidmemInfo = mapFind(&pThirdPartyP2P->vidmemInfoMap, hMemory);
570     if (pVidmemInfo == NULL)
571     {
572         return NV_ERR_OBJECT_NOT_FOUND;
573     }
574 
575     pNode = pVidmemInfo->pMappingInfoList;
576     while (pNode != NULL)
577     {
578         pMappingInfo = pNode->Data;
579         pKey = (void *)(NvUPtr)pNode->keyStart;
580 
581         if (pMappingInfo->pFreeCallback != NULL)
582         {
583             pMappingInfo->pFreeCallback(pMappingInfo->pData);
584         }
585 
586         status = thirdpartyp2pDelMappingInfoByKey(pThirdPartyP2P, pKey, NV_FALSE);
587         NV_ASSERT(status == NV_OK);
588 
589         pNode = pVidmemInfo->pMappingInfoList;
590 
591         bPendingMappings = NV_TRUE;
592     }
593 
594     // RSYNC is needed only if there are outstanding mappings.
595     if (bPendingMappings)
596     {
597         osWaitForIbmnpuRsync(pVidmemInfo->pMemDesc->pGpu->pOsGpuInfo);
598     }
599 
600     mapRemove(&pThirdPartyP2P->vidmemInfoMap, pVidmemInfo);
601 
602     status = btreeUnlink(&pVidmemInfo->addressRangeNode,
603                          &pThirdPartyP2P->pAddressRangeTree);
604     NV_ASSERT(status == NV_OK);
605 
606     portMemFree(pVidmemInfo);
607 
608     return NV_OK;
609 }
610 
CliGetThirdPartyP2PVidmemInfoFromAddress(ThirdPartyP2P * pThirdPartyP2P,NvU64 address,NvU64 length,NvU64 * pOffset,PCLI_THIRD_PARTY_P2P_VIDMEM_INFO * ppVidmemInfo)611 NV_STATUS CliGetThirdPartyP2PVidmemInfoFromAddress
612 (
613     ThirdPartyP2P                    *pThirdPartyP2P,
614     NvU64                             address,
615     NvU64                             length,
616     NvU64                            *pOffset,
617     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO *ppVidmemInfo
618 )
619 {
620     NV_STATUS status;
621     PNODE pNode;
622     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO pVidmemInfo;
623 
624     NV_ASSERT_OR_RETURN((pOffset != NULL), NV_ERR_INVALID_ARGUMENT);
625     NV_ASSERT_OR_RETURN((ppVidmemInfo != NULL), NV_ERR_INVALID_ARGUMENT);
626 
627     status = btreeSearch(address, &pNode,
628                          pThirdPartyP2P->pAddressRangeTree);
629     if (status != NV_OK)
630     {
631         return status;
632     }
633 
634     pVidmemInfo = pNode->Data;
635 
636     if (address + length - 1 > pVidmemInfo->addressRangeNode.keyEnd)
637         return NV_ERR_INVALID_ARGUMENT;
638 
639     *ppVidmemInfo = pVidmemInfo;
640 
641     //
642     // Adjust offset w.r.t. the memdesc associated with PCLI_THIRD_PARTY_P2P_VIDMEM_INFO,
643     // so that it can be safely consumed by memdescGetPhysAddr.
644     //
645     *pOffset = pVidmemInfo->offset +
646                (address - pVidmemInfo->addressRangeNode.keyStart);
647 
648     return NV_OK;
649 }
650 
CliGetThirdPartyP2PVidmemInfoFromId(ThirdPartyP2P * pThirdPartyP2P,NvU64 id,CLI_THIRD_PARTY_P2P_VIDMEM_INFO ** ppVidmemInfo)651 NV_STATUS CliGetThirdPartyP2PVidmemInfoFromId
652 (
653     ThirdPartyP2P                    *pThirdPartyP2P,
654     NvU64                             id,
655     CLI_THIRD_PARTY_P2P_VIDMEM_INFO **ppVidmemInfo
656 )
657 {
658     NV_STATUS status;
659     PNODE pNode;
660 
661     NV_ASSERT_OR_RETURN((ppVidmemInfo != NULL), NV_ERR_INVALID_ARGUMENT);
662 
663     status = btreeSearch(id, &pNode, pThirdPartyP2P->pAddressRangeTree);
664     if (status != NV_OK)
665     {
666         return status;
667     }
668 
669     *ppVidmemInfo = pNode->Data;
670 
671     return NV_OK;
672 }
673 
CliRegisterThirdPartyP2PMappingCallback(ThirdPartyP2P * pThirdPartyP2P,NvHandle hMemory,void * pKey,THIRD_PARTY_P2P_VIDMEM_FREE_CALLBACK * pFreeCallback,void * pData)674 NV_STATUS CliRegisterThirdPartyP2PMappingCallback
675 (
676     ThirdPartyP2P                        *pThirdPartyP2P,
677     NvHandle                              hMemory,
678     void                                 *pKey,
679     THIRD_PARTY_P2P_VIDMEM_FREE_CALLBACK *pFreeCallback,
680     void                                 *pData
681 )
682 {
683     NV_STATUS status;
684     PCLI_THIRD_PARTY_P2P_MAPPING_INFO pMappingInfo;
685 
686     NV_ASSERT_OR_RETURN((pFreeCallback != NULL), NV_ERR_INVALID_ARGUMENT);
687 
688     status = CliGetThirdPartyP2PMappingInfoFromKey(pThirdPartyP2P, hMemory, pKey,
689                                                    &pMappingInfo);
690     if (status != NV_OK)
691     {
692         return status;
693     }
694 
695     NV_ASSERT_OR_RETURN((pMappingInfo->pFreeCallback == NULL), NV_ERR_INVALID_STATE);
696 
697     pMappingInfo->pFreeCallback = pFreeCallback;
698     pMappingInfo->pData         = pData;
699 
700     return NV_OK;
701 }
702 
CliAddThirdPartyP2PMappingInfo(ThirdPartyP2P * pThirdPartyP2P,NvHandle hMemory,void * pKey,THIRD_PARTY_P2P_VIDMEM_FREE_CALLBACK * pFreeCallback,void * pData,PCLI_THIRD_PARTY_P2P_MAPPING_INFO * ppMappingInfo)703 NV_STATUS CliAddThirdPartyP2PMappingInfo
704 (
705     ThirdPartyP2P                        *pThirdPartyP2P,
706     NvHandle                              hMemory,
707     void                                 *pKey,
708     THIRD_PARTY_P2P_VIDMEM_FREE_CALLBACK *pFreeCallback,
709     void                                 *pData,
710     PCLI_THIRD_PARTY_P2P_MAPPING_INFO    *ppMappingInfo
711 )
712 {
713     NV_STATUS status;
714     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO pVidmemInfo;
715     PCLI_THIRD_PARTY_P2P_MAPPING_INFO pMappingInfo;
716 
717     NV_ASSERT_OR_RETURN((pKey != NULL), NV_ERR_INVALID_ARGUMENT);
718     NV_ASSERT_OR_RETURN((ppMappingInfo != NULL), NV_ERR_INVALID_ARGUMENT);
719 
720     pVidmemInfo = mapFind(&pThirdPartyP2P->vidmemInfoMap, hMemory);
721     if (pVidmemInfo == NULL)
722     {
723         return NV_ERR_OBJECT_NOT_FOUND;
724     }
725 
726     pMappingInfo = portMemAllocNonPaged(sizeof(CLI_THIRD_PARTY_P2P_MAPPING_INFO));
727     if (pMappingInfo == NULL)
728     {
729         return NV_ERR_NO_MEMORY;
730     }
731 
732     portMemSet(pMappingInfo, 0, sizeof(CLI_THIRD_PARTY_P2P_MAPPING_INFO));
733 
734     pMappingInfo->Node.keyStart = (NvU64)(NvUPtr)pKey;
735     pMappingInfo->Node.keyEnd = (NvU64)(NvUPtr)pKey;
736     pMappingInfo->Node.Data = pMappingInfo;
737 
738     status = btreeInsert(&pMappingInfo->Node, &pVidmemInfo->pMappingInfoList);
739     if (status != NV_OK)
740     {
741         portMemFree(pMappingInfo);
742         return status;
743     }
744 
745     pMappingInfo->pFreeCallback = pFreeCallback;
746     pMappingInfo->pData = pData;
747 
748     *ppMappingInfo = pMappingInfo;
749 
750     return NV_OK;
751 }
752 
CliGetThirdPartyP2PMappingInfoFromKey(ThirdPartyP2P * pThirdPartyP2P,NvHandle hMemory,void * pKey,PCLI_THIRD_PARTY_P2P_MAPPING_INFO * ppMappingInfo)753 NV_STATUS CliGetThirdPartyP2PMappingInfoFromKey
754 (
755     ThirdPartyP2P                     *pThirdPartyP2P,
756     NvHandle                           hMemory,
757     void                              *pKey,
758     PCLI_THIRD_PARTY_P2P_MAPPING_INFO *ppMappingInfo
759 )
760 {
761     NV_STATUS status;
762     PNODE pNode;
763     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO pVidmemInfo;
764 
765     NV_ASSERT_OR_RETURN((pKey != NULL), NV_ERR_INVALID_ARGUMENT);
766     NV_ASSERT_OR_RETURN((ppMappingInfo != NULL), NV_ERR_INVALID_ARGUMENT);
767 
768     pVidmemInfo = mapFind(&pThirdPartyP2P->vidmemInfoMap, hMemory);
769     if (pVidmemInfo == NULL)
770     {
771         return NV_ERR_OBJECT_NOT_FOUND;
772     }
773 
774     status = btreeSearch((NvU64)(NvUPtr)pKey,
775                          &pNode, pVidmemInfo->pMappingInfoList);
776     if (status != NV_OK)
777     {
778         return status;
779     }
780 
781     *ppMappingInfo = pNode->Data;
782 
783     return NV_OK;
784 }
785 
_thirdpartyp2pDelMappingInfoByKey(ThirdPartyP2P * pThirdPartyP2P,void * pKey,NvBool bIsRsyncNeeded,CLI_THIRD_PARTY_P2P_VIDMEM_INFO ** ppVidmemInfo)786 static NV_STATUS _thirdpartyp2pDelMappingInfoByKey
787 (
788     ThirdPartyP2P                    *pThirdPartyP2P,
789     void                             *pKey,
790     NvBool                            bIsRsyncNeeded,
791     CLI_THIRD_PARTY_P2P_VIDMEM_INFO **ppVidmemInfo
792 )
793 {
794     NV_STATUS                                status;
795     PNODE                                    pNode;
796     PCLI_THIRD_PARTY_P2P_VIDMEM_INFO         pVidmemInfo;
797     PCLI_THIRD_PARTY_P2P_MAPPING_INFO        pMappingInfo;
798     PCLI_THIRD_PARTY_P2P_MAPPING_EXTENT_INFO pExtentInfo;
799     PCLI_THIRD_PARTY_P2P_MAPPING_EXTENT_INFO pExtentInfoNext;
800     Subdevice                               *pSubdevice;
801     OBJGPU                                  *pGpu = GPU_RES_GET_GPU(pThirdPartyP2P);
802     KernelBus                               *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
803     NvU64                                    length;
804     NvU64                                    mappingLength;
805     NvU64                                    address;
806     NvU64                                    startOffset;
807     CLI_THIRD_PARTY_P2P_VIDMEM_INFO_MAPIter  vidMemMapIter;
808     NvBool                                   bGpuLockTaken;
809     NvBool                                   bVgpuRpc;
810 
811     NV_ASSERT_OR_RETURN((pKey != NULL), NV_ERR_INVALID_ARGUMENT);
812 
813     bGpuLockTaken = (rmDeviceGpuLockIsOwner(gpuGetInstance(pGpu)) ||
814                      rmGpuLockIsOwner());
815 
816     bVgpuRpc = IS_VIRTUAL(pGpu) && gpuIsWarBug200577889SriovHeavyEnabled(pGpu);
817 
818     pSubdevice = pThirdPartyP2P->pSubdevice;
819 
820     GPU_RES_SET_THREAD_BC_STATE(pThirdPartyP2P);
821 
822     //
823     // vGPU RPC is being called without GPU lock held.
824     // So acquire the lock only for non-vGPU case and if
825     // no locks are held.
826     //
827     if (!bVgpuRpc && !bGpuLockTaken)
828     {
829         status = rmDeviceGpuLocksAcquire(pGpu, GPUS_LOCK_FLAGS_NONE,
830                                          RM_LOCK_MODULES_P2P);
831         NV_ASSERT_OK_OR_RETURN(status);
832     }
833 
834     vidMemMapIter = mapIterAll(&pThirdPartyP2P->vidmemInfoMap);
835     while (mapIterNext(&vidMemMapIter))
836     {
837         pVidmemInfo = vidMemMapIter.pValue;
838 
839         status = btreeSearch((NvU64)(NvUPtr)pKey,
840                              &pNode, pVidmemInfo->pMappingInfoList);
841         if (status == NV_OK)
842         {
843             pMappingInfo = pNode->Data;
844             length = pMappingInfo->length;
845             address = pMappingInfo->address;
846 
847             for(pExtentInfo = pMappingInfo->pStart; (pExtentInfo != NULL) && (length != 0);
848                 pExtentInfo = pExtentInfoNext)
849             {
850                 pExtentInfoNext = listNext(&pVidmemInfo->mappingExtentList, pExtentInfo);
851                 startOffset = address - pExtentInfo->address;
852                 mappingLength = NV_MIN(length, (pExtentInfo->length - startOffset));
853 
854                 address += mappingLength;
855                 length -= mappingLength;
856                 pExtentInfo->refCount--;
857                 if (pExtentInfo->refCount == 0)
858                 {
859                     NV_PRINTF(LEVEL_INFO,
860                               "Freeing P2P mapping for gpu VA: 0x%llx, length: 0x%llx\n",
861                               pExtentInfo->address, pExtentInfo->length);
862 
863                     if (bVgpuRpc)
864                     {
865                         NV_RM_RPC_UNMAP_MEMORY(pGpu, pThirdPartyP2P->hClient,
866                                                RES_GET_PARENT_HANDLE(pSubdevice),
867                                                pVidmemInfo->hMemory,
868                                                0,
869                                                pExtentInfo->fbApertureOffset, status);
870                     }
871                     else
872                     {
873                         status = kbusUnmapFbAperture_HAL(pGpu, pKernelBus,
874                                                          pExtentInfo->pMemDesc,
875                                                          pExtentInfo->fbApertureOffset,
876                                                          pExtentInfo->length,
877                                                          BUS_MAP_FB_FLAGS_MAP_UNICAST);
878                     }
879                     NV_ASSERT(status == NV_OK);
880 
881                     listRemove(&pVidmemInfo->mappingExtentList, pExtentInfo);
882 
883                     pSubdevice->P2PfbMappedBytes -= pExtentInfo->length;
884                     memdescDestroy(pExtentInfo->pMemDesc);
885                     portMemFree(pExtentInfo);
886                 }
887             }
888             NV_ASSERT(length == 0);
889 
890             status = btreeUnlink(&pMappingInfo->Node,
891                                  &pVidmemInfo->pMappingInfoList);
892             if (status == NV_OK)
893             {
894                 portMemFree(pMappingInfo);
895             }
896 
897             if (bIsRsyncNeeded)
898             {
899                 osWaitForIbmnpuRsync(pVidmemInfo->pMemDesc->pGpu->pOsGpuInfo);
900             }
901 
902             //
903             // For persistent mappings, we return the VidmemInfo and clean up
904             // the internal ThirdPartyP2P object and duped memory handle.
905             //
906             if (ppVidmemInfo != NULL)
907             {
908                 *ppVidmemInfo = pVidmemInfo;
909                 break;
910             }
911         }
912     }
913 
914     if (!bVgpuRpc && !bGpuLockTaken)
915     {
916         rmDeviceGpuLocksRelease(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
917     }
918 
919     return NV_OK;
920 }
921 
thirdpartyp2pDelMappingInfoByKey_IMPL(ThirdPartyP2P * pThirdPartyP2P,void * pKey,NvBool bIsRsyncNeeded)922 NV_STATUS thirdpartyp2pDelMappingInfoByKey_IMPL
923 (
924     ThirdPartyP2P                    *pThirdPartyP2P,
925     void                             *pKey,
926     NvBool                            bIsRsyncNeeded
927 )
928 {
929     return _thirdpartyp2pDelMappingInfoByKey(pThirdPartyP2P,
930                                              pKey,
931                                              bIsRsyncNeeded,
932                                              NULL);
933 }
934 
thirdpartyp2pDelPersistentMappingInfoByKey_IMPL(ThirdPartyP2P * pThirdPartyP2P,void * pKey,NvBool bIsRsyncNeeded)935 NV_STATUS thirdpartyp2pDelPersistentMappingInfoByKey_IMPL
936 (
937     ThirdPartyP2P                    *pThirdPartyP2P,
938     void                             *pKey,
939     NvBool                            bIsRsyncNeeded
940 )
941 {
942     CLI_THIRD_PARTY_P2P_VIDMEM_INFO *pVidmemInfo = NULL;
943 
944     NV_ASSERT_OK_OR_RETURN(
945         _thirdpartyp2pDelMappingInfoByKey(pThirdPartyP2P, pKey,
946                                           bIsRsyncNeeded, &pVidmemInfo));
947 
948     CliDelThirdPartyP2PVidmemInfoPersistent(pThirdPartyP2P, pVidmemInfo);
949 
950     return NV_OK;
951 }
952 
953 NV_STATUS
CliAddThirdPartyP2PClientPid(NvHandle hClient,NvHandle hThirdPartyP2P,NvU32 pid,NvU32 client)954 CliAddThirdPartyP2PClientPid
955 (
956     NvHandle hClient,
957     NvHandle hThirdPartyP2P,
958     NvU32    pid,
959     NvU32    client
960 )
961 {
962     RsResourceRef *pThirdPartyP2PRef;
963     ThirdPartyP2P *pThirdPartyP2P;
964     NvU32          pidIndex;
965     RsClient      *pClient;
966 
967     NV_ASSERT_OK_OR_RETURN(
968         serverGetClientUnderLock(&g_resServ, hClient, &pClient));
969 
970     NV_ASSERT_OK_OR_RETURN(
971         clientGetResourceRef(pClient,
972                                   hThirdPartyP2P,
973                                   &pThirdPartyP2PRef));
974 
975     pThirdPartyP2P = dynamicCast(pThirdPartyP2PRef->pResource, ThirdPartyP2P);
976     if (pThirdPartyP2P == NULL)
977     {
978         return NV_ERR_INVALID_OBJECT;
979     }
980 
981     // Do not register another client if one already exists for this PID
982     if (thirdpartyp2pIsValidClientPid(pThirdPartyP2P, pid, client))
983     {
984         return NV_OK;
985     }
986     NV_ASSERT_OR_RETURN(!thirdpartyp2pIsValidClientPid(pThirdPartyP2P, pid, 0), NV_ERR_STATE_IN_USE);
987 
988 
989     for (pidIndex = 0; pidIndex < CLI_THIRD_PARTY_P2P_MAX_CLIENT; pidIndex++)
990     {
991         if (0 == pThirdPartyP2P->pidClientList[pidIndex].pid)
992         {
993             pThirdPartyP2P->pidClientList[pidIndex].pid = pid;
994             pThirdPartyP2P->pidClientList[pidIndex].hClient = client;
995             return NV_OK;
996         }
997     }
998 
999     return NV_ERR_OBJECT_NOT_FOUND;
1000 }
1001 
1002 NvBool
thirdpartyp2pIsValidClientPid_IMPL(ThirdPartyP2P * pThirdPartyP2P,NvU32 pid,NvHandle hClient)1003 thirdpartyp2pIsValidClientPid_IMPL
1004 (
1005     ThirdPartyP2P* pThirdPartyP2P,
1006     NvU32    pid,
1007     NvHandle hClient
1008 )
1009 {
1010     NvU32 pidIndex;
1011 
1012     for (pidIndex = 0; pidIndex < CLI_THIRD_PARTY_P2P_MAX_CLIENT; pidIndex++)
1013     {
1014         if (pid == pThirdPartyP2P->pidClientList[pidIndex].pid &&
1015            (hClient == 0 || hClient == pThirdPartyP2P->pidClientList[pidIndex].hClient))
1016         {
1017             return NV_TRUE;
1018         }
1019     }
1020 
1021     return NV_FALSE;
1022 }
1023 
1024 NV_STATUS
CliDelThirdPartyP2PClientPid(RmClient * pClient,NvHandle hThirdPartyP2P,NvU32 pid,NvU32 client)1025 CliDelThirdPartyP2PClientPid
1026 (
1027     RmClient *pClient,
1028     NvHandle hThirdPartyP2P,
1029     NvU32    pid,
1030     NvU32    client
1031 )
1032 {
1033     NvU32 pidIndex;
1034     RsResource               *pRes;
1035     ThirdPartyP2P            *pThirdPartyP2P;
1036 
1037     pThirdPartyP2P = serverutilGetDerived(pClient, hThirdPartyP2P, &pRes, ThirdPartyP2P);
1038     if (pThirdPartyP2P == NULL)
1039     {
1040         return NV_ERR_OBJECT_NOT_FOUND;
1041     }
1042 
1043     for (pidIndex = 0; pidIndex < CLI_THIRD_PARTY_P2P_MAX_CLIENT; pidIndex++)
1044     {
1045         if (pid == pThirdPartyP2P->pidClientList[pidIndex].pid &&
1046             client == pThirdPartyP2P->pidClientList[pidIndex].hClient)
1047         {
1048             pThirdPartyP2P->pidClientList[pidIndex].pid = 0;
1049             pThirdPartyP2P->pidClientList[pidIndex].hClient = 0;
1050             return NV_OK;
1051         }
1052     }
1053 
1054     return NV_ERR_OBJECT_NOT_FOUND;
1055 }
1056 
1057 NV_STATUS
CliUnregisterFromThirdPartyP2P(RmClient * pClient)1058 CliUnregisterFromThirdPartyP2P
1059 (
1060     RmClient *pClient
1061 )
1062 {
1063     NV_STATUS status = NV_OK;
1064     ThirdPartyP2P *pThirdPartyP2P = NULL;
1065     NvU32 pid;
1066     NvHandle hClient = staticCast(pClient, RsClient)->hClient;
1067 
1068     pid = pClient->ProcID;
1069 
1070     while (1)
1071     {
1072         RmClient *pThirdPartyP2PClient;
1073         status = CliNextThirdPartyP2PInfoWithPid(NULL, pid, hClient, &pThirdPartyP2PClient, &pThirdPartyP2P);
1074         if (status != NV_OK)
1075         {
1076             return NV_OK;
1077         }
1078 
1079         CliDelThirdPartyP2PClientPid(pThirdPartyP2PClient,
1080                                pThirdPartyP2P->hThirdPartyP2P,
1081                                pid,
1082                                hClient);
1083     }
1084 
1085     return status;
1086 }
1087 
1088 NV_STATUS
shrp2pConstruct_IMPL(P2PTokenShare * pP2PTokenShare)1089 shrp2pConstruct_IMPL(P2PTokenShare *pP2PTokenShare)
1090 {
1091     return NV_OK;
1092 }
1093 
shrp2pDestruct_IMPL(P2PTokenShare * pP2PTokenShare)1094 void shrp2pDestruct_IMPL(P2PTokenShare *pP2PTokenShare)
1095 {
1096 }
1097 
1098 void
CliUnregisterMemoryFromThirdPartyP2P(Memory * pMemory)1099 CliUnregisterMemoryFromThirdPartyP2P
1100 (
1101     Memory   *pMemory
1102 )
1103 {
1104     RsClient *pRsClient = RES_GET_CLIENT(pMemory);
1105     NvHandle hMemory = RES_GET_HANDLE(pMemory);
1106     ThirdPartyP2P *pThirdPartyP2P;
1107     Device *pDevice = pMemory->pDevice;
1108     RsResourceRef *pDeviceRef = RES_GET_REF(pDevice);
1109     RS_ITERATOR subDevIt;
1110     RS_ITERATOR it;
1111 
1112     subDevIt = clientRefIter(pRsClient, pDeviceRef, classId(Subdevice),
1113                              RS_ITERATE_CHILDREN, NV_TRUE);
1114     while (clientRefIterNext(pRsClient, &subDevIt))
1115     {
1116         it = clientRefIter(pRsClient, subDevIt.pResourceRef, classId(ThirdPartyP2P), \
1117                            RS_ITERATE_CHILDREN, NV_TRUE);
1118 
1119         while (clientRefIterNext(pRsClient, &it))
1120         {
1121             pThirdPartyP2P = dynamicCast(it.pResourceRef->pResource, ThirdPartyP2P);
1122             if (pThirdPartyP2P == NULL)
1123                 continue;
1124 
1125             (void)CliDelThirdPartyP2PVidmemInfo(pThirdPartyP2P, hMemory);
1126         }
1127     }
1128 }
1129