mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-01-30 04:59:46 +00:00
1343 lines
42 KiB
C
1343 lines
42 KiB
C
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "soe/soe_nvswitch.h"
|
|
#include "soe/soe_priv_nvswitch.h"
|
|
|
|
#include "rmlsfm.h"
|
|
|
|
#include "nvlink_export.h"
|
|
|
|
#include "common_nvswitch.h"
|
|
#include "ls10/ls10.h"
|
|
#include "ls10/soe_ls10.h"
|
|
|
|
#include "nvswitch/ls10/dev_soe_ip.h"
|
|
#include "nvswitch/ls10/dev_soe_ip_addendum.h"
|
|
#include "nvswitch/ls10/dev_falcon_v4.h"
|
|
#include "nvswitch/ls10/dev_nvlsaw_ip.h"
|
|
#include "nvswitch/ls10/dev_nvlsaw_ip_addendum.h"
|
|
#include "nvswitch/ls10/dev_riscv_pri.h"
|
|
|
|
#include "flcn/flcnable_nvswitch.h"
|
|
#include "flcn/flcn_nvswitch.h"
|
|
#include "rmflcncmdif_nvswitch.h"
|
|
#include "soe/soeifcmn.h"
|
|
|
|
/**
|
|
* @brief Sets pEngDescUc and pEngDescBc to the discovered
|
|
* engine that matches this flcnable instance
|
|
*
|
|
* @param[in] device nvswitch_device pointer
|
|
* @param[in] pSoe SOE pointer
|
|
* @param[out] pEngDescUc pointer to the UniCast Engine
|
|
* Descriptor
|
|
* @param[out] pEngDescBc pointer to the BroadCast Engine
|
|
* Descriptor
|
|
*/
|
|
static void
|
|
_soeFetchEngines_LS10
|
|
(
|
|
nvswitch_device *device,
|
|
FLCNABLE *pSoe,
|
|
ENGINE_DESCRIPTOR_TYPE *pEngDescUc,
|
|
ENGINE_DESCRIPTOR_TYPE *pEngDescBc
|
|
)
|
|
{
|
|
pEngDescUc->initialized = NV_FALSE;
|
|
if (NVSWITCH_ENG_IS_VALID(device, SOE, 0))
|
|
{
|
|
pEngDescUc->base = NVSWITCH_GET_ENG(device, SOE, , 0);
|
|
}
|
|
else
|
|
{
|
|
pEngDescUc->base = 0;
|
|
}
|
|
|
|
pEngDescBc->initialized = NV_FALSE;
|
|
pEngDescBc->base = 0;
|
|
}
|
|
|
|
/*
|
|
* @Brief : Send a test command to SOE
|
|
*
|
|
* @param device The nvswitch device
|
|
*/
|
|
static NV_STATUS
|
|
_nvswitch_soe_send_test_cmd
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
RM_FLCN_CMD_SOE cmd;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
NvU32 cmdSeqDesc;
|
|
NV_STATUS status;
|
|
|
|
FLCN *pFlcn = device->pSoe->pFlcn;
|
|
|
|
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
|
|
|
cmd.hdr.unitId = RM_SOE_UNIT_NULL;
|
|
// sending nothing but a header for UNIT_NULL
|
|
cmd.hdr.size = RM_FLCN_QUEUE_HDR_SIZE;
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS * 5, &timeout);
|
|
status = flcnQueueCmdPostBlocking(device, pFlcn,
|
|
(PRM_FLCN_CMD)&cmd,
|
|
NULL, // pMsg - not used for now
|
|
NULL, // pPayload - not used for now
|
|
SOE_RM_CMDQ_LOG_ID,
|
|
&cmdSeqDesc,
|
|
&timeout);
|
|
|
|
NVSWITCH_ASSERT(status == NVL_SUCCESS);
|
|
return status;
|
|
}
|
|
|
|
#if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
|
|
/*!
|
|
* Helper function to dump some registers for debug.
|
|
*
|
|
* @param[in] device nvswitch_device pointer
|
|
*/
|
|
static void
|
|
dumpDebugRegisters
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
FLCN *pFlcn = device->pSoe->pFlcn;
|
|
|
|
NvU32 regOS = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_OS);
|
|
NvU32 regPC = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_RPC);
|
|
NvU32 regCPUCTL = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_CPUCTL);
|
|
NvU32 regIDLESTATE = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_IDLESTATE);
|
|
NvU32 regMAILBOX0 = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_MAILBOX0);
|
|
NvU32 regMAILBOX1 = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_MAILBOX1);
|
|
NvU32 regIRQSTAT = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQSTAT);
|
|
NvU32 regIRQMODE = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQMODE);
|
|
NvU32 regIRQMASK = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_IRQMASK);
|
|
NvU32 regIRQDEST = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_IRQDEST);
|
|
NvU32 regIRQDELEG = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_IRQDELEG);
|
|
NvU32 regDMACTL = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMACTL);
|
|
NvU32 regDMATRFCMD = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMATRFCMD);
|
|
NvU32 regDMATRFBASE = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMATRFBASE);
|
|
NvU32 regDMATRFMOFFS = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMATRFMOFFS);
|
|
NvU32 regDMATRFFBOFFS = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMATRFFBOFFS);
|
|
NvU32 regPRIVERR_STAT = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_PRIV_ERR_STAT);
|
|
NvU32 regPRIVERR_INFO = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_PRIV_ERR_INFO);
|
|
NvU32 regPRIVERR_ADDR_HI = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_PRIV_ERR_ADDR_HI);
|
|
NvU32 regPRIVERR_ADDR_LO = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_PRIV_ERR_ADDR);
|
|
NvU32 regHUBERR_STAT = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_HUB_ERR_STAT);
|
|
NvU32 regBCR_CTRL = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_BCR_CTRL);
|
|
NvU32 regRESET_PLM = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_RESET_PRIV_LEVEL_MASK);
|
|
NvU32 regEXE_PLM = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_EXE_PRIV_LEVEL_MASK);
|
|
|
|
NVSWITCH_PRINT(device, ERROR, "Peregrine Registers:\n");
|
|
NVSWITCH_PRINT(device, ERROR, "OS : 0x%08x\n", regOS);
|
|
NVSWITCH_PRINT(device, ERROR, "PC (lo32) : 0x%08x\n", regPC);
|
|
NVSWITCH_PRINT(device, ERROR, "CPUCTL : 0x%08x\n", regCPUCTL);
|
|
NVSWITCH_PRINT(device, ERROR, "IDLESTATE : 0x%08x\n", regIDLESTATE);
|
|
NVSWITCH_PRINT(device, ERROR, "MAILBOX0 : 0x%08x\n", regMAILBOX0);
|
|
NVSWITCH_PRINT(device, ERROR, "MAILBOX1 : 0x%08x\n", regMAILBOX1);
|
|
NVSWITCH_PRINT(device, ERROR, "IRQSTAT : 0x%08x\n", regIRQSTAT);
|
|
NVSWITCH_PRINT(device, ERROR, "IRQMODE : 0x%08x\n", regIRQMODE);
|
|
NVSWITCH_PRINT(device, ERROR, "IRQMASK : 0x%08x\n", regIRQMASK);
|
|
NVSWITCH_PRINT(device, ERROR, "IRQDEST : 0x%08x\n", regIRQDEST);
|
|
NVSWITCH_PRINT(device, ERROR, "IRQDELEG : 0x%08x\n", regIRQDELEG);
|
|
NVSWITCH_PRINT(device, ERROR, "DMACTL : 0x%08x\n", regDMACTL);
|
|
NVSWITCH_PRINT(device, ERROR, "DMATRFCMD : 0x%08x\n", regDMATRFCMD);
|
|
NVSWITCH_PRINT(device, ERROR, "DMATRFBASE : 0x%08x\n", regDMATRFBASE);
|
|
NVSWITCH_PRINT(device, ERROR, "DMATRFMOFFS : 0x%08x\n", regDMATRFMOFFS);
|
|
NVSWITCH_PRINT(device, ERROR, "DMATRFFBOFFS : 0x%08x\n", regDMATRFFBOFFS);
|
|
NVSWITCH_PRINT(device, ERROR, "PRIVERR_STAT : 0x%08x\n", regPRIVERR_STAT);
|
|
NVSWITCH_PRINT(device, ERROR, "PRIVERR_INFO : 0x%08x\n", regPRIVERR_INFO);
|
|
NVSWITCH_PRINT(device, ERROR, "PRIVERR_ADDR : 0x%08x%08x\n", regPRIVERR_ADDR_HI, regPRIVERR_ADDR_LO);
|
|
NVSWITCH_PRINT(device, ERROR, "HUBERR_STAT : 0x%08x\n", regHUBERR_STAT);
|
|
NVSWITCH_PRINT(device, ERROR, "BCR_CTRL : 0x%08x\n", regBCR_CTRL);
|
|
NVSWITCH_PRINT(device, ERROR, "RESET_PLM : 0x%08x\n", regRESET_PLM);
|
|
NVSWITCH_PRINT(device, ERROR, "EXE_PLM : 0x%08x\n", regEXE_PLM);
|
|
}
|
|
#endif // defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
|
|
|
|
/*
|
|
* @Brief : Attach or Detach driver to SOE Queues
|
|
*
|
|
* @param[in] device
|
|
*/
|
|
static void
|
|
_nvswitch_soe_attach_detach_driver_ls10
|
|
(
|
|
nvswitch_device *device,
|
|
NvBool bAttach
|
|
)
|
|
{
|
|
NvU32 val;
|
|
|
|
val = NVSWITCH_SAW_RD32_LS10(device, _NVLSAW, _DRIVER_ATTACH_DETACH);
|
|
|
|
if (bAttach)
|
|
{
|
|
val = FLD_SET_DRF(_NVLSAW, _DRIVER_ATTACH_DETACH, _STATUS,
|
|
_ATTACHED, val);
|
|
}
|
|
else
|
|
{
|
|
val = FLD_SET_DRF(_NVLSAW, _DRIVER_ATTACH_DETACH, _STATUS,
|
|
_DETACHED, val);
|
|
}
|
|
|
|
NVSWITCH_SAW_WR32_LS10(device, _NVLSAW, _DRIVER_ATTACH_DETACH, val);
|
|
}
|
|
|
|
/*
|
|
* @Brief : Returns if SOE is attached to the Queues
|
|
*
|
|
* @param[in] device
|
|
*/
|
|
static NvBool
|
|
_nvswitch_is_soe_attached_ls10
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
NvU32 val;
|
|
NvBool bSoeAttached;
|
|
|
|
val = NVSWITCH_SAW_RD32_LS10(device, _NVLSAW, _SOE_ATTACH_DETACH);
|
|
bSoeAttached = FLD_TEST_DRF(_NVLSAW, _SOE_ATTACH_DETACH, _STATUS, _ATTACHED, val);
|
|
|
|
return bSoeAttached;
|
|
}
|
|
|
|
/*
|
|
* @Brief : Backup NPORT state and issue NPORT reset
|
|
*
|
|
* @param[in] device
|
|
* @param[in] nport
|
|
*/
|
|
NvlStatus
|
|
nvswitch_soe_issue_nport_reset_ls10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 nport
|
|
)
|
|
{
|
|
FLCN *pFlcn = device->pSoe->pFlcn;
|
|
NvU32 cmdSeqDesc = 0;
|
|
NV_STATUS status;
|
|
RM_FLCN_CMD_SOE cmd;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
RM_SOE_CORE_CMD_NPORT_RESET *pNportReset;
|
|
|
|
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
|
|
|
cmd.hdr.unitId = RM_SOE_UNIT_CORE;
|
|
cmd.hdr.size = RM_SOE_CMD_SIZE(CORE, NPORT_RESET);
|
|
|
|
pNportReset = &cmd.cmd.core.nportReset;
|
|
pNportReset->nport = nport;
|
|
pNportReset->cmdType = RM_SOE_CORE_CMD_ISSUE_NPORT_RESET;
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
|
|
status = flcnQueueCmdPostBlocking(device, pFlcn,
|
|
(PRM_FLCN_CMD)&cmd,
|
|
NULL, // pMsg
|
|
NULL, // pPayload
|
|
SOE_RM_CMDQ_LOG_ID,
|
|
&cmdSeqDesc,
|
|
&timeout);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to send NPORT RESET command to SOE status 0x%x\n",
|
|
__FUNCTION__, status);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @Brief : De-Assert NPORT reset and restore NPORT state
|
|
*
|
|
* @param[in] device
|
|
* @param[in] nport
|
|
*/
|
|
NvlStatus
|
|
nvswitch_soe_restore_nport_state_ls10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 nport
|
|
)
|
|
{
|
|
FLCN *pFlcn = device->pSoe->pFlcn;
|
|
NvU32 cmdSeqDesc = 0;
|
|
NV_STATUS status;
|
|
RM_FLCN_CMD_SOE cmd;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
RM_SOE_CORE_CMD_NPORT_STATE *pNportState;
|
|
|
|
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
|
|
|
cmd.hdr.unitId = RM_SOE_UNIT_CORE;
|
|
cmd.hdr.size = RM_SOE_CMD_SIZE(CORE, NPORT_STATE);
|
|
|
|
pNportState = &cmd.cmd.core.nportState;
|
|
pNportState->nport = nport;
|
|
pNportState->cmdType = RM_SOE_CORE_CMD_RESTORE_NPORT_STATE;
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
|
|
status = flcnQueueCmdPostBlocking(device, pFlcn,
|
|
(PRM_FLCN_CMD)&cmd,
|
|
NULL, // pMsg
|
|
NULL, // pPayload
|
|
SOE_RM_CMDQ_LOG_ID,
|
|
&cmdSeqDesc,
|
|
&timeout);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to send NPORT BACKUP command to SOE status 0x%x\n",
|
|
__FUNCTION__, status);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @Brief : Set NPORT TPROD state in SOE
|
|
*
|
|
* @param[in] device
|
|
* @param[in] nport
|
|
*/
|
|
NvlStatus
|
|
nvswitch_set_nport_tprod_state_ls10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 nport
|
|
)
|
|
{
|
|
FLCN *pFlcn = device->pSoe->pFlcn;
|
|
NvU32 cmdSeqDesc = 0;
|
|
NV_STATUS status;
|
|
RM_FLCN_CMD_SOE cmd;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
RM_SOE_CORE_CMD_NPORT_TPROD_STATE *nportTprodState;
|
|
|
|
if (!NVSWITCH_ENG_IS_VALID(device, NPORT, nport))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: NPORT #%d invalid\n",
|
|
__FUNCTION__, nport);
|
|
return -NVL_BAD_ARGS;
|
|
}
|
|
|
|
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
|
|
|
cmd.hdr.unitId = RM_SOE_UNIT_CORE;
|
|
cmd.hdr.size = RM_SOE_CMD_SIZE(CORE, NPORT_TPROD_STATE);
|
|
|
|
nportTprodState = &cmd.cmd.core.nportTprodState;
|
|
nportTprodState->nport = nport;
|
|
nportTprodState->cmdType = RM_SOE_CORE_CMD_SET_NPORT_TPROD_STATE;
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
|
|
status = flcnQueueCmdPostBlocking(device, pFlcn,
|
|
(PRM_FLCN_CMD)&cmd,
|
|
NULL, // pMsg
|
|
NULL, // pPayload
|
|
SOE_RM_CMDQ_LOG_ID,
|
|
&cmdSeqDesc,
|
|
&timeout);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to send NPORT SET_TPROD_STATE command to SOE, status 0x%x\n",
|
|
__FUNCTION__, status);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @Brief : INIT L2 register state in SOE
|
|
*
|
|
* @param[in] device
|
|
* @param[in] nport
|
|
*/
|
|
void
|
|
nvswitch_soe_init_l2_state_ls10
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
FLCN *pFlcn;
|
|
NvU32 cmdSeqDesc = 0;
|
|
NV_STATUS status;
|
|
RM_FLCN_CMD_SOE cmd;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
RM_SOE_CORE_CMD_L2_STATE *pL2State;
|
|
|
|
if (!nvswitch_is_soe_supported(device))
|
|
{
|
|
NVSWITCH_PRINT(device, INFO, "%s: SOE is not supported\n",
|
|
__FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
pFlcn = device->pSoe->pFlcn;
|
|
|
|
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
|
cmd.hdr.unitId = RM_SOE_UNIT_CORE;
|
|
cmd.hdr.size = RM_SOE_CMD_SIZE(CORE, L2_STATE);
|
|
|
|
pL2State = &cmd.cmd.core.l2State;
|
|
pL2State->cmdType = RM_SOE_CORE_CMD_INIT_L2_STATE;
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
|
|
status = flcnQueueCmdPostBlocking(device, pFlcn,
|
|
(PRM_FLCN_CMD)&cmd,
|
|
NULL, // pMsg
|
|
NULL, // pPayload
|
|
SOE_RM_CMDQ_LOG_ID,
|
|
&cmdSeqDesc,
|
|
&timeout);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to send INIT_L2_STATE command to SOE, status 0x%x\n",
|
|
__FUNCTION__, status);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @Brief : Enable/Disable NPORT interrupts
|
|
*
|
|
* @param[in] device
|
|
* @param[in] nport
|
|
*/
|
|
NvlStatus
|
|
nvswitch_soe_set_nport_interrupts_ls10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 nport,
|
|
NvBool bEnable
|
|
)
|
|
{
|
|
FLCN *pFlcn;
|
|
NvU32 cmdSeqDesc = 0;
|
|
NV_STATUS status;
|
|
RM_FLCN_CMD_SOE cmd;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
RM_SOE_CORE_CMD_NPORT_INTRS *pNportIntrs;
|
|
|
|
if (!nvswitch_is_soe_supported(device))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: SOE is not supported\n",
|
|
__FUNCTION__);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
pFlcn = device->pSoe->pFlcn;
|
|
|
|
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
|
cmd.hdr.unitId = RM_SOE_UNIT_CORE;
|
|
cmd.hdr.size = RM_SOE_CMD_SIZE(CORE, NPORT_INTRS);
|
|
|
|
pNportIntrs = &cmd.cmd.core.nportIntrs;
|
|
pNportIntrs->cmdType = RM_SOE_CORE_CMD_SET_NPORT_INTRS;
|
|
pNportIntrs->nport = nport;
|
|
pNportIntrs->bEnable = bEnable;
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
|
|
status = flcnQueueCmdPostBlocking(device, pFlcn,
|
|
(PRM_FLCN_CMD)&cmd,
|
|
NULL, // pMsg
|
|
NULL, // pPayload
|
|
SOE_RM_CMDQ_LOG_ID,
|
|
&cmdSeqDesc,
|
|
&timeout);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Failed to send SET_NPORT_INTRS command to SOE, status 0x%x\n",
|
|
__FUNCTION__, status);
|
|
return -NVL_ERR_GENERIC;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @Brief : Disable NPORT Fatal Interrupt in SOE
|
|
*
|
|
* @param[in] device
|
|
* @param[in] nport
|
|
* @param[in] nportIntrEnable
|
|
* @param[in] nportIntrType
|
|
*/
|
|
void
|
|
nvswitch_soe_disable_nport_fatal_interrupts_ls10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 nport,
|
|
NvU32 nportIntrEnable,
|
|
NvU8 nportIntrType
|
|
)
|
|
{
|
|
FLCN *pFlcn;
|
|
NvU32 cmdSeqDesc = 0;
|
|
NV_STATUS status;
|
|
RM_FLCN_CMD_SOE cmd;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
RM_SOE_CORE_CMD_NPORT_FATAL_INTR *pNportIntrDisable;
|
|
NVSWITCH_GET_BIOS_INFO_PARAMS p = { 0 };
|
|
NvlStatus stat;
|
|
|
|
stat = device->hal.nvswitch_ctrl_get_bios_info(device, &p);
|
|
if ((stat != NVL_SUCCESS) || ((p.version & SOE_VBIOS_VERSION_MASK) <
|
|
SOE_VBIOS_REVLOCK_DISABLE_NPORT_FATAL_INTR))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Skipping DISABLE_NPORT_FATAL_INTR command to SOE. Update firmware "
|
|
"from .%02X to .%02X\n",
|
|
__FUNCTION__, (NvU32)((p.version & SOE_VBIOS_VERSION_MASK) >> 16),
|
|
SOE_VBIOS_REVLOCK_DISABLE_NPORT_FATAL_INTR);
|
|
return;
|
|
}
|
|
|
|
if (!nvswitch_is_soe_supported(device))
|
|
{
|
|
NVSWITCH_PRINT(device, INFO, "%s: SOE is not supported\n",
|
|
__FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
pFlcn = device->pSoe->pFlcn;
|
|
|
|
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
|
cmd.hdr.unitId = RM_SOE_UNIT_CORE;
|
|
cmd.hdr.size = RM_SOE_CMD_SIZE(CORE, NPORT_FATAL_INTR);
|
|
|
|
pNportIntrDisable = &cmd.cmd.core.nportDisableIntr;
|
|
pNportIntrDisable->cmdType = RM_SOE_CORE_CMD_DISABLE_NPORT_FATAL_INTR;
|
|
pNportIntrDisable->nport = nport;
|
|
pNportIntrDisable->nportIntrEnable = nportIntrEnable;
|
|
pNportIntrDisable->nportIntrType = nportIntrType;
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
|
|
status = flcnQueueCmdPostBlocking(device, pFlcn,
|
|
(PRM_FLCN_CMD)&cmd,
|
|
NULL, // pMsg
|
|
NULL, // pPayload
|
|
SOE_RM_CMDQ_LOG_ID,
|
|
&cmdSeqDesc,
|
|
&timeout);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to send DISABLE_NPORT_FATAL_INTR command to SOE, status 0x%x\n",
|
|
__FUNCTION__, status);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @Brief : Init sequence for SOE FSP RISCV image
|
|
*
|
|
* The driver assumes SOE is already booted by FSP.
|
|
* Driver checks for SOE state and handshakes with a test command.
|
|
* If FSP or SOE fails to boot, driver fails and quits.
|
|
*
|
|
* @param[in] nvswitch device
|
|
*/
|
|
NvlStatus
|
|
nvswitch_init_soe_ls10
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
NvlStatus status;
|
|
NvU32 data;
|
|
FLCN *pFlcn = device->pSoe->pFlcn;
|
|
|
|
//
|
|
// Check if SOE has halted unexpectedly.
|
|
//
|
|
// The explicit check is required because the interrupts
|
|
// are not yet enabled as the device is still initializing.
|
|
//
|
|
if (soeIsCpuHalted_HAL(device, ((PSOE)pFlcn->pFlcnable)))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: SOE halted\n",
|
|
__FUNCTION__);
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_BOOTSTRAP,
|
|
"SOE init Failed(0)\n");
|
|
status = -NVL_ERR_INVALID_STATE;
|
|
goto nvswitch_init_soe_fail;
|
|
}
|
|
|
|
// Check for SOE BOOT SUCCESS
|
|
data = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_MAILBOX1);
|
|
if (data != SOE_BOOTSTRAP_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: SOE boot failed\n",
|
|
__FUNCTION__);
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_BOOTSTRAP,
|
|
"SOE init failed(1)\n");
|
|
status = -NVL_ERR_INVALID_STATE;
|
|
goto nvswitch_init_soe_fail;
|
|
}
|
|
|
|
// Register SOE callbacks
|
|
status = nvswitch_soe_register_event_callbacks(device);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_COMMAND_QUEUE,
|
|
"Failed to register SOE events\n");
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_BOOTSTRAP,
|
|
"SOE init failed(2)\n");
|
|
return status;
|
|
}
|
|
|
|
// Sanity the command and message queues as a final check
|
|
if (_nvswitch_soe_send_test_cmd(device) != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_BOOTSTRAP,
|
|
"SOE init failed(4)\n");
|
|
status = -NVL_ERR_INVALID_STATE;
|
|
goto nvswitch_init_soe_fail;
|
|
}
|
|
|
|
NVSWITCH_PRINT(device, SETUP,
|
|
"%s: SOE successfully bootstrapped.\n",
|
|
__FUNCTION__);
|
|
|
|
return NVL_SUCCESS;
|
|
|
|
nvswitch_init_soe_fail :
|
|
// Log any failures SOE may have had during bootstrap
|
|
(void)soeService_HAL(device, ((PSOE)pFlcn->pFlcnable));
|
|
#if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
|
|
dumpDebugRegisters(device);
|
|
#endif // defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
|
|
|
|
flcnDbgInfoCapturePcTrace_HAL(device, pFlcn);
|
|
NVSWITCH_ASSERT(0);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* @Brief : Shutdown SOE during driver unload
|
|
*
|
|
* @param[in] device Bootstrap SOE on this device
|
|
*/
|
|
NvlStatus
|
|
nvswitch_unload_soe_ls10
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
// Detach driver from SOE Queues
|
|
_nvswitch_soe_attach_detach_driver_ls10(device, NV_FALSE);
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
/*!
|
|
* @brief : Register callback functions for events and messages from SOE
|
|
*
|
|
* @param[in] device nvswitch_device pointer
|
|
*/
|
|
NvlStatus
|
|
nvswitch_soe_register_event_callbacks_ls10
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
|
|
NV_STATUS status;
|
|
PFLCN pFlcn = device->pSoe->pFlcn;
|
|
PSOE pSoe = (PSOE)device->pSoe;
|
|
|
|
// Register Thermal callback funcion
|
|
status = flcnQueueEventRegister(
|
|
device, pFlcn,
|
|
RM_SOE_UNIT_THERM,
|
|
NULL,
|
|
nvswitch_therm_soe_callback_ls10,
|
|
NULL,
|
|
&pSoe->thermEvtDesc);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Failed to register thermal event handler.\n",
|
|
__FUNCTION__);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
void
|
|
nvswitch_soe_unregister_events_ls10
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
PFLCN pFlcn = device->pSoe->pFlcn;
|
|
PSOE pSoe = (PSOE)device->pSoe;
|
|
NV_STATUS status;
|
|
|
|
// un-register thermal callback funcion
|
|
status = flcnQueueEventUnregister(device, pFlcn,
|
|
pSoe->thermEvtDesc);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Failed to un-register thermal event handler.\n",
|
|
__FUNCTION__);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* @brief Determine if the SOE RISCV CPU is halted
|
|
*
|
|
* @param[in] device nvswitch_device pointer
|
|
* @param[in] pSoe SOE pointer
|
|
*
|
|
* @return NvBool reflecting the SOE Riscv CPU halted state
|
|
*/
|
|
static NvBool
|
|
_soeIsCpuHalted_LS10
|
|
(
|
|
nvswitch_device *device,
|
|
PSOE pSoe
|
|
)
|
|
{
|
|
NvU32 data;
|
|
|
|
data = NVSWITCH_SOE_RD32_LS10(device, 0, _SOE_RISCV, _CPUCTL);
|
|
return FLD_TEST_DRF(_PFALCON, _FALCON_CPUCTL, _HALTED, _TRUE, data);
|
|
}
|
|
|
|
static NvU32
|
|
_soeIntrStatus_LS10
|
|
(
|
|
nvswitch_device *device
|
|
)
|
|
{
|
|
NvU32 irq, mask, dest;
|
|
|
|
irq = NVSWITCH_SOE_RD32_LS10(device, 0, _SOE_FALCON, _IRQSTAT);
|
|
mask = NVSWITCH_SOE_RD32_LS10(device, 0, _SOE_RISCV, _IRQMASK);
|
|
dest = NVSWITCH_SOE_RD32_LS10(device, 0, _SOE_RISCV, _IRQDEST);
|
|
|
|
return (irq & mask & dest);
|
|
}
|
|
|
|
/*!
|
|
* @brief Top level service routine
|
|
*
|
|
* @param[in] device nvswitch_device pointer
|
|
* @param[in] pSoe SOE pointer
|
|
*
|
|
* @return 32-bit interrupt status AFTER all known interrupt-sources were
|
|
* serviced.
|
|
*/
|
|
static NvU32
|
|
_soeService_LS10
|
|
(
|
|
nvswitch_device *device,
|
|
PSOE pSoe
|
|
)
|
|
{
|
|
NvBool bRecheckMsgQ = NV_FALSE;
|
|
NvBool bRecheckPrintQ = NV_FALSE;
|
|
NvU32 clearBits = 0;
|
|
NvU32 intrStatus;
|
|
PFLCN pFlcn = ENG_GET_FLCN(pSoe);
|
|
|
|
if (pFlcn == NULL)
|
|
{
|
|
NVSWITCH_ASSERT(0);
|
|
return NV_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
// Get the IRQ status and mask the sources not directed to host.
|
|
intrStatus = _soeIntrStatus_LS10(device);
|
|
|
|
// Exit if there is nothing to do
|
|
if (intrStatus == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Service pending interrupts
|
|
if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _WDTMR, _TRUE))
|
|
{
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_WATCHDOG,
|
|
"SOE Watchdog error\n");
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s: Watchdog timer fired. We do not support this "
|
|
"yet.\n", __FUNCTION__);
|
|
NVSWITCH_ASSERT(0);
|
|
|
|
clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _WDTMR, _SET);
|
|
}
|
|
|
|
if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _EXTERR, _TRUE))
|
|
{
|
|
clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _EXTERR, _SET);
|
|
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_EXTERR, "SOE EXTERR\n");
|
|
}
|
|
|
|
if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _HALT, _TRUE))
|
|
{
|
|
clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _HALT, _SET);
|
|
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_SOE_HALT, "SOE HALTED\n");
|
|
soeServiceHalt_HAL(device, pSoe);
|
|
}
|
|
|
|
if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _SWGEN0, _TRUE))
|
|
{
|
|
clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _SWGEN0, _SET);
|
|
|
|
NVSWITCH_PRINT(device, MMIO,
|
|
"%s: Received a message from SOE via SWGEN0\n",
|
|
__FUNCTION__);
|
|
soeProcessMessages_HAL(device, pSoe);
|
|
bRecheckMsgQ = NV_TRUE;
|
|
}
|
|
|
|
if (intrStatus & DRF_DEF(_PFALCON, _FALCON_IRQSTAT, _SWGEN1, _TRUE))
|
|
{
|
|
clearBits |= DRF_DEF(_PFALCON, _FALCON_IRQSCLR, _SWGEN1, _SET);
|
|
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s: Received a SWGEN1 interrupt\n",
|
|
__FUNCTION__);
|
|
flcnDebugBufferDisplay_HAL(device, pFlcn);
|
|
bRecheckPrintQ = NV_TRUE;
|
|
}
|
|
|
|
// Clear any sources that were serviced and get the new status.
|
|
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQSCLR, clearBits);
|
|
|
|
// Re-read interrupt status before retriggering to return correct value
|
|
intrStatus = _soeIntrStatus_LS10(device);
|
|
|
|
//
|
|
// If we just processed a SWGEN0 message queue interrupt, peek
|
|
// into the message queue and see if any messages were missed the last time
|
|
// the queue was purged (above). If it is not empty, re-generate SWGEN0
|
|
// (since it is now cleared) and exit. As long as an interrupt is pending,
|
|
// this function will be re-entered and the message(s) will be processed.
|
|
//
|
|
if (bRecheckMsgQ)
|
|
{
|
|
PFALCON_QUEUE_INFO pQueueInfo;
|
|
FLCNQUEUE *pMsgQ;
|
|
|
|
pQueueInfo = pFlcn->pQueueInfo;
|
|
|
|
NVSWITCH_ASSERT(pQueueInfo != NULL);
|
|
NVSWITCH_ASSERT(pQueueInfo->pQueues != NULL);
|
|
|
|
pMsgQ = &pQueueInfo->pQueues[SOE_RM_MSGQ_LOG_ID];
|
|
|
|
if (!pMsgQ->isEmpty(device, pFlcn, pMsgQ))
|
|
{
|
|
// It is not necessary to RMW IRQSSET (zeros are ignored)
|
|
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQSSET,
|
|
DRF_DEF(_PFALCON, _FALCON_IRQSSET, _SWGEN0, _SET));
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we just processed a SWGEN1 interrupt (Debug Buffer interrupt), peek
|
|
// into the Debug Buffer and see if any text was missed the last time
|
|
// the buffer was displayed (above). If it is not empty, re-generate SWGEN1
|
|
// (since it is now cleared) and exit. As long as an interrupt is pending,
|
|
// this function will be re-entered and the message(s) will be processed.
|
|
//
|
|
if (bRecheckPrintQ)
|
|
{
|
|
if (!flcnDebugBufferIsEmpty_HAL(device, pFlcn))
|
|
{
|
|
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_IRQSSET,
|
|
DRF_DEF(_PFALCON, _FALCON_IRQSSET, _SWGEN1, _SET));
|
|
}
|
|
}
|
|
|
|
flcnIntrRetrigger_HAL(device, pFlcn);
|
|
|
|
return intrStatus;
|
|
}
|
|
|
|
/*!
|
|
* Called by soeService to handle a SOE halt. This function will dump the
|
|
* current status of SOE and then trap the CPU for further inspection for a
|
|
* debug build.
|
|
*
|
|
* @param[in] device nvswitch_device pointer
|
|
* @param[in] pSoe SOE object pointer
|
|
*/
|
|
static void
|
|
_soeServiceHalt_LS10
|
|
(
|
|
nvswitch_device *device,
|
|
PSOE pSoe
|
|
)
|
|
{
|
|
PFLCN pFlcn = ENG_GET_FLCN(pSoe);
|
|
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
|
"!! ** SOE HALTED ** !!\n"
|
|
"!! Please file a bug with the following information. !!\n"
|
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
|
|
|
|
#if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
|
|
dumpDebugRegisters(device);
|
|
#endif // defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
|
|
|
|
flcnDbgInfoCaptureRiscvPcTrace_HAL(device, pFlcn);
|
|
NVSWITCH_ASSERT(0);
|
|
}
|
|
|
|
/*!
|
|
* Use the SOE INIT Message to construct, initialize or update SOE Queues.
|
|
*
|
|
* @param[in] device nvswitch_device pointer
|
|
* @param[in] pSoe SOE object pointer
|
|
*
|
|
* @return 'NV_OK' upon successful creation of all SOE Queues
|
|
*/
|
|
static NV_STATUS
|
|
_soeUpdateInitMsgQueuesInfo
|
|
(
|
|
nvswitch_device *device,
|
|
PSOE pSoe
|
|
)
|
|
{
|
|
FLCNQUEUE *pQueue;
|
|
PFLCN pFlcn = ENG_GET_FLCN(pSoe);
|
|
PFALCON_QUEUE_INFO pQueueInfo;
|
|
NvU32 queueOffset;
|
|
NvU16 queueSize;
|
|
NvU8 queuePhyId;
|
|
NvU8 queueLogId;
|
|
NV_STATUS status;
|
|
|
|
//
|
|
// No command should be longer than half the queue size.
|
|
// See _soeQueueCmdValidate_IMPL().
|
|
//
|
|
ct_assert(sizeof(RM_FLCN_CMD_SOE) <= (SOE_CMD_QUEUE_LENGTH / 2));
|
|
|
|
NVSWITCH_ASSERT(pFlcn != NULL);
|
|
|
|
pQueueInfo = pFlcn->pQueueInfo;
|
|
NVSWITCH_ASSERT(pQueueInfo != NULL);
|
|
|
|
// Construct DMEM for CMDQ
|
|
queueOffset = SOE_EMEM_CHANNEL_CMDQ_OFFSET;
|
|
queueSize = SOE_CMD_QUEUE_LENGTH;
|
|
queuePhyId = 0;
|
|
queueLogId = SOE_RM_CMDQ_LOG_ID;
|
|
pQueue = &pQueueInfo->pQueues[queueLogId];
|
|
status = flcnQueueConstruct_dmem_nvswitch(
|
|
device,
|
|
pFlcn,
|
|
&pQueue, // ppQueue
|
|
queueLogId, // Logical ID of the queue
|
|
queuePhyId, // Physical ID of the queue
|
|
queueOffset, // offset
|
|
queueSize, // size
|
|
RM_FLCN_QUEUE_HDR_SIZE); // cmdHdrSize
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Error constructing SOE CmdQueue (status="
|
|
"0x%08x).\n", __FUNCTION__, status);
|
|
NVSWITCH_ASSERT(0);
|
|
return status;
|
|
}
|
|
|
|
// Construct DMEM for MSGQ
|
|
queueOffset = SOE_EMEM_CHANNEL_MSGQ_OFFSET;
|
|
queueSize = SOE_MSG_QUEUE_LENGTH;
|
|
queuePhyId = 0;
|
|
queueLogId = SOE_RM_MSGQ_LOG_ID;
|
|
pQueue = &pQueueInfo->pQueues[queueLogId];
|
|
status = flcnQueueConstruct_dmem_nvswitch(
|
|
device,
|
|
pFlcn,
|
|
&pQueue, // ppQueue
|
|
queueLogId, // Logical ID of the queue
|
|
queuePhyId, // Physical ID of the queue
|
|
queueOffset, // offset
|
|
queueSize, // size
|
|
RM_FLCN_QUEUE_HDR_SIZE); // cmdHdrSize
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Error constructing SOE MsgQueue (status="
|
|
"0x%08x).\n", __FUNCTION__, status);
|
|
NVSWITCH_ASSERT(0);
|
|
return status;
|
|
}
|
|
|
|
pFlcn->bOSReady = NV_TRUE;
|
|
|
|
return NV_OK;
|
|
}
|
|
|
|
static NV_STATUS
|
|
_soeWaitForInitAck_LS10
|
|
(
|
|
nvswitch_device *device,
|
|
PSOE pSoe
|
|
)
|
|
{
|
|
NV_STATUS status;
|
|
PFLCN pFlcn = ENG_GET_FLCN(pSoe);
|
|
|
|
if (!_nvswitch_is_soe_attached_ls10(device))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s SOE is not to attached!\n",
|
|
__FUNCTION__);
|
|
NVSWITCH_ASSERT(0);
|
|
return NV_ERR_NOT_READY;
|
|
}
|
|
|
|
// Update InitMsg Queue info before sending any commands
|
|
if (!pFlcn->bOSReady)
|
|
{
|
|
status = _soeUpdateInitMsgQueuesInfo(device, pSoe);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s Failed to attach driver!\n",
|
|
__FUNCTION__);
|
|
NVSWITCH_ASSERT(0);
|
|
return status;
|
|
}
|
|
|
|
// Attach driver to SOE Queues
|
|
_nvswitch_soe_attach_detach_driver_ls10(device, NV_TRUE);
|
|
}
|
|
|
|
return NV_OK;
|
|
}
|
|
|
|
/*!
|
|
* Purges all the messages from the SOE's message queue. Each message will
|
|
* be analyzed, clients will be notified of status, and events will be routed
|
|
* to all registered event listeners.
|
|
*
|
|
* @param[in] device nvswitch_device pointer
|
|
* @param[in] pSoe SOE object pointer
|
|
*
|
|
* @return 'NV_OK' if the message queue was successfully purged.
|
|
*/
|
|
static NV_STATUS
|
|
_soeProcessMessages_LS10
|
|
(
|
|
nvswitch_device *device,
|
|
PSOE pSoe
|
|
)
|
|
{
|
|
RM_FLCN_MSG_SOE soeMessage;
|
|
NV_STATUS status;
|
|
PFLCN pFlcn = ENG_GET_FLCN(pSoe);
|
|
|
|
// Update InitMsg Queue info before recieving any messages
|
|
if (!pFlcn->bOSReady)
|
|
{
|
|
status = _soeUpdateInitMsgQueuesInfo(device, pSoe);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s Failed to attach driver!\n",
|
|
__FUNCTION__);
|
|
NVSWITCH_ASSERT(0);
|
|
return status;
|
|
}
|
|
|
|
// Attach driver to SOE Queues
|
|
_nvswitch_soe_attach_detach_driver_ls10(device, NV_TRUE);
|
|
}
|
|
|
|
|
|
// keep processing messages until no more exist in the message queue
|
|
while (NV_OK == (status = flcnQueueReadData(
|
|
device,
|
|
pFlcn,
|
|
SOE_RM_MSGQ_LOG_ID,
|
|
(RM_FLCN_MSG *)&soeMessage, NV_TRUE)))
|
|
{
|
|
NVSWITCH_PRINT(device, MMIO,
|
|
"%s: unitId=0x%02x, size=0x%02x, ctrlFlags=0x%02x, " \
|
|
"seqNumId=0x%02x\n",
|
|
__FUNCTION__,
|
|
soeMessage.hdr.unitId,
|
|
soeMessage.hdr.size,
|
|
soeMessage.hdr.ctrlFlags,
|
|
soeMessage.hdr.seqNumId);
|
|
|
|
// check to see if the message is a reply or an event.
|
|
if ((soeMessage.hdr.ctrlFlags &= RM_FLCN_QUEUE_HDR_FLAGS_EVENT) != 0)
|
|
{
|
|
flcnQueueEventHandle(device, pFlcn, (RM_FLCN_MSG *)&soeMessage, NV_OK);
|
|
}
|
|
// the message is a response from a previously queued command
|
|
else
|
|
{
|
|
flcnQueueResponseHandle(device, pFlcn, (RM_FLCN_MSG *)&soeMessage);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Status NV_ERR_NOT_READY implies, Queue is empty.
|
|
// Log the message in other error cases.
|
|
//
|
|
if (status != NV_ERR_NOT_READY)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: unexpected error while purging message queue (status=0x%x).\n",
|
|
__FUNCTION__, (status));
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static NV_STATUS
|
|
_soeHandleInitEvent_LS10
|
|
(
|
|
nvswitch_device *device,
|
|
PFLCNABLE pSoe,
|
|
RM_FLCN_MSG *pGenMsg
|
|
)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Init handle event not Supported!\n",
|
|
__FUNCTION__);
|
|
NVSWITCH_ASSERT(0);
|
|
return NV_ERR_GENERIC;
|
|
}
|
|
|
|
static NvlStatus
|
|
_soeI2CAccessSend
|
|
(
|
|
nvswitch_device *device,
|
|
void *cpuAddr,
|
|
NvU64 dmaHandle,
|
|
NvU16 xferSize
|
|
)
|
|
{
|
|
FLCN *pFlcn = device->pSoe->pFlcn;
|
|
NvU32 cmdSeqDesc;
|
|
NV_STATUS status;
|
|
RM_FLCN_CMD_SOE cmd;
|
|
RM_SOE_CORE_CMD_I2C *pI2cCmd;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
|
|
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
|
|
|
cmd.hdr.unitId = RM_SOE_UNIT_CORE;
|
|
cmd.hdr.size = RM_SOE_CMD_SIZE(CORE, I2C);
|
|
|
|
pI2cCmd = &cmd.cmd.core.i2c;
|
|
RM_FLCN_U64_PACK(&pI2cCmd->dmaHandle, &dmaHandle);
|
|
pI2cCmd->xferSize = xferSize;
|
|
pI2cCmd->cmdType = RM_SOE_CORE_CMD_I2C_ACCESS;
|
|
|
|
cmdSeqDesc = 0;
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS * 5, &timeout);
|
|
status = flcnQueueCmdPostBlocking(device, pFlcn,
|
|
(PRM_FLCN_CMD)&cmd,
|
|
NULL, // pMsg
|
|
NULL, // pPayload
|
|
SOE_RM_CMDQ_LOG_ID,
|
|
&cmdSeqDesc,
|
|
&timeout);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to send I2C command to SOE status 0x%x\n",
|
|
__FUNCTION__, status);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
static NvlStatus
|
|
_soeI2cFlcnStatusToNvlStatus
|
|
(
|
|
NvU8 flcnStatus
|
|
)
|
|
{
|
|
switch (flcnStatus)
|
|
{
|
|
case FLCN_OK:
|
|
return NVL_SUCCESS;
|
|
case FLCN_ERR_INVALID_ARGUMENT:
|
|
return -NVL_BAD_ARGS;
|
|
case FLCN_ERR_OBJECT_NOT_FOUND:
|
|
return -NVL_NOT_FOUND;
|
|
case FLCN_ERROR:
|
|
return -NVL_ERR_GENERIC;
|
|
case FLCN_ERR_INVALID_STATE:
|
|
return -NVL_ERR_INVALID_STATE;
|
|
case FLCN_ERR_MORE_PROCESSING_REQUIRED:
|
|
return -NVL_MORE_PROCESSING_REQUIRED;
|
|
case FLCN_ERR_TIMEOUT:
|
|
return -NVL_IO_ERROR;
|
|
case FLCN_ERR_I2C_BUSY:
|
|
return -NVL_ERR_STATE_IN_USE;
|
|
case FLCN_ERR_NOT_SUPPORTED:
|
|
return -NVL_ERR_NOT_SUPPORTED;
|
|
default:
|
|
return -NVL_ERR_GENERIC;
|
|
}
|
|
}
|
|
|
|
static NvlStatus
|
|
_soeI2CAccess_LS10
|
|
(
|
|
nvswitch_device *device,
|
|
NVSWITCH_CTRL_I2C_INDEXED_PARAMS *pParams
|
|
)
|
|
{
|
|
NvlStatus ret;
|
|
NvU8 flcnRet;
|
|
PNVSWITCH_OBJI2C pI2c;
|
|
void *pCpuAddr;
|
|
NvU64 dmaHandle;
|
|
|
|
if (pParams == NULL)
|
|
{
|
|
return -NVL_BAD_ARGS;
|
|
}
|
|
|
|
pI2c = device->pI2c;
|
|
|
|
if (pI2c == NULL || !pI2c->soeI2CSupported)
|
|
{
|
|
return -NVL_ERR_NOT_SUPPORTED;
|
|
}
|
|
|
|
pCpuAddr = pI2c->pCpuAddr;
|
|
dmaHandle = pI2c->dmaHandle;
|
|
|
|
ret = nvswitch_os_sync_dma_region_for_cpu(device->os_handle, dmaHandle,
|
|
SOE_I2C_DMA_BUF_SIZE,
|
|
NVSWITCH_DMA_DIR_FROM_SYSMEM);
|
|
if (ret != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: nvswitch_os_sync_dma_region_for_cpu returned %d\n",
|
|
__FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
// Required for error reporting from SOE to driver
|
|
ct_assert(sizeof(NVSWITCH_CTRL_I2C_INDEXED_PARAMS) < SOE_I2C_STATUS_INDEX);
|
|
|
|
// Copy I2C struct into buffer
|
|
nvswitch_os_memcpy(pCpuAddr, pParams, sizeof(NVSWITCH_CTRL_I2C_INDEXED_PARAMS));
|
|
|
|
ret = nvswitch_os_sync_dma_region_for_device(device->os_handle, dmaHandle,
|
|
SOE_I2C_DMA_BUF_SIZE,
|
|
NVSWITCH_DMA_DIR_FROM_SYSMEM);
|
|
if (ret != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: nvswitch_os_sync_dma_region_for_device returned %d\n",
|
|
__FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
// Send I2C access command to SOE
|
|
ret = _soeI2CAccessSend(device, pCpuAddr, dmaHandle, SOE_I2C_DMA_BUF_SIZE);
|
|
if (ret != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: _soeI2CAccessSend returned %d\n",
|
|
__FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
// Get result
|
|
ret = nvswitch_os_sync_dma_region_for_cpu(device->os_handle, dmaHandle,
|
|
SOE_I2C_DMA_BUF_SIZE,
|
|
NVSWITCH_DMA_DIR_TO_SYSMEM);
|
|
if (ret != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: nvswitch_os_sync_dma_region_for_cpu returned %d\n",
|
|
__FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
nvswitch_os_memcpy(pParams, pCpuAddr, sizeof(NVSWITCH_CTRL_I2C_INDEXED_PARAMS));
|
|
|
|
// Return value of the I2C operation that was performed in SOE
|
|
flcnRet = ((NvU8*)pCpuAddr)[SOE_I2C_STATUS_INDEX];
|
|
ret = _soeI2cFlcnStatusToNvlStatus(flcnRet);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief set hal function pointers for functions defined in LR10 (i.e. this file)
|
|
*
|
|
* this function has to be at the end of the file so that all the
|
|
* other functions are already defined.
|
|
*
|
|
* @param[in] pFlcnable The flcnable for which to set hals
|
|
*/
|
|
void
|
|
soeSetupHal_LS10
|
|
(
|
|
SOE *pSoe
|
|
)
|
|
{
|
|
soe_hal *pHal = pSoe->base.pHal;
|
|
flcnable_hal *pParentHal = (flcnable_hal *)pHal;
|
|
|
|
soeSetupHal_LR10(pSoe);
|
|
|
|
pParentHal->fetchEngines = _soeFetchEngines_LS10;
|
|
pParentHal->handleInitEvent = _soeHandleInitEvent_LS10;
|
|
|
|
pHal->isCpuHalted = _soeIsCpuHalted_LS10;
|
|
pHal->service = _soeService_LS10;
|
|
pHal->serviceHalt = _soeServiceHalt_LS10;
|
|
pHal->processMessages = _soeProcessMessages_LS10;
|
|
pHal->waitForInitAck = _soeWaitForInitAck_LS10;
|
|
pHal->i2cAccess = _soeI2CAccess_LS10;
|
|
}
|