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