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