1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 * SPDX-License-Identifier: MIT
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "nvlink_export.h"
25
26 #include "common_nvswitch.h"
27 #include "ls10/ls10.h"
28 #include "ls10/minion_ls10.h"
29 #include "ls10/minion_nvlink_defines_public_ls10.h"
30 #include "regkey_nvswitch.h"
31
32 #include "nvswitch/ls10/dev_minion_ip.h"
33 #include "nvswitch/ls10/dev_minion_ip_addendum.h"
34 #include "nvswitch/ls10/dev_ingress_ip.h"
35 #include "nvswitch/ls10/dev_egress_ip.h"
36 #include "nvswitch/ls10/dev_riscv_pri.h"
37 #include "nvswitch/ls10/dev_nvlphyctl_ip.h"
38
39 #include "flcn/flcn_nvswitch.h"
40
41 /*
42 * @Brief : Check if MINION is already running.
43 *
44 * The function assumes that if one of MINIONs is running, all of them are
45 * running. This approach needs to be fixed.
46 *
47 * TODO: Refactor minion code to check for each minion's status individually.
48 *
49 * @param[in] device Bootstrap MINIONs on this device
50 */
51 static NvBool
_nvswitch_check_running_minions(nvswitch_device * device)52 _nvswitch_check_running_minions
53 (
54 nvswitch_device *device
55 )
56 {
57 NvU32 data, i;
58 NvBool bMinionRunning = NV_FALSE;
59
60 for (i = 0; i < NUM_MINION_ENGINE_LS10; i++)
61 {
62 if (!NVSWITCH_ENG_VALID_LS10(device, MINION, i))
63 {
64 NVSWITCH_PRINT(device, SETUP,
65 "%s: MINION instance %d is not valid.\n",
66 __FUNCTION__, i);
67 continue;
68 }
69
70 data = NVSWITCH_MINION_RD32_LS10(device, i, _CMINION, _FALCON_IRQSTAT);
71 if (FLD_TEST_DRF(_CMINION, _FALCON_IRQSTAT, _HALT, _FALSE, data))
72 {
73 data = NVSWITCH_MINION_RD32_LS10(device, i, _MINION, _MINION_STATUS);
74 if (FLD_TEST_DRF(_MINION, _MINION_STATUS, _STATUS, _BOOT, data))
75 {
76 //
77 // Set initialized flag if MINION is running.
78 // We don't want to bootstrap a falcon that is already running.
79 //
80 nvswitch_set_minion_initialized(device, i, NV_TRUE);
81
82 NVSWITCH_PRINT(device, SETUP,
83 "%s: MINION instance %d is already bootstrapped.\n",
84 __FUNCTION__, i);
85 bMinionRunning = NV_TRUE;
86 }
87 }
88 }
89
90 return bMinionRunning;
91 }
92
93 NvlStatus
nvswitch_minion_get_dl_status_ls10(nvswitch_device * device,NvU32 linkId,NvU32 statusIdx,NvU32 statusArgs,NvU32 * statusData)94 nvswitch_minion_get_dl_status_ls10
95 (
96 nvswitch_device *device,
97 NvU32 linkId,
98 NvU32 statusIdx,
99 NvU32 statusArgs,
100 NvU32 *statusData
101 )
102 {
103 NVSWITCH_TIMEOUT timeout;
104 NvBool keepPolling;
105 NvU32 regData, localLinkNumber;
106 localLinkNumber = linkId % NVSWITCH_LINKS_PER_MINION_LS10;
107
108 if (NVSWITCH_IS_LINK_ENG_VALID_LS10(device, MINION, linkId) &&
109 !nvswitch_is_minion_initialized(device, NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION)))
110 {
111 NVSWITCH_PRINT(device, ERROR,
112 "%s: MINION %d is not initialized for link %08x.\n",
113 __FUNCTION__, NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
114 linkId);
115 return -NVL_ERR_INVALID_STATE;
116 }
117
118 // Query the DL status interface to get the data
119 NVSWITCH_MINION_LINK_WR32_LS10(device, linkId, _MINION, _NVLINK_DL_STAT(localLinkNumber),
120 DRF_NUM(_MINION, _NVLINK_DL_STAT, _ARGS, statusArgs) |
121 DRF_NUM(_MINION, _NVLINK_DL_STAT, _STATUSIDX, statusIdx));
122
123 if (IS_FMODEL(device) || IS_EMULATION(device) || IS_RTLSIM(device))
124 {
125 nvswitch_timeout_create(20 * NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
126 }
127 else
128 {
129 nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
130 }
131
132 // Poll for READY bit to be set
133 do
134 {
135 keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
136
137 regData = NVSWITCH_MINION_LINK_RD32_LS10(device, linkId, _MINION, _NVLINK_DL_STAT(localLinkNumber));
138 if (FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_STAT, _READY, 1, regData))
139 {
140 *statusData = NVSWITCH_MINION_LINK_RD32_LS10(device, linkId, _MINION, _NVLINK_DL_STATDATA(localLinkNumber));
141 return NVL_SUCCESS;
142 }
143 if (IS_FMODEL(device) || IS_RTLSIM(device))
144 {
145 nvswitch_os_sleep(1);
146 }
147 }
148 while (keepPolling);
149
150 NVSWITCH_PRINT(device, ERROR,
151 "%s: Timeout waiting for DL_STAT request to complete"
152 " NV_MINION_NVLINK_DL_STAT(%d) = 0x%08x\n",
153 __FUNCTION__, linkId, regData);
154 return -NVL_ERR_INVALID_STATE;
155 }
156
157 /*
158 * @Brief : Send MINION DL CMD for a particular link
159 *
160 * @param[in] device Send command to MINION on this device
161 * @param[in] linkNumber DLCMD will be sent on this link number
162 *
163 * @return Returns true if the DLCMD passed
164 */
165 NvlStatus
nvswitch_minion_send_command_ls10(nvswitch_device * device,NvU32 linkNumber,NvU32 command,NvU32 scratch0)166 nvswitch_minion_send_command_ls10
167 (
168 nvswitch_device *device,
169 NvU32 linkNumber,
170 NvU32 command,
171 NvU32 scratch0
172 )
173 {
174 NvU32 data = 0, localLinkNumber, statData = 0;
175 NvU32 ingressEccRegVal = 0, egressEccRegVal = 0;
176 NVSWITCH_TIMEOUT timeout;
177 NvBool keepPolling;
178
179 localLinkNumber = linkNumber % NVSWITCH_LINKS_PER_MINION_LS10;
180
181 if (NVSWITCH_IS_LINK_ENG_VALID_LS10(device, MINION, linkNumber) &&
182 !nvswitch_is_minion_initialized(device, NVSWITCH_GET_LINK_ENG_INST(device, linkNumber, MINION)))
183 {
184 NVSWITCH_PRINT(device, ERROR,
185 "%s: MINION %d is not initialized for link %08x.\n",
186 __FUNCTION__, NVSWITCH_GET_LINK_ENG_INST(device, linkNumber, MINION),
187 linkNumber);
188 return NVL_SUCCESS;
189 }
190
191 data = NVSWITCH_MINION_LINK_RD32_LS10(device, linkNumber, _MINION, _NVLINK_DL_CMD(localLinkNumber));
192 if (FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_CMD, _FAULT, 1, data))
193 {
194 NVSWITCH_PRINT(device, ERROR,
195 "%s: MINION %d is in fault state. NV_MINION_NVLINK_DL_CMD(%d) = %08x\n",
196 __FUNCTION__, NVSWITCH_GET_LINK_ENG_INST(device, linkNumber, MINION),
197 linkNumber, data);
198 return -NVL_ERR_GENERIC;
199 }
200
201 // Write to minion scratch if needed by command
202 switch (command)
203 {
204 case NV_MINION_NVLINK_DL_CMD_COMMAND_CONFIGEOM:
205 data = 0;
206 data = FLD_SET_DRF_NUM(_MINION, _MISC_0, _SCRATCH_SWRW_0, scratch0, data);
207 NVSWITCH_MINION_WR32_LS10(device,
208 NVSWITCH_GET_LINK_ENG_INST(device, linkNumber, MINION), _MINION, _MISC_0, data);
209 break;
210 case NV_MINION_NVLINK_DL_CMD_COMMAND_INITPHASE1:
211 //
212 // WAR bug 2708497
213 // Before INITPHASE1, we must clear these values, then set back to
214 // _PROD after the call
215 // NV_INGRESS_ERR_ECC_CTRL_NCISOC_PARITY_ENABLE
216 // NV_EGRESS_ERR_ECC_CTRL_NCISOC_PARITY_ENABLE
217 //
218
219 ingressEccRegVal = NVSWITCH_NPORT_RD32_LS10(device, linkNumber, _INGRESS, _ERR_ECC_CTRL);
220 NVSWITCH_NPORT_WR32_LS10(device, linkNumber, _INGRESS, _ERR_ECC_CTRL,
221 FLD_SET_DRF(_INGRESS, _ERR_ECC_CTRL, _NCISOC_PARITY_ENABLE, _DISABLE, ingressEccRegVal));
222
223 egressEccRegVal = NVSWITCH_NPORT_RD32_LS10(device, linkNumber, _EGRESS, _ERR_ECC_CTRL);
224 NVSWITCH_NPORT_WR32_LS10(device, linkNumber, _EGRESS, _ERR_ECC_CTRL,
225 FLD_SET_DRF(_EGRESS, _ERR_ECC_CTRL, _NCISOC_PARITY_ENABLE, _DISABLE, egressEccRegVal));
226 break;
227 default:
228 break;
229 }
230
231 data = FLD_SET_DRF_NUM(_MINION, _NVLINK_DL_CMD, _COMMAND, command, data);
232 data = FLD_SET_DRF_NUM(_MINION, _NVLINK_DL_CMD, _FAULT, 1, data);
233 NVSWITCH_MINION_LINK_WR32_LS10(device, linkNumber, _MINION, _NVLINK_DL_CMD(localLinkNumber), data);
234
235 if (IS_FMODEL(device) || IS_EMULATION(device) || IS_RTLSIM(device))
236 {
237 nvswitch_timeout_create(10 * NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
238 }
239 else
240 {
241 nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
242 }
243
244 //
245 // We will exit this if the command is successful OR
246 // if timeout waiting for the READY bit to be set OR
247 // if it generates a MINION FAULT
248 //
249 do
250 {
251 keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
252
253 data = NVSWITCH_MINION_LINK_RD32_LS10(device, linkNumber, _MINION, _NVLINK_DL_CMD(localLinkNumber));
254 if (FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_CMD, _READY, 1, data))
255 {
256 // The command has completed, success?
257 if (FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_CMD, _FAULT, 1, data))
258 {
259 NVSWITCH_PRINT(device, ERROR,
260 "%s: NVLink MINION command faulted!"
261 " NV_MINION_NVLINK_DL_CMD(%d) = 0x%08x\n",
262 __FUNCTION__, linkNumber, data);
263
264 // Pull fault code and subcode
265 if (nvswitch_minion_get_dl_status(device, linkNumber,
266 NV_NVLSTAT_MN00, 0, &statData) == NVL_SUCCESS)
267 {
268 NVSWITCH_PRINT(device, ERROR,
269 "%s: Minion DLCMD Fault code = 0x%x, Sub-code = 0x%x\n",
270 __FUNCTION__,
271 DRF_VAL(_NVLSTAT, _MN00, _LINK_INTR_CODE, statData),
272 DRF_VAL(_NVLSTAT, _MN00, _LINK_INTR_SUBCODE, statData));
273 }
274 else
275 {
276 NVSWITCH_PRINT(device, ERROR,
277 "%s: Failed to get code and subcode from DLSTAT, link %d\n",
278 __FUNCTION__, linkNumber);
279 }
280
281 // Clear the fault and return
282 NVSWITCH_PRINT(device, ERROR,
283 "%s: Clearing NVLink MINION fault for link %d\n",
284 __FUNCTION__, linkNumber);
285
286 data = FLD_SET_DRF_NUM(_MINION, _NVLINK_DL_CMD, _FAULT, 1, 0x0);
287 NVSWITCH_MINION_LINK_WR32_LS10(device, linkNumber, _MINION, _NVLINK_DL_CMD(localLinkNumber), data);
288 return -NVL_ERR_INVALID_STATE;
289 }
290 else
291 {
292 NVSWITCH_PRINT(device, SETUP,
293 "%s: NVLink MINION command %x was sent successfully for link %d\n",
294 __FUNCTION__, command, linkNumber);
295 break;
296 }
297 }
298
299 nvswitch_os_sleep(1);
300 }
301 while (keepPolling);
302
303 if (!FLD_TEST_DRF_NUM(_MINION, _NVLINK_DL_CMD, _READY, 1, data))
304 {
305 NVSWITCH_PRINT(device, ERROR,
306 "%s: Timeout waiting for NVLink MINION command to complete!"
307 " NV_MINION_NVLINK_DL_CMD(%d) = 0x%08x\n",
308 __FUNCTION__, linkNumber, data);
309 return -NVL_ERR_INVALID_STATE;
310 }
311
312 if (command == NV_MINION_NVLINK_DL_CMD_COMMAND_INITPHASE1)
313 {
314 NVSWITCH_NPORT_WR32_LS10(device, linkNumber, _INGRESS, _ERR_ECC_CTRL, ingressEccRegVal);
315 NVSWITCH_NPORT_WR32_LS10(device, linkNumber, _EGRESS, _ERR_ECC_CTRL, egressEccRegVal);
316 }
317
318 return NVL_SUCCESS;
319 }
320
321 /*
322 * @Brief : Bootstrap all MINIONs on the specified device
323 *
324 * @param[in] device Bootstrap MINIONs on this device
325 */
326 NvlStatus
nvswitch_init_minion_ls10(nvswitch_device * device)327 nvswitch_init_minion_ls10
328 (
329 nvswitch_device *device
330 )
331 {
332 NvlStatus status = NVL_SUCCESS;
333
334 if (_nvswitch_check_running_minions(device))
335 {
336 return NVL_SUCCESS;
337 }
338
339 status = -NVL_INITIALIZATION_TOTAL_FAILURE;
340
341 return status;
342 }
343
344 NvlStatus
nvswitch_set_minion_initialized_ls10(nvswitch_device * device,NvU32 idx_minion,NvBool initialized)345 nvswitch_set_minion_initialized_ls10
346 (
347 nvswitch_device *device,
348 NvU32 idx_minion,
349 NvBool initialized
350 )
351 {
352 ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device);
353
354 if (!NVSWITCH_ENG_VALID_LS10(device, MINION, idx_minion))
355 {
356 return -NVL_BAD_ARGS;
357 }
358
359 chip_device->engMINION[idx_minion].initialized = initialized;
360 return NVL_SUCCESS;
361 }
362
363 NvBool
nvswitch_is_minion_initialized_ls10(nvswitch_device * device,NvU32 idx_minion)364 nvswitch_is_minion_initialized_ls10
365 (
366 nvswitch_device *device,
367 NvU32 idx_minion
368 )
369 {
370 ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device);
371
372 if (!NVSWITCH_ENG_VALID_LS10(device, MINION, idx_minion))
373 {
374 return NV_FALSE;
375 }
376 return (chip_device->engMINION[idx_minion].initialized != 0);
377 }
378
379 NvlStatus
nvswitch_minion_set_sim_mode_ls10(nvswitch_device * device,nvlink_link * link)380 nvswitch_minion_set_sim_mode_ls10
381 (
382 nvswitch_device *device,
383 nvlink_link *link
384 )
385 {
386 NvlStatus status = NVL_SUCCESS;
387 NvU32 dlcmd;
388 NvU32 linkNumber = link->linkNumber;
389 NvU32 localLinkNumber = linkNumber % NVSWITCH_LINKS_PER_MINION_LS10;
390
391 switch (device->regkeys.set_simmode)
392 {
393 case NV_SWITCH_REGKEY_MINION_SET_SIMMODE_FAST:
394 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_FAST;
395 break;
396 case NV_SWITCH_REGKEY_MINION_SET_SIMMODE_MEDIUM:
397 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_MEDIUM;
398 break;
399 case NV_SWITCH_REGKEY_MINION_SET_SIMMODE_SLOW:
400 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SLOW;
401 break;
402 default:
403 return NVL_SUCCESS;
404 }
405
406 status = nvswitch_minion_send_command(device, linkNumber, dlcmd, 0);
407 if (status != NVL_SUCCESS)
408 {
409 NVSWITCH_PRINT(device, ERROR,
410 "%s: DLCMD 0x%x failed on link: %d\n",
411 __FUNCTION__, dlcmd, linkNumber);
412 return status;
413 }
414
415 // Setting RXCAL_EN_ALARM timer value
416 NVSWITCH_MINION_LINK_WR32_LS10(device, linkNumber, _MINION,
417 _NVLINK_DL_CMD_DATA(localLinkNumber),
418 NV_MINION_DL_CMD_DATA_RXCAL_EN_ALARM);
419
420 status = nvswitch_minion_send_command(device, linkNumber,
421 NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_RXCAL_EN_ALARM, 0);
422 if (status != NVL_SUCCESS)
423 {
424 NVSWITCH_PRINT(device, ERROR,
425 "%s: DLCMD DBG_SETSIMMODE_RXCAL_EN_ALARM failed on link: %d\n",
426 __FUNCTION__, linkNumber);
427 return status;
428 }
429
430 // Setting INIT_CAL_DONE timer value
431 NVSWITCH_MINION_LINK_WR32_LS10(device, linkNumber, _MINION,
432 _NVLINK_DL_CMD_DATA(localLinkNumber),
433 NV_MINION_DL_CMD_DATA_INIT_CAL_DONE);
434
435 status = nvswitch_minion_send_command(device, linkNumber,
436 NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_INIT_CAL_DONE, 0);
437 if (status != NVL_SUCCESS)
438 {
439 NVSWITCH_PRINT(device, ERROR,
440 "%s: DLCMD DBG_SETSIMMODE_INIT_CAL_DONE failed on link: %d\n",
441 __FUNCTION__, linkNumber);
442 return status;
443 }
444
445 return status;
446 }
447
448 NvlStatus
nvswitch_minion_set_smf_settings_ls10(nvswitch_device * device,nvlink_link * link)449 nvswitch_minion_set_smf_settings_ls10
450 (
451 nvswitch_device *device,
452 nvlink_link *link
453 )
454 {
455 NvlStatus status = NVL_SUCCESS;
456 NvU32 dlcmd;
457 NvU32 linkNumber = link->linkNumber;
458
459 switch (device->regkeys.set_smf_settings)
460 {
461 case NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_SLOW:
462 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SMF_VALUES_SLOW;
463 break;
464 case NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_MEDIUM:
465 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SMF_VALUES_MEDIUM;
466 break;
467 case NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_FAST:
468 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SMF_VALUES_FAST;
469 break;
470 case NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_MEDIUM_SERIAL:
471 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_SMF_VALUES_MEDIUM_SERIAL;
472 break;
473 default:
474 return NVL_SUCCESS;
475 }
476
477 status = nvswitch_minion_send_command(device, linkNumber, dlcmd, 0);
478 if (status != NVL_SUCCESS)
479 {
480 NVSWITCH_PRINT(device, ERROR,
481 "%s: DLCMD 0x%x failed on link: %d\n",
482 __FUNCTION__, dlcmd, linkNumber);
483 return status;
484 }
485
486 return status;
487 }
488
489 NvlStatus
nvswitch_minion_select_uphy_tables_ls10(nvswitch_device * device,nvlink_link * link)490 nvswitch_minion_select_uphy_tables_ls10
491 (
492 nvswitch_device *device,
493 nvlink_link *link
494 )
495 {
496 NvlStatus status = NVL_SUCCESS;
497 NvU32 dlcmd;
498 NvU32 linkNumber = link->linkNumber;
499
500 switch (device->regkeys.select_uphy_tables)
501 {
502 case NV_SWITCH_REGKEY_MINION_SELECT_UPHY_TABLES_SHORT:
503 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_UPHY_TABLES_SHORT;
504 break;
505 case NV_SWITCH_REGKEY_MINION_SELECT_UPHY_TABLES_FAST:
506 dlcmd = NV_MINION_NVLINK_DL_CMD_COMMAND_DBG_SETSIMMODE_UPHY_TABLES_FAST;
507 break;
508 default:
509 return NVL_SUCCESS;
510 }
511
512 status = nvswitch_minion_send_command(device, linkNumber, dlcmd, 0);
513 if (status != NVL_SUCCESS)
514 {
515 NVSWITCH_PRINT(device, ERROR,
516 "%s: DLCMD 0x%x failed on link: %d\n",
517 __FUNCTION__, dlcmd, linkNumber);
518 return status;
519 }
520
521 return status;
522 }
523
524
525 NvlStatus
nvswitch_minion_get_rxdet_status_ls10(nvswitch_device * device,NvU32 linkId)526 nvswitch_minion_get_rxdet_status_ls10
527 (
528 nvswitch_device *device,
529 NvU32 linkId
530 )
531 {
532 NvU32 statData;
533 NvlStatus status;
534 NVSWITCH_TIMEOUT timeout;
535 NvBool keepPolling;
536
537 if (IS_FMODEL(device) || IS_EMULATION(device) || IS_RTLSIM(device))
538 {
539 nvswitch_timeout_create(30*NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
540 }
541 else
542 {
543 nvswitch_timeout_create(20 * NVSWITCH_INTERVAL_1MSEC_IN_NS, &timeout);
544 }
545
546 // Poll for READY bit to be set
547 do
548 {
549 keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
550
551 // Check RXDET status on MINION DL STAT interface
552 status = nvswitch_minion_get_dl_status(device, linkId, NV_NVLSTAT_LNK2, 0, &statData);
553 if (status != NVL_SUCCESS)
554 {
555 return status;
556 }
557
558 if (FLD_TEST_DRF(_NVLSTAT, _LNK2, _RXDET_LINK_STATUS, _FOUND, statData))
559 {
560 NVSWITCH_PRINT(device, INFO,
561 "%s: RXDET LINK_STATUS = FOUND on link: %d\n",
562 __FUNCTION__, linkId);
563
564 // Retrieve which lanes were found (should be all)
565 device->link[linkId].lane_rxdet_status_mask =
566 DRF_VAL(_NVLSTAT, _LNK2, _RXDET_LANE_STATUS, statData);
567
568 //
569 // MINION doesn't have knowledge of lane reversal and therefore
570 // reports logical lanes. We must reverse the bitmask here if applicable
571 // since RM reports physical lanes.
572 //
573 if (nvswitch_link_lane_reversed_lr10(device, linkId))
574 {
575 NVSWITCH_REVERSE_BITMASK_32(NVSWITCH_NUM_LANES_LS10,
576 device->link[linkId].lane_rxdet_status_mask);
577 }
578
579 return NVL_SUCCESS;
580 }
581
582 if (FLD_TEST_DRF(_NVLSTAT, _LNK2, _RXDET_LINK_STATUS, _TIMEOUT, statData))
583 {
584 NVSWITCH_PRINT(device, ERROR,
585 "%s: RXDET LINK_STATUS = TIMEOUT on link: %d\n",
586 __FUNCTION__, linkId);
587
588 // Retrieve which lanes were found
589 device->link[linkId].lane_rxdet_status_mask =
590 DRF_VAL(_NVLSTAT, _LNK2, _RXDET_LANE_STATUS, statData);
591
592 //
593 // MINION doesn't have knowledge of lane reversal and therefore
594 // reports logical lanes. We must reverse the bitmask here if applicable
595 // since RM reports physical lanes.
596 //
597 if (nvswitch_link_lane_reversed_lr10(device, linkId))
598 {
599 NVSWITCH_REVERSE_BITMASK_32(NVSWITCH_NUM_LANES_LS10,
600 device->link[linkId].lane_rxdet_status_mask);
601 }
602
603 return -NVL_ERR_INVALID_STATE;
604 }
605
606 nvswitch_os_sleep(1);
607 }
608 while (keepPolling);
609
610 NVSWITCH_PRINT(device, ERROR,
611 "%s: Timeout waiting for RXDET STATUS on link: %d\n",
612 __FUNCTION__, linkId);
613
614 return -NVL_ERR_INVALID_STATE;
615 }
616
617 /*
618 * @Brief : Check if the RISCV CPU has started
619 *
620 * @param[in] device The Nvswitch device
621 * @param[in] idx_minion MINION instance to use
622 */
623 NvBool
nvswitch_minion_is_riscv_active_ls10(nvswitch_device * device,NvU32 idx_minion)624 nvswitch_minion_is_riscv_active_ls10
625 (
626 nvswitch_device *device,
627 NvU32 idx_minion
628 )
629 {
630 NvU32 val;
631
632 val = NVSWITCH_MINION_RD32_LS10(device, idx_minion, _CMINION_RISCV, _CPUCTL);
633
634 return FLD_TEST_DRF(_CMINION, _RISCV_CPUCTL, _ACTIVE_STAT, _ACTIVE, val);
635
636 }
637
638 NvlStatus
nvswitch_minion_clear_dl_error_counters_ls10(nvswitch_device * device,NvU32 linkId)639 nvswitch_minion_clear_dl_error_counters_ls10
640 (
641 nvswitch_device *device,
642 NvU32 linkId
643 )
644 {
645 NvlStatus status;
646
647 status = nvswitch_minion_send_command(device, linkId,
648 NV_MINION_NVLINK_DL_CMD_COMMAND_DLSTAT_CLR_DLERRCNT, 0);
649 if (status != NVL_SUCCESS)
650 {
651 NVSWITCH_PRINT(device, ERROR, "%s : Failed to clear error count to MINION for link # %d\n",
652 __FUNCTION__, linkId);
653 }
654 return status;
655 }
656
657 NvlStatus
nvswitch_minion_send_inband_data_ls10(nvswitch_device * device,NvU32 linkId,nvswitch_inband_send_data * inBandData)658 nvswitch_minion_send_inband_data_ls10
659 (
660 nvswitch_device *device,
661 NvU32 linkId,
662 nvswitch_inband_send_data *inBandData
663 )
664 {
665 NvlStatus status = NVL_SUCCESS;
666 #if defined(INCLUDE_NVLINK_LIB)
667 NvlStatus tempStatus = NVL_SUCCESS;
668 NvU32 localLinkNumber = linkId % NVSWITCH_LINKS_PER_MINION_LS10;
669 NvU8 *sendBuffer = inBandData->sendBuffer;
670 NvU32 bufferSize = inBandData->bufferSize;
671 NvU32 data = 0;
672 NvU32 regval = 0;
673 NvU32 statData = 0;
674 NVSWITCH_TIMEOUT timeout;
675 NvBool bKeepPolling = NV_TRUE;
676
677 if (bufferSize == 0 || bufferSize > NVLINK_INBAND_MAX_XFER_SIZE)
678 {
679 NVSWITCH_PRINT(device, ERROR, "Bad Inband data size %d. Skipping Inband Send\n", bufferSize);
680 return -NVL_ERR_INVALID_STATE;
681 }
682
683 // Buffer Size must be reduced by 1 as per the minion protocol
684 regval = DRF_NUM(_MINION, _INBAND_SEND_DATA, _BUFFER_SIZE, (bufferSize - 1));
685
686 regval |= DRF_NUM(_MINION, _INBAND_SEND_DATA, _FLAGS,inBandData->hdr.data);
687
688 NVSWITCH_MINION_WR32_LS10(device,
689 NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
690 _MINION, _NVLINK_DL_CMD_DATA(localLinkNumber),
691 regval);
692
693 status = nvswitch_minion_send_command(device, linkId,
694 NV_MINION_NVLINK_DL_CMD_COMMAND_WRITE_TX_BUFFER_START, 0);
695
696 if (status != NVL_SUCCESS)
697 {
698 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer for TX_BUFFER_START failed\n", linkId);
699 return status;
700 }
701
702 while (bufferSize != 0)
703 {
704 nvswitch_os_memcpy(&data, sendBuffer, NV_MIN(sizeof(data), bufferSize));
705
706 NVSWITCH_MINION_WR32_LS10(device,
707 NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
708 _MINION, _NVLINK_DL_CMD_DATA(localLinkNumber),
709 data);
710
711 status = nvswitch_minion_send_command(device, linkId,
712 NV_MINION_NVLINK_DL_CMD_COMMAND_WRITE_TX_BUFFER_MIDDLE, 0);
713
714 if (status != NVL_SUCCESS)
715 {
716 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer failed\n", linkId);
717 goto clear_buffer;
718 }
719
720 bufferSize -= NV_MIN(sizeof(data), bufferSize);
721 sendBuffer += NV_MIN(sizeof(data), bufferSize);
722 }
723
724 status = nvswitch_minion_send_command(device, linkId,
725 NV_MINION_NVLINK_DL_CMD_COMMAND_WRITE_TX_BUFFER_END, 0);
726
727 if (status != NVL_SUCCESS)
728 {
729 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer for TX_BUFFER_END\n", linkId);
730 goto clear_buffer;
731 }
732
733 // Wait for buffer complete or buffer fail
734 nvswitch_timeout_create(2 * NVSWITCH_INTERVAL_4SEC_IN_NS, &timeout);
735 do
736 {
737 bKeepPolling = !nvswitch_timeout_check(&timeout);
738 // DLSTAT need to explicitly checked
739 status = nvswitch_minion_get_dl_status(device, linkId, NV_NVLSTAT_UC01, 0, &statData);
740
741 if (status != NVL_SUCCESS)
742 {
743 NVSWITCH_PRINT(device, INFO,"%s : Failed to poll DLSTAT register for (%s):(%d)\n",
744 __FUNCTION__, device->name, linkId);
745 status = -NVL_ERR_INVALID_STATE;
746 goto clear_buffer;
747 }
748
749 if (FLD_TEST_DRF(_NVLSTAT, _UC01, _INBAND_BUFFER_COMPLETE, _TRUE, statData))
750 {
751 return NVL_SUCCESS;
752 }
753
754 if (FLD_TEST_DRF(_NVLSTAT, _UC01, _INBAND_BUFFER_FAIL, _TRUE, statData))
755 {
756 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer BUFFER_FAILED\n", linkId);
757 status = -NVL_ERR_INVALID_STATE;
758 goto clear_buffer;
759 }
760 //
761 // Consider a case where both FM and RM trying to write on the same NVLink at the same time.
762 // Both are waiting on each other to read the buffer, but they have also blocked the ISR,
763 // as while waiting they hold the device lock. Thus, it is necessary to unblock one of them.
764 // And to do that we have service BUFFER_AVAILABLE while waiting.
765 //
766 nvswitch_service_minion_all_links_ls10(device);
767
768 nvswitch_os_sleep(10);
769
770 } while (bKeepPolling);
771
772 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Neither got BUFFER_FAIL nor BUFFER_COMPLETE\n", linkId);
773
774 clear_buffer:
775 tempStatus = nvswitch_minion_send_command(device, linkId,
776 NV_MINION_NVLINK_DL_CMD_COMMAND_CLEAR_TX_BUFFER,
777 0);
778 if (tempStatus != NVL_SUCCESS)
779 {
780 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer for TX_BUFFER_CLEAR\n", linkId);
781 return status;
782 }
783
784 // Check if we received BUFFER_COMPLETE is seen while doing a BUFFER_CLEAR
785 tempStatus = nvswitch_minion_get_dl_status(device, linkId, NV_NVLSTAT_UC01, 0, &statData);
786
787 if (tempStatus != NVL_SUCCESS)
788 {
789 NVSWITCH_PRINT(device, INFO,"%s : Failed to poll DLSTAT register for (%s):(%d)\n",
790 __FUNCTION__, device->name, linkId);
791 return status;
792 }
793
794 if (FLD_TEST_DRF(_NVLSTAT, _UC01, _INBAND_BUFFER_COMPLETE, _TRUE, statData))
795 {
796 status = NVL_SUCCESS;
797 }
798 else
799 {
800 status = bKeepPolling ? status: -NVL_ERR_STATE_IN_USE;
801 }
802 #endif
803 return status;
804 }
805
806 void
nvswitch_minion_receive_inband_data_ls10(nvswitch_device * device,NvU32 linkId)807 nvswitch_minion_receive_inband_data_ls10
808 (
809 nvswitch_device *device,
810 NvU32 linkId
811 )
812 {
813 NvlStatus status = NVL_SUCCESS;
814 #if defined(INCLUDE_NVLINK_LIB)
815 NvlStatus tempStatus = NVL_SUCCESS;
816 NvU32 numEntries = 0;
817 NvU32 i;
818 NvU32 localLinkNumber = linkId % NVSWITCH_LINKS_PER_MINION_LS10;
819 NvU8 *receiveBuffer;
820 NvU32 regVal, dataSize, remainingBuffer, bytesToXfer;
821 nvlink_inband_drv_hdr_t hdr;
822
823 status = nvswitch_minion_send_command(device, linkId,
824 NV_MINION_NVLINK_DL_CMD_COMMAND_READ_RX_BUFFER_START,
825 0);
826 if (status != NV_OK)
827 goto cleanup;
828
829 regVal = NVSWITCH_MINION_RD32_LS10(device,
830 NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
831 _MINION, _NVLINK_DL_CMD_DATA(localLinkNumber));
832
833 // Add 1 to the data as per minion protocol
834 dataSize = DRF_VAL(_MINION, _INBAND_SEND_DATA, _BUFFER_SIZE, regVal) + 1;
835 hdr.data = DRF_VAL(_MINION, _INBAND_SEND_DATA, _FLAGS, regVal);
836 numEntries = NV_ALIGN_UP(dataSize, NVLINK_INBAND_MAX_XFER_AT_ONCE)/
837 NVLINK_INBAND_MAX_XFER_AT_ONCE;
838 remainingBuffer = dataSize;
839
840 if ((hdr.data & (NVLINK_INBAND_DRV_HDR_TYPE_START |
841 NVLINK_INBAND_DRV_HDR_TYPE_MID |
842 NVLINK_INBAND_DRV_HDR_TYPE_END)) == 0)
843 {
844 NVSWITCH_PRINT(device, ERROR, "InBand: HDR is wrong\n");
845 goto cleanup;
846 }
847
848 if (hdr.data & NVLINK_INBAND_DRV_HDR_TYPE_START)
849 {
850 if (device->link[linkId].inbandData.message != NULL)
851 {
852 NVSWITCH_PRINT(device, ERROR, "InBand: Got TYPE_START for existing data\n");
853 NVSWITCH_ASSERT(0);
854 goto cleanup;
855 }
856
857 device->link[linkId].inbandData.message =
858 nvswitch_os_malloc(sizeof(nvswitch_inband_data_list));
859 if (device->link[linkId].inbandData.message == NULL)
860 {
861 status = -NVL_NO_MEM;
862 goto cleanup;
863 }
864
865 device->link[linkId].inbandData.message->dataSize = 0;
866 }
867
868 if (device->link[linkId].inbandData.message == NULL)
869 {
870 NVSWITCH_PRINT(device, ERROR, "InBand: Data being sent without _START\n");
871 goto cleanup;
872 }
873
874 receiveBuffer = device->link[linkId].inbandData.message->data;
875
876 receiveBuffer += device->link[linkId].inbandData.message->dataSize;
877
878 if (((dataSize + device->link[linkId].inbandData.message->dataSize) >
879 NVSWITCH_INBAND_DATA_SIZE) ||
880 (dataSize > NVLINK_INBAND_MAX_XFER_SIZE) ||
881 (dataSize == 0))
882 {
883 NVSWITCH_PRINT(device, ERROR, "InBand: Msg is of wrong Size :DataSize = %d Msg Size= %d\n",
884 dataSize, device->link[linkId].inbandData.message->dataSize);
885 NVSWITCH_ASSERT(0);
886 goto cleanup;
887 }
888
889 for (i = 0; i < numEntries; i++)
890 {
891 status = nvswitch_minion_send_command(device, linkId,
892 NV_MINION_NVLINK_DL_CMD_COMMAND_READ_RX_BUFFER_MIDDLE, 0);
893 if (status != NV_OK)
894 {
895 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer receive"
896 "for entry %d failed\n", linkId, i);
897 goto cleanup;
898 }
899
900 regVal = NVSWITCH_MINION_RD32_LS10(device,
901 NVSWITCH_GET_LINK_ENG_INST(device, linkId, MINION),
902 _MINION, _NVLINK_DL_CMD_DATA(localLinkNumber));
903
904 bytesToXfer = NV_MIN(remainingBuffer, NVLINK_INBAND_MAX_XFER_AT_ONCE);
905
906 nvswitch_os_memcpy(receiveBuffer, ®Val, bytesToXfer);
907
908 receiveBuffer += bytesToXfer;
909 remainingBuffer -= bytesToXfer;
910 }
911
912 status = nvswitch_minion_send_command(device, linkId,
913 NV_MINION_NVLINK_DL_CMD_COMMAND_READ_RX_BUFFER_END, 0);
914 if (status != NV_OK)
915 {
916 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer receive"
917 "for entry %d failed\n", linkId, numEntries);
918 goto cleanup;
919 }
920
921 device->link[linkId].inbandData.message->dataSize += dataSize;
922
923 if (hdr.data & NVLINK_INBAND_DRV_HDR_TYPE_END)
924 {
925 nvswitch_filter_messages(device, linkId);
926 }
927
928 return;
929
930 cleanup:
931 tempStatus = nvswitch_minion_send_command(device, linkId,
932 NV_MINION_NVLINK_DL_CMD_COMMAND_CLEAR_RX_BUFFER,
933 0);
934 if (tempStatus != NVL_SUCCESS)
935 {
936 NVSWITCH_PRINT(device, ERROR, "Link %d Inband Buffer transfer for RX_BUFFER_CLEAR\n", linkId);
937 return;
938 }
939 if (device->link[linkId].inbandData.message != NULL)
940 {
941 nvswitch_os_free(device->link[linkId].inbandData.message);
942 device->link[linkId].inbandData.message = NULL;
943 }
944 //TODO: Check if we need to send a failure msg to client?
945 #endif
946 }
947
948 NvlStatus
nvswitch_minion_get_ali_debug_registers_ls10(nvswitch_device * device,nvlink_link * link,NVSWITCH_MINION_ALI_DEBUG_REGISTERS * params)949 nvswitch_minion_get_ali_debug_registers_ls10
950 (
951 nvswitch_device *device,
952 nvlink_link *link,
953 NVSWITCH_MINION_ALI_DEBUG_REGISTERS *params
954 )
955 {
956 NvU32 localLinkNumber = link->linkNumber % NVSWITCH_LINKS_PER_MINION_LS10;
957 if (nvswitch_minion_get_dl_status(device, link->linkNumber,
958 NV_NVLSTAT_MN00, 0, &(params->dlstatMn00)) != NVL_SUCCESS)
959 {
960 NVSWITCH_PRINT(device, INFO,"%s : Failed to poll DLSTAT _MN00 register for (%s):(%d)\n",
961 __FUNCTION__, device->name, link->linkNumber);
962 }
963
964 if (nvswitch_minion_get_dl_status(device, link->linkNumber,
965 NV_NVLSTAT_UC01, 0, &(params->dlstatUc01)) != NVL_SUCCESS)
966 {
967 NVSWITCH_PRINT(device, INFO,"%s : Failed to poll DLSTAT UC01 register for (%s):(%d)\n",
968 __FUNCTION__, device->name, link->linkNumber);
969 }
970
971 params->dlstatLinkIntr = NVSWITCH_MINION_LINK_RD32_LS10(device, link->linkNumber,
972 _MINION, _NVLINK_LINK_INTR(localLinkNumber));
973
974 return NVL_SUCCESS;
975 }
976
977