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, &regVal, 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