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 "soe/soe_nvswitch.h"
25 #include "soe/soe_priv_nvswitch.h"
26 
27 #include "rmlsfm.h"
28 
29 #include "nvlink_export.h"
30 
31 #include "common_nvswitch.h"
32 #include "ls10/ls10.h"
33 #include "ls10/soe_ls10.h"
34 
35 #include "nvswitch/ls10/dev_soe_ip.h"
36 #include "nvswitch/ls10/dev_soe_ip_addendum.h"
37 #include "nvswitch/ls10/dev_falcon_v4.h"
38 #include "nvswitch/ls10/dev_nvlsaw_ip.h"
39 #include "nvswitch/ls10/dev_nvlsaw_ip_addendum.h"
40 #include "nvswitch/ls10/dev_riscv_pri.h"
41 
42 #include "flcn/flcnable_nvswitch.h"
43 #include "flcn/flcn_nvswitch.h"
44 #include "rmflcncmdif_nvswitch.h"
45 #include "soe/soeifcmn.h"
46 
47 /**
48  * @brief   Sets pEngDescUc and pEngDescBc to the discovered
49  * engine that matches this flcnable instance
50  *
51  * @param[in]   device       nvswitch_device pointer
52  * @param[in]   pSoe         SOE pointer
53  * @param[out]  pEngDescUc  pointer to the UniCast Engine
54  *       Descriptor
55  * @param[out]  pEngDescBc  pointer to the BroadCast Engine
56  *       Descriptor
57  */
58 static void
_soeFetchEngines_LS10(nvswitch_device * device,FLCNABLE * pSoe,ENGINE_DESCRIPTOR_TYPE * pEngDescUc,ENGINE_DESCRIPTOR_TYPE * pEngDescBc)59 _soeFetchEngines_LS10
60 (
61     nvswitch_device         *device,
62     FLCNABLE                *pSoe,
63     ENGINE_DESCRIPTOR_TYPE *pEngDescUc,
64     ENGINE_DESCRIPTOR_TYPE *pEngDescBc
65 )
66 {
67     pEngDescUc->initialized = NV_FALSE;
68     if (NVSWITCH_ENG_IS_VALID(device, SOE, 0))
69     {
70         pEngDescUc->base = NVSWITCH_GET_ENG(device, SOE, , 0);
71     }
72     else
73     {
74         pEngDescUc->base = 0;
75     }
76 
77     pEngDescBc->initialized = NV_FALSE;
78     pEngDescBc->base = 0;
79 }
80 
81 /*
82  * @Brief : Send a test command to SOE
83  *
84  * @param   device  The nvswitch device
85  */
86 static NV_STATUS
_nvswitch_soe_send_test_cmd(nvswitch_device * device)87 _nvswitch_soe_send_test_cmd
88 (
89     nvswitch_device *device
90 )
91 {
92     RM_FLCN_CMD_SOE     cmd;
93     NVSWITCH_TIMEOUT    timeout;
94     NvU32               cmdSeqDesc;
95     NV_STATUS           status;
96 
97     FLCN *pFlcn = device->pSoe->pFlcn;
98 
99     nvswitch_os_memset(&cmd, 0, sizeof(cmd));
100 
101     cmd.hdr.unitId = RM_SOE_UNIT_NULL;
102     // sending nothing but a header for UNIT_NULL
103     cmd.hdr.size   = RM_FLCN_QUEUE_HDR_SIZE;
104 
105     nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS * 5, &timeout);
106     status = flcnQueueCmdPostBlocking(device, pFlcn,
107                                 (PRM_FLCN_CMD)&cmd,
108                                 NULL,   // pMsg             - not used for now
109                                 NULL,   // pPayload         - not used for now
110                                 SOE_RM_CMDQ_LOG_ID,
111                                 &cmdSeqDesc,
112                                 &timeout);
113 
114     NVSWITCH_ASSERT(status == NVL_SUCCESS);
115     return status;
116 }
117 
118 #if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
119 /*!
120  * Helper function to dump some registers for debug.
121  *
122  * @param[in]  device  nvswitch_device pointer
123  */
124 static void
dumpDebugRegisters(nvswitch_device * device)125 dumpDebugRegisters
126 (
127     nvswitch_device *device
128 )
129 {
130     FLCN *pFlcn = device->pSoe->pFlcn;
131 
132     NvU32 regOS              = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_OS);
133     NvU32 regPC              = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_RPC);
134     NvU32 regCPUCTL          = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_CPUCTL);
135     NvU32 regIDLESTATE       = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_IDLESTATE);
136     NvU32 regMAILBOX0        = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_MAILBOX0);
137     NvU32 regMAILBOX1        = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_MAILBOX1);
138     NvU32 regIRQSTAT         = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQSTAT);
139     NvU32 regIRQMODE         = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQMODE);
140     NvU32 regIRQMASK         = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_IRQMASK);
141     NvU32 regIRQDEST         = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_IRQDEST);
142     NvU32 regIRQDELEG        = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_IRQDELEG);
143     NvU32 regDMACTL          = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMACTL);
144     NvU32 regDMATRFCMD       = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMATRFCMD);
145     NvU32 regDMATRFBASE      = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMATRFBASE);
146     NvU32 regDMATRFMOFFS     = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMATRFMOFFS);
147     NvU32 regDMATRFFBOFFS    = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMATRFFBOFFS);
148     NvU32 regPRIVERR_STAT    = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_PRIV_ERR_STAT);
149     NvU32 regPRIVERR_INFO    = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_PRIV_ERR_INFO);
150     NvU32 regPRIVERR_ADDR_HI = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_PRIV_ERR_ADDR_HI);
151     NvU32 regPRIVERR_ADDR_LO = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_PRIV_ERR_ADDR);
152     NvU32 regHUBERR_STAT     = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_HUB_ERR_STAT);
153     NvU32 regBCR_CTRL        = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_BCR_CTRL);
154     NvU32 regRESET_PLM       = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_RESET_PRIV_LEVEL_MASK);
155     NvU32 regEXE_PLM         = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_EXE_PRIV_LEVEL_MASK);
156 
157     NVSWITCH_PRINT(device, ERROR, "Peregrine Registers:\n");
158     NVSWITCH_PRINT(device, ERROR, "OS                    : 0x%08x\n", regOS);
159     NVSWITCH_PRINT(device, ERROR, "PC (lo32)             : 0x%08x\n", regPC);
160     NVSWITCH_PRINT(device, ERROR, "CPUCTL                : 0x%08x\n", regCPUCTL);
161     NVSWITCH_PRINT(device, ERROR, "IDLESTATE             : 0x%08x\n", regIDLESTATE);
162     NVSWITCH_PRINT(device, ERROR, "MAILBOX0              : 0x%08x\n", regMAILBOX0);
163     NVSWITCH_PRINT(device, ERROR, "MAILBOX1              : 0x%08x\n", regMAILBOX1);
164     NVSWITCH_PRINT(device, ERROR, "IRQSTAT               : 0x%08x\n", regIRQSTAT);
165     NVSWITCH_PRINT(device, ERROR, "IRQMODE               : 0x%08x\n", regIRQMODE);
166     NVSWITCH_PRINT(device, ERROR, "IRQMASK               : 0x%08x\n", regIRQMASK);
167     NVSWITCH_PRINT(device, ERROR, "IRQDEST               : 0x%08x\n", regIRQDEST);
168     NVSWITCH_PRINT(device, ERROR, "IRQDELEG              : 0x%08x\n", regIRQDELEG);
169     NVSWITCH_PRINT(device, ERROR, "DMACTL                : 0x%08x\n", regDMACTL);
170     NVSWITCH_PRINT(device, ERROR, "DMATRFCMD             : 0x%08x\n", regDMATRFCMD);
171     NVSWITCH_PRINT(device, ERROR, "DMATRFBASE            : 0x%08x\n", regDMATRFBASE);
172     NVSWITCH_PRINT(device, ERROR, "DMATRFMOFFS           : 0x%08x\n", regDMATRFMOFFS);
173     NVSWITCH_PRINT(device, ERROR, "DMATRFFBOFFS          : 0x%08x\n", regDMATRFFBOFFS);
174     NVSWITCH_PRINT(device, ERROR, "PRIVERR_STAT          : 0x%08x\n", regPRIVERR_STAT);
175     NVSWITCH_PRINT(device, ERROR, "PRIVERR_INFO          : 0x%08x\n", regPRIVERR_INFO);
176     NVSWITCH_PRINT(device, ERROR, "PRIVERR_ADDR          : 0x%08x%08x\n", regPRIVERR_ADDR_HI, regPRIVERR_ADDR_LO);
177     NVSWITCH_PRINT(device, ERROR, "HUBERR_STAT           : 0x%08x\n", regHUBERR_STAT);
178     NVSWITCH_PRINT(device, ERROR, "BCR_CTRL              : 0x%08x\n", regBCR_CTRL);
179     NVSWITCH_PRINT(device, ERROR, "RESET_PLM             : 0x%08x\n", regRESET_PLM);
180     NVSWITCH_PRINT(device, ERROR, "EXE_PLM               : 0x%08x\n", regEXE_PLM);
181 }
182 #endif  // defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
183 
184 /*
185  * @Brief : Attach or Detach driver to SOE Queues
186  *
187  * @param[in] device
188  */
189 static void
_nvswitch_soe_attach_detach_driver_ls10(nvswitch_device * device,NvBool bAttach)190 _nvswitch_soe_attach_detach_driver_ls10
191 (
192     nvswitch_device *device,
193     NvBool bAttach
194 )
195 {
196     NvU32 val;
197 
198     val = NVSWITCH_SAW_RD32_LS10(device, _NVLSAW, _DRIVER_ATTACH_DETACH);
199 
200     if (bAttach)
201     {
202         val = FLD_SET_DRF(_NVLSAW, _DRIVER_ATTACH_DETACH, _STATUS,
203                           _ATTACHED, val);
204     }
205     else
206     {
207         val = FLD_SET_DRF(_NVLSAW, _DRIVER_ATTACH_DETACH, _STATUS,
208                           _DETACHED, val);
209     }
210 
211     NVSWITCH_SAW_WR32_LS10(device, _NVLSAW, _DRIVER_ATTACH_DETACH, val);
212 }
213 
214 /*
215  * @Brief : Returns if SOE is attached to the Queues
216  *
217  * @param[in] device
218  */
219 static NvBool
_nvswitch_is_soe_attached_ls10(nvswitch_device * device)220 _nvswitch_is_soe_attached_ls10
221 (
222     nvswitch_device *device
223 )
224 {
225     NvU32 val;
226     NvBool bSoeAttached;
227 
228     val = NVSWITCH_SAW_RD32_LS10(device, _NVLSAW, _SOE_ATTACH_DETACH);
229     bSoeAttached = FLD_TEST_DRF(_NVLSAW, _SOE_ATTACH_DETACH, _STATUS, _ATTACHED, val);
230 
231     return bSoeAttached;
232 }
233 
234 /*
235  * @Brief : Backup NPORT state and issue NPORT reset
236  *
237  * @param[in] device
238  * @param[in] nport
239  */
240 NvlStatus
nvswitch_soe_issue_nport_reset_ls10(nvswitch_device * device,NvU32 nport)241 nvswitch_soe_issue_nport_reset_ls10
242 (
243     nvswitch_device *device,
244     NvU32 nport
245 )
246 {
247     FLCN *pFlcn = device->pSoe->pFlcn;
248     NvU32               cmdSeqDesc = 0;
249     NV_STATUS           status;
250     RM_FLCN_CMD_SOE     cmd;
251     NVSWITCH_TIMEOUT    timeout;
252     RM_SOE_CORE_CMD_NPORT_RESET *pNportReset;
253 
254     nvswitch_os_memset(&cmd, 0, sizeof(cmd));
255 
256     cmd.hdr.unitId = RM_SOE_UNIT_CORE;
257     cmd.hdr.size   = RM_SOE_CMD_SIZE(CORE, NPORT_RESET);
258 
259     pNportReset = &cmd.cmd.core.nportReset;
260     pNportReset->nport = nport;
261     pNportReset->cmdType = RM_SOE_CORE_CMD_ISSUE_NPORT_RESET;
262 
263     nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
264     status = flcnQueueCmdPostBlocking(device, pFlcn,
265                                       (PRM_FLCN_CMD)&cmd,
266                                       NULL,                 // pMsg
267                                       NULL,                 // pPayload
268                                       SOE_RM_CMDQ_LOG_ID,
269                                       &cmdSeqDesc,
270                                       &timeout);
271     if (status != NV_OK)
272     {
273         NVSWITCH_PRINT(device, ERROR, "%s: Failed to send NPORT RESET command to SOE status 0x%x\n",
274                        __FUNCTION__, status);
275         return -NVL_ERR_INVALID_STATE;
276     }
277 
278     return NVL_SUCCESS;
279 }
280 
281 /*
282  * @Brief : De-Assert NPORT reset and restore NPORT state
283  *
284  * @param[in] device
285  * @param[in] nport
286  */
287 NvlStatus
nvswitch_soe_restore_nport_state_ls10(nvswitch_device * device,NvU32 nport)288 nvswitch_soe_restore_nport_state_ls10
289 (
290     nvswitch_device *device,
291     NvU32 nport
292 )
293 {
294     FLCN *pFlcn       = device->pSoe->pFlcn;
295     NvU32               cmdSeqDesc = 0;
296     NV_STATUS           status;
297     RM_FLCN_CMD_SOE     cmd;
298     NVSWITCH_TIMEOUT    timeout;
299     RM_SOE_CORE_CMD_NPORT_STATE *pNportState;
300 
301     nvswitch_os_memset(&cmd, 0, sizeof(cmd));
302 
303     cmd.hdr.unitId = RM_SOE_UNIT_CORE;
304     cmd.hdr.size   = RM_SOE_CMD_SIZE(CORE, NPORT_STATE);
305 
306     pNportState = &cmd.cmd.core.nportState;
307     pNportState->nport = nport;
308     pNportState->cmdType = RM_SOE_CORE_CMD_RESTORE_NPORT_STATE;
309 
310     nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
311     status = flcnQueueCmdPostBlocking(device, pFlcn,
312                                       (PRM_FLCN_CMD)&cmd,
313                                       NULL,                 // pMsg
314                                       NULL,                 // pPayload
315                                       SOE_RM_CMDQ_LOG_ID,
316                                       &cmdSeqDesc,
317                                       &timeout);
318     if (status != NV_OK)
319     {
320         NVSWITCH_PRINT(device, ERROR, "%s: Failed to send NPORT BACKUP command to SOE status 0x%x\n",
321                        __FUNCTION__, status);
322         return -NVL_ERR_INVALID_STATE;
323     }
324 
325     return NVL_SUCCESS;
326 }
327 
328 /*
329  * @Brief : Set NPORT TPROD state in SOE
330  *
331  * @param[in] device
332  * @param[in] nport
333  */
334 NvlStatus
nvswitch_set_nport_tprod_state_ls10(nvswitch_device * device,NvU32 nport)335 nvswitch_set_nport_tprod_state_ls10
336 (
337     nvswitch_device *device,
338     NvU32 nport
339 )
340 {
341     FLCN *pFlcn       = device->pSoe->pFlcn;
342     NvU32               cmdSeqDesc = 0;
343     NV_STATUS           status;
344     RM_FLCN_CMD_SOE     cmd;
345     NVSWITCH_TIMEOUT    timeout;
346     RM_SOE_CORE_CMD_NPORT_TPROD_STATE *nportTprodState;
347 
348     if (!NVSWITCH_ENG_IS_VALID(device, NPORT, nport))
349     {
350          NVSWITCH_PRINT(device, ERROR, "%s: NPORT #%d invalid\n",
351                         __FUNCTION__, nport);
352         return -NVL_BAD_ARGS;
353     }
354 
355     nvswitch_os_memset(&cmd, 0, sizeof(cmd));
356 
357     cmd.hdr.unitId = RM_SOE_UNIT_CORE;
358     cmd.hdr.size   = RM_SOE_CMD_SIZE(CORE, NPORT_TPROD_STATE);
359 
360     nportTprodState = &cmd.cmd.core.nportTprodState;
361     nportTprodState->nport = nport;
362     nportTprodState->cmdType = RM_SOE_CORE_CMD_SET_NPORT_TPROD_STATE;
363 
364     nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
365     status = flcnQueueCmdPostBlocking(device, pFlcn,
366                                       (PRM_FLCN_CMD)&cmd,
367                                       NULL,                 // pMsg
368                                       NULL,                 // pPayload
369                                       SOE_RM_CMDQ_LOG_ID,
370                                       &cmdSeqDesc,
371                                       &timeout);
372     if (status != NV_OK)
373     {
374         NVSWITCH_PRINT(device, ERROR, "%s: Failed to send NPORT SET_TPROD_STATE command to SOE, status 0x%x\n",
375                        __FUNCTION__, status);
376         return -NVL_ERR_INVALID_STATE;
377     }
378 
379     return NVL_SUCCESS;
380 }
381 
382 /*
383  * @Brief : INIT L2 register state in SOE
384  *
385  * @param[in] device
386  * @param[in] nport
387  */
388 void
nvswitch_soe_init_l2_state_ls10(nvswitch_device * device)389 nvswitch_soe_init_l2_state_ls10
390 (
391     nvswitch_device *device
392 )
393 {
394     FLCN            *pFlcn;
395     NvU32            cmdSeqDesc = 0;
396     NV_STATUS        status;
397     RM_FLCN_CMD_SOE  cmd;
398     NVSWITCH_TIMEOUT timeout;
399     RM_SOE_CORE_CMD_L2_STATE *pL2State;
400 
401     if (!nvswitch_is_soe_supported(device))
402     {
403         NVSWITCH_PRINT(device, INFO, "%s: SOE is not supported\n",
404                        __FUNCTION__);
405         return;
406     }
407 
408     pFlcn       = device->pSoe->pFlcn;
409 
410     nvswitch_os_memset(&cmd, 0, sizeof(cmd));
411     cmd.hdr.unitId = RM_SOE_UNIT_CORE;
412     cmd.hdr.size   = RM_SOE_CMD_SIZE(CORE, L2_STATE);
413 
414     pL2State = &cmd.cmd.core.l2State;
415     pL2State->cmdType = RM_SOE_CORE_CMD_INIT_L2_STATE;
416 
417     nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
418     status = flcnQueueCmdPostBlocking(device, pFlcn,
419                                       (PRM_FLCN_CMD)&cmd,
420                                       NULL,                 // pMsg
421                                       NULL,                 // pPayload
422                                       SOE_RM_CMDQ_LOG_ID,
423                                       &cmdSeqDesc,
424                                       &timeout);
425     if (status != NV_OK)
426     {
427         NVSWITCH_PRINT(device, ERROR, "%s: Failed to send INIT_L2_STATE command to SOE, status 0x%x\n",
428                        __FUNCTION__, status);
429     }
430 }
431 
432 /*
433  * @Brief : Enable/Disable NPORT interrupts
434  *
435  * @param[in] device
436  * @param[in] nport
437  */
438 NvlStatus
nvswitch_soe_set_nport_interrupts_ls10(nvswitch_device * device,NvU32 nport,NvBool bEnable)439 nvswitch_soe_set_nport_interrupts_ls10
440 (
441     nvswitch_device *device,
442     NvU32           nport,
443     NvBool          bEnable
444 )
445 {
446     FLCN            *pFlcn;
447     NvU32            cmdSeqDesc = 0;
448     NV_STATUS        status;
449     RM_FLCN_CMD_SOE  cmd;
450     NVSWITCH_TIMEOUT timeout;
451     RM_SOE_CORE_CMD_NPORT_INTRS *pNportIntrs;
452 
453     if (!nvswitch_is_soe_supported(device))
454     {
455         NVSWITCH_PRINT(device, ERROR,
456             "%s: SOE is not supported\n",
457             __FUNCTION__);
458         return -NVL_ERR_INVALID_STATE;
459     }
460 
461     pFlcn       = device->pSoe->pFlcn;
462 
463     nvswitch_os_memset(&cmd, 0, sizeof(cmd));
464     cmd.hdr.unitId = RM_SOE_UNIT_CORE;
465     cmd.hdr.size   = RM_SOE_CMD_SIZE(CORE, NPORT_INTRS);
466 
467     pNportIntrs = &cmd.cmd.core.nportIntrs;
468     pNportIntrs->cmdType = RM_SOE_CORE_CMD_SET_NPORT_INTRS;
469     pNportIntrs->nport = nport;
470     pNportIntrs->bEnable = bEnable;
471 
472     nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
473     status = flcnQueueCmdPostBlocking(device, pFlcn,
474                                       (PRM_FLCN_CMD)&cmd,
475                                       NULL,                 // pMsg
476                                       NULL,                 // pPayload
477                                       SOE_RM_CMDQ_LOG_ID,
478                                       &cmdSeqDesc,
479                                       &timeout);
480     if (status != NV_OK)
481     {
482         NVSWITCH_PRINT(device, ERROR,
483             "%s: Failed to send SET_NPORT_INTRS command to SOE, status 0x%x\n",
484             __FUNCTION__, status);
485         return -NVL_ERR_GENERIC;
486     }
487 
488     return NVL_SUCCESS;
489 }
490 
491 /*
492  * @Brief : Disable NPORT Fatal Interrupt in SOE
493  *
494  * @param[in] device
495  * @param[in] nport
496  * @param[in] nportIntrEnable
497  * @param[in] nportIntrType
498  */
499 void
nvswitch_soe_disable_nport_fatal_interrupts_ls10(nvswitch_device * device,NvU32 nport,NvU32 nportIntrEnable,NvU8 nportIntrType)500 nvswitch_soe_disable_nport_fatal_interrupts_ls10
501 (
502     nvswitch_device *device,
503     NvU32 nport,
504     NvU32 nportIntrEnable,
505     NvU8  nportIntrType
506 )
507 {
508     FLCN            *pFlcn;
509     NvU32            cmdSeqDesc = 0;
510     NV_STATUS        status;
511     RM_FLCN_CMD_SOE  cmd;
512     NVSWITCH_TIMEOUT timeout;
513     RM_SOE_CORE_CMD_NPORT_FATAL_INTR *pNportIntrDisable;
514     NVSWITCH_GET_BIOS_INFO_PARAMS p = { 0 };
515 
516     status = device->hal.nvswitch_ctrl_get_bios_info(device, &p);
517     if ((status != NVL_SUCCESS) || ((p.version & SOE_VBIOS_VERSION_MASK) <
518             SOE_VBIOS_REVLOCK_DISABLE_NPORT_FATAL_INTR))
519     {
520         NVSWITCH_PRINT(device, ERROR,
521             "%s: Skipping DISABLE_NPORT_FATAL_INTR command to SOE.  Update firmware "
522             "from .%02X to .%02X\n",
523             __FUNCTION__, (NvU32)((p.version & SOE_VBIOS_VERSION_MASK) >> 16),
524                 SOE_VBIOS_REVLOCK_DISABLE_NPORT_FATAL_INTR);
525         return;
526     }
527 
528     if (!nvswitch_is_soe_supported(device))
529     {
530         NVSWITCH_PRINT(device, INFO, "%s: SOE is not supported\n",
531                        __FUNCTION__);
532         return;
533     }
534 
535     pFlcn       = device->pSoe->pFlcn;
536 
537     nvswitch_os_memset(&cmd, 0, sizeof(cmd));
538     cmd.hdr.unitId = RM_SOE_UNIT_CORE;
539     cmd.hdr.size   = RM_SOE_CMD_SIZE(CORE, NPORT_FATAL_INTR);
540 
541     pNportIntrDisable = &cmd.cmd.core.nportDisableIntr;
542     pNportIntrDisable->cmdType = RM_SOE_CORE_CMD_DISABLE_NPORT_FATAL_INTR;
543     pNportIntrDisable->nport   = nport;
544     pNportIntrDisable->nportIntrEnable = nportIntrEnable;
545     pNportIntrDisable->nportIntrType = nportIntrType;
546 
547     nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
548     status = flcnQueueCmdPostBlocking(device, pFlcn,
549                                       (PRM_FLCN_CMD)&cmd,
550                                       NULL,                 // pMsg
551                                       NULL,                 // pPayload
552                                       SOE_RM_CMDQ_LOG_ID,
553                                       &cmdSeqDesc,
554                                       &timeout);
555     if (status != NV_OK)
556     {
557         NVSWITCH_PRINT(device, ERROR, "%s: Failed to send DISABLE_NPORT_FATAL_INTR command to SOE, status 0x%x\n",
558                        __FUNCTION__, status);
559     }
560 }
561 
562 /*
563  * @Brief : Init sequence for SOE FSP RISCV image
564  *
565  * The driver assumes SOE is already booted by FSP.
566  * Driver checks for SOE state and  handshakes with a test command.
567  * If FSP or SOE fails to boot, driver fails and quits.
568  *
569  * @param[in] nvswitch device
570  */
571 NvlStatus
nvswitch_init_soe_ls10(nvswitch_device * device)572 nvswitch_init_soe_ls10
573 (
574     nvswitch_device *device
575 )
576 {
577     NvlStatus status;
578     NvU32 data;
579     FLCN *pFlcn = device->pSoe->pFlcn;
580 
581     //
582     // Check if SOE has halted unexpectedly.
583     //
584     // The explicit check is required because the interrupts
585     // are not yet enabled as the device is still initializing.
586     //
587     if (soeIsCpuHalted_HAL(device, ((PSOE)pFlcn->pFlcnable)))
588     {
589         NVSWITCH_PRINT(device, ERROR,
590             "%s: SOE halted\n",
591             __FUNCTION__);
592         NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_BOOTSTRAP,
593             "SOE init Failed(0)\n");
594         status = -NVL_ERR_INVALID_STATE;
595         goto nvswitch_init_soe_fail;
596     }
597 
598     // Check for SOE BOOT SUCCESS
599     data = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_MAILBOX1);
600     if (data != SOE_BOOTSTRAP_SUCCESS)
601     {
602         NVSWITCH_PRINT(device, ERROR,
603             "%s: SOE boot failed\n",
604             __FUNCTION__);
605         NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_BOOTSTRAP,
606             "SOE init failed(1)\n");
607         status = -NVL_ERR_INVALID_STATE;
608         goto nvswitch_init_soe_fail;
609     }
610 
611     // Register SOE callbacks
612     status = nvswitch_soe_register_event_callbacks(device);
613     if (status != NVL_SUCCESS)
614     {
615         NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_COMMAND_QUEUE,
616             "Failed to register SOE events\n");
617         NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_BOOTSTRAP,
618             "SOE init failed(2)\n");
619         return status;
620     }
621 
622     // Sanity the command and message queues as a final check
623     if (_nvswitch_soe_send_test_cmd(device) != NV_OK)
624     {
625         NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_BOOTSTRAP,
626             "SOE init failed(4)\n");
627         status = -NVL_ERR_INVALID_STATE;
628         goto nvswitch_init_soe_fail;
629     }
630 
631     NVSWITCH_PRINT(device, SETUP,
632                    "%s: SOE successfully bootstrapped.\n",
633                    __FUNCTION__);
634 
635     return NVL_SUCCESS;
636 
637 nvswitch_init_soe_fail :
638     // Log any failures SOE may have had during bootstrap
639     (void)soeService_HAL(device, ((PSOE)pFlcn->pFlcnable));
640 #if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
641         dumpDebugRegisters(device);
642 #endif // defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
643 
644     flcnDbgInfoCapturePcTrace_HAL(device, pFlcn);
645     NVSWITCH_ASSERT(0);
646     return status;
647 }
648 
649 /*
650  * @Brief : Shutdown SOE during driver unload
651  *
652  * @param[in] device Bootstrap SOE on this device
653  */
654 NvlStatus
nvswitch_unload_soe_ls10(nvswitch_device * device)655 nvswitch_unload_soe_ls10
656 (
657     nvswitch_device *device
658 )
659 {
660     // Detach driver from SOE Queues
661     _nvswitch_soe_attach_detach_driver_ls10(device, NV_FALSE);
662 
663     return NVL_SUCCESS;
664 }
665 
666 /*!
667  * @brief : Register callback functions for events and messages from SOE
668  *
669  * @param[in] device nvswitch_device pointer
670  */
671 NvlStatus
nvswitch_soe_register_event_callbacks_ls10(nvswitch_device * device)672 nvswitch_soe_register_event_callbacks_ls10
673 (
674     nvswitch_device *device
675 )
676 {
677 
678     NV_STATUS status;
679     PFLCN     pFlcn = device->pSoe->pFlcn;
680     PSOE      pSoe  = (PSOE)device->pSoe;
681 
682     // Register Thermal callback funcion
683     status = flcnQueueEventRegister(
684                  device, pFlcn,
685                  RM_SOE_UNIT_THERM,
686                  NULL,
687                  nvswitch_therm_soe_callback_ls10,
688                  NULL,
689                  &pSoe->thermEvtDesc);
690     if (status != NV_OK)
691     {
692         NVSWITCH_PRINT(device, ERROR,
693             "%s: Failed to register thermal event handler.\n",
694             __FUNCTION__);
695         return -NVL_ERR_INVALID_STATE;
696     }
697 
698     // Register CCI callback funcion
699     status = flcnQueueEventRegister(
700                 device, pFlcn,
701                 RM_SOE_UNIT_CCI,
702                 NULL,
703                 nvswitch_cci_soe_callback_ls10,
704                 NULL,
705                 &pSoe->cciEvtDesc);
706 
707     if (status != NV_OK)
708     {
709         NVSWITCH_PRINT(device, ERROR,
710             "%s: Failed to register CCI event handler.\n",
711             __FUNCTION__);
712         return -NVL_ERR_INVALID_STATE;
713     }
714 
715     // Register Heartbeat callback funcion
716     status = flcnQueueEventRegister(
717                 device, pFlcn,
718                 RM_SOE_UNIT_HEARTBEAT,
719                 NULL,
720                 nvswitch_heartbeat_soe_callback_ls10,
721                 NULL,
722                 &pSoe->heartbeatEvtDesc);
723 
724     if (status != NV_OK)
725     {
726         NVSWITCH_PRINT(device, ERROR,
727             "%s: Failed to register Heartbeat event handler.\n",
728             __FUNCTION__);
729         return -NVL_ERR_INVALID_STATE;
730     }
731 
732     return NVL_SUCCESS;
733 }
734 
735 void
nvswitch_soe_unregister_events_ls10(nvswitch_device * device)736 nvswitch_soe_unregister_events_ls10
737 (
738     nvswitch_device *device
739 )
740 {
741     PFLCN pFlcn = device->pSoe->pFlcn;
742     PSOE   pSoe  = (PSOE)device->pSoe;
743     NV_STATUS status;
744 
745     // un-register thermal callback funcion
746     status = flcnQueueEventUnregister(device, pFlcn,
747                                       pSoe->thermEvtDesc);
748     if (status != NV_OK)
749     {
750         NVSWITCH_PRINT(device, ERROR,
751             "%s: Failed to un-register thermal event handler.\n",
752             __FUNCTION__);
753     }
754     // un-register thermal callback funcion
755     status = flcnQueueEventUnregister(device, pFlcn,
756                                       pSoe->cciEvtDesc);
757     if (status != NV_OK)
758     {
759         NVSWITCH_PRINT(device, ERROR,
760             "%s: Failed to un-register cci event handler.\n",
761             __FUNCTION__);
762     }
763 
764     // un-register heartbeat callback funcion
765     status = flcnQueueEventUnregister(device, pFlcn,
766                                       pSoe->heartbeatEvtDesc);
767     if (status != NV_OK)
768     {
769         NVSWITCH_PRINT(device, ERROR,
770             "%s: Failed to un-register heartbeat event handler.\n",
771             __FUNCTION__);
772     }
773 }
774 
775 /*!
776  * @brief Determine if the SOE RISCV CPU is halted
777  *
778  * @param[in] device         nvswitch_device  pointer
779  * @param[in] pSoe           SOE  pointer
780  *
781  * @return NvBool reflecting the SOE Riscv CPU halted state
782  */
783 static NvBool
_soeIsCpuHalted_LS10(nvswitch_device * device,PSOE pSoe)784 _soeIsCpuHalted_LS10
785 (
786     nvswitch_device *device,
787     PSOE             pSoe
788 )
789 {
790     NvU32 data;
791 
792     data = NVSWITCH_SOE_RD32_LS10(device, 0, _SOE_RISCV, _CPUCTL);
793     return FLD_TEST_DRF(_PFALCON, _FALCON_CPUCTL, _HALTED, _TRUE, data);
794 }
795 
796 static NvU32
_soeIntrStatus_LS10(nvswitch_device * device)797 _soeIntrStatus_LS10
798 (
799     nvswitch_device *device
800 )
801 {
802     NvU32 irq, mask, dest;
803 
804     irq =  NVSWITCH_SOE_RD32_LS10(device, 0, _SOE_FALCON, _IRQSTAT);
805     mask = NVSWITCH_SOE_RD32_LS10(device, 0, _SOE_RISCV,  _IRQMASK);
806     dest = NVSWITCH_SOE_RD32_LS10(device, 0, _SOE_RISCV,  _IRQDEST);
807 
808     return (irq & mask & dest);
809 }
810 
811 /*!
812  * @brief Top level service routine
813  *
814  * @param[in] device         nvswitch_device  pointer
815  * @param[in] pSoe           SOE  pointer
816  *
817  * @return 32-bit interrupt status AFTER all known interrupt-sources were
818  *         serviced.
819  */
820 static NvU32
_soeService_LS10(nvswitch_device * device,PSOE pSoe)821 _soeService_LS10
822 (
823     nvswitch_device *device,
824     PSOE             pSoe
825 )
826 {
827     NvBool  bRecheckMsgQ    = NV_FALSE;
828     NvBool  bRecheckPrintQ  = NV_FALSE;
829     NvU32   clearBits       = 0;
830     NvU32   intrStatus;
831     PFLCN   pFlcn  = ENG_GET_FLCN(pSoe);
832 
833     if (pFlcn == NULL)
834     {
835         NVSWITCH_ASSERT(0);
836         return NV_ERR_INVALID_ARGUMENT;
837     }
838 
839     // Get the IRQ status and mask the sources not directed to host.
840     intrStatus =  _soeIntrStatus_LS10(device);
841 
842     // Exit if there is nothing to do
843     if (intrStatus == 0)
844     {
845        return 0;
846     }
847 
848     // Service pending interrupts
849     if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _WDTMR, _TRUE))
850     {
851         NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_WATCHDOG,
852             "SOE Watchdog error\n");
853         NVSWITCH_PRINT(device, INFO,
854                     "%s: Watchdog timer fired. We do not support this "
855                     "yet.\n", __FUNCTION__);
856         NVSWITCH_ASSERT(0);
857 
858         clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _WDTMR, _SET);
859     }
860 
861     if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _EXTERR, _TRUE))
862     {
863         clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _EXTERR, _SET);
864 
865         NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_EXTERR, "SOE EXTERR\n");
866     }
867 
868     if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _HALT, _TRUE))
869     {
870         clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _HALT, _SET);
871 
872         NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_HALT, "SOE HALTED\n");
873         soeServiceHalt_HAL(device, pSoe);
874     }
875 
876     if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _SWGEN0, _TRUE))
877     {
878         clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _SWGEN0, _SET);
879 
880         NVSWITCH_PRINT(device, MMIO,
881                     "%s: Received a message from SOE via SWGEN0\n",
882                     __FUNCTION__);
883         soeProcessMessages_HAL(device, pSoe);
884         bRecheckMsgQ = NV_TRUE;
885     }
886 
887     if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _SWGEN1, _TRUE))
888     {
889         clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _SWGEN1, _SET);
890 
891         NVSWITCH_PRINT(device, INFO,
892                     "%s: Received a SWGEN1 interrupt\n",
893                     __FUNCTION__);
894         flcnDebugBufferDisplay_HAL(device, pFlcn);
895         bRecheckPrintQ = NV_TRUE;
896     }
897 
898     // Clear any sources that were serviced and get the new status.
899     flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQSCLR, clearBits);
900 
901     // Re-read interrupt status before retriggering to return correct value
902     intrStatus =  _soeIntrStatus_LS10(device);
903 
904     //
905     // If we just processed a SWGEN0 message queue interrupt, peek
906     // into the message queue and see if any messages were missed the last time
907     // the queue was purged (above). If it is not empty, re-generate SWGEN0
908     // (since it is now cleared) and exit. As long as an interrupt is pending,
909     // this function will be re-entered and the message(s) will be processed.
910     //
911     if (bRecheckMsgQ)
912     {
913         PFALCON_QUEUE_INFO      pQueueInfo;
914         FLCNQUEUE              *pMsgQ;
915 
916         pQueueInfo = pFlcn->pQueueInfo;
917 
918         NVSWITCH_ASSERT(pQueueInfo != NULL);
919         NVSWITCH_ASSERT(pQueueInfo->pQueues != NULL);
920 
921         pMsgQ = &pQueueInfo->pQueues[SOE_RM_MSGQ_LOG_ID];
922 
923         if (!pMsgQ->isEmpty(device, pFlcn, pMsgQ))
924         {
925            // It is not necessary to RMW IRQSSET (zeros are ignored)
926            flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQSSET,
927                             DRF_DEF(_PFALCON, _FALCON_IRQSSET, _SWGEN0, _SET));
928         }
929     }
930 
931     //
932     // If we just processed a SWGEN1 interrupt (Debug Buffer interrupt), peek
933     // into the Debug Buffer and see if any text was missed the last time
934     // the buffer was displayed (above). If it is not empty, re-generate SWGEN1
935     // (since it is now cleared) and exit. As long as an interrupt is pending,
936     // this function will be re-entered and the message(s) will be processed.
937     //
938     if (bRecheckPrintQ)
939     {
940         if (!flcnDebugBufferIsEmpty_HAL(device, pFlcn))
941         {
942             flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQSSET,
943                               DRF_DEF(_PFALCON, _FALCON_IRQSSET, _SWGEN1, _SET));
944         }
945     }
946 
947     flcnIntrRetrigger_HAL(device, pFlcn);
948 
949     return intrStatus;
950 }
951 
952 /*!
953  * Called by soeService to handle a SOE halt. This function will dump the
954  * current status of SOE and then trap the CPU for further inspection for a
955  * debug build.
956  *
957  * @param[in]  device  nvswitch_device pointer
958  * @param[in]  pSoe    SOE object pointer
959  */
960 static void
_soeServiceHalt_LS10(nvswitch_device * device,PSOE pSoe)961 _soeServiceHalt_LS10
962 (
963     nvswitch_device *device,
964     PSOE             pSoe
965 )
966 {
967     PFLCN    pFlcn = ENG_GET_FLCN(pSoe);
968 
969     NVSWITCH_PRINT(device, ERROR,
970                 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
971                 "!!                   ** SOE HALTED **                !!\n"
972                 "!! Please file a bug with the following information. !!\n"
973                 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
974 
975 #if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
976     dumpDebugRegisters(device);
977 #endif // defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
978 
979     flcnDbgInfoCaptureRiscvPcTrace_HAL(device, pFlcn);
980     NVSWITCH_ASSERT(0);
981 }
982 
983 /*!
984  * Use the SOE INIT Message to construct, initialize or update SOE Queues.
985  *
986  * @param[in]      device nvswitch_device pointer
987  * @param[in]      pSoe   SOE object pointer
988  *
989  * @return 'NV_OK' upon successful creation of all SOE Queues
990  */
991 static NV_STATUS
_soeUpdateInitMsgQueuesInfo(nvswitch_device * device,PSOE pSoe)992 _soeUpdateInitMsgQueuesInfo
993 (
994     nvswitch_device  *device,
995     PSOE              pSoe
996 )
997 {
998     FLCNQUEUE                *pQueue;
999     PFLCN                     pFlcn = ENG_GET_FLCN(pSoe);
1000     PFALCON_QUEUE_INFO        pQueueInfo;
1001     NvU32                     queueOffset;
1002     NvU16                     queueSize;
1003     NvU8                      queuePhyId;
1004     NvU8                      queueLogId;
1005     NV_STATUS                 status;
1006 
1007     //
1008     // No command should be longer than half the queue size.
1009     // See _soeQueueCmdValidate_IMPL().
1010     //
1011     ct_assert(sizeof(RM_FLCN_CMD_SOE) <= (SOE_CMD_QUEUE_LENGTH / 2));
1012 
1013     NVSWITCH_ASSERT(pFlcn != NULL);
1014 
1015     pQueueInfo = pFlcn->pQueueInfo;
1016     NVSWITCH_ASSERT(pQueueInfo != NULL);
1017 
1018     // Construct DMEM for CMDQ
1019     queueOffset = SOE_EMEM_CHANNEL_CMDQ_OFFSET;
1020     queueSize   = SOE_CMD_QUEUE_LENGTH;
1021     queuePhyId  = 0;
1022     queueLogId  = SOE_RM_CMDQ_LOG_ID;
1023     pQueue = &pQueueInfo->pQueues[queueLogId];
1024     status = flcnQueueConstruct_dmem_nvswitch(
1025                  device,
1026                  pFlcn,
1027                  &pQueue,                  // ppQueue
1028                  queueLogId,               // Logical ID of the queue
1029                  queuePhyId,               // Physical ID of the queue
1030                  queueOffset,              // offset
1031                  queueSize,                // size
1032                  RM_FLCN_QUEUE_HDR_SIZE);  // cmdHdrSize
1033     if (status != NV_OK)
1034     {
1035         NVSWITCH_PRINT(device, ERROR,
1036             "%s: Error constructing SOE CmdQueue (status="
1037             "0x%08x).\n", __FUNCTION__, status);
1038         NVSWITCH_ASSERT(0);
1039         return status;
1040     }
1041 
1042     // Construct DMEM for MSGQ
1043     queueOffset = SOE_EMEM_CHANNEL_MSGQ_OFFSET;
1044     queueSize   = SOE_MSG_QUEUE_LENGTH;
1045     queuePhyId  = 0;
1046     queueLogId  = SOE_RM_MSGQ_LOG_ID;
1047     pQueue = &pQueueInfo->pQueues[queueLogId];
1048     status = flcnQueueConstruct_dmem_nvswitch(
1049                  device,
1050                  pFlcn,
1051                  &pQueue,                  // ppQueue
1052                  queueLogId,               // Logical ID of the queue
1053                  queuePhyId,               // Physical ID of the queue
1054                  queueOffset,              // offset
1055                  queueSize,                // size
1056                  RM_FLCN_QUEUE_HDR_SIZE);  // cmdHdrSize
1057     if (status != NV_OK)
1058     {
1059         NVSWITCH_PRINT(device, ERROR,
1060             "%s: Error constructing SOE MsgQueue (status="
1061             "0x%08x).\n", __FUNCTION__, status);
1062         NVSWITCH_ASSERT(0);
1063         return status;
1064     }
1065 
1066     pFlcn->bOSReady = NV_TRUE;
1067 
1068     return NV_OK;
1069 }
1070 
1071 static NV_STATUS
_soeWaitForInitAck_LS10(nvswitch_device * device,PSOE pSoe)1072 _soeWaitForInitAck_LS10
1073 (
1074     nvswitch_device    *device,
1075     PSOE               pSoe
1076 )
1077 {
1078     NV_STATUS status;
1079     PFLCN     pFlcn  = ENG_GET_FLCN(pSoe);
1080 
1081     if (!_nvswitch_is_soe_attached_ls10(device))
1082     {
1083         NVSWITCH_PRINT(device, ERROR,
1084             "%s SOE is not to attached!\n",
1085             __FUNCTION__);
1086         NVSWITCH_ASSERT(0);
1087         return NV_ERR_NOT_READY;
1088     }
1089 
1090     // Update InitMsg Queue info before sending any commands
1091     if (!pFlcn->bOSReady)
1092     {
1093         status = _soeUpdateInitMsgQueuesInfo(device, pSoe);
1094         if (status != NV_OK)
1095         {
1096             NVSWITCH_PRINT(device, ERROR,
1097                 "%s Failed to attach driver!\n",
1098                 __FUNCTION__);
1099                 NVSWITCH_ASSERT(0);
1100                 return status;
1101         }
1102 
1103         // Attach driver to SOE Queues
1104         _nvswitch_soe_attach_detach_driver_ls10(device, NV_TRUE);
1105     }
1106 
1107     return NV_OK;
1108 }
1109 
1110 /*!
1111  * Purges all the messages from the SOE's message queue.  Each message will
1112  * be analyzed, clients will be notified of status, and events will be routed
1113  * to all registered event listeners.
1114  *
1115  * @param[in]  device nvswitch_device pointer
1116  * @param[in]  pSoe   SOE object pointer
1117  *
1118  * @return 'NV_OK' if the message queue was successfully purged.
1119  */
1120 static NV_STATUS
_soeProcessMessages_LS10(nvswitch_device * device,PSOE pSoe)1121 _soeProcessMessages_LS10
1122 (
1123     nvswitch_device *device,
1124     PSOE             pSoe
1125 )
1126 {
1127     RM_FLCN_MSG_SOE  soeMessage;
1128     NV_STATUS        status;
1129     PFLCN            pFlcn  = ENG_GET_FLCN(pSoe);
1130 
1131     // Update InitMsg Queue info before recieving any messages
1132     if (!pFlcn->bOSReady)
1133     {
1134         status = _soeUpdateInitMsgQueuesInfo(device, pSoe);
1135         if (status != NV_OK)
1136         {
1137             NVSWITCH_PRINT(device, ERROR,
1138                 "%s Failed to attach driver!\n",
1139                 __FUNCTION__);
1140                 NVSWITCH_ASSERT(0);
1141                 return status;
1142         }
1143 
1144         // Attach driver to SOE Queues
1145         _nvswitch_soe_attach_detach_driver_ls10(device, NV_TRUE);
1146     }
1147 
1148 
1149     // keep processing messages until no more exist in the message queue
1150     while (NV_OK == (status = flcnQueueReadData(
1151                                      device,
1152                                      pFlcn,
1153                                      SOE_RM_MSGQ_LOG_ID,
1154                                      (RM_FLCN_MSG *)&soeMessage, NV_TRUE)))
1155     {
1156         NVSWITCH_PRINT(device, MMIO,
1157                     "%s: unitId=0x%02x, size=0x%02x, ctrlFlags=0x%02x, " \
1158                     "seqNumId=0x%02x\n",
1159                     __FUNCTION__,
1160                     soeMessage.hdr.unitId,
1161                     soeMessage.hdr.size,
1162                     soeMessage.hdr.ctrlFlags,
1163                     soeMessage.hdr.seqNumId);
1164 
1165         // check to see if the message is a reply or an event.
1166         if ((soeMessage.hdr.ctrlFlags &= RM_FLCN_QUEUE_HDR_FLAGS_EVENT) != 0)
1167         {
1168             flcnQueueEventHandle(device, pFlcn, (RM_FLCN_MSG *)&soeMessage, NV_OK);
1169         }
1170         // the message is a response from a previously queued command
1171         else
1172         {
1173             flcnQueueResponseHandle(device, pFlcn, (RM_FLCN_MSG *)&soeMessage);
1174         }
1175     }
1176 
1177     //
1178     // Status NV_ERR_NOT_READY implies, Queue is empty.
1179     // Log the message in other error cases.
1180     //
1181     if (status != NV_ERR_NOT_READY)
1182     {
1183         NVSWITCH_PRINT(device, ERROR,
1184             "%s: unexpected error while purging message queue (status=0x%x).\n",
1185             __FUNCTION__, (status));
1186     }
1187 
1188     return status;
1189 }
1190 
1191 static NV_STATUS
_soeHandleInitEvent_LS10(nvswitch_device * device,PFLCNABLE pSoe,RM_FLCN_MSG * pGenMsg)1192 _soeHandleInitEvent_LS10
1193 (
1194     nvswitch_device  *device,
1195     PFLCNABLE         pSoe,
1196     RM_FLCN_MSG      *pGenMsg
1197 )
1198 {
1199     NVSWITCH_PRINT(device, ERROR,
1200         "%s: Init handle event not Supported!\n",
1201         __FUNCTION__);
1202     NVSWITCH_ASSERT(0);
1203     return NV_ERR_GENERIC;
1204 }
1205 
1206 static NvlStatus
_soeI2CAccessSend(nvswitch_device * device,void * cpuAddr,NvU64 dmaHandle,NvU16 xferSize)1207 _soeI2CAccessSend
1208 (
1209     nvswitch_device *device,
1210     void            *cpuAddr,
1211     NvU64           dmaHandle,
1212     NvU16           xferSize
1213 )
1214 {
1215     FLCN *pFlcn       = device->pSoe->pFlcn;
1216     NvU32               cmdSeqDesc;
1217     NV_STATUS           status;
1218     RM_FLCN_CMD_SOE     cmd;
1219     RM_SOE_CORE_CMD_I2C *pI2cCmd;
1220     NVSWITCH_TIMEOUT    timeout;
1221 
1222     nvswitch_os_memset(&cmd, 0, sizeof(cmd));
1223 
1224     cmd.hdr.unitId = RM_SOE_UNIT_CORE;
1225     cmd.hdr.size   = RM_SOE_CMD_SIZE(CORE, I2C);
1226 
1227     pI2cCmd = &cmd.cmd.core.i2c;
1228     RM_FLCN_U64_PACK(&pI2cCmd->dmaHandle, &dmaHandle);
1229     pI2cCmd->xferSize    = xferSize;
1230     pI2cCmd->cmdType = RM_SOE_CORE_CMD_I2C_ACCESS;
1231 
1232     cmdSeqDesc = 0;
1233 
1234     nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS * 5, &timeout);
1235     status = flcnQueueCmdPostBlocking(device, pFlcn,
1236                                       (PRM_FLCN_CMD)&cmd,
1237                                       NULL,                 // pMsg
1238                                       NULL,                 // pPayload
1239                                       SOE_RM_CMDQ_LOG_ID,
1240                                       &cmdSeqDesc,
1241                                       &timeout);
1242     if (status != NV_OK)
1243     {
1244         NVSWITCH_PRINT(device, ERROR, "%s: Failed to send I2C command to SOE status 0x%x\n",
1245                        __FUNCTION__, status);
1246         return -NVL_ERR_INVALID_STATE;
1247     }
1248 
1249     return NVL_SUCCESS;
1250 }
1251 
1252 static NvlStatus
_soeI2cFlcnStatusToNvlStatus(NvU8 flcnStatus)1253 _soeI2cFlcnStatusToNvlStatus
1254 (
1255     NvU8 flcnStatus
1256 )
1257 {
1258     switch (flcnStatus)
1259     {
1260         case FLCN_OK:
1261             return NVL_SUCCESS;
1262         case FLCN_ERR_INVALID_ARGUMENT:
1263             return -NVL_BAD_ARGS;
1264         case FLCN_ERR_OBJECT_NOT_FOUND:
1265             return -NVL_NOT_FOUND;
1266         case FLCN_ERROR:
1267             return -NVL_ERR_GENERIC;
1268         case FLCN_ERR_INVALID_STATE:
1269             return -NVL_ERR_INVALID_STATE;
1270         case FLCN_ERR_MORE_PROCESSING_REQUIRED:
1271             return -NVL_MORE_PROCESSING_REQUIRED;
1272         case FLCN_ERR_TIMEOUT:
1273             return -NVL_IO_ERROR;
1274         case FLCN_ERR_I2C_BUSY:
1275             return -NVL_ERR_STATE_IN_USE;
1276         case FLCN_ERR_NOT_SUPPORTED:
1277             return -NVL_ERR_NOT_SUPPORTED;
1278         default:
1279             return -NVL_ERR_GENERIC;
1280     }
1281 }
1282 
1283 static NvlStatus
_soeI2CAccess_LS10(nvswitch_device * device,NVSWITCH_CTRL_I2C_INDEXED_PARAMS * pParams)1284 _soeI2CAccess_LS10
1285 (
1286     nvswitch_device  *device,
1287     NVSWITCH_CTRL_I2C_INDEXED_PARAMS *pParams
1288 )
1289 {
1290     NvlStatus        ret;
1291     NvU8             flcnRet;
1292     PNVSWITCH_OBJI2C pI2c;
1293     void             *pCpuAddr;
1294     NvU64            dmaHandle;
1295 
1296     if (pParams == NULL)
1297     {
1298         return -NVL_BAD_ARGS;
1299     }
1300 
1301     pI2c = device->pI2c;
1302 
1303     if (pI2c == NULL || !pI2c->soeI2CSupported)
1304     {
1305         return -NVL_ERR_NOT_SUPPORTED;
1306     }
1307 
1308     pCpuAddr = pI2c->pCpuAddr;
1309     dmaHandle = pI2c->dmaHandle;
1310 
1311     ret = nvswitch_os_sync_dma_region_for_cpu(device->os_handle, dmaHandle,
1312                                               SOE_I2C_DMA_BUF_SIZE,
1313                                               NVSWITCH_DMA_DIR_FROM_SYSMEM);
1314     if (ret != NVL_SUCCESS)
1315     {
1316         NVSWITCH_PRINT(device, ERROR, "%s: nvswitch_os_sync_dma_region_for_cpu returned %d\n",
1317                        __FUNCTION__,  ret);
1318         return ret;
1319     }
1320 
1321     // Required for error reporting from SOE to driver
1322     ct_assert(sizeof(NVSWITCH_CTRL_I2C_INDEXED_PARAMS) < SOE_I2C_STATUS_INDEX);
1323 
1324     // Copy I2C struct into buffer
1325     nvswitch_os_memcpy(pCpuAddr, pParams, sizeof(NVSWITCH_CTRL_I2C_INDEXED_PARAMS));
1326 
1327     ret = nvswitch_os_sync_dma_region_for_device(device->os_handle, dmaHandle,
1328                                                  SOE_I2C_DMA_BUF_SIZE,
1329                                                  NVSWITCH_DMA_DIR_FROM_SYSMEM);
1330     if (ret != NVL_SUCCESS)
1331     {
1332         NVSWITCH_PRINT(device, ERROR, "%s: nvswitch_os_sync_dma_region_for_device returned %d\n",
1333                        __FUNCTION__,  ret);
1334         return ret;
1335     }
1336 
1337     // Send I2C access command to SOE
1338     ret = _soeI2CAccessSend(device, pCpuAddr, dmaHandle, SOE_I2C_DMA_BUF_SIZE);
1339     if (ret != NVL_SUCCESS)
1340     {
1341         NVSWITCH_PRINT(device, ERROR, "%s: _soeI2CAccessSend returned %d\n",
1342                        __FUNCTION__,  ret);
1343         return ret;
1344     }
1345 
1346     // Get result
1347     ret = nvswitch_os_sync_dma_region_for_cpu(device->os_handle, dmaHandle,
1348                                               SOE_I2C_DMA_BUF_SIZE,
1349                                               NVSWITCH_DMA_DIR_TO_SYSMEM);
1350     if (ret != NVL_SUCCESS)
1351     {
1352         NVSWITCH_PRINT(device, ERROR, "%s: nvswitch_os_sync_dma_region_for_cpu returned %d\n",
1353                        __FUNCTION__, ret);
1354         return ret;
1355     }
1356 
1357     nvswitch_os_memcpy(pParams, pCpuAddr, sizeof(NVSWITCH_CTRL_I2C_INDEXED_PARAMS));
1358 
1359     // Return value of the I2C operation that was performed in SOE
1360     flcnRet = ((NvU8*)pCpuAddr)[SOE_I2C_STATUS_INDEX];
1361     ret = _soeI2cFlcnStatusToNvlStatus(flcnRet);
1362 
1363     return ret;
1364 }
1365 
1366 /**
1367  * @brief   set hal function pointers for functions defined in LR10 (i.e. this file)
1368  *
1369  * this function has to be at the end of the file so that all the
1370  * other functions are already defined.
1371  *
1372  * @param[in] pFlcnable   The flcnable for which to set hals
1373  */
1374 void
soeSetupHal_LS10(SOE * pSoe)1375 soeSetupHal_LS10
1376 (
1377     SOE *pSoe
1378 )
1379 {
1380     soe_hal *pHal = pSoe->base.pHal;
1381     flcnable_hal *pParentHal = (flcnable_hal *)pHal;
1382 
1383     soeSetupHal_LR10(pSoe);
1384 
1385     pParentHal->fetchEngines = _soeFetchEngines_LS10;
1386     pParentHal->handleInitEvent = _soeHandleInitEvent_LS10;
1387 
1388     pHal->isCpuHalted        = _soeIsCpuHalted_LS10;
1389     pHal->service            = _soeService_LS10;
1390     pHal->serviceHalt        = _soeServiceHalt_LS10;
1391     pHal->processMessages    = _soeProcessMessages_LS10;
1392     pHal->waitForInitAck     = _soeWaitForInitAck_LS10;
1393     pHal->i2cAccess          = _soeI2CAccess_LS10;
1394 }
1395