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(¶ms, 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 *)¶ms, 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