1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 * SPDX-License-Identifier: MIT
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #define NVOC_KERNEL_NVLINK_H_PRIVATE_ACCESS_ALLOWED
25
26 // FIXME XXX
27 #define NVOC_KERNEL_IOCTRL_H_PRIVATE_ACCESS_ALLOWED
28
29 #include "os/os.h"
30 #include "core/hal.h"
31 #include "core/locks.h"
32 #include "gpu_mgr/gpu_mgr.h"
33 #include "gpu/gpu.h"
34 #include "kernel/gpu/nvlink/kernel_nvlink.h"
35 #include "kernel/gpu/nvlink/kernel_ioctrl.h"
36 #include "gpu/mem_mgr/mem_mgr.h"
37 #include "gpu/mmu/kern_gmmu.h"
38 #include "gpu/ce/kernel_ce.h"
39 #include "platform/sli/sli.h"
40 #include "gpu/gpu_fabric_probe.h"
41 #include "compute/imex_session_api.h"
42 #include "compute/fabric.h"
43 #include "mem_mgr/mem_multicast_fabric.h"
44
45 /*!
46 * @brief Is NVLINK topology forced? NVLink topology is considered
47 * forced for both legacy forced config and chiplib configs
48 *
49 * @param[in] pGpu OBJGPU
50 * @param[in] pKernelNvlink KernelNvlink pointer
51 *
52 * @return NV_TRUE if topology is forced
53 */
54 NvBool
knvlinkIsForcedConfig_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)55 knvlinkIsForcedConfig_IMPL
56 (
57 OBJGPU *pGpu,
58 KernelNvlink *pKernelNvlink
59 )
60 {
61 return (pKernelNvlink->bChiplibConfig);
62 }
63
64 /*!
65 * @brief Determine if NVLink is enabled or disabled by default
66 *
67 * @param[in] pGpu OBJGPU pointer
68 * @param[in] pKernelNvlink KernelNvlink pointer
69 *
70 * @return NV_TRUE if NVLink is enabled on the GPU/platform
71 */
72 NvBool
knvlinkIsNvlinkDefaultEnabled_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)73 knvlinkIsNvlinkDefaultEnabled_IMPL
74 (
75 OBJGPU *pGpu,
76 KernelNvlink *pKernelNvlink
77 )
78 {
79 //
80 // Currently it is critical that the following lib check be present.
81 // Burying this in the hal below it may get lost as the stub is all
82 // thats required for POR (always true from the hals perspective)
83 //
84 #if !defined(INCLUDE_NVLINK_LIB)
85
86 return NV_FALSE;
87
88 #endif
89
90 // Let the PDB handle the final decision.
91 return pKernelNvlink->getProperty(pKernelNvlink, PDB_PROP_KNVLINK_ENABLED);
92 }
93
94 /*!
95 * @brief Determine if P2P loopback over NVLink is supported for
96 * the given GPU. This function returns true if any link
97 * is connected in loopback mode.
98 *
99 * @param[in] pGpu OBJGPU pointer
100 * @param[in] pKernelNvlink KernelNvlink pointer
101 *
102 * @return NV_TRUE if any link is in loopback mode
103 */
104 NvBool
knvlinkIsP2pLoopbackSupported_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)105 knvlinkIsP2pLoopbackSupported_IMPL
106 (
107 OBJGPU *pGpu,
108 KernelNvlink *pKernelNvlink
109 )
110 {
111 #if defined(INCLUDE_NVLINK_LIB)
112
113 NvU32 i;
114
115 if ((pGpu == NULL) || (pKernelNvlink == NULL))
116 {
117 return NV_FALSE;
118 }
119
120 // Return false if P2P loopback is disabled through regkey
121 if (pGpu->getProperty(pGpu, PDB_PROP_GPU_NVLINK_P2P_LOOPBACK_DISABLED))
122 {
123 return NV_FALSE;
124 }
125
126 FOR_EACH_INDEX_IN_MASK(32, i, pKernelNvlink->enabledLinks)
127 {
128 if (knvlinkIsP2pLoopbackSupportedPerLink_IMPL(pGpu, pKernelNvlink, i))
129 return NV_TRUE;
130 }
131 FOR_EACH_INDEX_IN_MASK_END
132
133 #endif
134
135 return NV_FALSE;
136 }
137
138 /*!
139 * @brief Determine if P2P loopback over NVLink is supported for
140 * the given link. This function returns true if the link
141 * is connected in loopback mode.
142 *
143 * @param[in] pGpu OBJGPU pointer
144 * @param[in] pKernelNvlink KernelNvlink pointer
145 * @param[in] link Link ID
146 *
147 * @return NV_TRUE if the link is in loopback mode
148 */
149 NvBool
knvlinkIsP2pLoopbackSupportedPerLink_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU32 link)150 knvlinkIsP2pLoopbackSupportedPerLink_IMPL
151 (
152 OBJGPU *pGpu,
153 KernelNvlink *pKernelNvlink,
154 NvU32 link
155 )
156 {
157 #if defined(INCLUDE_NVLINK_LIB)
158
159 if ((pGpu == NULL) || (pKernelNvlink == NULL))
160 {
161 return NV_FALSE;
162 }
163
164 // Return false if P2P loopback is disabled through regkey
165 if (pGpu->getProperty(pGpu, PDB_PROP_GPU_NVLINK_P2P_LOOPBACK_DISABLED))
166 {
167 return NV_FALSE;
168 }
169
170 // Return false if the given link is disabled
171 if (!(NVBIT(link) & pKernelNvlink->enabledLinks))
172 {
173 return NV_FALSE;
174 }
175
176 // Check the link connected to the same GPU (loopback)
177 if (pKernelNvlink->nvlinkLinks[link].remoteEndInfo.bConnected)
178 {
179 if (((pKernelNvlink->nvlinkLinks[link].remoteEndInfo.domain == gpuGetDomain(pGpu)) &&
180 (pKernelNvlink->nvlinkLinks[link].remoteEndInfo.bus == gpuGetBus(pGpu)) &&
181 (pKernelNvlink->nvlinkLinks[link].remoteEndInfo.device == gpuGetDevice(pGpu)) &&
182 (pKernelNvlink->nvlinkLinks[link].remoteEndInfo.function == 0)) ||
183 pKernelNvlink->PDB_PROP_KNVLINK_FORCED_LOOPBACK_ON_SWITCH_MODE_ENABLED)
184 {
185 return NV_TRUE;
186 }
187 }
188
189 #endif
190
191 return NV_FALSE;
192 }
193
194 /*!
195 * @brief Determine if P2P over NVLINK is supported between 2 GPUs
196 *
197 * @param[in] pGpu OBJGPU pointer for local GPU
198 * @param[in] pKernelNvlink KernelNvlink pointer
199 * @param[in] pPeerGpu OBJGPU pointer for remote GPU
200 *
201 * @return NV_TRUE if P2P is supported between the 2 GPUs
202 */
203 NvBool
knvlinkIsNvlinkP2pSupported_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,OBJGPU * pPeerGpu)204 knvlinkIsNvlinkP2pSupported_IMPL
205 (
206 OBJGPU *pGpu,
207 KernelNvlink *pKernelNvlink,
208 OBJGPU *pPeerGpu
209 )
210 {
211 NV_STATUS status = NV_OK;
212
213 if (pKernelNvlink == NULL)
214 {
215 return NV_FALSE;
216 }
217
218 if (knvlinkIsBandwidthModeOff(pKernelNvlink))
219 {
220 return NV_FALSE;
221 }
222
223 // Get the Nvlink P2P connections from the core library
224 status = knvlinkGetP2pConnectionStatus(pGpu, pKernelNvlink, pPeerGpu);
225
226 if (status == NV_OK)
227 {
228 return NV_TRUE;
229 }
230
231 return NV_FALSE;
232 }
233
234 static NvBool
_knvlinkCheckFabricCliqueId(OBJGPU * pGpu,OBJGPU * pPeerGpu)235 _knvlinkCheckFabricCliqueId
236 (
237 OBJGPU *pGpu,
238 OBJGPU *pPeerGpu
239 )
240 {
241 NvU32 cliqueId, peerCliqueId;
242 NV_STATUS status;
243
244 status = gpuFabricProbeGetFabricCliqueId(pGpu->pGpuFabricProbeInfoKernel,
245 &cliqueId);
246 if (status != NV_OK)
247 {
248 NV_PRINTF(LEVEL_ERROR, "GPU %d failed to get fabric clique Id: 0x%x\n",
249 gpuGetInstance(pGpu), status);
250 return NV_FALSE;
251 }
252
253 status = gpuFabricProbeGetFabricCliqueId(pPeerGpu->pGpuFabricProbeInfoKernel,
254 &peerCliqueId);
255 if (status != NV_OK)
256 {
257 NV_PRINTF(LEVEL_ERROR, "GPU %d failed to get fabric clique Id 0x%x\n",
258 gpuGetInstance(pPeerGpu), status);
259 return NV_FALSE;
260 }
261
262 if (cliqueId != peerCliqueId)
263 {
264 NV_PRINTF(LEVEL_ERROR, "GPU %d and Peer GPU %d cliqueId doesn't match\n",
265 gpuGetInstance(pGpu), gpuGetInstance(pPeerGpu));
266 return NV_FALSE;
267 }
268
269 return NV_TRUE;
270 }
271
272 /*!
273 * @brief Checks whether EGM addresses are valid for P2P
274 * when GPU is connected to NVSwitch
275 *
276 * @param[in] pGpu OBJGPU pointer for local GPU
277 * @param[in] pKernelNvlink KernelNvlink pointer
278 * @param[in] pPeerGpu OBJGPU pointer for remote GPU
279 *
280 * @return NV_TRUE if EGM addresses are valid
281 */
282 static NvBool
_knvlinkCheckNvswitchEgmAddressSanity(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,OBJGPU * pPeerGpu)283 _knvlinkCheckNvswitchEgmAddressSanity
284 (
285 OBJGPU *pGpu,
286 KernelNvlink *pKernelNvlink,
287 OBJGPU *pPeerGpu
288 )
289 {
290 NvU64 egmRangeStart = knvlinkGetUniqueFabricEgmBaseAddress(pGpu, pKernelNvlink);
291
292 if (knvlinkIsGpuConnectedToNvswitch(pGpu, pKernelNvlink))
293 {
294 if (gpuIsSriovEnabled(pGpu))
295 {
296 // currently vgpu + switch doesn't support GPA addressing.
297 return NV_TRUE;
298 }
299
300 if (gpuFabricProbeIsSupported(pGpu) && gpuFabricProbeIsSupported(pPeerGpu))
301 {
302 if (!_knvlinkCheckFabricCliqueId(pGpu, pPeerGpu))
303 {
304 return NV_FALSE;
305 }
306 }
307
308 // Sanity checks for EGM address
309 if (egmRangeStart == NVLINK_INVALID_FABRIC_ADDR)
310 {
311 NV_PRINTF(LEVEL_ERROR, "GPU %d doesn't have a EGM fabric address\n",
312 gpuGetInstance(pGpu));
313
314 return NV_FALSE;
315 }
316 }
317 else
318 {
319 // Sanity check for EGM address
320 if (egmRangeStart != NVLINK_INVALID_FABRIC_ADDR)
321 {
322 NV_PRINTF(LEVEL_ERROR,
323 "non-NVSwitch GPU %d has a valid EGM fabric address\n",
324 gpuGetInstance(pGpu));
325
326 return NV_FALSE;
327 }
328
329 }
330
331 return NV_TRUE;
332 }
333
334 /*!
335 * @brief Checks whether necessary the config setup is done to
336 * support P2P over NVSwitch
337 *
338 * @param[in] pGpu OBJGPU pointer for local GPU
339 * @param[in] pKernelNvlink KernelNvlink pointer
340 * @param[in] pPeerGpu OBJGPU pointer for remote GPU
341 *
342 * @return NV_TRUE if P2P over NVSwitch
343 */
344 NvBool
knvlinkCheckNvswitchP2pConfig_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,OBJGPU * pPeerGpu)345 knvlinkCheckNvswitchP2pConfig_IMPL
346 (
347 OBJGPU *pGpu,
348 KernelNvlink *pKernelNvlink,
349 OBJGPU *pPeerGpu
350 )
351 {
352 MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
353 NvU64 hbmRangeStart = knvlinkGetUniqueFabricBaseAddress(pGpu, pKernelNvlink);
354 NvU64 hbmRangeEnd = hbmRangeStart + (pMemoryManager->Ram.fbTotalMemSizeMb << 20);
355 NvU64 hbmPeerRangeStart = knvlinkGetUniqueFabricBaseAddress(pPeerGpu,
356 GPU_GET_KERNEL_NVLINK(pPeerGpu));
357
358 if (knvlinkIsGpuConnectedToNvswitch(pGpu, pKernelNvlink))
359 {
360 if (gpuIsSriovEnabled(pGpu))
361 {
362 // currently vgpu + switch doesn't support GPA addresing.
363 return NV_TRUE;
364 }
365
366 if (gpuFabricProbeIsSupported(pGpu) && gpuFabricProbeIsSupported(pPeerGpu))
367 {
368 if (!_knvlinkCheckFabricCliqueId(pGpu, pPeerGpu))
369 {
370 return NV_FALSE;
371 }
372 }
373
374 // Sanity checks for HBM addresses
375 if (hbmRangeStart == NVLINK_INVALID_FABRIC_ADDR)
376 {
377 NV_PRINTF(LEVEL_ERROR, "GPU %d doesn't have a fabric address\n",
378 gpuGetInstance(pGpu));
379
380 return NV_FALSE;
381 }
382
383 if ((pGpu != pPeerGpu) &&
384 ((hbmPeerRangeStart >= hbmRangeStart) && (hbmPeerRangeStart < hbmRangeEnd)))
385 {
386 NV_PRINTF(LEVEL_ERROR,
387 "GPU %d doesn't have a unique fabric address\n",
388 gpuGetInstance(pGpu));
389
390 return NV_FALSE;
391 }
392 }
393 else
394 {
395 // Sanity check for HBM address
396 if (hbmRangeStart != NVLINK_INVALID_FABRIC_ADDR)
397 {
398 NV_PRINTF(LEVEL_ERROR,
399 "non-NVSwitch GPU %d has a valid fabric address\n",
400 gpuGetInstance(pGpu));
401
402 return NV_FALSE;
403 }
404 }
405
406 if (memmgrIsLocalEgmEnabled(pMemoryManager))
407 {
408 return _knvlinkCheckNvswitchEgmAddressSanity(pGpu, pKernelNvlink, pPeerGpu);
409 }
410
411 return NV_TRUE;
412 }
413
414 /*!
415 * @brief Get Nvlink P2P connections between 2 GPUs
416 *
417 * @param[in] pGpu OBJGPU pointer for local GPU
418 * @param[in] pKernelNvlink KernelNvlink pointer
419 * @param[in] pPeerGpu OBJGPU pointer for remote GPU
420 *
421 * @return NV_OK if P2P connections are present
422 */
423 NV_STATUS
knvlinkGetP2pConnectionStatus_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,OBJGPU * pPeerGpu)424 knvlinkGetP2pConnectionStatus_IMPL
425 (
426 OBJGPU *pGpu,
427 KernelNvlink *pKernelNvlink,
428 OBJGPU *pPeerGpu
429 )
430 {
431 NV_STATUS status = NV_OK;
432 OBJGPU *pGpu0 = pGpu;
433 OBJGPU *pGpu1 = pPeerGpu;
434 KernelNvlink *pKernelNvlink0 = pKernelNvlink;
435 KernelNvlink *pKernelNvlink1 = NULL;
436 NvU32 numPeerLinks = 0;
437
438 if (pGpu1 == NULL)
439 {
440 NV_PRINTF(LEVEL_INFO, "Invalid pPeerGpu.\n");
441
442 return NV_ERR_INVALID_ARGUMENT;
443 }
444 else if ((pGpu0 == pGpu1) &&
445 (pGpu0->getProperty(pGpu0, PDB_PROP_GPU_NVLINK_P2P_LOOPBACK_DISABLED)))
446 {
447 // P2P over loopback links are disabled through regkey overrides
448 NV_PRINTF(LEVEL_INFO, "loopback P2P on GPU%u disabled by regkey\n",
449 gpuGetInstance(pGpu0));
450
451 return NV_ERR_NOT_SUPPORTED;
452 }
453 else
454 {
455 pKernelNvlink1 = GPU_GET_KERNEL_NVLINK(pGpu1);
456 }
457
458 if (pKernelNvlink1 == NULL)
459 {
460 NV_PRINTF(LEVEL_INFO,
461 "Input mask contains a GPU on which NVLink is disabled.\n");
462
463 return NV_ERR_INVALID_ARGUMENT;
464 }
465
466 if(pKernelNvlink0->bIsGpuDegraded)
467 {
468 NV_PRINTF(LEVEL_INFO,
469 "NVLink P2P is NOT supported between GPU%d and GPU%d\n",
470 gpuGetInstance(pGpu0), gpuGetInstance(pGpu1));
471
472 return NV_ERR_NOT_SUPPORTED;
473 }
474
475 if(pKernelNvlink1->bIsGpuDegraded)
476 {
477 NV_PRINTF(LEVEL_INFO,
478 "NVLink P2P is NOT supported between GPU%d and GPU%d\n",
479 gpuGetInstance(pGpu0), gpuGetInstance(pGpu1));
480
481 return NV_ERR_NOT_SUPPORTED;
482 }
483
484 if ((IS_RTLSIM(pGpu0) && !pKernelNvlink0->bForceEnableCoreLibRtlsims) ||
485 knvlinkIsForcedConfig(pGpu0, pKernelNvlink0))
486 {
487 // For non-legacy configs.
488 if (pKernelNvlink0->bChiplibConfig)
489 {
490 NV_PRINTF(LEVEL_INFO,
491 "NVLink P2P is supported between GPU%d and GPU%d\n",
492 gpuGetInstance(pGpu0), gpuGetInstance(pGpu1));
493
494 return NV_OK;
495 }
496 }
497
498 // Get the remote ends of the links of local GPU from the nvlink core
499 status = knvlinkCoreGetRemoteDeviceInfo(pGpu0, pKernelNvlink0);
500 if (status != NV_OK)
501 {
502 return status;
503 }
504
505 // Post topology link enable on links of local GPU
506 status = knvlinkEnableLinksPostTopology_HAL(pGpu0, pKernelNvlink0,
507 pKernelNvlink0->enabledLinks);
508 if (status != NV_OK)
509 {
510 return status;
511 }
512
513 numPeerLinks = knvlinkGetNumLinksToPeer(pGpu0, pKernelNvlink0, pGpu1);
514
515 //
516 // Maybe knvlinkCoreGetRemoteDeviceInfo was never called on pGpu1.
517 // This can happen on systems where FM doesn't configure GPUs
518 // using RM control calls explicitly.
519 //
520 if ((numPeerLinks == 0) && gpuFabricProbeIsSupported(pGpu1))
521 {
522 knvlinkCoreGetRemoteDeviceInfo(pGpu1, pKernelNvlink1);
523
524 // Post topology link enable on links of remote GPU
525 status = knvlinkEnableLinksPostTopology_HAL(pGpu1, pKernelNvlink1,
526 pKernelNvlink1->enabledLinks);
527 if (status != NV_OK)
528 {
529 return status;
530 }
531
532 numPeerLinks = knvlinkGetNumLinksToPeer(pGpu0, pKernelNvlink0, pGpu1);
533 }
534
535 if (numPeerLinks > 0)
536 {
537 if (knvlinkGetNumLinksToPeer(pGpu1, pKernelNvlink1, pGpu0) != numPeerLinks)
538 {
539 // Get the remote ends of the links of remote GPU from the nvlink core
540 status = knvlinkCoreGetRemoteDeviceInfo(pGpu1, pKernelNvlink1);
541 if (status != NV_OK)
542 {
543 return status;
544 }
545
546 // Post topology link enable on links of remote GPU
547 status = knvlinkEnableLinksPostTopology_HAL(pGpu1, pKernelNvlink1,
548 pKernelNvlink1->enabledLinks);
549 if (status != NV_OK)
550 {
551 return status;
552 }
553 }
554
555 // Peers should have the same number of links pointing back at us
556 NV_CHECK_OR_RETURN(LEVEL_INFO,
557 (knvlinkGetNumLinksToPeer(pGpu1, pKernelNvlink1, pGpu0) == numPeerLinks),
558 NV_ERR_INVALID_STATE);
559
560 NV_CHECK_OR_RETURN(LEVEL_INFO,
561 knvlinkCheckNvswitchP2pConfig(pGpu0, pKernelNvlink0, pGpu1),
562 NV_ERR_INVALID_STATE);
563
564 NV_CHECK_OR_RETURN(LEVEL_INFO,
565 knvlinkCheckNvswitchP2pConfig(pGpu1, pKernelNvlink1, pGpu0),
566 NV_ERR_INVALID_STATE);
567
568 NV_PRINTF(LEVEL_INFO,
569 "NVLink P2P is supported between GPU%d and GPU%d\n",
570 gpuGetInstance(pGpu0), gpuGetInstance(pGpu1));
571
572 return NV_OK;
573 }
574
575 NV_PRINTF(LEVEL_INFO,
576 "NVLink P2P is NOT supported between between GPU%d and GPU%d\n",
577 pGpu->gpuInstance, pGpu1->gpuInstance);
578
579 return NV_ERR_NOT_SUPPORTED;
580 }
581
582 /*!
583 * @brief Update the settings for the current established NVLink
584 * topology. This is the top level function that should be
585 * called, instead of applying the settings individually,
586 * since it grabs the required locks
587 *
588 * @param[in] pGpu OBJGPU pointer
589 * @param[in] pKernelNvlink KernelNvlink pointer
590 *
591 * @return NV_OK on success
592 */
593 NV_STATUS
knvlinkUpdateCurrentConfig_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)594 knvlinkUpdateCurrentConfig_IMPL
595 (
596 OBJGPU *pGpu,
597 KernelNvlink *pKernelNvlink
598 )
599 {
600 OBJSYS *pSys = SYS_GET_INSTANCE();
601 KernelCE *pKCe = NULL;
602 NvBool bOwnsLock = NV_FALSE;
603 NV_STATUS status = NV_OK;
604
605 if (osAcquireRmSema(pSys->pSema) == NV_OK)
606 {
607 //
608 // XXX Bug 1795328: Fix P2P path to acquire locks for the GPU
609 // Due to platform differences in the P2P path, the GPU lock is not
610 // consistently held at this point in the call stack. This function
611 // requires exclusive access to RM/PMU data structures to update HSHUB,
612 // and therefore requires the GPU lock to be held at this point.
613 // This check should be removed once the P2P paths have been updated to
614 // acquire the GPU locks consistently for all platforms.
615 //
616 if (!rmDeviceGpuLockIsOwner(pGpu->gpuInstance))
617 {
618 status = rmDeviceGpuLocksAcquire(pGpu, GPUS_LOCK_FLAGS_NONE,
619 RM_LOCK_MODULES_NVLINK);
620 if (status != NV_OK)
621 {
622 NV_ASSERT(0);
623 goto fail;
624 }
625
626 bOwnsLock = NV_TRUE;
627 }
628
629 //
630 // Links that have remote end detected should have passed RXDET
631 // Update the mask of connected links and bridged links
632 //
633 knvlinkFilterBridgeLinks_HAL(pGpu, pKernelNvlink);
634
635 NV2080_CTRL_NVLINK_UPDATE_CURRENT_CONFIG_PARAMS params;
636 portMemSet(¶ms, 0, sizeof(params));
637
638 // Reset timeout to clear any accumulated timeouts from link init
639 if (IS_GSP_CLIENT(pGpu))
640 {
641 threadStateResetTimeout(pGpu);
642 }
643
644 //
645 // RPC into GSP-RM for programming the HSHUB, CONNECTION_CFG and LTCS
646 // registers.
647 //
648 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
649 NV2080_CTRL_CMD_NVLINK_UPDATE_CURRENT_CONFIG,
650 (void *)¶ms, sizeof(params));
651 if (status != NV_OK)
652 {
653 NV_PRINTF(LEVEL_ERROR, "Updating current NVLink config failed\n");
654 goto fail;
655 }
656
657 // Sync the GPU property for NVLINK over SYSMEM with GSP-RM
658 pGpu->setProperty(pGpu, PDB_PROP_GPU_NVLINK_SYSMEM, params.bNvlinkSysmemEnabled);
659
660 // Update the PCE-LCE mappings
661 status = kceFindFirstInstance(pGpu, &pKCe);
662 if (status == NV_OK)
663 {
664 status = kceTopLevelPceLceMappingsUpdate(pGpu, pKCe);
665 if (status != NV_OK)
666 {
667 NV_PRINTF(LEVEL_ERROR, "Failed to update PCE-LCE mappings\n");
668 }
669 }
670
671 fail:
672 if (bOwnsLock)
673 {
674 rmDeviceGpuLocksRelease(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
675 }
676
677 osReleaseRmSema(pSys->pSema, NULL);
678 }
679
680 return status;
681 }
682
683 const static NVLINK_INBAND_MSG_CALLBACK nvlink_inband_callbacks[] =
684 {
685 {
686 .messageType = NVLINK_INBAND_MSG_TYPE_GPU_PROBE_RSP,
687 .pCallback = gpuFabricProbeReceiveKernelCallback,
688 .wqItemFlags = OS_QUEUE_WORKITEM_FLAGS_LOCK_SEMA |
689 OS_QUEUE_WORKITEM_FLAGS_LOCK_GPU_GROUP_SUBDEVICE_RW
690 },
691
692 {
693 .messageType = NVLINK_INBAND_MSG_TYPE_MC_TEAM_SETUP_RSP,
694 .pCallback = memorymulticastfabricTeamSetupResponseCallback,
695 .wqItemFlags = OS_QUEUE_WORKITEM_FLAGS_LOCK_SEMA |
696 OS_QUEUE_WORKITEM_FLAGS_LOCK_GPUS_RW
697 },
698
699 {
700 .messageType = NVLINK_INBAND_MSG_TYPE_GPU_PROBE_UPDATE_REQ,
701 .pCallback = gpuFabricProbeReceiveUpdateKernelCallback,
702 .wqItemFlags = OS_QUEUE_WORKITEM_FLAGS_LOCK_SEMA |
703 OS_QUEUE_WORKITEM_FLAGS_LOCK_GPU_GROUP_SUBDEVICE_RW
704 }
705 };
706
707 void
knvlinkInbandMsgCallbackDispatcher_WORKITEM(NvU32 gpuInstance,void * pData)708 knvlinkInbandMsgCallbackDispatcher_WORKITEM
709 (
710 NvU32 gpuInstance,
711 void *pData
712 )
713 {
714 nvlink_inband_msg_header_t *pHeader;
715 NV2080_CTRL_NVLINK_INBAND_RECEIVED_DATA_PARAMS *pMessage = pData;
716 NvU8 i;
717 const NVLINK_INBAND_MSG_CALLBACK *pCb = NULL;
718
719 // Dispatcher may not be called under GPU lock, so don't access pGpu.
720
721 pHeader = (nvlink_inband_msg_header_t *)pMessage->data;
722
723 for (i = 0; i < NV_ARRAY_ELEMENTS(nvlink_inband_callbacks); i++)
724 {
725 if ((nvlink_inband_callbacks[i].messageType == pHeader->type) &&
726 (nvlink_inband_callbacks[i].pCallback != NULL))
727 {
728 pCb = &nvlink_inband_callbacks[i];
729 break;
730 }
731 }
732
733 if (pCb == NULL)
734 {
735 NV_PRINTF(LEVEL_ERROR,
736 "No Callback Registered for type %d. Dropping the msg\n",
737 pHeader->type);
738 return;
739 }
740
741 #if defined(DEBUG) || defined(DEVELOP)
742 {
743 NvU8 *pRsvd = NULL;
744
745 // Assert reserved in msgHdr are zero
746 pRsvd = &pHeader->reserved[0];
747 NV_ASSERT((pRsvd[0] == 0) && portMemCmp(pRsvd, pRsvd + 1,
748 sizeof(pHeader->reserved) - 1) == 0);
749 }
750 #endif
751
752 (void)pCb->pCallback(gpuInstance, NULL, pData);
753 }
754
755 NV_STATUS
knvlinkInbandMsgCallbackDispatcher_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU32 dataSize,NvU8 * pMessage)756 knvlinkInbandMsgCallbackDispatcher_IMPL
757 (
758 OBJGPU *pGpu,
759 KernelNvlink *pKernelNvlink,
760 NvU32 dataSize,
761 NvU8 *pMessage
762 )
763 {
764 NV_STATUS status;
765 nvlink_inband_msg_header_t *pHeader;
766 NV2080_CTRL_NVLINK_INBAND_RECEIVED_DATA_PARAMS *pData = NULL;
767 const NVLINK_INBAND_MSG_CALLBACK *pCb = NULL;
768 NvU8 i;
769
770 pHeader = (nvlink_inband_msg_header_t *)pMessage;
771
772 if (pHeader->type >= NVLINK_INBAND_MSG_TYPE_MAX)
773 {
774 NV_PRINTF(LEVEL_ERROR, "Message type received is Out of Bounds. Dropping the msg\n");
775 return NV_ERR_INVALID_REQUEST;
776 }
777
778 for (i = 0; i < NV_ARRAY_ELEMENTS(nvlink_inband_callbacks); i++)
779 {
780 if ((nvlink_inband_callbacks[i].messageType == pHeader->type) &&
781 (nvlink_inband_callbacks[i].pCallback != NULL))
782 {
783 pCb = &nvlink_inband_callbacks[i];
784 break;
785 }
786 }
787
788 if (pCb == NULL)
789 {
790 NV_PRINTF(LEVEL_ERROR,
791 "No Callback Registered for type %d. Dropping the msg\n",
792 pHeader->type);
793 return NV_ERR_INVALID_REQUEST;
794 }
795
796 pData = portMemAllocNonPaged(sizeof(NV2080_CTRL_NVLINK_INBAND_RECEIVED_DATA_PARAMS));
797 if (pData == NULL)
798 {
799 NV_PRINTF(LEVEL_ERROR, "Out of memory, Dropping message\n");
800 return NV_ERR_NO_MEMORY;
801 }
802
803 pData->dataSize = dataSize;
804 portMemCopy(pData->data, pData->dataSize, pMessage, dataSize);
805
806 status = osQueueWorkItemWithFlags(pGpu, knvlinkInbandMsgCallbackDispatcher_WORKITEM, pData,
807 pCb->wqItemFlags);
808 if (status != NV_OK)
809 {
810 portMemFree(pData);
811 return status;
812 }
813
814 return NV_OK;
815 }
816
817 NV_STATUS
knvlinkSendInbandData_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NV2080_CTRL_NVLINK_INBAND_SEND_DATA_PARAMS * pParams)818 knvlinkSendInbandData_IMPL
819 (
820 OBJGPU *pGpu,
821 KernelNvlink *pKernelNvlink,
822 NV2080_CTRL_NVLINK_INBAND_SEND_DATA_PARAMS *pParams
823 )
824 {
825 NV_STATUS status;
826
827 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
828 NV2080_CTRL_CMD_NVLINK_INBAND_SEND_DATA,
829 (void *)pParams,
830 sizeof(*pParams));
831
832 return status;
833 }
834 /*!
835 * @brief Return the mask of links enabled on the system
836 *
837 * @param[in] pGpu OBJGPU pointer
838 * @param[in] pKernelNvlink KernelNvlink pointer
839 */
840 NvU32
knvlinkGetEnabledLinkMask_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)841 knvlinkGetEnabledLinkMask_IMPL
842 (
843 OBJGPU *pGpu,
844 KernelNvlink *pKernelNvlink
845 )
846 {
847 return pKernelNvlink->enabledLinks;
848 }
849
850 /*!
851 * @brief Return the mask of links discovered on the system
852 *
853 * @param[in] pGpu OBJGPU pointer
854 * @param[in] pKernelNvlink KernelNvlink pointer
855 */
856 NvU32
knvlinkGetDiscoveredLinkMask_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)857 knvlinkGetDiscoveredLinkMask_IMPL
858 (
859 OBJGPU *pGpu,
860 KernelNvlink *pKernelNvlink
861 )
862 {
863 return pKernelNvlink->discoveredLinks;
864 }
865
866 /*!
867 * @brief Returns the number of sysmem links
868 *
869 * @param[in] pGpu OBJGPU pointer
870 * @param[in] pKernelNvlink KernelNvlink pointer
871 *
872 * @return The #sysmem NVLinks
873 */
874 NvU32
knvlinkGetNumLinksToSystem_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)875 knvlinkGetNumLinksToSystem_IMPL
876 (
877 OBJGPU *pGpu,
878 KernelNvlink *pKernelNvlink
879 )
880 {
881 NvU32 numSysmemLinks = pKernelNvlink->sysmemLinkMask;
882
883 if (numSysmemLinks != 0)
884 {
885 NUMSETBITS_32(numSysmemLinks);
886 }
887
888 return numSysmemLinks;
889 }
890
891 /*!
892 * @brief Returns number of peer links to a remote GPU
893 *
894 * @param[in] pGpu OBJGPU pointer of local GPU
895 * @param[in] pKernelNvlink KernelNvlink pointer
896 * @param[in] pRemoteGpu OBJGPU pointer of remote GPU
897 *
898 * @return The #peer NVLinks to the remote GPU
899 */
900 NvU32
knvlinkGetNumLinksToPeer_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,OBJGPU * pRemoteGpu)901 knvlinkGetNumLinksToPeer_IMPL
902 (
903 OBJGPU *pGpu,
904 KernelNvlink *pKernelNvlink,
905 OBJGPU *pRemoteGpu
906 )
907 {
908 NvU32 numPeerLinks =
909 knvlinkGetLinkMaskToPeer(pGpu, pKernelNvlink, pRemoteGpu);
910
911 if (numPeerLinks != 0)
912 {
913 NUMSETBITS_32(numPeerLinks);
914 }
915
916 return numPeerLinks;
917 }
918
919 /*!
920 * @brief Gets the mask of peer links between the GPUs
921 *
922 * @param[in] pGpu0 OBJGPU pointer
923 * @param[in] pKernelNvlink0 Nvlink pointer
924 * @param[in] pGpu1 Remote OBJGPU pointer
925 *
926 * @return Returns the mask of peer links between the GPUs
927 */
928 NvU32
knvlinkGetLinkMaskToPeer_IMPL(OBJGPU * pGpu0,KernelNvlink * pKernelNvlink0,OBJGPU * pGpu1)929 knvlinkGetLinkMaskToPeer_IMPL
930 (
931 OBJGPU *pGpu0,
932 KernelNvlink *pKernelNvlink0,
933 OBJGPU *pGpu1
934 )
935 {
936 NvU32 peerLinkMask = 0;
937 KernelNvlink *pKernelNvlink1 = NULL;
938
939 pKernelNvlink1 = GPU_GET_KERNEL_NVLINK(pGpu1);
940
941 if (pKernelNvlink1 == NULL)
942 {
943 NV_PRINTF(LEVEL_INFO,
944 "on GPU%d NVLink is disabled.\n", gpuGetInstance(pGpu1));
945
946 return 0;
947 }
948
949 if(pKernelNvlink0->bIsGpuDegraded)
950 {
951 return peerLinkMask;
952 }
953
954 if(pKernelNvlink1->bIsGpuDegraded)
955 {
956 return peerLinkMask;
957 }
958
959 if (!knvlinkIsForcedConfig(pGpu0, pKernelNvlink0))
960 {
961 //
962 // If nvlink topology is not forced, then the hshub registers
963 // are updated only when a P2P object is allocated. So, return
964 // the cached value of mask of links connected to a GPU
965 //
966 peerLinkMask = pKernelNvlink0->peerLinkMasks[gpuGetInstance(pGpu1)];
967 }
968
969 return peerLinkMask;
970 }
971
972 /*!
973 * @brief Sets the mask of peer links between the GPUs
974 *
975 * @param[in] pGpu0 OBJGPU pointer
976 * @param[in] pKernelNvlink0 Nvlink pointer
977 * @param[in] pGpu1 Remote OBJGPU pointer
978 * @param[in] peerLinkMask Mask of links to the peer GPU
979 *
980 * @return NV_OK on success
981 */
982 NV_STATUS
knvlinkSetLinkMaskToPeer_IMPL(OBJGPU * pGpu0,KernelNvlink * pKernelNvlink0,OBJGPU * pGpu1,NvU32 peerLinkMask)983 knvlinkSetLinkMaskToPeer_IMPL
984 (
985 OBJGPU *pGpu0,
986 KernelNvlink *pKernelNvlink0,
987 OBJGPU *pGpu1,
988 NvU32 peerLinkMask
989 )
990 {
991 NV_STATUS status = NV_OK;
992
993 // Return early if no update needed to the peer link mask
994 if (pKernelNvlink0->peerLinkMasks[gpuGetInstance(pGpu1)] == peerLinkMask)
995 return NV_OK;
996
997 pKernelNvlink0->peerLinkMasks[gpuGetInstance(pGpu1)] = peerLinkMask;
998
999 NV2080_CTRL_NVLINK_UPDATE_PEER_LINK_MASK_PARAMS params;
1000
1001 portMemSet(¶ms, 0, sizeof(params));
1002 params.gpuInst = gpuGetInstance(pGpu1);
1003 params.peerLinkMask = peerLinkMask;
1004
1005 // Reset timeout to clear any accumulated timeouts from link init
1006 if (IS_GSP_CLIENT(pGpu0))
1007 {
1008 threadStateResetTimeout(pGpu0);
1009 }
1010
1011 // Sync the peerLinkMask with GSP-RM
1012 status = knvlinkExecGspRmRpc(pGpu0, pKernelNvlink0,
1013 NV2080_CTRL_CMD_NVLINK_UPDATE_PEER_LINK_MASK,
1014 (void *)¶ms, sizeof(params));
1015 if (status != NV_OK)
1016 {
1017 NV_PRINTF(LEVEL_ERROR,
1018 "Failed to sync peerLinksMask from GPU%d to GPU%d\n",
1019 gpuGetInstance(pGpu0), gpuGetInstance(pGpu1));
1020 return status;
1021 }
1022
1023 return NV_OK;
1024 }
1025
1026 /*!
1027 * @brief Get the mask of links that are peer links
1028 *
1029 * @param[in] pGpu OBJGPU pointer
1030 * @param[in] pKernelNvlink KernelNvlink pointer
1031 */
1032 NvU32
knvlinkGetPeersNvlinkMaskFromHshub_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1033 knvlinkGetPeersNvlinkMaskFromHshub_IMPL
1034 (
1035 OBJGPU *pGpu,
1036 KernelNvlink *pKernelNvlink
1037 )
1038 {
1039 NV_STATUS status = NV_OK;
1040 NvU32 peerLinkMask = 0;
1041 NvU32 i;
1042
1043 NV2080_CTRL_NVLINK_GET_LINK_AND_CLOCK_INFO_PARAMS params;
1044
1045 portMemSet(¶ms, 0, sizeof(params));
1046 params.linkMask = pKernelNvlink->enabledLinks;
1047 params.bSublinkStateInst = NV_TRUE;
1048
1049 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1050 NV2080_CTRL_CMD_NVLINK_GET_LINK_AND_CLOCK_INFO,
1051 (void *)¶ms, sizeof(params));
1052 if (status != NV_OK)
1053 return 0;
1054
1055 // Scan enabled links for peer connections
1056 FOR_EACH_INDEX_IN_MASK(32, i, pKernelNvlink->enabledLinks)
1057 {
1058 if (params.linkInfo[i].bLinkConnectedToPeer)
1059 peerLinkMask |= NVBIT(i);
1060 }
1061 FOR_EACH_INDEX_IN_MASK_END;
1062
1063 return peerLinkMask;
1064 }
1065
1066 /*!
1067 * @brief Prepare a GPU's NVLink engine for reset by removing mappings
1068 * to it from other GPUs.
1069 *
1070 * @param[in] pGpu OBJGPU pointer
1071 * @param[in] pKernelNvlink KernelNvlink pointer
1072 *
1073 * return NV_OK on success
1074 */
1075 NV_STATUS
knvlinkPrepareForXVEReset_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvBool bForceShutdown)1076 knvlinkPrepareForXVEReset_IMPL
1077 (
1078 OBJGPU *pGpu,
1079 KernelNvlink *pKernelNvlink,
1080 NvBool bForceShutdown
1081 )
1082 {
1083 OBJSYS *pSys = SYS_GET_INSTANCE();
1084 NV_STATUS retStatus = NV_OK;
1085 OBJGPU *pRemoteGpu;
1086 NV_STATUS status;
1087 NvU32 gpuInstance;
1088 NvU32 gpuMask;
1089
1090 // This is not supported on forced configs
1091 if (knvlinkIsForcedConfig(pGpu, pKernelNvlink))
1092 {
1093 return NV_OK;
1094 }
1095
1096 //
1097 // Let fabric manager handle link shutdown/reset if the fabric is managed
1098 // externally.
1099 //
1100 if (pKernelNvlink->ipVerNvlink < NVLINK_VERSION_40 &&
1101 pSys->getProperty(pSys, PDB_PROP_SYS_FABRIC_IS_EXTERNALLY_MANAGED))
1102 {
1103 NV_PRINTF(LEVEL_INFO,
1104 "NVLink fabric is externally managed, skipping\n");
1105 return NV_OK;
1106 }
1107
1108 status = gpumgrGetGpuAttachInfo(NULL, &gpuMask);
1109 NV_ASSERT_OR_RETURN(status == NV_OK, status);
1110
1111 gpuInstance = 0;
1112 while ((pRemoteGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL)
1113 {
1114 KernelNvlink *pRemoteKernelNvlink = GPU_GET_KERNEL_NVLINK(pRemoteGpu);
1115
1116 if ((pRemoteGpu == pGpu) || (pRemoteKernelNvlink == NULL) ||
1117 (knvlinkGetNumLinksToPeer(pRemoteGpu, pRemoteKernelNvlink, pGpu) == 0) ||
1118 API_GPU_IN_RESET_SANITY_CHECK(pRemoteGpu) ||
1119 pRemoteGpu->getProperty(pRemoteGpu, PDB_PROP_GPU_IS_LOST))
1120 {
1121 continue;
1122 }
1123
1124 //
1125 // Reset the peer masks in HSHUB of the remote GPU. Partial resets
1126 // (only removing the links connected to the GPU being reset) don't
1127 // appear to be sufficient. The reset will work fine, but the next
1128 // time we attempt to initialize this GPU, the copy engines will time
1129 // out while scrubbing FB and a GPU sysmembar (NV_UFLUSH_FB_FLUSH) will
1130 // fail to complete.
1131 //
1132 // The above symptoms haven't been root-caused (yet), but the current
1133 // POR for GPU reset is that once one GPU is reset, the others
1134 // connected to it over NVLink must also be reset before using NVLink
1135 // for peer traffic, so just use the big hammer and squash all HSHUB
1136 // configs on GPU reset.
1137 //
1138 // This allows us to reset the GPUs one by one, with GPU
1139 // initializations in between, without hanging up the GPU trying to
1140 // flush data over links that aren't available anymore.
1141 //
1142 // Starting from Ampere single GPU reset is supported and hence remove
1143 // only the nvlink's of the remote GPU's which are connected to the
1144 // current GPU.
1145 //
1146
1147 if (IsAMPEREorBetter(pGpu))
1148 {
1149 NvU32 remPeerId = kbusGetPeerId_HAL(pRemoteGpu, GPU_GET_KERNEL_BUS(pRemoteGpu), pGpu);
1150 if (remPeerId != BUS_INVALID_PEER)
1151 status = knvlinkRemoveMapping_HAL(pRemoteGpu, pRemoteKernelNvlink, NV_FALSE,
1152 NVBIT(remPeerId),
1153 NV_FALSE /* bL2Entry */);
1154 }
1155 else
1156 {
1157 status = knvlinkRemoveMapping_HAL(pRemoteGpu, pRemoteKernelNvlink, NV_FALSE,
1158 ((1 << NVLINK_MAX_PEERS_SW) - 1),
1159 NV_FALSE /* bL2Entry */);
1160 }
1161 if (status != NV_OK)
1162 {
1163 NV_PRINTF(LEVEL_ERROR,
1164 "failed to reset HSHUB on GPU%u while preparing for GPU%u XVE reset (0x%x)\n",
1165 gpuGetInstance(pRemoteGpu), gpuGetInstance(pGpu),
1166 status);
1167
1168 retStatus = (retStatus == NV_OK) ? status : retStatus;
1169 }
1170 }
1171
1172 // Remove all NVLink mappings in HSHUB config registers to init values
1173 if (!API_GPU_IN_RESET_SANITY_CHECK(pGpu) && !pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_LOST))
1174 status = knvlinkRemoveMapping_HAL(pGpu, pKernelNvlink, NV_TRUE, ((1 << NVLINK_MAX_PEERS_SW) - 1),
1175 NV_FALSE /* bL2Entry */);
1176 if (status != NV_OK)
1177 {
1178 NV_PRINTF(LEVEL_ERROR,
1179 "failed to reset HSHUB on GPU%u while preparing XVE reset: %s (0x%x)\n",
1180 gpuGetInstance(pGpu), nvstatusToString(status), status);
1181
1182 retStatus = (retStatus == NV_OK) ? status : retStatus;
1183 }
1184
1185 //
1186 // If GFW is booted and running through link-training, then no need to tear-down the
1187 // links to reset. Exit out early from the function
1188 //
1189 if (!bForceShutdown && pKernelNvlink->getProperty(pKernelNvlink, PDB_PROP_KNVLINK_MINION_GFW_BOOT))
1190 {
1191 return NV_OK;
1192 }
1193
1194 // Pseudo-clean shutdown the links from this GPU
1195 status = knvlinkCoreShutdownDeviceLinks(pGpu, pKernelNvlink, bForceShutdown);
1196 if (status != NV_OK)
1197 {
1198 NV_PRINTF(LEVEL_ERROR,
1199 "failed to shutdown links on GPU%u while preparing XVE reset: %s (0x%x)\n",
1200 gpuGetInstance(pGpu), nvstatusToString(status), status);
1201
1202 retStatus = (retStatus == NV_OK) ? status : retStatus;
1203 }
1204
1205 //
1206 // Reset links related to this device and its peers (see Bug 2346447)
1207 // The property is disabled on Pascal, since the path hasn't been verified
1208 // and link reset after pseudo-clean shutdown results in DL and TL errors.
1209 //
1210 if (pKernelNvlink->getProperty(pKernelNvlink, PDB_PROP_KNVLINK_LINKRESET_AFTER_SHUTDOWN))
1211 {
1212 status = knvlinkCoreResetDeviceLinks(pGpu, pKernelNvlink);
1213 if (status != NV_OK)
1214 {
1215 NV_PRINTF(LEVEL_ERROR,
1216 "failed to reset links on GPU%u while preparing XVE reset: %s (0x%x)\n",
1217 gpuGetInstance(pGpu), nvstatusToString(status), status);
1218
1219 retStatus = (retStatus == NV_OK) ? status : retStatus;
1220 }
1221 #if defined(INCLUDE_NVLINK_LIB)
1222 else
1223 {
1224 NvU32 linkId;
1225
1226 //
1227 // The connections have been successfully reset, update connected and disconnected
1228 // links masks on both the devices
1229 //
1230 FOR_EACH_INDEX_IN_MASK(32, linkId, pKernelNvlink->enabledLinks)
1231 {
1232 pKernelNvlink->disconnectedLinkMask |= NVBIT(linkId);
1233 pKernelNvlink->connectedLinksMask &= ~NVBIT(linkId);
1234
1235 if (pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.deviceType !=
1236 NV2080_CTRL_NVLINK_DEVICE_INFO_DEVICE_TYPE_GPU)
1237 {
1238 continue;
1239 }
1240
1241 OBJGPU *pRemoteGpu = gpumgrGetGpuFromBusInfo(
1242 pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.domain,
1243 pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.bus,
1244 pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.device);
1245
1246 if (!API_GPU_IN_RESET_SANITY_CHECK(pRemoteGpu))
1247 {
1248 KernelNvlink *pRemoteKernelNvlink = GPU_GET_KERNEL_NVLINK(pRemoteGpu);
1249 NvU32 remoteLinkId = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.linkNumber;
1250
1251 pRemoteKernelNvlink->disconnectedLinkMask |= NVBIT(remoteLinkId);
1252 pRemoteKernelNvlink->connectedLinksMask &= ~NVBIT(remoteLinkId);
1253 }
1254 }
1255 FOR_EACH_INDEX_IN_MASK_END;
1256 }
1257 #endif
1258
1259 //
1260 // knvlinkCoreResetDeviceLinks() only resets the links which have
1261 // connectivity.
1262 // Pre-Ampere, we may run into a situation where the PLL
1263 // sharing partner links (both) may not be reset due to no connectivity.
1264 //
1265 // Hence, (re-)reset all the links to recover them after shutdown (pre-Ampere)
1266 //
1267 NV2080_CTRL_NVLINK_RESET_LINKS_PARAMS resetLinksparams;
1268
1269 portMemSet(&resetLinksparams, 0, sizeof(resetLinksparams));
1270 resetLinksparams.linkMask = pKernelNvlink->enabledLinks;
1271 resetLinksparams.flags = NV2080_CTRL_NVLINK_RESET_FLAGS_TOGGLE;
1272
1273 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1274 NV2080_CTRL_CMD_NVLINK_RESET_LINKS,
1275 (void *)&resetLinksparams, sizeof(resetLinksparams));
1276
1277 retStatus = (retStatus == NV_OK) ? status : retStatus;
1278 }
1279
1280 return retStatus;
1281 }
1282
1283 /*!
1284 * @brief Set the power features supported on this NVLink IP
1285 *
1286 * @param[in] pGpu OBJGPU pointer
1287 * @param[in] pKernelNvlink KernelNvlink pointer
1288 */
1289 void
knvlinkSetPowerFeatures_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1290 knvlinkSetPowerFeatures_IMPL
1291 (
1292 OBJGPU *pGpu,
1293 KernelNvlink *pKernelNvlink
1294 )
1295 {
1296 // Get the Ip Verion from the First available IOCTRL.
1297 switch (pKernelNvlink->ipVerNvlink)
1298 {
1299 case NVLINK_VERSION_22:
1300 {
1301 // NVLink L2 is supported only on MODS and Windows LDDM
1302 if (RMCFG_FEATURE_PLATFORM_WINDOWS || RMCFG_FEATURE_MODS_FEATURES)
1303 {
1304 pKernelNvlink->setProperty(pKernelNvlink, PDB_PROP_KNVLINK_L2_POWER_STATE_ENABLED,
1305 (pKernelNvlink->bDisableL2Mode ? NV_FALSE : NV_TRUE));
1306 }
1307
1308 break;
1309 }
1310 default:
1311 break;
1312 }
1313 }
1314
1315 /*!
1316 * @brief Checks if NVSWITCH_FABRIC_ADDR field is valid.
1317 *
1318 * @param[in] pGpu OBJGPU pointer
1319 * @param[in] pKernelNvlink KernelNvlink pointer
1320 */
1321 void
knvlinkDetectNvswitchProxy_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1322 knvlinkDetectNvswitchProxy_IMPL
1323 (
1324 OBJGPU *pGpu,
1325 KernelNvlink *pKernelNvlink
1326 )
1327 {
1328 OBJSYS *pSys = SYS_GET_INSTANCE();
1329 NV_STATUS status = NV_OK;
1330 NvU32 i;
1331
1332 // Initialize fabricBaseAddr to NVLINK_INVALID_FABRIC_ADDR
1333 pKernelNvlink->fabricBaseAddr = NVLINK_INVALID_FABRIC_ADDR;
1334
1335 if (pSys->getProperty(pSys, PDB_PROP_SYS_NVSWITCH_IS_PRESENT) ||
1336 pSys->getProperty(pSys, PDB_PROP_SYS_FABRIC_MANAGER_IS_REGISTERED) ||
1337 GPU_IS_NVSWITCH_DETECTED(pGpu))
1338 {
1339 return;
1340 }
1341
1342 if (pKernelNvlink->discoveredLinks == 0)
1343 {
1344 return;
1345 }
1346
1347 // Get the link train status for the enabled link masks
1348 NV2080_CTRL_NVLINK_ARE_LINKS_TRAINED_PARAMS linkTrainedParams;
1349
1350 portMemSet(&linkTrainedParams, 0, sizeof(linkTrainedParams));
1351 linkTrainedParams.linkMask = pKernelNvlink->enabledLinks;
1352 linkTrainedParams.bActiveOnly = NV_FALSE;
1353
1354 // Reset timeout to clear any accumulated timeouts from link init
1355 if (IS_GSP_CLIENT(pGpu))
1356 {
1357 threadStateResetTimeout(pGpu);
1358 }
1359
1360 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1361 NV2080_CTRL_CMD_NVLINK_ARE_LINKS_TRAINED,
1362 (void *)&linkTrainedParams, sizeof(linkTrainedParams));
1363 if (status != NV_OK)
1364 {
1365 NV_PRINTF(LEVEL_ERROR, "Failed to get the link train status for links\n");
1366 return;
1367 }
1368
1369 FOR_EACH_INDEX_IN_MASK(32, i, pKernelNvlink->enabledLinks)
1370 {
1371 if (!linkTrainedParams.bIsLinkActive[i])
1372 {
1373 return;
1374 }
1375 }
1376 FOR_EACH_INDEX_IN_MASK_END;
1377
1378 NV2080_CTRL_INTERNAL_NVLINK_GET_SET_NVSWITCH_FABRIC_ADDR_PARAMS params;
1379
1380 portMemSet(¶ms, 0, sizeof(params));
1381 params.bGet = NV_TRUE;
1382 params.addr = NVLINK_INVALID_FABRIC_ADDR;
1383
1384 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1385 NV2080_CTRL_CMD_INTERNAL_NVLINK_GET_SET_NVSWITCH_FABRIC_ADDR,
1386 (void *)¶ms, sizeof(params));
1387 if (status != NV_OK)
1388 {
1389 NV_PRINTF(LEVEL_ERROR, "Failed to get fabric address for GPU %x\n",
1390 pGpu->gpuInstance);
1391 return;
1392 }
1393
1394 if (params.addr != NVLINK_INVALID_FABRIC_ADDR)
1395 {
1396 pKernelNvlink->fabricBaseAddr = params.addr;
1397 pKernelNvlink->bNvswitchProxy = NV_TRUE;
1398 }
1399 }
1400
1401 /*!
1402 * @brief Sets NVSWITCH_FLA_ADDR field in the scratch register.
1403 *
1404 * @param[in] pGpu OBJGPU pointer
1405 * @param[in] pKernelNvlink KernelNvlink pointer
1406 * @param[in] addr FLA addr
1407 *
1408 * @return Returns NV_OK upon success.
1409 * Otherwise, returns NV_ERR_XXX.
1410 */
1411 NV_STATUS
knvlinkSetNvswitchFlaAddr_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU64 addr)1412 knvlinkSetNvswitchFlaAddr_IMPL
1413 (
1414 OBJGPU *pGpu,
1415 KernelNvlink *pKernelNvlink,
1416 NvU64 addr
1417 )
1418 {
1419 return NV_OK;
1420 }
1421
1422 /*!
1423 * @brief Gets NVSWITCH_FLA_ADDR field from the scratch register.
1424 *
1425 * @param[in] pGpu OBJGPU pointer
1426 * @param[in] pKernelNvlink KernelNvlink pointer
1427 *
1428 * @return Returns the stashed FLA starting address.
1429 */
1430 NvU64
knvlinkGetNvswitchFlaAddr_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1431 knvlinkGetNvswitchFlaAddr_IMPL
1432 (
1433 OBJGPU *pGpu,
1434 KernelNvlink *pKernelNvlink
1435 )
1436 {
1437 return 0;
1438 }
1439
1440 /*!
1441 * @brief Checks if fabricBaseAddr is valid.
1442 *
1443 * @param[in] pGpu OBJGPU pointer
1444 * @param[in] pKernelNvlink KernelNvlink pointer
1445 *
1446 * @return Returns true if the fabricBaseAddr is valid.
1447 */
1448 NvBool
knvlinkIsNvswitchProxyPresent_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1449 knvlinkIsNvswitchProxyPresent_IMPL
1450 (
1451 OBJGPU *pGpu,
1452 KernelNvlink *pKernelNvlink
1453 )
1454 {
1455 return pKernelNvlink->bNvswitchProxy;
1456 }
1457
1458
1459 /*!
1460 * @brief Set unique FLA base address for NVSwitch enabled systems.
1461 * Validates FLA base address and programs the base address
1462 * in switch scratch registers for guest VM to pick it up.
1463 *
1464 * @param[in] pGpu OBJGPU pointer
1465 * @param[in] pKernelNvlink KernelNvlink pointer
1466 * @param[in] flaBaseAddr NvU64 base address
1467 *
1468 * @returns On success, sets unique FLA base address and returns NV_OK.
1469 * On failure, returns NV_ERR_XXX.
1470 */
1471 NV_STATUS
knvlinkSetUniqueFlaBaseAddress_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU64 flaBaseAddr)1472 knvlinkSetUniqueFlaBaseAddress_IMPL
1473 (
1474 OBJGPU *pGpu,
1475 KernelNvlink *pKernelNvlink,
1476 NvU64 flaBaseAddr
1477 )
1478 {
1479 NV_STATUS status = NV_OK;
1480 KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
1481
1482 NV2080_CTRL_NVLINK_GET_SET_NVSWITCH_FLA_ADDR_PARAMS params;
1483
1484 if (!knvlinkIsForcedConfig(pGpu, pKernelNvlink))
1485 {
1486 knvlinkCoreGetRemoteDeviceInfo(pGpu, pKernelNvlink);
1487
1488 status = knvlinkEnableLinksPostTopology_HAL(pGpu, pKernelNvlink,
1489 pKernelNvlink->enabledLinks);
1490 if (status != NV_OK)
1491 {
1492 return status;
1493 }
1494 }
1495
1496 status = kbusValidateFlaBaseAddress_HAL(pGpu, pKernelBus, flaBaseAddr);
1497 if (status != NV_OK)
1498 {
1499 NV_PRINTF(LEVEL_ERROR, "FLA base addr validation failed for GPU %x\n",
1500 pGpu->gpuInstance);
1501 return status;
1502 }
1503
1504 if (IsSLIEnabled(pGpu))
1505 {
1506 NV_PRINTF(LEVEL_ERROR,
1507 "Operation is unsupported on SLI enabled GPU %x\n",
1508 pGpu->gpuInstance);
1509 return NV_ERR_NOT_SUPPORTED;
1510 }
1511
1512 portMemSet(¶ms, 0, sizeof(params));
1513 params.bGet = NV_FALSE;
1514 params.addr = flaBaseAddr;
1515
1516 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1517 NV2080_CTRL_CMD_NVLINK_GET_SET_NVSWITCH_FLA_ADDR,
1518 (void *)¶ms, sizeof(params));
1519 if (status != NV_OK)
1520 {
1521 NV_PRINTF(LEVEL_ERROR, "Failed to stash fla base address for GPU %x\n",
1522 pGpu->gpuInstance);
1523 return status;
1524 }
1525
1526 NV_PRINTF(LEVEL_INFO, "FLA base addr %llx is assigned to GPU %x\n",
1527 flaBaseAddr, pGpu->gpuInstance);
1528
1529 return NV_OK;
1530 }
1531
1532 /*!
1533 * @brief Synchronize the link masks and vbios defined properties
1534 * between CPU and GSP-RMs
1535 *
1536 * @param[in] pGpu OBJGPU pointer
1537 * @param[in] pKernelNvlink KernelNvlink pointer
1538 */
1539 NV_STATUS
knvlinkSyncLinkMasksAndVbiosInfo_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1540 knvlinkSyncLinkMasksAndVbiosInfo_IMPL
1541 (
1542 OBJGPU *pGpu,
1543 KernelNvlink *pKernelNvlink
1544 )
1545 {
1546 NV_STATUS status = NV_OK;
1547
1548 NV2080_CTRL_NVLINK_SYNC_LINK_MASKS_AND_VBIOS_INFO_PARAMS params;
1549
1550 portMemSet(¶ms, 0, sizeof(params));
1551
1552 params.discoveredLinks = pKernelNvlink->discoveredLinks;
1553 params.connectedLinksMask = pKernelNvlink->connectedLinksMask;
1554 params.bridgeSensableLinks = pKernelNvlink->bridgeSensableLinks;
1555 params.bridgedLinks = pKernelNvlink->bridgedLinks;
1556
1557 // Reset timeout to clear any accumulated timeouts from link init
1558 if (IS_GSP_CLIENT(pGpu))
1559 {
1560 threadStateResetTimeout(pGpu);
1561 }
1562
1563 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1564 NV2080_CTRL_CMD_NVLINK_SYNC_LINK_MASKS_AND_VBIOS_INFO,
1565 (void *)¶ms, sizeof(params));
1566
1567 pKernelNvlink->vbiosDisabledLinkMask = params.vbiosDisabledLinkMask;
1568 pKernelNvlink->initializedLinks = params.initializedLinks;
1569 pKernelNvlink->initDisabledLinksMask = params.initDisabledLinksMask;
1570 pKernelNvlink->bEnableSafeModeAtLoad = params.bEnableSafeModeAtLoad;
1571 pKernelNvlink->bEnableTrainingAtLoad = params.bEnableTrainingAtLoad;
1572
1573 return status;
1574 }
1575
1576 /*!
1577 * @brief Update link connection status.
1578 *
1579 * @param[in] pGpu OBJGPU pointer
1580 * @param[in] pKernelNvlink KernelNvlink pointer
1581 * @param[in] linkId Target link Id
1582 */
1583 NV_STATUS
knvlinkUpdateLinkConnectionStatus_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU32 linkId)1584 knvlinkUpdateLinkConnectionStatus_IMPL
1585 (
1586 OBJGPU *pGpu,
1587 KernelNvlink *pKernelNvlink,
1588 NvU32 linkId
1589 )
1590 {
1591 NV_STATUS status = NV_OK;
1592
1593 NV2080_CTRL_NVLINK_UPDATE_LINK_CONNECTION_PARAMS params;
1594
1595 portMemSet(¶ms, 0, sizeof(params));
1596
1597 params.linkId = linkId;
1598
1599 #if defined(INCLUDE_NVLINK_LIB)
1600
1601 params.bConnected = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.bConnected;
1602 params.remoteDeviceType = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.deviceType;
1603 params.remoteLinkNumber = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.linkNumber;
1604 params.remoteChipSid = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.chipSid;
1605 params.remoteDomain = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.domain;
1606 params.remoteBus = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.bus;
1607 params.remoteDevice = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.device;
1608 params.remoteFunction = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.function;
1609 params.remotePciDeviceId = pKernelNvlink->nvlinkLinks[linkId].remoteEndInfo.pciDeviceId;
1610 params.laneRxdetStatusMask = pKernelNvlink->nvlinkLinks[linkId].laneRxdetStatusMask;
1611
1612 #endif
1613
1614 // Reset timeout to clear any accumulated timeouts from link init
1615 if (IS_GSP_CLIENT(pGpu))
1616 {
1617 threadStateResetTimeout(pGpu);
1618 }
1619
1620 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1621 NV2080_CTRL_CMD_NVLINK_UPDATE_LINK_CONNECTION,
1622 (void *)¶ms, sizeof(params));
1623 if (status != NV_OK)
1624 {
1625 NV_PRINTF(LEVEL_ERROR, "Failed to update Link connection status!\n");
1626 return status;
1627 }
1628
1629 return NV_OK;
1630 }
1631
1632 /*!
1633 * @brief Execute initial steps to Train links for ALI.
1634 *
1635 * @param[in] pGpu OBJGPU pointer for local GPU
1636 * @param[in] pKernelNvlink KernelNvlink pointer
1637 * @param[in] linkMask Masks of links to enable
1638 * @param[in] bSync Input sync boolean
1639 *
1640 */
1641 NV_STATUS
knvlinkPreTrainLinksToActiveAli_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU32 linkMask,NvBool bSync)1642 knvlinkPreTrainLinksToActiveAli_IMPL
1643 (
1644 OBJGPU *pGpu,
1645 KernelNvlink *pKernelNvlink,
1646 NvU32 linkMask,
1647 NvBool bSync
1648 )
1649 {
1650 NV_STATUS status = NV_OK;
1651
1652 NV2080_CTRL_NVLINK_PRE_LINK_TRAIN_ALI_PARAMS params;
1653
1654 portMemSet(¶ms, 0, sizeof(params));
1655
1656 params.linkMask = linkMask;
1657 params.bSync = bSync;
1658
1659 // Reset timeout to clear any accumulated timeouts from link init
1660 if (IS_GSP_CLIENT(pGpu))
1661 {
1662 threadStateResetTimeout(pGpu);
1663 }
1664
1665 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1666 NV2080_CTRL_CMD_NVLINK_PRE_LINK_TRAIN_ALI,
1667 (void *)¶ms, sizeof(params));
1668 if (status != NV_OK)
1669 {
1670 NV_PRINTF(LEVEL_ERROR, "Failed to execute Pre Link Training ALI steps!\n");
1671 return status;
1672 }
1673
1674 return NV_OK;
1675 }
1676
1677 /*!
1678 * @brief Train links to active for ALI.
1679 *
1680 * @param[in] pGpu OBJGPU pointer for local GPU
1681 * @param[in] pKernelNvlink KernelNvlink pointer
1682 * @param[in] linkMask Masks of links to enable
1683 * @param[in] bSync Input sync boolean
1684 *
1685 */
1686 NV_STATUS
knvlinkTrainLinksToActiveAli_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU32 linkMask,NvBool bSync)1687 knvlinkTrainLinksToActiveAli_IMPL
1688 (
1689 OBJGPU *pGpu,
1690 KernelNvlink *pKernelNvlink,
1691 NvU32 linkMask,
1692 NvBool bSync
1693 )
1694 {
1695 NV_STATUS status = NV_OK;
1696
1697 NV2080_CTRL_NVLINK_PRE_LINK_TRAIN_ALI_PARAMS params;
1698
1699 portMemSet(¶ms, 0, sizeof(params));
1700
1701 params.linkMask = linkMask;
1702 params.bSync = bSync;
1703
1704 // Reset timeout to clear any accumulated timeouts from link init
1705 if (IS_GSP_CLIENT(pGpu))
1706 {
1707 threadStateResetTimeout(pGpu);
1708 }
1709
1710 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1711 NV2080_CTRL_CMD_NVLINK_LINK_TRAIN_ALI,
1712 (void *)¶ms, sizeof(params));
1713 if (status != NV_OK)
1714 {
1715 NV_PRINTF(LEVEL_ERROR, "Failed to change ALI Links to active!\n");
1716 return status;
1717 }
1718
1719 return NV_OK;
1720 }
1721
1722 /*!
1723 * @brief Update the post Rx Detect link mask.
1724 *
1725 * @param[in] pGpu OBJGPU pointer for local GPU
1726 * @param[in] pKernelNvlink KernelNvlink pointer
1727 *
1728 */
1729 NV_STATUS
knvlinkUpdatePostRxDetectLinkMask_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1730 knvlinkUpdatePostRxDetectLinkMask_IMPL
1731 (
1732 OBJGPU *pGpu,
1733 KernelNvlink *pKernelNvlink
1734 )
1735 {
1736 NV_STATUS status = NV_OK;
1737
1738 NV2080_CTRL_NVLINK_GET_LINK_MASK_POST_RX_DET_PARAMS params;
1739
1740 portMemSet(¶ms, 0, sizeof(params));
1741
1742 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1743 NV2080_CTRL_CMD_NVLINK_GET_LINK_MASK_POST_RX_DET,
1744 (void *)¶ms, sizeof(params));
1745 if (status != NV_OK)
1746 {
1747 NV_PRINTF(LEVEL_ERROR, "Failed to update Rx Detect Link mask!\n");
1748 return status;
1749 }
1750
1751 pKernelNvlink->postRxDetLinkMask = params.postRxDetLinkMask;
1752
1753 return NV_OK;
1754 }
1755
1756 /*!
1757 * @brief Copy over the NVLink devices information from GSP-RM.
1758 *
1759 * @param[in] pGpu OBJGPU pointer for local GPU
1760 * @param[in] pKernelNvlink KernelNvlink pointer
1761 */
1762 NV_STATUS
knvlinkCopyNvlinkDeviceInfo_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1763 knvlinkCopyNvlinkDeviceInfo_IMPL
1764 (
1765 OBJGPU *pGpu,
1766 KernelNvlink *pKernelNvlink
1767 )
1768 {
1769 NV_STATUS status = NV_OK;
1770 NvU32 i;
1771
1772 NV2080_CTRL_NVLINK_GET_NVLINK_DEVICE_INFO_PARAMS nvlinkInfoParams;
1773
1774 portMemSet(&nvlinkInfoParams, 0, sizeof(nvlinkInfoParams));
1775
1776 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1777 NV2080_CTRL_CMD_NVLINK_GET_NVLINK_DEVICE_INFO,
1778 (void *)&nvlinkInfoParams, sizeof(nvlinkInfoParams));
1779
1780 if (status == NV_ERR_NOT_SUPPORTED)
1781 {
1782 NV_PRINTF(LEVEL_WARNING, "NVLink is unavailable\n");
1783 return status;
1784 }
1785 else if (status != NV_OK)
1786 {
1787 NV_PRINTF(LEVEL_ERROR, "Failed to retrieve all nvlink device info!\n");
1788 return status;
1789 }
1790
1791 // Update CPU-RM's NVLink state with the information received from GSP-RM RPC
1792 pKernelNvlink->ioctrlMask = nvlinkInfoParams.ioctrlMask;
1793 pKernelNvlink->ioctrlNumEntries = nvlinkInfoParams.ioctrlNumEntries;
1794 pKernelNvlink->ioctrlSize = nvlinkInfoParams.ioctrlSize;
1795 pKernelNvlink->discoveredLinks = nvlinkInfoParams.discoveredLinks;
1796 pKernelNvlink->ipVerNvlink = nvlinkInfoParams.ipVerNvlink;
1797
1798 for (i = 0; i < NVLINK_MAX_LINKS_SW; i++)
1799 {
1800 pKernelNvlink->nvlinkLinks[i].pGpu = pGpu;
1801 pKernelNvlink->nvlinkLinks[i].bValid = nvlinkInfoParams.linkInfo[i].bValid;
1802 pKernelNvlink->nvlinkLinks[i].linkId = nvlinkInfoParams.linkInfo[i].linkId;
1803 pKernelNvlink->nvlinkLinks[i].ioctrlId = nvlinkInfoParams.linkInfo[i].ioctrlId;
1804
1805 // Copy over the link PLL master and slave relationship for each link
1806 pKernelNvlink->nvlinkLinks[i].pllMasterLinkId = nvlinkInfoParams.linkInfo[i].pllMasterLinkId;
1807 pKernelNvlink->nvlinkLinks[i].pllSlaveLinkId = nvlinkInfoParams.linkInfo[i].pllSlaveLinkId;
1808
1809 // Copy over the ip versions for DLPL devices discovered
1810 pKernelNvlink->nvlinkLinks[i].ipVerDlPl = nvlinkInfoParams.linkInfo[i].ipVerDlPl;
1811 }
1812
1813 return NV_OK;
1814 }
1815
1816 /*!
1817 * @brief Copy over the Ioctrl devices information from GSP-RM.
1818 *
1819 * @param[in] pGpu OBJGPU pointer for local GPU
1820 * @param[in] pKernelNvlink KernelNvlink pointer
1821 */
1822 NV_STATUS
knvlinkCopyIoctrlDeviceInfo_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1823 knvlinkCopyIoctrlDeviceInfo_IMPL
1824 (
1825 OBJGPU *pGpu,
1826 KernelNvlink *pKernelNvlink
1827 )
1828 {
1829 KernelIoctrl *pKernelIoctrl = NULL;
1830 NV_STATUS status = NV_OK;
1831 NvU32 ioctrlIdx;
1832
1833 NV2080_CTRL_NVLINK_GET_IOCTRL_DEVICE_INFO_PARAMS ioctrlInfoParams;
1834
1835 // Query the IOCTRL information for each of the IOCTRLs discovered
1836 FOR_EACH_INDEX_IN_MASK(32, ioctrlIdx, pKernelNvlink->ioctrlMask)
1837 {
1838 portMemSet(&ioctrlInfoParams, 0, sizeof(ioctrlInfoParams));
1839
1840 ioctrlInfoParams.ioctrlIdx = ioctrlIdx;
1841
1842 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1843 NV2080_CTRL_CMD_NVLINK_GET_IOCTRL_DEVICE_INFO,
1844 (void *)&ioctrlInfoParams, sizeof(ioctrlInfoParams));
1845
1846 if (status == NV_ERR_NOT_SUPPORTED)
1847 {
1848 NV_PRINTF(LEVEL_WARNING, "NVLink is unavailable\n");
1849 return status;
1850 }
1851 else if (status != NV_OK)
1852 {
1853 NV_PRINTF(LEVEL_ERROR, "Failed to retrieve device info for IOCTRL %d!\n", ioctrlIdx);
1854 return status;
1855 }
1856
1857 pKernelIoctrl = KNVLINK_GET_IOCTRL(pKernelNvlink, ioctrlIdx);
1858
1859 // Update CPU-RM's NVLink state with the information received from GSP-RM RPC
1860 pKernelIoctrl->PublicId = ioctrlInfoParams.PublicId;
1861 pKernelIoctrl->localDiscoveredLinks = ioctrlInfoParams.localDiscoveredLinks;
1862 pKernelIoctrl->localGlobalLinkOffset = ioctrlInfoParams.localGlobalLinkOffset;
1863 pKernelIoctrl->ioctrlDiscoverySize = ioctrlInfoParams.ioctrlDiscoverySize;
1864 pKernelIoctrl->numDevices = ioctrlInfoParams.numDevices;
1865
1866 // Copy over the ip versions for the ioctrl and minion devices discovered
1867 pKernelIoctrl->ipVerIoctrl = ioctrlInfoParams.ipRevisions.ipVerIoctrl;
1868 pKernelIoctrl->ipVerMinion = ioctrlInfoParams.ipRevisions.ipVerMinion;
1869
1870 if (pKernelIoctrl->ipVerMinion == 0)
1871 {
1872 pKernelIoctrl->setProperty(pKernelIoctrl, PDB_PROP_KIOCTRL_MINION_AVAILABLE, NV_FALSE);
1873 }
1874 }
1875 FOR_EACH_INDEX_IN_MASK_END;
1876
1877 return NV_OK;
1878 }
1879
1880 /**
1881 * @brief Setup topology information for the forced nvlink configurations
1882 *
1883 * @param[in] pGpu OBJGPU pointer for local GPU
1884 * @param[in] pKernelNvlink KernelNvlink pointer
1885 */
1886 NV_STATUS
knvlinkSetupTopologyForForcedConfig_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1887 knvlinkSetupTopologyForForcedConfig_IMPL
1888 (
1889 OBJGPU *pGpu,
1890 KernelNvlink *pKernelNvlink
1891 )
1892 {
1893 NV_STATUS status = NV_OK;
1894 NvU32 i, physLink;
1895
1896 // Start with all links disabled and no forced config in effect
1897 pKernelNvlink->bRegistryLinkOverride = NV_TRUE;
1898 pKernelNvlink->registryLinkMask = 0;
1899 pKernelNvlink->bChiplibConfig = NV_FALSE;
1900
1901 for (i = 0; i < NVLINK_MAX_LINKS_SW; i++)
1902 {
1903 // Filter against the links discovered from IOCTRL
1904 if (!(pKernelNvlink->discoveredLinks & NVBIT(i)))
1905 continue;
1906
1907 // The physical link is guaranteed valid in all cases
1908 physLink = DRF_VAL(_NVLINK, _ARCH_CONNECTION, _PHYSICAL_LINK, pKernelNvlink->pLinkConnection[i]);
1909
1910 // Update link tracking
1911 if (DRF_VAL(_NVLINK, _ARCH_CONNECTION, _ENABLED, pKernelNvlink->pLinkConnection[i]))
1912 {
1913 NV_PRINTF(LEVEL_INFO,
1914 "ARCH_CONNECTION info from chiplib: ENABLED Logical link %d (Physical "
1915 "link %d) = 0x%X\n", i, physLink,
1916 pKernelNvlink->pLinkConnection[i]);
1917
1918 //
1919 // This "link" should be ENABLED. We use the physical link since RM only deals with
1920 // physical links.
1921 //
1922 pKernelNvlink->registryLinkMask |= NVBIT(physLink);
1923
1924 // Config is forced (at least one link requested)
1925 pKernelNvlink->bChiplibConfig = NV_TRUE;
1926 }
1927 else
1928 {
1929 NV_PRINTF(LEVEL_INFO,
1930 "ARCH_CONNECTION info from chiplib: DISABLED Logical link %d (Physical "
1931 "link %d) = 0x%X\n", i, physLink,
1932 pKernelNvlink->pLinkConnection[i]);
1933 }
1934
1935 // Accumulate any PEER links
1936 if (DRF_VAL(_NVLINK, _ARCH_CONNECTION, _PEER_MASK, pKernelNvlink->pLinkConnection[i]))
1937 {
1938 #if defined(INCLUDE_NVLINK_LIB)
1939 // Ensure reginit has the info it needs for the remote side
1940 pKernelNvlink->nvlinkLinks[i].remoteEndInfo.bConnected = NV_TRUE;
1941 pKernelNvlink->nvlinkLinks[i].remoteEndInfo.deviceType =
1942 NV2080_CTRL_NVLINK_DEVICE_INFO_DEVICE_TYPE_GPU;
1943
1944 #endif
1945 }
1946
1947 // Accumulate any CPU links
1948 if (DRF_VAL(_NVLINK, _ARCH_CONNECTION, _CPU, pKernelNvlink->pLinkConnection[i]))
1949 {
1950 #if defined(INCLUDE_NVLINK_LIB)
1951 // Ensure reginit has the info it needs for the remote side
1952 pKernelNvlink->nvlinkLinks[i].remoteEndInfo.bConnected = NV_TRUE;
1953 pKernelNvlink->nvlinkLinks[i].remoteEndInfo.deviceType = pKernelNvlink->forcedSysmemDeviceType;
1954 #endif
1955 }
1956
1957 // RPC into GSP-RM to update the link remote connection status
1958 status = knvlinkUpdateLinkConnectionStatus(pGpu, pKernelNvlink, i);
1959 if (status != NV_OK)
1960 {
1961 return status;
1962 }
1963 }
1964
1965 // Update enabledLinks mask with the mask of forced link configurations
1966 pKernelNvlink->enabledLinks = pKernelNvlink->discoveredLinks & pKernelNvlink->registryLinkMask;
1967
1968 return NV_OK;
1969 }
1970
1971 /*!
1972 * @brief Sync the lane shutdown properties with GSP-RM
1973 *
1974 * @param[in] pGpu OBJGPU pointer
1975 * @param[in] pKernelNvlink KernelNvlink pointer
1976 */
1977 NV_STATUS
knvlinkSyncLaneShutdownProps_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)1978 knvlinkSyncLaneShutdownProps_IMPL
1979 (
1980 OBJGPU *pGpu,
1981 KernelNvlink *pKernelNvlink
1982 )
1983 {
1984 NV_STATUS status = NV_OK;
1985
1986 NV2080_CTRL_NVLINK_SYNC_NVLINK_SHUTDOWN_PROPS_PARAMS params;
1987
1988 portMemSet(¶ms, 0, sizeof(params));
1989
1990 params.bLaneShutdownEnabled =
1991 pKernelNvlink->getProperty(pKernelNvlink, PDB_PROP_KNVLINK_LANE_SHUTDOWN_ENABLED);
1992 params.bLaneShutdownOnUnload =
1993 pKernelNvlink->getProperty(pKernelNvlink, PDB_PROP_KNVLINK_LANE_SHUTDOWN_ON_UNLOAD);
1994
1995 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1996 NV2080_CTRL_CMD_NVLINK_SYNC_NVLINK_SHUTDOWN_PROPS,
1997 (void *)¶ms, sizeof(params));
1998 if (status != NV_OK)
1999 {
2000 NV_PRINTF(LEVEL_ERROR, "Failed to sync NVLink shutdown properties with GSP!\n");
2001 return status;
2002 }
2003
2004 return NV_OK;
2005 }
2006
2007 /*!
2008 * @brief Get the number of active links allowed per IOCTRL
2009 *
2010 * @param[in] pGpu OBJGPU pointer
2011 * @param[in] pKernelNvlink KernelNvlink pointer
2012 *
2013 * @returns On success, returns the number of active links per IOCTRL.
2014 * On failure, returns 0.
2015 */
2016 NvU32
knvlinkGetNumActiveLinksPerIoctrl_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)2017 knvlinkGetNumActiveLinksPerIoctrl_IMPL
2018 (
2019 OBJGPU *pGpu,
2020 KernelNvlink *pKernelNvlink
2021 )
2022 {
2023 NV_STATUS status;
2024 NV2080_CTRL_INTERNAL_NVLINK_GET_NUM_ACTIVE_LINK_PER_IOCTRL_PARAMS params;
2025 portMemSet(¶ms, 0, sizeof(params));
2026 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
2027 NV2080_CTRL_INTERNAL_NVLINK_GET_NUM_ACTIVE_LINK_PER_IOCTRL,
2028 (void *)¶ms, sizeof(params));
2029 if (status != NV_OK)
2030 {
2031 NV_PRINTF(LEVEL_ERROR, "Failed to get the number of active links per IOCTRL\n");
2032 return 0;
2033 }
2034 return params.numActiveLinksPerIoctrl;
2035 }
2036
2037 /*!
2038 * @brief Get the number of total links per IOCTRL
2039 *
2040 * @param[in] pGpu OBJGPU pointer
2041 * @param[in] pKernelNvlink KernelNvlink pointer
2042 *
2043 * @returns On success, returns the number of total links per IOCTRL.
2044 * On failure, returns 0.
2045 */
2046 NvU32
knvlinkGetTotalNumLinksPerIoctrl_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)2047 knvlinkGetTotalNumLinksPerIoctrl_IMPL
2048 (
2049 OBJGPU *pGpu,
2050 KernelNvlink *pKernelNvlink
2051 )
2052 {
2053 NV_STATUS status;
2054 NV2080_CTRL_INTERNAL_NVLINK_GET_TOTAL_NUM_LINK_PER_IOCTRL_PARAMS params;
2055 portMemSet(¶ms, 0, sizeof(params));
2056 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
2057 NV2080_CTRL_INTERNAL_NVLINK_GET_TOTAL_NUM_LINK_PER_IOCTRL,
2058 (void *)¶ms, sizeof(params));
2059 if (status != NV_OK)
2060 {
2061 NV_PRINTF(LEVEL_ERROR, "Failed to get the total number of links per IOCTRL\n");
2062 return 0;
2063 }
2064 return params.numLinksPerIoctrl;
2065 }
2066
2067 /**
2068 * @brief Process the mask of init disabled links
2069 *
2070 * @param[in] pGpu OBJGPU pointer
2071 * @param[in] pKernelNvlink KernelNvlink pointer
2072 */
2073 NV_STATUS
knvlinkProcessInitDisabledLinks_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)2074 knvlinkProcessInitDisabledLinks_IMPL
2075 (
2076 OBJGPU *pGpu,
2077 KernelNvlink *pKernelNvlink
2078 )
2079 {
2080 NvU32 mask = 0;
2081 NvBool bSkipHwNvlinkDisable = 0;
2082 NV_STATUS status = NV_OK;
2083
2084 NV2080_CTRL_NVLINK_PROCESS_INIT_DISABLED_LINKS_PARAMS params;
2085
2086 status = gpumgrGetGpuInitDisabledNvlinks(pGpu->gpuId, &mask, &bSkipHwNvlinkDisable);
2087 if (status != NV_OK)
2088 {
2089 NV_PRINTF(LEVEL_ERROR, "Failed to get init disabled links from gpumgr\n");
2090 return status;
2091 }
2092
2093 portMemSet(¶ms, 0, sizeof(params));
2094
2095 params.initDisabledLinksMask = mask;
2096 params.bSkipHwNvlinkDisable = bSkipHwNvlinkDisable;
2097
2098 status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
2099 NV2080_CTRL_CMD_NVLINK_PROCESS_INIT_DISABLED_LINKS,
2100 (void *)¶ms, sizeof(params));
2101 if (status != NV_OK)
2102 {
2103 NV_PRINTF(LEVEL_ERROR, "Failed to process init disabled links in GSP\n");
2104 return status;
2105 }
2106
2107 pKernelNvlink->initDisabledLinksMask = params.initDisabledLinksMask;
2108
2109 return NV_OK;
2110 }
2111
2112 void
knvlinkFatalErrorRecovery_WORKITEM(NvU32 gpuInstance,void * pArgs)2113 knvlinkFatalErrorRecovery_WORKITEM
2114 (
2115 NvU32 gpuInstance,
2116 void *pArgs
2117 )
2118 {
2119 OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);
2120 rcAndDisableOutstandingClientsWithImportedMemory(pGpu, NV_FABRIC_INVALID_NODE_ID);
2121 }
2122
2123 NV_STATUS
knvlinkFatalErrorRecovery_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)2124 knvlinkFatalErrorRecovery_IMPL
2125 (
2126 OBJGPU *pGpu,
2127 KernelNvlink *pKernelNvlink
2128 )
2129 {
2130 NV_STATUS status;
2131
2132 status = osQueueWorkItemWithFlags(pGpu, knvlinkFatalErrorRecovery_WORKITEM, NULL,
2133 (OS_QUEUE_WORKITEM_FLAGS_LOCK_SEMA |
2134 OS_QUEUE_WORKITEM_FLAGS_LOCK_API_RW |
2135 OS_QUEUE_WORKITEM_FLAGS_LOCK_GPU_GROUP_SUBDEVICE_RW));
2136
2137 return status;
2138 }
2139
2140 // Grab GPU locks before RPCing into GSP-RM for NVLink RPCs
2141 NV_STATUS
knvlinkExecGspRmRpc_IMPL(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU32 cmd,void * paramAddr,NvU32 paramSize)2142 knvlinkExecGspRmRpc_IMPL
2143 (
2144 OBJGPU *pGpu,
2145 KernelNvlink *pKernelNvlink,
2146 NvU32 cmd,
2147 void *paramAddr,
2148 NvU32 paramSize
2149 )
2150 {
2151 NvU32 gpuMaskRelease = 0;
2152 NvU32 gpuMaskInitial = rmGpuLocksGetOwnedMask();
2153 NvU32 gpuMask = gpuMaskInitial | NVBIT(pGpu->gpuInstance);
2154 NV_STATUS status = NV_OK;
2155
2156 if (IS_GSP_CLIENT(pGpu))
2157 {
2158 if (!rmGpuGroupLockIsOwner(pGpu->gpuInstance, GPU_LOCK_GRP_MASK, &gpuMask))
2159 {
2160 status = rmGpuGroupLockAcquire(pGpu->gpuInstance,
2161 GPU_LOCK_GRP_MASK,
2162 GPU_LOCK_FLAGS_SAFE_LOCK_UPGRADE,
2163 RM_LOCK_MODULES_NVLINK,
2164 &gpuMask);
2165 if (status != NV_OK)
2166 {
2167 NV_PRINTF(LEVEL_ERROR, "Failed to acquire locks for gpumask 0x%x\n", gpuMask);
2168 return status;
2169 }
2170
2171 gpuMaskRelease = (gpuMask & (~gpuMaskInitial));
2172 }
2173 }
2174
2175 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
2176 status = pRmApi->Control(pRmApi,
2177 pGpu->hInternalClient,
2178 pGpu->hInternalSubdevice,
2179 cmd, paramAddr, paramSize);
2180 if (gpuMaskRelease)
2181 {
2182 rmGpuGroupLockRelease(gpuMaskRelease, GPUS_LOCK_FLAGS_NONE);
2183 }
2184
2185 return status;
2186 }
2187
2188 void
knvlinkUtoa(NvU8 * str,NvU64 length,NvU64 val)2189 knvlinkUtoa(NvU8 *str, NvU64 length, NvU64 val)
2190 {
2191 NvU8 temp[NV2080_GPU_MAX_NAME_STRING_LENGTH];
2192 NvU8 *ptr = temp;
2193 NvU64 i = 0;
2194
2195 NV_ASSERT(str != NULL);
2196
2197 do
2198 {
2199 i = val % 10;
2200 val = val / 10;
2201 *ptr++ = (NvU8)(i + '0');
2202 } while(val);
2203
2204 NV_ASSERT(length > (NvU64) (ptr - temp));
2205
2206 while (ptr > temp)
2207 *str++ = *--ptr;
2208
2209 *str = '\0';
2210 }
2211