1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #define NVOC_KERNEL_NVLINK_H_PRIVATE_ACCESS_ALLOWED
25 
26 #include "os/os.h"
27 #include "kernel/gpu/nvlink/kernel_nvlink.h"
28 #include "kernel/gpu/nvlink/kernel_ioctrl.h"
29 
30 #include "gpu/gpu.h"
31 #include "gpu/ce/kernel_ce.h"
32 #include "nvRmReg.h"
33 
34 //
35 // NVLINK Override Configuration
36 //
37 NV_STATUS
knvlinkOverrideConfig_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU32 phase)38 knvlinkOverrideConfig_GP100
39 (
40     OBJGPU       *pGpu,
41     KernelNvlink *pKernelNvlink,
42     NvU32         phase
43 )
44 {
45     NV_STATUS status = NV_OK;
46 
47     NV2080_CTRL_NVLINK_PROCESS_FORCED_CONFIGS_PARAMS forcedConfigParams;
48     portMemSet(&forcedConfigParams, 0, sizeof(forcedConfigParams));
49 
50     forcedConfigParams.bLegacyForcedConfig = NV_TRUE;
51     forcedConfigParams.phase               = phase;
52 
53     // RPC to GSP-RM to for GSP-RM to process the forced NVLink configurations.
54     status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
55                                  NV2080_CTRL_CMD_NVLINK_PROCESS_FORCED_CONFIGS,
56                                  (void *)&forcedConfigParams,
57                                  sizeof(forcedConfigParams));
58     if (status != NV_OK)
59     {
60         NV_PRINTF(LEVEL_ERROR, "Failed to process forced NVLink configurations !\n");
61         return status;
62     }
63 
64     return NV_OK;
65 }
66 
67 /*!
68  * Get a mask with one bit set for each unique GPU peer connected via
69  * NVLINK. In this implementation, each bit is the lowest link ID of
70  * all links connected to a given GPU peer. This allows a static peer
71  * ID assignment based on link topology.
72  *
73  * Note: Ampere and beyond, there is no static peer ID allocation for
74  *       NVLink.
75  *
76  * @param[in] pGpu          OBJGPU ptr
77  * @param[in] pKernelNvlink KernelNvlink ptr
78  *
79  * return NvU32 unique nvlink peer ID mask for pGpu
80  */
81 NvU32
knvlinkGetUniquePeerIdMask_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)82 knvlinkGetUniquePeerIdMask_GP100
83 (
84     OBJGPU       *pGpu,
85     KernelNvlink *pKernelNvlink
86 )
87 {
88     NvU32 uniqueIdMask = 0;
89     NvU32 i;
90 
91     for (i = 0; i < NV_ARRAY_ELEMENTS(pKernelNvlink->peerLinkMasks); i++)
92     {
93         NvU32 peerLinkMask = pKernelNvlink->peerLinkMasks[i];
94         if (peerLinkMask != 0)
95         {
96             uniqueIdMask |= LOWESTBIT(peerLinkMask);
97         }
98     }
99 
100     return uniqueIdMask;
101 }
102 
103 /**
104  * Get a unique peerID for the remote GPU connected via NVLINK. In this
105  * implementation, that peer ID is the lowest link ID of all the links
106  * connected to the peer GPU. This allows a static peer ID assignment
107  * based on link topology.
108  *
109  * Note: Ampere and beyond, there is no static peer ID allocation for
110  *       NVLink.
111  *
112  * @param[in]  pGpu          OBJGPU pointer for local GPU
113  * @param[in]  pKernelNvlink KernelNvlink pointer
114  * @param[in]  pRemoteGpu    OBJGPU pointer for remote GPU
115  *
116  * return NvU32 unique nvlink peer ID pGpu to pRemoteGpu
117  */
118 NvU32
knvlinkGetUniquePeerId_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,OBJGPU * pRemoteGpu)119 knvlinkGetUniquePeerId_GP100
120 (
121     OBJGPU       *pGpu,
122     KernelNvlink *pKernelNvlink,
123     OBJGPU       *pRemoteGpu
124 )
125 {
126     NvU32 peerLinkMask;
127 
128     peerLinkMask = pKernelNvlink->peerLinkMasks[gpuGetInstance(pRemoteGpu)];
129     if (peerLinkMask == 0)
130     {
131         return BUS_INVALID_PEER;
132     }
133 
134     LOWESTBITIDX_32(peerLinkMask);
135 
136     return peerLinkMask;
137 }
138 
139 /*!
140  * @brief Wrapper function chose between removing all or peer mappings
141  *
142  * @param[in] pGpu          OBJGPU pointer
143  * @param[in] pKernelNvlink KernelNvlink pointer
144  * @param[in] bAllMapping   Whether both sysmem and peer mappings should be removed
145  * @param[in] peerMask      Mask of peers for which mappings will be removed
146  * @param[in] bL2Entry      Are the mappings being removed because of L2 entry?
147  *
148  * @return   Returns NV_OK on success
149  */
150 NV_STATUS
knvlinkRemoveMapping_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvBool bAllMapping,NvU32 peerMask,NvBool bL2Entry)151 knvlinkRemoveMapping_GP100
152 (
153     OBJGPU       *pGpu,
154     KernelNvlink *pKernelNvlink,
155     NvBool        bAllMapping,
156     NvU32         peerMask,
157     NvBool        bL2Entry
158 )
159 {
160     NV_STATUS status = NV_OK;
161 
162     NV2080_CTRL_NVLINK_REMOVE_NVLINK_MAPPING_PARAMS params;
163     portMemSet(&params, 0, sizeof(params));
164 
165     params.bL2Entry = bL2Entry;
166 
167     if (bAllMapping)
168     {
169         params.mapTypeMask = NV2080_CTRL_NVLINK_REMOVE_NVLINK_MAPPING_TYPE_SYSMEM |
170                              NV2080_CTRL_NVLINK_REMOVE_NVLINK_MAPPING_TYPE_PEER;
171         params.peerMask    = (1 << NVLINK_MAX_PEERS_SW) - 1;
172     }
173     else
174     {
175         params.mapTypeMask = NV2080_CTRL_NVLINK_REMOVE_NVLINK_MAPPING_TYPE_PEER;
176         params.peerMask    = peerMask;
177     }
178 
179     status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
180                                  NV2080_CTRL_CMD_NVLINK_REMOVE_NVLINK_MAPPING,
181                                  (void *)&params, sizeof(params));
182     return status;
183 }
184 
185 /**
186  * @brief Get the mask of optimal CEs for P2P reads/writes
187  *
188  * @param[in]   pGpu                    OBJGPU pointer
189  * @param[in]   pKernelNvlink           KernelNvlink pointer
190  * @param[in]   gpuMask                 Mask of GPUs instances
191  * @param[out]  sysmemOptimalReadCEs    Mask of CEs for SYSMEM reads
192  * @param[out]  sysmemOptimalWriteCEs   Mask of CEs for SYSMEM writes
193  * @param[out]  p2pOptimalReadCEs       Mask of CEs for P2P reads
194  * @param[out]  p2pOptimalWriteCEs      Mask of CEs for P2P writes
195  */
196 NV_STATUS
knvlinkGetP2POptimalCEs_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,NvU32 gpuMask,NvU32 * sysmemOptimalReadCEs,NvU32 * sysmemOptimalWriteCEs,NvU32 * p2pOptimalReadCEs,NvU32 * p2pOptimalWriteCEs)197 knvlinkGetP2POptimalCEs_GP100
198 (
199     OBJGPU       *pGpu,
200     KernelNvlink *pKernelNvlink,
201     NvU32         gpuMask,
202     NvU32        *sysmemOptimalReadCEs,
203     NvU32        *sysmemOptimalWriteCEs,
204     NvU32        *p2pOptimalReadCEs,
205     NvU32        *p2pOptimalWriteCEs
206 )
207 {
208     KernelCE *pKCe            = NULL;
209     NvU32     sysmemReadCE    = 0;
210     NvU32     sysmemWriteCE   = 0;
211     NvU32     nvlinkP2PCeMask = 0;
212 
213     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kceFindFirstInstance(pGpu, &pKCe));
214     kceGetCeFromNvlinkConfig(pGpu, pKCe,
215                              gpuMask,
216                              &sysmemReadCE,
217                              &sysmemWriteCE,
218                              &nvlinkP2PCeMask);
219 
220     if (sysmemOptimalReadCEs != NULL)
221     {
222         *sysmemOptimalReadCEs = NVBIT(sysmemReadCE);
223     }
224 
225     if (sysmemOptimalWriteCEs != NULL)
226     {
227         *sysmemOptimalWriteCEs = NVBIT(sysmemWriteCE);
228     }
229 
230     if (p2pOptimalReadCEs != NULL)
231     {
232         *p2pOptimalReadCEs  = nvlinkP2PCeMask;
233     }
234 
235     if (p2pOptimalWriteCEs != NULL)
236     {
237         *p2pOptimalWriteCEs = nvlinkP2PCeMask;
238     }
239 
240     return NV_OK;
241 }
242 
243 /**
244  * @brief Setup peer mapping for the given ID to the remote GPU,
245  *        and program HSHUB to finalize the mapping.
246  *
247  * @param[in] pGpu          OBJGPU pointer (Local)
248  * @param[in] pKernelNvlink KernelNvlink pointer
249  * @param[in] pRemoteGpu    OBJGPU pointer (Remote)
250  * @param[in] peerId        peer ID
251  */
252 void
knvlinkSetupPeerMapping_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,OBJGPU * pRemoteGpu,NvU32 peerId)253 knvlinkSetupPeerMapping_GP100
254 (
255     OBJGPU       *pGpu,
256     KernelNvlink *pKernelNvlink,
257     OBJGPU       *pRemoteGpu,
258     NvU32         peerId
259 )
260 {
261     NV_STATUS status = NV_OK;
262     NvU32     peerLinkMask;
263 
264     NV2080_CTRL_NVLINK_PRE_SETUP_NVLINK_PEER_PARAMS  preSetupNvlinkPeerParams;
265     NV2080_CTRL_NVLINK_POST_SETUP_NVLINK_PEER_PARAMS postSetupNvlinkPeerParams;
266 
267     // HSHUB registers are updated during driver load if nvlink topology is forced
268     if (!knvlinkIsForcedConfig(pGpu, pKernelNvlink))
269     {
270         if ((pGpu == pRemoteGpu) &&
271              pGpu->getProperty(pGpu, PDB_PROP_GPU_NVLINK_P2P_LOOPBACK_DISABLED))
272         {
273             NV_PRINTF(LEVEL_ERROR,
274                       "P2P loopback is disabled on GPU%u, aborting peer setup (0x%x)\n",
275                       gpuGetInstance(pGpu), peerId);
276             return;
277         }
278 
279         peerLinkMask = pKernelNvlink->peerLinkMasks[gpuGetInstance(pRemoteGpu)];
280         knvlinkGetEffectivePeerLinkMask_HAL(pGpu, pKernelNvlink, pRemoteGpu, &peerLinkMask);
281 
282         if (peerLinkMask != 0)
283         {
284             portMemSet(&preSetupNvlinkPeerParams, 0, sizeof(preSetupNvlinkPeerParams));
285             preSetupNvlinkPeerParams.peerId        = peerId;
286             preSetupNvlinkPeerParams.peerLinkMask  = peerLinkMask;
287             preSetupNvlinkPeerParams.bEgmPeer      = GPU_GET_KERNEL_BUS(pGpu)->p2p.bEgmPeer[peerId];
288             preSetupNvlinkPeerParams.bNvswitchConn = knvlinkIsGpuConnectedToNvswitch(pGpu, pKernelNvlink);
289 
290             status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
291                                          NV2080_CTRL_CMD_NVLINK_PRE_SETUP_NVLINK_PEER,
292                                          (void *)&preSetupNvlinkPeerParams,
293                                          sizeof(preSetupNvlinkPeerParams));
294             NV_ASSERT(status == NV_OK);
295 
296             // Update *ALL* the HSHUB settings together
297             knvlinkUpdateCurrentConfig(pGpu, pKernelNvlink);
298 
299             portMemSet(&postSetupNvlinkPeerParams, 0, sizeof(postSetupNvlinkPeerParams));
300             postSetupNvlinkPeerParams.peerMask = NVBIT(peerId);
301 
302             status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
303                                          NV2080_CTRL_CMD_NVLINK_POST_SETUP_NVLINK_PEER,
304                                          (void *)&postSetupNvlinkPeerParams,
305                                          sizeof(postSetupNvlinkPeerParams));
306             NV_ASSERT(status == NV_OK);
307         }
308     }
309 }
310 
311 /*!
312  * @brief Return the mask of links that are connected
313  *
314  * @param[in] pGpu           OBJGPU ptr
315  * @param[in] pKernelNvlink  KernelNvlink ptr
316  */
317 NvU32
knvlinkGetConnectedLinksMask_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)318 knvlinkGetConnectedLinksMask_GP100
319 (
320     OBJGPU       *pGpu,
321     KernelNvlink *pKernelNvlink
322 )
323 {
324     //
325     // Connected links are already filtered against the
326     // enabled links. Hence, enabledLinks has final say
327     //
328     return knvlinkGetEnabledLinkMask(pGpu, pKernelNvlink);
329 }
330 
331 /*!
332  * @brief Program NVLink Speed for the enabled links
333  *
334  * @param[in] pGpu           OBJGPU ptr
335  * @param[in] pKernelNvlink  KernelNvlink ptr
336  */
337 NV_STATUS
knvlinkProgramLinkSpeed_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink)338 knvlinkProgramLinkSpeed_GP100
339 (
340     OBJGPU       *pGpu,
341     KernelNvlink *pKernelNvlink
342 )
343 {
344     NV_STATUS status = NV_OK;
345 
346     NV2080_CTRL_NVLINK_PROGRAM_LINK_SPEED_PARAMS programLinkSpeedParams;
347     portMemSet(&programLinkSpeedParams, 0, sizeof(programLinkSpeedParams));
348 
349     programLinkSpeedParams.bPlatformLinerateDefined = NV_FALSE;
350     programLinkSpeedParams.platformLineRate         =
351                           NV_REG_STR_RM_NVLINK_SPEED_CONTROL_SPEED_DEFAULT;
352 
353     status = knvlinkExecGspRmRpc(pGpu, pKernelNvlink,
354                                  NV2080_CTRL_CMD_NVLINK_PROGRAM_LINK_SPEED,
355                                  (void *)&programLinkSpeedParams,
356                                  sizeof(programLinkSpeedParams));
357     if (status != NV_OK)
358     {
359         NV_PRINTF(LEVEL_ERROR, "Failed to program NVLink speed for links!\n");
360         return status;
361     }
362 
363     pKernelNvlink->nvlinkLinkSpeed = programLinkSpeedParams.nvlinkLinkSpeed;
364 
365     return NV_OK;
366 }
367 
368 /*!
369  * @brief Get the device PCI info and store it in
370  * nvlink_device_info struct which will be passed to corelib
371  *
372  * @param[in]  pGpu                 OBJGPU pointer
373  * @param[in]  pKernelNvlink        KernelNvlink pointer
374  * @param[out] nvlink_device_info   Nvlink device info pointer
375  *
376  */
377 #if defined(INCLUDE_NVLINK_LIB)
378 void
knvlinkCoreGetDevicePciInfo_GP100(OBJGPU * pGpu,KernelNvlink * pKernelNvlink,nvlink_device_info * devInfo)379 knvlinkCoreGetDevicePciInfo_GP100
380 (
381     OBJGPU             *pGpu,
382     KernelNvlink       *pKernelNvlink,
383     nvlink_device_info *devInfo
384 )
385 {
386     devInfo->pciInfo.domain   = gpuGetDomain(pGpu);
387     devInfo->pciInfo.bus      = gpuGetBus(pGpu);
388     devInfo->pciInfo.device   = gpuGetDevice(pGpu);
389     devInfo->pciInfo.function = 0;
390 }
391 #endif
392