1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 1993-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/system.h" 25 #include "gpu_mgr/gpu_mgr.h" 26 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h" 27 #include "kernel/gpu/nvlink/kernel_nvlink.h" 28 #include "kernel/gpu/bif/kernel_bif.h" 29 #include "gpu/subdevice/subdevice.h" 30 #include "gpu/gpu.h" 31 #include "vgpu/rpc.h" 32 #include "vgpu/vgpu_events.h" 33 #include "platform/chipset/chipset.h" 34 #include "platform/p2p/p2p_caps.h" 35 #include "nvRmReg.h" 36 #include "nvlimits.h" 37 #include "nvdevid.h" 38 39 ct_assert(NV2080_GET_P2P_CAPS_UUID_LEN == NV_GPU_UUID_LEN); 40 41 /** 42 * @brief Determines if the GPUs are P2P compatible 43 * 44 * @param[in] pGpu0 45 * @param[in] pGpu1 46 * 47 * @return NV_TRUE if the GPUs are P2P compatible 48 */ 49 static NvBool 50 areGpusP2PCompatible(OBJGPU *pGpu0, OBJGPU *pGpu1) 51 { 52 // Mark GPUs of different arch or impl incapable of P2P over pcie 53 if ((gpuGetChipArch(pGpu0) != gpuGetChipArch(pGpu1)) || 54 (gpuGetChipImpl(pGpu0) != gpuGetChipImpl(pGpu1))) 55 { 56 return NV_FALSE; 57 } 58 59 // Mark GPUs of different notebook implementation incapable of P2P over pcie 60 if (IsMobile(pGpu0) != IsMobile(pGpu1)) 61 { 62 return NV_FALSE; 63 } 64 65 return NV_TRUE; 66 } 67 68 NV_STATUS 69 p2pGetCaps 70 ( 71 NvU32 gpuMask, 72 NvBool *pP2PWriteCapable, 73 NvBool *pP2PReadCapable, 74 P2P_CONNECTIVITY *pConnectivity 75 ) 76 { 77 NvU8 p2PWriteCapsStatus; 78 NvU8 p2PReadCapsStatus; 79 NV_STATUS status; 80 P2P_CONNECTIVITY connectivity; 81 82 if ((pP2PWriteCapable == NULL) || (pP2PReadCapable == NULL)) 83 { 84 return NV_ERR_INVALID_ARGUMENT; 85 } 86 87 status = p2pGetCapsStatus(gpuMask, &p2PWriteCapsStatus, 88 &p2PReadCapsStatus, &connectivity 89 ); 90 if (status != NV_OK) 91 { 92 return status; 93 } 94 95 // 96 // The classes like NV50_P2P, NV50_THIRD_PARTY_P2P depends on direct P2P 97 // connectivity, hence the check. 98 // 99 if (!((connectivity == P2P_CONNECTIVITY_PCIE) || 100 (connectivity == P2P_CONNECTIVITY_PCIE_BAR1) || 101 (connectivity == P2P_CONNECTIVITY_NVLINK) || 102 (connectivity == P2P_CONNECTIVITY_C2C))) 103 { 104 return NV_ERR_NOT_SUPPORTED; 105 } 106 107 *pP2PWriteCapable = (p2PWriteCapsStatus == NV0000_P2P_CAPS_STATUS_OK); 108 *pP2PReadCapable = (p2PReadCapsStatus == NV0000_P2P_CAPS_STATUS_OK); 109 110 if (pConnectivity != NULL) 111 { 112 *pConnectivity = connectivity; 113 } 114 115 return status; 116 } 117 118 static NV_STATUS 119 _kp2pCapsGetStatusIndirectOverNvLink 120 ( 121 NvU32 gpuMask, 122 NvU8 *pP2PWriteCapStatus, 123 NvU8 *pP2PReadCapStatus 124 ) 125 { 126 OBJGPU *pGpu = NULL; 127 NvU32 gpuInstance = 0; 128 OBJGPU *pFirstGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance); 129 NvBool bIndirectPeers = NV_FALSE; 130 KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pFirstGpu); 131 132 if ((pKernelBif->forceP2PType != NV_REG_STR_RM_FORCE_P2P_TYPE_DEFAULT) && 133 (pKernelBif->forceP2PType != NV_REG_STR_RM_FORCE_P2P_TYPE_NVLINK)) 134 { 135 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 136 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 137 return NV_OK; 138 } 139 140 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL) 141 { 142 bIndirectPeers = gpumgrCheckIndirectPeer(pFirstGpu, pGpu); 143 if (!bIndirectPeers) 144 { 145 break; 146 } 147 } 148 149 if (bIndirectPeers) 150 { 151 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_OK; 152 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_OK; 153 } 154 else 155 { 156 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 157 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 158 } 159 160 return NV_OK; 161 } 162 163 static NV_STATUS 164 _gpumgrGetP2PCapsStatusOverNvLink 165 ( 166 NvU32 gpuMask, 167 NvU8 *pP2PWriteCapStatus, 168 NvU8 *pP2PReadCapStatus 169 ) 170 { 171 OBJGPU *pGpu = NULL; 172 NvU32 gpuInstance = 0; 173 NV_STATUS status; 174 OBJGPU *pFirstGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance); 175 RMTIMEOUT timeout; 176 NvU32 linkTrainingTimeout = 10000000; 177 KernelBif *pKernelBif = NULL; 178 KernelNvlink *pKernelNvlink = NULL; 179 180 NV_ASSERT_OR_RETURN(pFirstGpu != NULL, NV_ERR_INVALID_ARGUMENT); 181 pKernelNvlink = GPU_GET_KERNEL_NVLINK(pFirstGpu); 182 pKernelBif = GPU_GET_KERNEL_BIF(pFirstGpu); 183 184 if ((pKernelBif->forceP2PType != NV_REG_STR_RM_FORCE_P2P_TYPE_DEFAULT) && 185 (pKernelBif->forceP2PType != NV_REG_STR_RM_FORCE_P2P_TYPE_NVLINK)) 186 { 187 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 188 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 189 return NV_OK; 190 } 191 192 // 193 // Re-initialize to check loop back configuration if only single GPU in 194 // requested mask. 195 // 196 gpuInstance = (gpumgrGetSubDeviceCount(gpuMask) > 1) ? gpuInstance : 0; 197 198 // Check NvLink P2P connectivity 199 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL) 200 { 201 // 202 // If ALI is enabled then poll to make sure that the links have 203 // finished training on the two given gpus. If timeout occurs then 204 // log an error, but continue on as there could be another gpu pair 205 // that could have connectivity 206 // 207 208 if ((pKernelNvlink != NULL) && 209 knvlinkDiscoverPostRxDetLinks_HAL(pFirstGpu, pKernelNvlink, pGpu) == NV_OK) 210 { 211 // Check to make sure that the links are active 212 213 gpuSetTimeout(pGpu, linkTrainingTimeout, &timeout, IS_SILICON(pGpu) ? 214 (GPU_TIMEOUT_FLAGS_BYPASS_THREAD_STATE | GPU_TIMEOUT_FLAGS_DEFAULT) : 0); 215 do 216 { 217 status = gpuCheckTimeout(pGpu, &timeout); 218 219 if (knvlinkCheckTrainingIsComplete(pFirstGpu, pGpu, pKernelNvlink) == NV_OK) 220 { 221 break; 222 } 223 224 if (status == NV_ERR_TIMEOUT) 225 { 226 NV_PRINTF(LEVEL_ERROR, 227 "Links failed to train for the given gpu pairs!\n"); 228 return status; 229 } 230 } 231 while(status != NV_ERR_TIMEOUT); 232 } 233 234 // Ensure that we can create a NvLink P2P object between the two object 235 if ((pKernelNvlink != NULL) && 236 knvlinkIsNvlinkP2pSupported(pFirstGpu, pKernelNvlink, pGpu)) 237 { 238 // Ensure training completes on legacy nvlink devices 239 status = knvlinkTrainP2pLinksToActive(pFirstGpu, pGpu, pKernelNvlink); 240 NV_ASSERT(status == NV_OK); 241 242 if (status != NV_OK) 243 { 244 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 245 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 246 return NV_OK; 247 } 248 } 249 else 250 { 251 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 252 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 253 return NV_OK; 254 } 255 } 256 257 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_OK; 258 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_OK; 259 return NV_OK; 260 } 261 262 // Returns true if overrides are enabled for PCI-E. 263 static NvBool 264 _kp2pCapsCheckStatusOverridesForPcie 265 ( 266 NvU32 gpuMask, 267 NvU8 *pP2PWriteCapStatus, 268 NvU8 *pP2PReadCapStatus 269 ) 270 { 271 KernelBif *pKernelBif = NULL; 272 NvU32 gpuInstance = 0; 273 OBJGPU *pGpu = NULL; 274 275 // Check overrides for all GPUs in the mask. 276 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL) 277 { 278 pKernelBif = GPU_GET_KERNEL_BIF(pGpu); 279 if (pKernelBif->p2pOverride != BIF_P2P_NOT_OVERRIDEN) 280 { 281 switch(DRF_VAL(_REG_STR, _CL_FORCE_P2P, _READ, pKernelBif->p2pOverride)) 282 { 283 case NV_REG_STR_CL_FORCE_P2P_READ_DISABLE: 284 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_DISABLED_BY_REGKEY; 285 break; 286 case NV_REG_STR_CL_FORCE_P2P_READ_ENABLE: 287 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_OK; 288 break; 289 default: 290 break; 291 } 292 293 switch(DRF_VAL(_REG_STR, _CL_FORCE_P2P, _WRITE, pKernelBif->p2pOverride)) 294 { 295 case NV_REG_STR_CL_FORCE_P2P_WRITE_DISABLE: 296 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_DISABLED_BY_REGKEY; 297 break; 298 case NV_REG_STR_CL_FORCE_P2P_WRITE_ENABLE: 299 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_OK; 300 break; 301 default: 302 break; 303 } 304 305 return NV_TRUE; 306 } 307 308 } 309 310 return NV_FALSE; 311 } 312 313 /** 314 * @brief Check GPU Pcie mailbox P2P capability 315 * 316 * @param[in] pGpu OBJGPU pointer 317 * @param[out] pP2PWriteCapStatus Pointer to get the P2P write capability 318 * @param[out] pP2PReadCapStatus Pointer to get the P2P read capability 319 * @param[out] pbCommonPciSwitch To return if GPUs are on a common PCIE switch 320 * 321 * @returns NV_OK, if successfully 322 * The write and read capability status are in the pP2PWriteCapStatus and pP2PReadCapStatus 323 */ 324 static NV_STATUS 325 _kp2pCapsGetStatusOverPcie 326 ( 327 NvU32 gpuMask, 328 NvU8 *pP2PWriteCapStatus, 329 NvU8 *pP2PReadCapStatus, 330 NvBool *pbCommonPciSwitch 331 ) 332 { 333 OBJGPU *pGpu = NULL; 334 OBJGPU *pFirstGpu = NULL; 335 NvU32 gpuInstance = 0; 336 KernelBif *pKernelBif = NULL; 337 OBJSYS *pSys = SYS_GET_INSTANCE(); 338 OBJCL *pCl = SYS_GET_CL(pSys); 339 NvU32 iohDomain_ref = 0xFFFFFFFF; 340 NvU8 iohBus_ref = 0xFF; 341 NvU8 pciSwitchBus = 0, pciSwitchBus_ref = 0xFF; 342 NvBool bCommonPciSwitchFound = NV_TRUE; 343 NvU16 deviceID; 344 NvU8 gpuP2PReadCapsStatus = NV0000_P2P_CAPS_STATUS_OK; 345 NvU8 gpuP2PWriteCapsStatus = NV0000_P2P_CAPS_STATUS_OK; 346 NvU32 lockedGpuMask = 0; 347 NV_STATUS status = NV_OK; 348 349 // Check if any overrides are enabled. 350 if (_kp2pCapsCheckStatusOverridesForPcie(gpuMask, pP2PWriteCapStatus, 351 pP2PReadCapStatus)) 352 { 353 return NV_OK; 354 } 355 356 pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance); 357 if (IS_GSP_CLIENT(pGpu)) 358 { 359 if (gpumgrGetPcieP2PCapsFromCache(gpuMask, pP2PWriteCapStatus, pP2PReadCapStatus)) 360 { 361 return NV_OK; 362 } 363 } 364 365 // PCI-E topology checks 366 gpuInstance = 0; 367 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL) 368 { 369 // 370 // While PCI-E P2P transactions are forwarded between different 371 // root ports implemented within a given Intel I/O hub, they 372 // are not forwarded between any two I/O hubs. We must therefore 373 // complement the table-driven chipset validation check below 374 // with an IOH-specific topology check. 375 // 376 if (pGpu->gpuClData.rootPort.addr.valid && 377 (pGpu->gpuClData.rootPort.VendorID == PCI_VENDOR_ID_INTEL)) 378 { 379 deviceID = pGpu->gpuClData.rootPort.DeviceID; 380 381 if (((deviceID >= DEVICE_ID_INTEL_3408_ROOT_PORT) && 382 (deviceID <= DEVICE_ID_INTEL_3411_ROOT_PORT)) || 383 ((deviceID >= DEVICE_ID_INTEL_3C02_ROOT_PORT) && 384 (deviceID <= DEVICE_ID_INTEL_3C0B_ROOT_PORT)) || 385 ((deviceID >= DEVICE_ID_INTEL_0E02_ROOT_PORT) && 386 (deviceID <= DEVICE_ID_INTEL_0E0B_ROOT_PORT)) || 387 ((deviceID >= DEVICE_ID_INTEL_2F01_ROOT_PORT) && 388 (deviceID <= DEVICE_ID_INTEL_2F0B_ROOT_PORT)) || 389 ((deviceID >= DEVICE_ID_INTEL_6F01_ROOT_PORT) && 390 (deviceID <= DEVICE_ID_INTEL_6F0B_ROOT_PORT)) || 391 (deviceID == DEVICE_ID_INTEL_3420_ROOT_PORT) || 392 (deviceID == DEVICE_ID_INTEL_3421_ROOT_PORT)) 393 { 394 if (iohDomain_ref == 0xFFFFFFFF) 395 { 396 iohDomain_ref = pGpu->gpuClData.rootPort.addr.domain; 397 iohBus_ref = pGpu->gpuClData.rootPort.addr.bus; 398 } 399 else if ((iohDomain_ref != pGpu->gpuClData.rootPort.addr.domain) || 400 (iohBus_ref != pGpu->gpuClData.rootPort.addr.bus)) 401 { 402 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED; 403 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED; 404 goto done; 405 } 406 } 407 } 408 409 // Test common bridges. Skip first GPU 410 if (pFirstGpu == NULL) 411 { 412 pFirstGpu = pGpu; 413 continue; 414 } 415 416 if (!areGpusP2PCompatible(pFirstGpu, pGpu)) 417 { 418 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 419 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 420 goto done; 421 } 422 423 // This call returns the most upper bridge 424 clFindCommonDownstreamBR(pFirstGpu, pGpu, pCl, &pciSwitchBus); 425 426 if (pciSwitchBus_ref == 0xFF) 427 { 428 pciSwitchBus_ref = pciSwitchBus; 429 } 430 431 // If no bridge found or different to the one previously found 432 if ((pciSwitchBus == 0xFF) || (pciSwitchBus_ref != pciSwitchBus)) 433 { 434 bCommonPciSwitchFound = NV_FALSE; 435 } 436 } 437 438 // Check if GPUs have the HW P2P implementation 439 440 // Only lock for GSP_CLIENT. Get one GPU. 441 if (pFirstGpu == NULL) 442 { 443 gpuInstance = 0; 444 pFirstGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance); 445 } 446 447 if (IS_GSP_CLIENT(pFirstGpu)) 448 { 449 // Lock GPUs 450 lockedGpuMask = gpuMask; 451 status = rmGpuGroupLockAcquire(0, GPU_LOCK_GRP_MASK, 452 GPU_LOCK_FLAGS_SAFE_LOCK_UPGRADE, RM_LOCK_MODULES_P2P, &lockedGpuMask); 453 454 // If we get NOTHING_TO_DO, we already have the needed locks, so don't free them 455 if (status == NV_WARN_NOTHING_TO_DO) 456 lockedGpuMask = 0; 457 else if (status != NV_OK) 458 { 459 lockedGpuMask = 0; 460 goto done; 461 } 462 } 463 464 // Reset P2P caps as statuses will be accumulated below. 465 *pP2PReadCapStatus = *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_OK; 466 467 gpuInstance = 0; 468 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL) 469 { 470 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu); 471 NV2080_CTRL_INTERNAL_GET_PCIE_P2P_CAPS_PARAMS p2pCapsParams = {0}; 472 473 p2pCapsParams.bCommonPciSwitchFound = bCommonPciSwitchFound; 474 475 NV_ASSERT_OK_OR_GOTO(status, pRmApi->Control(pRmApi, 476 pGpu->hInternalClient, 477 pGpu->hInternalSubdevice, 478 NV2080_CTRL_CMD_INTERNAL_GET_PCIE_P2P_CAPS, 479 &p2pCapsParams, 480 sizeof(NV2080_CTRL_INTERNAL_GET_PCIE_P2P_CAPS_PARAMS)), 481 done); 482 483 // GPU specific P2P caps 484 pKernelBif = GPU_GET_KERNEL_BIF(pGpu); 485 if (pKernelBif->getProperty(pKernelBif, PDB_PROP_KBIF_P2P_WRITES_DISABLED)) 486 gpuP2PWriteCapsStatus = NV0000_P2P_CAPS_STATUS_GPU_NOT_SUPPORTED; 487 if (pKernelBif->getProperty(pKernelBif, PDB_PROP_KBIF_P2P_READS_DISABLED)) 488 gpuP2PReadCapsStatus = NV0000_P2P_CAPS_STATUS_GPU_NOT_SUPPORTED; 489 490 // 491 // Reconcile the system and GPU specific P2P information 492 // The system P2P status takes precedence 493 // Do not override status from not OK to OK 494 // 495 if (*pP2PReadCapStatus == NV0000_P2P_CAPS_STATUS_OK) 496 *pP2PReadCapStatus = (p2pCapsParams.p2pReadCapsStatus == NV0000_P2P_CAPS_STATUS_OK ? gpuP2PReadCapsStatus : p2pCapsParams.p2pReadCapsStatus); 497 if (*pP2PWriteCapStatus == NV0000_P2P_CAPS_STATUS_OK) 498 *pP2PWriteCapStatus = (p2pCapsParams.p2pWriteCapsStatus == NV0000_P2P_CAPS_STATUS_OK ? gpuP2PWriteCapsStatus : p2pCapsParams.p2pWriteCapsStatus); 499 500 // No need to continue if P2P is not supported 501 if ((*pP2PReadCapStatus != NV0000_P2P_CAPS_STATUS_OK) && 502 (*pP2PWriteCapStatus != NV0000_P2P_CAPS_STATUS_OK)) 503 { 504 break; 505 } 506 } 507 508 done: 509 if (lockedGpuMask != 0) 510 { 511 rmGpuGroupLockRelease(lockedGpuMask, GPUS_LOCK_FLAGS_NONE); 512 } 513 514 if (status != NV_OK) 515 { 516 if (*pP2PReadCapStatus == NV0000_P2P_CAPS_STATUS_OK) 517 { 518 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 519 } 520 if (*pP2PWriteCapStatus == NV0000_P2P_CAPS_STATUS_OK) 521 { 522 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 523 } 524 } 525 526 if (pbCommonPciSwitch != NULL) 527 { 528 *pbCommonPciSwitch = bCommonPciSwitchFound; 529 } 530 531 // 532 // Not fatal if failing, effect would be perf degradation as we would not hit the cache. 533 // So just assert. 534 // 535 gpuInstance = 0; 536 pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance); 537 if (IS_GSP_CLIENT(pGpu)) 538 { 539 NV_ASSERT_OK(gpumgrStorePcieP2PCapsCache(gpuMask, *pP2PWriteCapStatus, *pP2PReadCapStatus)); 540 } 541 return status; 542 } 543 544 /** 545 * @brief Check the host system BAR1 P2P capability 546 * 547 * @param[in] pGpu OBJGPU pointer 548 * @param[out] pP2PWriteCapStatus Pointer to get the P2P write capability 549 * @param[out] pP2PReadCapStatus Pointer to get the P2P read capability 550 * @param[out] bCommonPciSwitchFound To indicate if GPUs are on a common PCIE switch 551 * 552 * @returns NV_OK 553 */ 554 static NV_STATUS 555 _p2pCapsGetHostSystemStatusOverPcieBar1 556 ( 557 OBJGPU *pGpu, 558 NvU8 *pP2PWriteCapStatus, 559 NvU8 *pP2PReadCapStatus, 560 NvBool bCommonPciSwitchFound 561 ) 562 { 563 OBJSYS *pSys = SYS_GET_INSTANCE(); 564 565 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_OK; 566 567 if (bCommonPciSwitchFound || 568 (pSys->cpuInfo.type == NV0000_CTRL_SYSTEM_CPU_TYPE_RYZEN) || 569 (pSys->cpuInfo.type == NV0000_CTRL_SYSTEM_CPU_TYPE_XEON_SPR)) 570 { 571 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_OK; 572 } 573 else 574 { 575 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_CHIPSET_NOT_SUPPORTED; 576 NV_PRINTF(LEVEL_INFO, "Unrecognized CPU. Read Cap is disabled\n"); 577 } 578 579 return NV_OK; 580 } 581 582 /** 583 * @brief Check GPU Pcie BAR1 P2P capability 584 * 585 * @param[in] pGpu OBJGPU pointer 586 * @param[out] pP2PWriteCapStatus Pointer to get the P2P write capability 587 * @param[out] pP2PReadCapStatus Pointer to get the P2P read capability 588 * @param[out] bCommonPciSwitchFound To indicate if GPUs are on a common PCIE switch 589 * 590 * @returns NV_OK, if GPUs at least support read or write 591 * NV_ERR_NOT_SUPPORTED, if GPUs does not support read and write 592 */ 593 static NV_STATUS 594 _kp2pCapsGetStatusOverPcieBar1 595 ( 596 NvU32 gpuMask, 597 NvU8 *pP2PWriteCapStatus, 598 NvU8 *pP2PReadCapStatus, 599 NvBool bCommonPciSwitchFound 600 ) 601 { 602 OBJGPU *pGpuPeer = NULL; 603 NvU32 gpuInstance = 0; 604 OBJGPU *pFirstGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance); 605 KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pFirstGpu); 606 NvU8 writeCapStatus = *pP2PWriteCapStatus; 607 NvU8 readCapStatus = *pP2PReadCapStatus; 608 609 if ((pKernelBif->forceP2PType != NV_REG_STR_RM_FORCE_P2P_TYPE_BAR1P2P)) 610 { 611 return NV_ERR_NOT_SUPPORTED; 612 } 613 614 // Check if any overrides are enabled. 615 if (_kp2pCapsCheckStatusOverridesForPcie(gpuMask, pP2PWriteCapStatus, 616 pP2PReadCapStatus)) 617 { 618 return NV_OK; 619 } 620 621 // 622 // Re-initialize to check loop back configuration if only single GPU in 623 // requested mask. 624 // 625 gpuInstance = (gpumgrGetSubDeviceCount(gpuMask) > 1) ? gpuInstance : 0; 626 627 while ((pGpuPeer = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL) 628 { 629 if (!kbusIsPcieBar1P2PMappingSupported_HAL(pFirstGpu, GPU_GET_KERNEL_BUS(pFirstGpu), 630 pGpuPeer, GPU_GET_KERNEL_BUS(pGpuPeer))) 631 { 632 return NV_ERR_NOT_SUPPORTED; 633 } 634 } 635 636 NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, 637 _p2pCapsGetHostSystemStatusOverPcieBar1(pFirstGpu, &writeCapStatus, 638 &readCapStatus, bCommonPciSwitchFound)); 639 640 if (*pP2PWriteCapStatus == NV0000_P2P_CAPS_STATUS_OK) 641 *pP2PWriteCapStatus = writeCapStatus; 642 if (*pP2PReadCapStatus == NV0000_P2P_CAPS_STATUS_OK) 643 *pP2PReadCapStatus = readCapStatus; 644 645 if ((*pP2PReadCapStatus != NV0000_P2P_CAPS_STATUS_OK) || 646 (*pP2PWriteCapStatus != NV0000_P2P_CAPS_STATUS_OK)) 647 { 648 // return not supported if it does not support both operations 649 return NV_ERR_NOT_SUPPORTED; 650 } 651 652 return NV_OK; 653 } 654 655 NV_STATUS 656 p2pGetCapsStatus 657 ( 658 NvU32 gpuMask, 659 NvU8 *pP2PWriteCapStatus, 660 NvU8 *pP2PReadCapStatus, 661 P2P_CONNECTIVITY *pConnectivity 662 ) 663 { 664 OBJSYS *pSys = SYS_GET_INSTANCE(); 665 KernelNvlink *pKernelNvlink = NULL; 666 OBJGPU *pGpu = NULL; 667 NvU32 gpuInstance = 0; 668 NvBool bCommonSwitchFound = NV_FALSE; 669 670 if ((pP2PWriteCapStatus == NULL) || 671 (pP2PReadCapStatus == NULL) || 672 (pConnectivity == NULL) 673 ) 674 { 675 return NV_ERR_INVALID_ARGUMENT; 676 } 677 678 // Default values 679 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 680 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 681 *pConnectivity = P2P_CONNECTIVITY_UNKNOWN; 682 683 // MIG-Nvlink-P2P can be incompatible, so check compatibility for all GPUs 684 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL) 685 { 686 KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu); 687 NvBool bSmcNvLinkP2PSupported = ((pKernelMIGManager != NULL) && 688 kmigmgrIsMIGNvlinkP2PSupported(pGpu, pKernelMIGManager)); 689 690 // If any of the GPU has MIG enabled, return with no P2P support 691 if (!bSmcNvLinkP2PSupported) 692 { 693 NV_PRINTF(LEVEL_NOTICE, 694 "P2P is marked unsupported with MIG for GPU instance = 0x%x\n", 695 gpuInstance); 696 return NV_OK; 697 } 698 } 699 700 gpuInstance = 0; 701 702 // Check NvLink P2P connectivity. 703 if (_gpumgrGetP2PCapsStatusOverNvLink(gpuMask, pP2PWriteCapStatus, 704 pP2PReadCapStatus) == NV_OK) 705 { 706 if (*pP2PWriteCapStatus == NV0000_P2P_CAPS_STATUS_OK && 707 *pP2PReadCapStatus == NV0000_P2P_CAPS_STATUS_OK) 708 { 709 *pConnectivity = P2P_CONNECTIVITY_NVLINK; 710 return NV_OK; 711 } 712 } 713 714 // 715 // On NVSwitch systems, if the NVLink P2P path fails, don't fall back to 716 // other P2P paths. To ensure that, check if any GPU in the mask has NVLink 717 // support. If supported, enforce NVSwitch/NVLink connectivity by returning 718 // NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED. 719 // 720 gpuInstance = 0; 721 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL) 722 { 723 pKernelNvlink = GPU_GET_KERNEL_NVLINK(pGpu); 724 if (pKernelNvlink != NULL && knvlinkGetDiscoveredLinkMask(pGpu, pKernelNvlink) != 0 && 725 (pSys->getProperty(pSys, PDB_PROP_SYS_NVSWITCH_IS_PRESENT) || 726 knvlinkIsNvswitchProxyPresent(pGpu, pKernelNvlink) || 727 GPU_IS_NVSWITCH_DETECTED(pGpu))) 728 { 729 *pP2PReadCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 730 *pP2PWriteCapStatus = NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED; 731 return NV_OK; 732 } 733 } 734 735 // We didn't find direct P2P, so check for indirect P2P. 736 if (_kp2pCapsGetStatusIndirectOverNvLink(gpuMask, pP2PWriteCapStatus, 737 pP2PReadCapStatus) == NV_OK) 738 { 739 if ((*pP2PWriteCapStatus == NV0000_P2P_CAPS_STATUS_OK) && 740 (*pP2PReadCapStatus == NV0000_P2P_CAPS_STATUS_OK)) 741 { 742 *pConnectivity = P2P_CONNECTIVITY_NVLINK_INDIRECT; 743 return NV_OK; 744 } 745 } 746 747 // 748 // Check PCIE P2P connectivity. 749 // 750 // We can control P2P connectivity for PCI-E peers using regkeys, hence 751 // if either read or write is supported, return success. See 752 // _kp2pCapsCheckStatusOverridesForPcie for details. 753 // 754 if (_kp2pCapsGetStatusOverPcie(gpuMask, pP2PWriteCapStatus, 755 pP2PReadCapStatus, &bCommonSwitchFound) == NV_OK) 756 { 757 if ((*pP2PWriteCapStatus == NV0000_P2P_CAPS_STATUS_OK) || 758 (*pP2PReadCapStatus == NV0000_P2P_CAPS_STATUS_OK)) 759 { 760 NvU8 bar1P2PWriteCapStatus = *pP2PWriteCapStatus; 761 NvU8 bar1P2PReadCapStatus = *pP2PReadCapStatus; 762 763 *pConnectivity = P2P_CONNECTIVITY_PCIE; 764 765 if (_kp2pCapsGetStatusOverPcieBar1(gpuMask, &bar1P2PWriteCapStatus, 766 &bar1P2PReadCapStatus, bCommonSwitchFound) == NV_OK) 767 { 768 *pP2PWriteCapStatus = bar1P2PWriteCapStatus; 769 *pP2PReadCapStatus = bar1P2PReadCapStatus; 770 *pConnectivity = P2P_CONNECTIVITY_PCIE_BAR1; 771 } 772 773 return NV_OK; 774 } 775 } 776 777 return NV_OK; 778 } 779 780 static NV_STATUS 781 _removeP2PPeerGpuCapsByGpuId 782 ( 783 OBJGPU *pGpu, 784 NvU32 peerGpuId 785 ) 786 { 787 GPU_P2P_PEER_GPU_CAPS *pLocalPeerCaps = NULL; 788 789 pLocalPeerCaps = gpuFindP2PPeerGpuCapsByGpuId(pGpu, peerGpuId); 790 NV_CHECK_OR_RETURN(LEVEL_WARNING, pLocalPeerCaps != NULL, NV_ERR_OBJECT_NOT_FOUND); 791 792 // Swap the target element with the last element and remove the last. 793 // pLocalPeerCaps points to an item in the pGpu->P2PPeerGpuCaps array. 794 NV_ASSERT(pGpu->P2PPeerGpuCount != 0); 795 pGpu->P2PPeerGpuCount--; 796 797 portMemMove(pLocalPeerCaps, 798 sizeof(GPU_P2P_PEER_GPU_CAPS), 799 &pGpu->P2PPeerGpuCaps[pGpu->P2PPeerGpuCount], 800 sizeof(GPU_P2P_PEER_GPU_CAPS)); 801 802 return NV_OK; 803 } 804 805 NV_STATUS 806 subdeviceCtrlCmdInternalSetP2pCaps_IMPL 807 ( 808 Subdevice *pSubdevice, 809 NV2080_CTRL_INTERNAL_SET_P2P_CAPS_PARAMS *pParams 810 ) 811 { 812 NV_STATUS status = NV_OK; 813 NvU32 i; 814 NvU32 failingIndex; 815 OBJGPU *pGpu = gpumgrGetGpuFromSubDeviceInst(pSubdevice->deviceInst, 816 pSubdevice->subDeviceInst); 817 818 // TODO: GPUSWSEC-1433 remove this check to enable this control for baremetal 819 if (!IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu)) 820 return NV_ERR_NOT_SUPPORTED; 821 822 NV_CHECK_OR_RETURN(LEVEL_ERROR, 823 pParams->peerGpuCount <= NV_ARRAY_ELEMENTS(pGpu->P2PPeerGpuCaps), 824 NV_ERR_INVALID_ARGUMENT); 825 826 for (i = 0; i < pParams->peerGpuCount; i++) 827 { 828 NV2080_CTRL_INTERNAL_SET_P2P_CAPS_PEER_INFO *pParamsPeerInfo = &pParams->peerGpuInfos[i]; 829 GPU_P2P_PEER_GPU_CAPS *pLocalPeerCaps = NULL; 830 831 // Try to find the existing entry 832 pLocalPeerCaps = gpuFindP2PPeerGpuCapsByGpuId(pGpu, pParamsPeerInfo->gpuId); 833 834 // If no entry has been found, add a new one instead 835 if (pLocalPeerCaps == NULL) 836 { 837 NV_CHECK_OR_ELSE(LEVEL_ERROR, 838 pGpu->P2PPeerGpuCount < NV_ARRAY_ELEMENTS(pGpu->P2PPeerGpuCaps), 839 status = NV_ERR_INSUFFICIENT_RESOURCES; goto fail); 840 841 pLocalPeerCaps = &pGpu->P2PPeerGpuCaps[pGpu->P2PPeerGpuCount]; 842 pLocalPeerCaps->peerGpuId = pParamsPeerInfo->gpuId; 843 844 pGpu->P2PPeerGpuCount++; 845 } 846 847 pLocalPeerCaps->peerGpuInstance = pParamsPeerInfo->gpuInstance; 848 pLocalPeerCaps->p2pCaps = pParamsPeerInfo->p2pCaps; 849 pLocalPeerCaps->p2pOptimalReadCEs = pParamsPeerInfo->p2pOptimalReadCEs; 850 pLocalPeerCaps->p2pOptimalWriteCEs = pParamsPeerInfo->p2pOptimalWriteCEs; 851 pLocalPeerCaps->busPeerId = pParamsPeerInfo->busPeerId; 852 853 portMemCopy(pLocalPeerCaps->p2pCapsStatus, 854 sizeof(pLocalPeerCaps->p2pCapsStatus), 855 pParamsPeerInfo->p2pCapsStatus, 856 sizeof(pParamsPeerInfo->p2pCapsStatus)); 857 } 858 859 goto done; 860 861 fail: 862 // Remove the successfully set caps 863 failingIndex = i; 864 for (i = 0; i < failingIndex; i++) 865 { 866 NV_STATUS ignoredStatus; 867 NV_CHECK_OK(ignoredStatus, LEVEL_ERROR, 868 _removeP2PPeerGpuCapsByGpuId(pGpu, pParams->peerGpuInfos[i].gpuId)); 869 } 870 871 done: 872 return status; 873 } 874 875 NV_STATUS 876 subdeviceCtrlCmdInternalRemoveP2pCaps_IMPL 877 ( 878 Subdevice *pSubdevice, 879 NV2080_CTRL_INTERNAL_REMOVE_P2P_CAPS_PARAMS *pParams 880 ) 881 { 882 NV_STATUS status = NV_OK; 883 NvU32 i; 884 OBJGPU *pGpu = gpumgrGetGpuFromSubDeviceInst(pSubdevice->deviceInst, 885 pSubdevice->subDeviceInst); 886 887 // TODO: GPUSWSEC-1433 remove this check to enable this control for baremetal 888 if (!IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu)) 889 return NV_ERR_NOT_SUPPORTED; 890 891 NV_CHECK_OR_RETURN(LEVEL_ERROR, 892 pParams->peerGpuIdCount <= NV_ARRAY_ELEMENTS(pGpu->P2PPeerGpuCaps), 893 NV_ERR_INVALID_ARGUMENT); 894 895 for (i = 0; i < pParams->peerGpuIdCount; i++) 896 { 897 // Capture only the first error here, as trying to remove all caps 898 // is the best effort here. 899 NV_CHECK_OK_OR_CAPTURE_FIRST_ERROR(status, LEVEL_ERROR, 900 _removeP2PPeerGpuCapsByGpuId(pGpu, pParams->peerGpuIds[i])); 901 } 902 903 return status; 904 } 905 906 static NV_STATUS 907 subdeviceGetP2pCaps_VIRTUAL 908 ( 909 OBJGPU *pGpu, 910 NV2080_CTRL_GET_P2P_CAPS_PARAMS *pParams 911 ) 912 { 913 NvU32 i; 914 NV_STATUS status = NV_OK; 915 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 916 RS_RES_CONTROL_PARAMS_INTERNAL *pControlParams = pCallContext->pControlParams; 917 NV2080_CTRL_GET_P2P_CAPS_PARAMS *pShimParams = 918 portMemAllocNonPaged(sizeof *pShimParams); 919 920 NV_CHECK_OR_RETURN(LEVEL_INFO, pShimParams != NULL, NV_ERR_NO_MEMORY); 921 922 portMemCopy(pShimParams, sizeof *pShimParams, pParams, sizeof *pParams); 923 924 if (!pShimParams->bAllCaps) 925 { 926 // Must translate Guest GpuIds to Guest UUIDs 927 for (i = 0; i < pShimParams->peerGpuCount; i++) 928 { 929 NV2080_CTRL_GPU_P2P_PEER_CAPS_PEER_INFO *pParamsPeerInfo = &pShimParams->peerGpuCaps[i]; 930 OBJGPU *pRemoteGpu = gpumgrGetGpuFromId(pParamsPeerInfo->gpuId); 931 932 NV_CHECK_OR_ELSE(LEVEL_INFO, pRemoteGpu != NULL, 933 status = NV_ERR_INVALID_ARGUMENT; goto done); 934 935 portMemCopy(pParamsPeerInfo->gpuUuid, 936 sizeof(pParamsPeerInfo->gpuUuid), 937 pRemoteGpu->gpuUuid.uuid, 938 sizeof(pRemoteGpu->gpuUuid.uuid)); 939 } 940 } 941 942 pShimParams->bUseUuid = 1; 943 944 NV_RM_RPC_CONTROL(pGpu, 945 pControlParams->hClient, 946 pControlParams->hObject, 947 pControlParams->cmd, 948 pShimParams, 949 sizeof *pShimParams, 950 status); 951 if (status != NV_OK) 952 { 953 goto done; 954 } 955 956 // If bAllCaps, transfer additional output gpuIds and peerGpuCount 957 if (pParams->bAllCaps) 958 { 959 pParams->peerGpuCount = pShimParams->peerGpuCount; 960 961 for (i = 0; i < pParams->peerGpuCount; ++i) 962 { 963 // Use UUID to compute corresponding Guest GPU ID 964 OBJGPU *pRemoteGpu = gpumgrGetGpuFromUuid(pShimParams->peerGpuCaps[i].gpuUuid, 965 DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _TYPE, _SHA1) | 966 DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _FORMAT, _BINARY)); 967 968 NV_CHECK_OR_ELSE(LEVEL_INFO, pRemoteGpu != NULL, 969 status = NV_ERR_GPU_UUID_NOT_FOUND; goto done); 970 971 pParams->peerGpuCaps[i].gpuId = pRemoteGpu->gpuId; 972 } 973 } 974 975 // Transfer output values from shimParams to user params. 976 for (i = 0; i < pParams->peerGpuCount; ++i) 977 { 978 pParams->peerGpuCaps[i].p2pCaps = pShimParams->peerGpuCaps[i].p2pCaps; 979 pParams->peerGpuCaps[i].p2pOptimalReadCEs = pShimParams->peerGpuCaps[i].p2pOptimalReadCEs; 980 pParams->peerGpuCaps[i].p2pOptimalWriteCEs = pShimParams->peerGpuCaps[i].p2pOptimalWriteCEs; 981 portMemCopy(pParams->peerGpuCaps[i].p2pCapsStatus, 982 sizeof(pParams->peerGpuCaps[i].p2pCapsStatus), 983 pShimParams->peerGpuCaps[i].p2pCapsStatus, 984 sizeof(pShimParams->peerGpuCaps[i].p2pCapsStatus)); 985 pParams->peerGpuCaps[i].busPeerId = pShimParams->peerGpuCaps[i].busPeerId; 986 } 987 988 done: 989 portMemFree(pShimParams); 990 991 return status; 992 } 993 994 NV_STATUS 995 subdeviceCtrlCmdGetP2pCaps_IMPL 996 ( 997 Subdevice *pSubdevice, 998 NV2080_CTRL_GET_P2P_CAPS_PARAMS *pParams 999 ) 1000 { 1001 NvU32 i; 1002 NvU32 gfid = GPU_GFID_PF; 1003 OBJGPU *pGpu = gpumgrGetGpuFromSubDeviceInst(pSubdevice->deviceInst, 1004 pSubdevice->subDeviceInst); 1005 1006 // TODO: GPUSWSEC-1433 remove this check to enable this control for baremetal 1007 if (!IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu)) 1008 return NV_ERR_NOT_SUPPORTED; 1009 1010 NV_CHECK_OR_RETURN(LEVEL_ERROR, pGpu != NULL, NV_ERR_INVALID_STATE); 1011 NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, vgpuGetCallingContextGfid(pGpu, &gfid)); 1012 1013 NV_CHECK_OR_RETURN(LEVEL_ERROR, 1014 (pParams->bAllCaps || 1015 (pParams->peerGpuCount <= NV_ARRAY_ELEMENTS(pGpu->P2PPeerGpuCaps))), 1016 NV_ERR_INVALID_ARGUMENT); 1017 1018 NV_CHECK_OR_RETURN(LEVEL_ERROR, (pParams->bUseUuid == NV_FALSE), NV_ERR_NOT_SUPPORTED); 1019 1020 if (IS_VIRTUAL(pGpu)) 1021 { 1022 return subdeviceGetP2pCaps_VIRTUAL(pGpu, pParams); 1023 } 1024 1025 NV_CHECK_OR_RETURN(LEVEL_ERROR, RMCFG_FEATURE_PLATFORM_GSP, NV_ERR_NOT_SUPPORTED); 1026 1027 if (pParams->bAllCaps) 1028 { 1029 pParams->peerGpuCount = pGpu->P2PPeerGpuCount; 1030 1031 for (i = 0; i < pParams->peerGpuCount; i++) 1032 { 1033 pParams->peerGpuCaps[i].gpuId = pGpu->P2PPeerGpuCaps[i].peerGpuId; 1034 } 1035 } 1036 1037 for (i = 0; i < pParams->peerGpuCount; i++) 1038 { 1039 NV2080_CTRL_GPU_P2P_PEER_CAPS_PEER_INFO *pParamsPeerInfo = &pParams->peerGpuCaps[i]; 1040 GPU_P2P_PEER_GPU_CAPS *pLocalPeerCaps = NULL; 1041 1042 pLocalPeerCaps = gpuFindP2PPeerGpuCapsByGpuId(pGpu, pParamsPeerInfo->gpuId); 1043 NV_CHECK_OR_RETURN(LEVEL_ERROR, pLocalPeerCaps != NULL, NV_ERR_OBJECT_NOT_FOUND); 1044 1045 // 1046 // TODO: Currently, vGPU-GSP Guest only supports NVLINK DIRECT so unset caps for other modes. 1047 // May remove once vGPU adds support for other modes. 1048 // 1049 if (IS_GFID_VF(gfid) && 1050 !REF_VAL(NV0000_CTRL_SYSTEM_GET_P2P_CAPS_NVLINK_SUPPORTED, pLocalPeerCaps->p2pCaps)) 1051 { 1052 pParamsPeerInfo->p2pCaps = 0; 1053 pParamsPeerInfo->p2pOptimalReadCEs = 0; 1054 pParamsPeerInfo->p2pOptimalWriteCEs = 0; 1055 pParamsPeerInfo->busPeerId = NV0000_CTRL_SYSTEM_GET_P2P_CAPS_INVALID_PEER; 1056 1057 portMemSet(pParamsPeerInfo->p2pCapsStatus, 1058 NV0000_P2P_CAPS_STATUS_NOT_SUPPORTED, 1059 sizeof(pParamsPeerInfo->p2pCapsStatus)); 1060 } 1061 else 1062 { 1063 pParamsPeerInfo->p2pCaps = pLocalPeerCaps->p2pCaps; 1064 pParamsPeerInfo->p2pOptimalReadCEs = pLocalPeerCaps->p2pOptimalReadCEs; 1065 pParamsPeerInfo->p2pOptimalWriteCEs = pLocalPeerCaps->p2pOptimalWriteCEs; 1066 pParamsPeerInfo->busPeerId = pLocalPeerCaps->busPeerId; 1067 1068 portMemCopy(pParamsPeerInfo->p2pCapsStatus, 1069 sizeof(pParamsPeerInfo->p2pCapsStatus), 1070 pLocalPeerCaps->p2pCapsStatus, 1071 sizeof(pLocalPeerCaps->p2pCapsStatus)); 1072 } 1073 } 1074 1075 return NV_OK; 1076 } 1077