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(&params, 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 *)&params, 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(&params, 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 *)&params, 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(&params, 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 *)&params, 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(&params, 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 *)&params, 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(&params, 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 *)&params, 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(&params, 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 *)&params, 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(&params, 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 *)&params, 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(&params, 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 *)&params, 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(&params, 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 *)&params, 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(&params, 0, sizeof(params));
1741 
1742     status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
1743                                  NV2080_CTRL_CMD_NVLINK_GET_LINK_MASK_POST_RX_DET,
1744                                  (void *)&params, 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(&params, 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 *)&params, 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(&params, 0, sizeof(params));
2026     status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
2027                                  NV2080_CTRL_INTERNAL_NVLINK_GET_NUM_ACTIVE_LINK_PER_IOCTRL,
2028                                  (void *)&params, 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(&params, 0, sizeof(params));
2056     status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
2057                                  NV2080_CTRL_INTERNAL_NVLINK_GET_TOTAL_NUM_LINK_PER_IOCTRL,
2058                                  (void *)&params, 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(&params, 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 *)&params, 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