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