1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2022 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 "os/os.h" 25 #include "kernel/gpu/nvlink/kernel_nvlink.h" 26 #include "kernel/gpu/nvlink/kernel_ioctrl.h" 27 #include "gpu/gpu.h" 28 #include "gpu/mem_mgr/mem_mgr.h" 29 #include "nverror.h" 30 #include "objtmr.h" 31 32 /*! 33 * @brief Check if ALI is supported for the given device 34 * 35 * @param[in] pGpu OBJGPU pointer 36 * @param[in] pKernelNvlink KernelNvlink pointer 37 */ 38 NV_STATUS 39 knvlinkIsAliSupported_GH100 40 ( 41 OBJGPU *pGpu, 42 KernelNvlink *pKernelNvlink 43 ) 44 { 45 NvU32 status = NV_OK; 46 47 NV2080_CTRL_NVLINK_GET_ALI_ENABLED_PARAMS params; 48 49 portMemSet(¶ms, 0, sizeof(params)); 50 51 // Initialize to default settings 52 params.bEnableAli = NV_FALSE; 53 54 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink, 55 NV2080_CTRL_CMD_NVLINK_GET_ALI_ENABLED, 56 (void *)¶ms, sizeof(params)); 57 if (status != NV_OK) 58 { 59 NV_PRINTF(LEVEL_ERROR, "Failed to get ALI enablement status!\n"); 60 return status; 61 } 62 63 pKernelNvlink->bEnableAli = params.bEnableAli; 64 65 return status; 66 } 67 68 /*! 69 * @brief Validates fabric base address. 70 * 71 * @param[in] pGpu OBJGPU pointer 72 * @param[in] pKernelNvlink KernelNvlink pointer 73 * @param[in] fabricBaseAddr Address to be validated 74 * 75 * @returns On success, NV_OK. 76 * On failure, returns NV_ERR_XXX. 77 */ 78 NV_STATUS 79 knvlinkValidateFabricBaseAddress_GH100 80 ( 81 OBJGPU *pGpu, 82 KernelNvlink *pKernelNvlink, 83 NvU64 fabricBaseAddr 84 ) 85 { 86 MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu); 87 NvU64 fbSizeBytes; 88 89 fbSizeBytes = pMemoryManager->Ram.fbTotalMemSizeMb << 20; 90 91 // 92 // Hopper SKUs will be paired with NVSwitches (Limerock-next) supporting 2K 93 // mapslots that can cover 512GB each. Make sure that the fabric base 94 // address being used is valid to cover whole frame buffer. 95 // 96 97 // Check if fabric address is aligned to mapslot size. 98 if (fabricBaseAddr & (NVBIT64(39) - 1)) 99 { 100 return NV_ERR_INVALID_ARGUMENT; 101 } 102 103 // Align fbSize to mapslot size. 104 fbSizeBytes = RM_ALIGN_UP(fbSizeBytes, NVBIT64(39)); 105 106 return NV_OK; 107 } 108 109 /*! 110 * @brief Do post setup on nvlink peers 111 * 112 * @param[in] pGpu OBJGPU pointer 113 * @param[in] pKernelNvlink KernelNvlink pointer 114 */ 115 NV_STATUS 116 knvlinkPostSetupNvlinkPeer_GH100 117 ( 118 OBJGPU *pGpu, 119 KernelNvlink *pKernelNvlink 120 ) 121 { 122 NvU32 status = NV_OK; 123 NV2080_CTRL_NVLINK_POST_SETUP_NVLINK_PEER_PARAMS postSetupNvlinkPeerParams; 124 125 portMemSet(&postSetupNvlinkPeerParams, 0, sizeof(postSetupNvlinkPeerParams)); 126 127 postSetupNvlinkPeerParams.peerMask = (1 << NVLINK_MAX_PEERS_SW) - 1; 128 129 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink, 130 NV2080_CTRL_CMD_NVLINK_POST_SETUP_NVLINK_PEER, 131 (void *)&postSetupNvlinkPeerParams, 132 sizeof(postSetupNvlinkPeerParams)); 133 if (status != NV_OK) 134 { 135 NV_PRINTF(LEVEL_ERROR, 136 "Failed to program post active settings and bufferready!\n"); 137 return status; 138 } 139 140 return status; 141 } 142 143 /*! 144 * @brief Discover all links that are training or have been 145 * trained on both GPUs 146 * 147 * @param[in] pGpu OBJGPU pointer for local GPU 148 * @param[in] pKernelNvlink KernelNvlink pointer 149 * @param[in] pPeerGpu OBJGPU pointer for remote GPU 150 * 151 * @return NV_OK if links are detected to be training 152 */ 153 NV_STATUS 154 knvlinkDiscoverPostRxDetLinks_GH100 155 ( 156 OBJGPU *pGpu, 157 KernelNvlink *pKernelNvlink, 158 OBJGPU *pPeerGpu 159 ) 160 { 161 NV_STATUS status = NV_ERR_NOT_SUPPORTED; 162 163 #if defined(INCLUDE_NVLINK_LIB) 164 165 OBJGPU *pGpu0 = pGpu; 166 OBJGPU *pGpu1 = pPeerGpu; 167 KernelNvlink *pKernelNvlink0 = GPU_GET_KERNEL_NVLINK(pGpu0); 168 KernelNvlink *pKernelNvlink1 = NULL; 169 170 if (pGpu1 == NULL) 171 { 172 NV_PRINTF(LEVEL_ERROR, "Invalid pPeerGpu.\n"); 173 174 return NV_ERR_INVALID_ARGUMENT; 175 } 176 else if ((pGpu0 == pGpu1) && 177 (pGpu0->getProperty(pGpu0, PDB_PROP_GPU_NVLINK_P2P_LOOPBACK_DISABLED))) 178 { 179 // P2P over loopback links are disabled through regkey overrides 180 NV_PRINTF(LEVEL_INFO, "loopback P2P on GPU%u disabled by regkey\n", 181 gpuGetInstance(pGpu0)); 182 183 return NV_ERR_NOT_SUPPORTED; 184 } 185 else 186 { 187 pKernelNvlink1 = GPU_GET_KERNEL_NVLINK(pGpu1); 188 } 189 190 if (pKernelNvlink1 == NULL) 191 { 192 NV_PRINTF(LEVEL_ERROR, 193 "Input mask contains a GPU on which NVLink is disabled.\n"); 194 195 return NV_ERR_INVALID_ARGUMENT; 196 } 197 198 if ((IS_RTLSIM(pGpu) && !pKernelNvlink0->bForceEnableCoreLibRtlsims) || 199 (pKernelNvlink0->pNvlinkDev == NULL) || 200 !pKernelNvlink0->bEnableAli || 201 (pKernelNvlink1->pNvlinkDev == NULL) || 202 !pKernelNvlink1->bEnableAli) 203 { 204 NV_PRINTF(LEVEL_INFO, 205 "Not in ALI, checking PostRxDetLinks not supported.\n"); 206 return NV_ERR_NOT_SUPPORTED; 207 } 208 209 // 210 // Initialize Mask of links that have made it past RxDet to 0 then 211 // request to get all links from the given GPU that have gotted past RxDet 212 // 213 pKernelNvlink0->postRxDetLinkMask = 0; 214 status = knvlinkUpdatePostRxDetectLinkMask(pGpu0, pKernelNvlink0); 215 if(status != NV_OK) 216 { 217 NV_PRINTF(LEVEL_ERROR, 218 "Getting peer0's postRxDetLinkMask failed!\n"); 219 return NV_ERR_INVALID_STATE; 220 } 221 222 // Only query if we are not in loopback 223 if (pKernelNvlink0 != pKernelNvlink1) 224 { 225 pKernelNvlink1->postRxDetLinkMask = 0; 226 status = knvlinkUpdatePostRxDetectLinkMask(pGpu1, pKernelNvlink1); 227 if(status != NV_OK) 228 { 229 NV_PRINTF(LEVEL_ERROR, 230 "Getting peer1's postRxDetLinkMask failed!\n"); 231 return NV_ERR_INVALID_STATE; 232 } 233 } 234 235 // 236 // If the current gpu has no actively training or trained link OR 237 // if the peer gpu has no actively training or trained links then 238 // return an error. If either side has 0 links passed RxDet then 239 // there is no chance that we will find links connecting the devices 240 // further into discovery. 241 // 242 if(pKernelNvlink0->postRxDetLinkMask == 0 || 243 pKernelNvlink1->postRxDetLinkMask == 0) 244 { 245 NV_PRINTF(LEVEL_ERROR, "Got 0 post RxDet Links!"); 246 return NV_ERR_NOT_READY; 247 } 248 249 #endif 250 251 return status; 252 } 253 254 NV_STATUS 255 ioctrlFaultUpTmrHandler 256 ( 257 OBJGPU *pGpu, 258 OBJTMR *pTmr, 259 TMR_EVENT *pEvent 260 ) 261 { 262 //NvU32 linkId = *(NvU32*)pData; 263 NV_STATUS status = NV_OK; 264 KernelNvlink *pKernelNvlink = GPU_GET_KERNEL_NVLINK(pGpu); 265 NV2080_CTRL_NVLINK_POST_FAULT_UP_PARAMS *nvlinkPostFaultUpParams 266 = portMemAllocNonPaged(sizeof(NV2080_CTRL_NVLINK_POST_FAULT_UP_PARAMS)); 267 PNVLINK_ID pFaultLink; 268 pFaultLink = listHead(&pKernelNvlink->faultUpLinks); 269 270 nvlinkPostFaultUpParams->linkId = pFaultLink->linkId; 271 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink, 272 NV2080_CTRL_CMD_NVLINK_POST_FAULT_UP, 273 (void *)nvlinkPostFaultUpParams, 274 sizeof(NV2080_CTRL_NVLINK_POST_FAULT_UP_PARAMS)); 275 276 if (status != NV_OK) 277 { 278 NV_PRINTF(LEVEL_ERROR, "Failed to send Faultup RPC\n"); 279 } 280 281 listRemove(&pKernelNvlink->faultUpLinks, pFaultLink); 282 portMemFree(nvlinkPostFaultUpParams); 283 284 return status; 285 } 286 287 NV_STATUS 288 knvlinkHandleFaultUpInterrupt_GH100 289 ( 290 OBJGPU *pGpu, 291 KernelNvlink *pKernelNvlink, 292 NvU32 linkId 293 ) 294 { 295 OBJTMR *pTmr = GPU_GET_TIMER(pGpu); 296 PNVLINK_ID pFaultLink; 297 NV_STATUS status = NV_OK; 298 299 pFaultLink = listAppendNew(&pKernelNvlink->faultUpLinks); 300 NV_ASSERT_OR_RETURN(pFaultLink != NULL, NV_ERR_GENERIC); 301 pFaultLink->linkId = linkId; 302 303 status = tmrEventScheduleRel(pTmr, pKernelNvlink->nvlinkLinks[linkId].pTmrEvent, NVLINK_RETRAIN_TIME); 304 if (status != NV_OK) 305 { 306 NV_PRINTF(LEVEL_ERROR, "GPU (ID: %d) tmrEventScheduleRel failed for linkid %d\n", 307 gpuGetInstance(pGpu), linkId); 308 return NV_ERR_GENERIC; 309 } 310 311 return status; 312 } 313 314 NV_STATUS 315 knvlinkLogAliDebugMessages_GH100 316 ( 317 OBJGPU *pGpu, 318 KernelNvlink *pKernelNvlink 319 ) 320 { 321 NV2080_CTRL_NVLINK_GET_ERR_INFO_PARAMS *nvlinkErrInfoParams = portMemAllocNonPaged(sizeof(NV2080_CTRL_NVLINK_GET_ERR_INFO_PARAMS)); 322 portMemSet(nvlinkErrInfoParams, 0, sizeof(NV2080_CTRL_NVLINK_GET_ERR_INFO_PARAMS)); 323 nvlinkErrInfoParams->ErrInfoFlags |= NV2080_CTRL_NVLINK_ERR_INFO_FLAGS_ALI_STATUS; 324 NvU32 i; 325 // This is a Physical, Hopper specific HAL for debug purposes. 326 NV_STATUS status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink, 327 NV2080_CTRL_CMD_NVLINK_GET_ERR_INFO, 328 (void *)nvlinkErrInfoParams, 329 sizeof(NV2080_CTRL_NVLINK_GET_ERR_INFO_PARAMS)); 330 if (status != NV_OK) 331 { 332 NV_PRINTF(LEVEL_ERROR, "Error getting debug info for link training!\n"); 333 portMemFree(nvlinkErrInfoParams); 334 return status; 335 } 336 337 FOR_EACH_INDEX_IN_MASK(32, i, pKernelNvlink->postRxDetLinkMask) 338 { 339 nvErrorLog_va((void *)pGpu, ALI_TRAINING_FAIL, 340 "NVLink: Link training failed for link %u", 341 "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", 342 i, 343 nvlinkErrInfoParams->linkErrInfo[i].NVLIPTLnkCtrlLinkStateRequest, 344 nvlinkErrInfoParams->linkErrInfo[i].NVLDLRxSlsmErrCntl, 345 nvlinkErrInfoParams->linkErrInfo[i].NVLDLTopLinkState, 346 nvlinkErrInfoParams->linkErrInfo[i].NVLDLTopIntr, 347 nvlinkErrInfoParams->linkErrInfo[i].DLStatMN00, 348 nvlinkErrInfoParams->linkErrInfo[i].DLStatUC01, 349 nvlinkErrInfoParams->linkErrInfo[i].MinionNvlinkLinkIntr); 350 351 if (pKernelNvlink->bLinkTrainingDebugSpew) 352 NV_PRINTF(LEVEL_ERROR,"ALI Error for GPU %d::linkId %d:" 353 "\nNVLIPT:\n\tCTRL_LINK_STATE_REQUEST_STATUS = %X\n" 354 "\nNVLDL :\n\tNV_NVLDL_RXSLSM_ERR_CNTL = %X\n" 355 "\n\tNV_NVLDL_TOP_LINK_STATE = %X\n" 356 "\n\tNV_NVLDL_TOP_INTR = %X\n" 357 "\nMINION DLSTAT:\n\tDLSTAT MN00 = %X\n" 358 "\n\tDLSTAT UC01 = %X\n" 359 "\n\tNV_MINION_NVLINK_LINK_INTR = %X\n", 360 pGpu->gpuInstance, i, 361 nvlinkErrInfoParams->linkErrInfo[i].NVLIPTLnkCtrlLinkStateRequest, 362 nvlinkErrInfoParams->linkErrInfo[i].NVLDLRxSlsmErrCntl, 363 nvlinkErrInfoParams->linkErrInfo[i].NVLDLTopLinkState, 364 nvlinkErrInfoParams->linkErrInfo[i].NVLDLTopIntr, 365 nvlinkErrInfoParams->linkErrInfo[i].DLStatMN00, 366 nvlinkErrInfoParams->linkErrInfo[i].DLStatUC01, 367 nvlinkErrInfoParams->linkErrInfo[i].MinionNvlinkLinkIntr); 368 } 369 FOR_EACH_INDEX_IN_MASK_END; 370 portMemFree(nvlinkErrInfoParams); 371 return NV_OK; 372 } 373 374 /*! 375 * @brief Set unique fabric address for NVSwitch enabled systems. 376 * 377 * @param[in] pGpu OBJGPU pointer 378 * @param[in] pKernelNvlink KernelNvlink pointer 379 * @param[in] fabricBaseAddr Fabric Address to set 380 * 381 * @returns On success, sets unique fabric address and returns NV_OK. 382 * On failure, returns NV_ERR_XXX. 383 */ 384 NV_STATUS 385 knvlinkSetUniqueFabricBaseAddress_GH100 386 ( 387 OBJGPU *pGpu, 388 KernelNvlink *pKernelNvlink, 389 NvU64 fabricBaseAddr 390 ) 391 { 392 NV_STATUS status = NV_OK; 393 394 status = knvlinkValidateFabricBaseAddress_HAL(pGpu, pKernelNvlink, 395 fabricBaseAddr); 396 if (status != NV_OK) 397 { 398 NV_PRINTF(LEVEL_ERROR, "Fabric addr validation failed for GPU %x\n", 399 pGpu->gpuInstance); 400 return status; 401 } 402 403 if (IsSLIEnabled(pGpu)) 404 { 405 NV_PRINTF(LEVEL_ERROR, 406 "Operation is unsupported on SLI enabled GPU %x\n", 407 pGpu->gpuInstance); 408 return NV_ERR_NOT_SUPPORTED; 409 } 410 411 if (pKernelNvlink->fabricBaseAddr == fabricBaseAddr) 412 { 413 NV_PRINTF(LEVEL_INFO, 414 "The same fabric addr is being re-assigned to GPU %x\n", 415 pGpu->gpuInstance); 416 return NV_OK; 417 } 418 419 if (pKernelNvlink->fabricBaseAddr != NVLINK_INVALID_FABRIC_ADDR) 420 { 421 NV_PRINTF(LEVEL_ERROR, "Fabric addr is already assigned to GPU %x\n", 422 pGpu->gpuInstance); 423 return NV_ERR_STATE_IN_USE; 424 } 425 426 pKernelNvlink->fabricBaseAddr = fabricBaseAddr; 427 428 NV_PRINTF(LEVEL_INFO, "Fabric base addr %llx is assigned to GPU %x\n", 429 pKernelNvlink->fabricBaseAddr, pGpu->gpuInstance); 430 431 return NV_OK; 432 } 433 434 /*! 435 * @brief Check if floorsweeping is needed for this particular chip 436 * 437 * @param[in] pGpu OBJGPU pointer 438 * @param[in] pKernelNvlink KernelNvlink pointer 439 * 440 * @returns On success, sets unique fabric address and returns NV_OK. 441 * On failure, returns NV_ERR_XXX. 442 */ 443 NvBool 444 knvlinkIsFloorSweepingNeeded_GH100 445 ( 446 OBJGPU *pGpu, 447 KernelNvlink *pKernelNvlink, 448 NvU32 numActiveLinksPerIoctrl, 449 NvU32 numLinksPerIoctrl 450 ) 451 { 452 453 // 454 // Only floorsweep down the given GPU if the following conditions are met: 455 // 1. The number of active links allowed for the IOCTRL is less then the 456 // total number of links for the IOCTRL. No reason to spend time in code 457 // if the exectution of it will be a NOP 458 // 459 // 2. If the GPU has never been floorswept. An optimization to make sure RM 460 // doesn't burn cycles repeatedly running running code that will be a NOP 461 // 462 // 3. (temporary) Run only on Silicon chips. Fmodel currently doesn't support 463 // this feature 464 // 465 466 if (numActiveLinksPerIoctrl < numLinksPerIoctrl && 467 !pKernelNvlink->bFloorSwept && 468 IS_SILICON(pGpu)) 469 { 470 return NV_TRUE; 471 } 472 473 return NV_FALSE; 474 } 475 476 /*! 477 * @brief Check if system has enough active NVLinks and 478 * enough NVLink bridges 479 * 480 * @param[in] pGpu OBJGPU pointer 481 * @param[in] pKernelNvlink KernelNvlink pointer 482 * 483 */ 484 void 485 knvlinkDirectConnectCheck_GH100 486 ( 487 OBJGPU *pGpu, 488 KernelNvlink *pKernelNvlink 489 ) 490 { 491 NV2080_CTRL_NVLINK_DIRECT_CONNECT_CHECK_PARAMS params = {0}; 492 493 knvlinkExecGspRmRpc(pGpu, pKernelNvlink, 494 NV2080_CTRL_CMD_NVLINK_DIRECT_CONNECT_CHECK, 495 (void *)¶ms, 496 sizeof(params)); 497 } 498