Files
open-gpu-kernel-modules/src/common/nvswitch/kernel/ls10/flcn_ls10.c
Andy Ritger dac2350c7f 525.78.01
2023-01-05 10:40:27 -08:00

512 lines
15 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 "common_nvswitch.h"
#include "ls10/ls10.h"
#include "flcn/flcn_nvswitch.h"
#include "nvswitch/ls10/dev_falcon_v4.h"
#include "nvswitch/ls10/dev_riscv_pri.h"
//
// Functions shared with LR10
//
void flcnSetupHal_LR10(PFLCN pFlcn);
static NvU32
_flcnRiscvRegRead_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 offset
)
{
// Probably should perform some checks on the offset, the device, and the engine descriptor
return nvswitch_reg_read_32(device, NV_FALCON2_SOE_BASE + offset);
}
static void
_flcnRiscvRegWrite_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 offset,
NvU32 data
)
{
// Probably should perform some checks on the offset, the device, and the engine descriptor
nvswitch_reg_write_32(device, NV_FALCON2_SOE_BASE + offset, data);
}
/*!
* @brief Retrieve the size of the falcon data memory.
*
* @param[in] device nvswitch_device pointer
* @param[in] pFlcn Falcon object pointer
* @param[in] bFalconReachable If set, returns size that can be reached by Falcon
*
* @return IMEM size in bytes
*/
static NvU32
_flcnDmemSize_LS10
(
nvswitch_device *device,
PFLCN pFlcn
)
{
NvU32 data = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_HWCFG3);
return (DRF_VAL(_PFALCON, _FALCON_HWCFG3, _DMEM_TOTAL_SIZE, data) <<
FALCON_DMEM_BLKSIZE2);
}
/*
* @brief Get the destination after masking
* off all but the OFFSET and BLOCK in IMEM
*
* @param[in] dst Destination in IMEM
*
* @returns dst with only OFFSET and BLOCK bits set
*/
static NvU32
_flcnSetImemAddr_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 dst
)
{
NVSWITCH_ASSERT(0);
return 0;
}
/*!
*
* @brief Copy contents of pSrc to IMEM
*
* @param[in] device nvswitch_device pointer
* @param[in] pFlcn Falcon object pointer
* @param[in] dst Destination in IMEM
* @param[in] pSrc IMEM contents
* @param[in] sizeInBytes Total IMEM size in bytes
* @param[in] bSecure NV_TRUE if IMEM is signed
* @param[in] tag IMEM tag
* @param[in] port PMB port to copy IMEM
*
* @returns void
*/
static void
_flcnImemCopyTo_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 dst,
NvU8 *pSrc,
NvU32 sizeBytes,
NvBool bSecure,
NvU32 tag,
NvU8 port
)
{
}
/*!
*
* @brief Mask the DMEM destination to have only the BLK and OFFSET bits set
*
* @param[in] dst Destination in DMEM
*
* @returns masked destination value in DMEM
*/
static NvU32
_flcnSetDmemAddr_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 dst
)
{
return (dst & (DRF_SHIFTMASK(NV_PFALCON_FALCON_DMEMC_OFFS) |
DRF_SHIFTMASK(NV_PFALCON_FALCON_DMEMC_BLK)));
}
/*!
* Depending on the direction of the copy, copies 'sizeBytes' to/from 'pBuf'
* from/to DMEM offset 'dmemAddr' using DMEM access port 'port'.
*
* @param[in] device nvswitch_device pointer
* @param[in] pFlcn Falcon object pointer
* @param[in] dmemAddr The DMEM offset for the copy
* @param[in] pBuf The pointer to the buffer containing the data to copy
* @param[in] sizeBytes The number of bytes to copy
* @param[in] port The DMEM port index to use when accessing DMEM
* @param[in] bCopyFrom Boolean representing the copy direction (to/from DMEM)
*
* @return NV_OK if the data was successfully copied
* NV_ERR_INVALID_ARGUMENT if the input argument(s) is/are invalid
*/
static NV_STATUS
_flcnDmemTransfer_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 dmemAddr,
NvU8 *pBuf,
NvU32 sizeBytes,
NvU8 port,
NvBool bCopyFrom
)
{
NvU32 numWords;
NvU32 numBytes;
NvU32 *pData = (NvU32 *)pBuf;
NvU32 reg32;
NvU32 i;
// simply return if the copy-size is zero
if (sizeBytes == 0)
{
NVSWITCH_PRINT(device, ERROR, "Zero-byte copy requested\n");
NVSWITCH_ASSERT(0);
return -NVL_BAD_ARGS;
}
// the DMEM address must be 4-byte aligned
if (!NV_IS_ALIGNED(dmemAddr, FLCN_DMEM_ACCESS_ALIGNMENT))
{
NVSWITCH_PRINT(device, ERROR, "Source not 4-byte aligned. dmemAddr=0x%08x\n", dmemAddr);
NVSWITCH_ASSERT(0);
return -NVL_BAD_ARGS;
}
// calculate the number of words and bytes
numWords = sizeBytes >> 2;
numBytes = sizeBytes & NVSWITCH_MASK_BITS(2);
// mask off all but the OFFSET and BLOCK in DMEM offset
reg32 = flcnSetDmemAddr_HAL(device, pFlcn, dmemAddr);
if (bCopyFrom)
{
// mark auto-increment on read
reg32 = FLD_SET_DRF_NUM(_PFALCON, _FALCON_DMEMC, _AINCR, 0x1, reg32);
}
else
{
// mark auto-increment on write
reg32 = FLD_SET_DRF_NUM(_PFALCON, _FALCON_DMEMC, _AINCW, 0x1, reg32);
}
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMC(port), reg32);
// directly copy as many words as possible
for (i = 0; i < numWords; i++)
{
if (bCopyFrom)
{
pData[i] = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMD(port));
}
else
{
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMD(port), pData[i]);
}
}
// Check if there are left over bytes to copy
if (numBytes > 0)
{
NvU32 bytesCopied = numWords << 2;
//
// Read the contents first. If we're copying to the DMEM, we've set
// autoincrement on write, so reading does not modify the pointer. We
// can, thus, do a read/modify/write without needing to worry about the
// pointer having moved forward. There is no special explanation needed
// if we're copying from the DMEM since this is the last access to HW
// in that case.
//
reg32 = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMD(port));
if (bCopyFrom)
{
// Copy byte-by-byte into the buffer as required
for (i = 0; i < numBytes; i++)
{
pBuf[bytesCopied + i] = ((NvU8 *)&reg32)[i];
}
}
else
{
// Modify what we read byte-by-byte before writing to dmem
for (i = 0; i < numBytes; i++)
{
((NvU8 *)&reg32)[i] = pBuf[bytesCopied + i];
}
flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_DMEMD(port), reg32);
}
}
return NVL_SUCCESS;
}
static void
_flcnDbgInfoCaptureRiscvPcTrace_LS10
(
nvswitch_device *device,
PFLCN pFlcn
)
{
NvU32 ctl, ridx, widx, bufferSize;
NvBool bWasFull;
// Only supported on riscv
if (!UPROC_ENG_ARCH_FALCON_RISCV(pFlcn))
{
NVSWITCH_PRINT(device, ERROR, "%s: is not supported on falcon\n",
__FUNCTION__);
NVSWITCH_ASSERT(0);
return;
}
ctl = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACECTL);
if (ctl == 0)
{
NVSWITCH_PRINT(device, ERROR, "Trace buffer is disabled.\n");
return;
}
bWasFull = FLD_TEST_DRF_NUM(_PRISCV_RISCV, _TRACECTL,_FULL, 1, ctl);
if (bWasFull)
{
NVSWITCH_PRINT(device, INFO, "%s: Trace buffer full. Entries may have been lost.\n", __FUNCTION__);
}
// Reset and disable buffer, we don't need it during dump (and if core is running)
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACECTL, 0);
widx = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_WTIDX);
widx = DRF_VAL(_PRISCV_RISCV, _TRACE_WTIDX, _WTIDX, widx);
ridx = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_RDIDX);
bufferSize = DRF_VAL(_PRISCV_RISCV, _TRACE_RDIDX, _MAXIDX, ridx);
ridx = DRF_VAL(_PRISCV_RISCV, _TRACE_RDIDX, _RDIDX, ridx);
if (bufferSize > 0)
{
NvU32 entry;
switch (DRF_VAL(_PRISCV_RISCV, _TRACECTL, _MODE, ctl))
{
case NV_PRISCV_RISCV_TRACECTL_MODE_FULL:
NVSWITCH_PRINT(device, ERROR, "Tracebuffer is in full mode.\n");
break;
case NV_PRISCV_RISCV_TRACECTL_MODE_REDUCED:
NVSWITCH_PRINT(device, ERROR, "Tracebuffer is in reduced mode.\n");
break;
case NV_PRISCV_RISCV_TRACECTL_MODE_STACK:
NVSWITCH_PRINT(device, ERROR, "Tracebuffer is in stack mode.\n");
break;
default:
NVSWITCH_PRINT(device, ERROR, "Tracebuffer is in unknown mode.\n");
}
NVSWITCH_PRINT(device, ERROR, "Entries (most recent first):\n");
ridx = widx;
for (entry = 0; entry < bufferSize; entry++)
{
NvU64 pc;
ridx = ridx > 0 ? ridx - 1 : bufferSize - 1;
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_RDIDX,
DRF_NUM(_PRISCV_RISCV, _TRACE_RDIDX, _RDIDX, ridx));
pc = flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACEPC_HI);
pc = (pc << 32) | flcnRiscvRegRead_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACEPC_LO);
// Non-mod2 values are invalid here, so stop (this likely indicates an init-marker val)
if (NvU64_LO32(pc) % 2U != 0U)
{
break;
}
NVSWITCH_PRINT(device, ERROR, "%s: TRACE[%d] = 0x%16llx\n", __FUNCTION__, entry, pc);
}
}
// reset trace buffer
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_RDIDX, 0);
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACE_WTIDX, 0);
// Clear full and empty bits
ctl = FLD_SET_DRF_NUM(_PRISCV_RISCV, _TRACECTL, _FULL, 0, ctl);
ctl = FLD_SET_DRF_NUM(_PRISCV_RISCV, _TRACECTL, _EMPTY, 0, ctl);
flcnRiscvRegWrite_HAL(device, pFlcn, NV_PRISCV_RISCV_TRACECTL, ctl);
}
static NV_STATUS
_flcnDebugBufferInit_LS10
(
nvswitch_device *device,
PFLCN pFlcn,
NvU32 debugBufferMaxSize,
NvU32 writeRegAddr,
NvU32 readRegAddr
)
{
return NVL_SUCCESS;
}
static NV_STATUS
_flcnDebugBufferDestroy_LS10
(
nvswitch_device *device,
PFLCN pFlcn
)
{
return NVL_SUCCESS;
}
static NV_STATUS
_flcnDebugBufferDisplay_LS10
(
nvswitch_device *device,
PFLCN pFlcn
)
{
return NVL_SUCCESS;
}
static NvBool
_flcnDebugBufferIsEmpty_LS10
(
nvswitch_device *device,
PFLCN pFlcn
)
{
return NV_TRUE;
}
//
// Store pointers to ucode header and data.
// Preload ucode from registry if available.
//
NV_STATUS
_flcnConstruct_LS10
(
nvswitch_device *device,
PFLCN pFlcn
)
{
NV_STATUS status;
PFLCNABLE pFlcnable = pFlcn->pFlcnable;
PFALCON_QUEUE_INFO pQueueInfo;
pFlcn->bConstructed = NV_TRUE;
// Set arch to Riscv
pFlcn->engArch = NV_UPROC_ENGINE_ARCH_FALCON_RISCV;
// Allocate the memory for Queue Data Structure if needed.
if (pFlcn->bQueuesEnabled)
{
pQueueInfo = pFlcn->pQueueInfo = nvswitch_os_malloc(sizeof(*pQueueInfo));
if (pQueueInfo == NULL)
{
status = NV_ERR_NO_MEMORY;
NVSWITCH_ASSERT(0);
goto _flcnConstruct_LR10_fail;
}
nvswitch_os_memset(pQueueInfo, 0, sizeof(FALCON_QUEUE_INFO));
// Assert if Number of Queues are zero
NVSWITCH_ASSERT(pFlcn->numQueues != 0);
pQueueInfo->pQueues = nvswitch_os_malloc(sizeof(FLCNQUEUE) * pFlcn->numQueues);
if (pQueueInfo->pQueues == NULL)
{
status = NV_ERR_NO_MEMORY;
NVSWITCH_ASSERT(0);
goto _flcnConstruct_LR10_fail;
}
nvswitch_os_memset(pQueueInfo->pQueues, 0, sizeof(FLCNQUEUE) * pFlcn->numQueues);
// Sequences can be optional
if (pFlcn->numSequences != 0)
{
if ((pFlcn->numSequences - 1) > ((NvU32)NV_U8_MAX))
{
status = NV_ERR_OUT_OF_RANGE;
NVSWITCH_PRINT(device, ERROR,
"Max numSequences index = %d cannot fit into byte\n",
(pFlcn->numSequences - 1));
NVSWITCH_ASSERT(0);
goto _flcnConstruct_LR10_fail;
}
flcnQueueSeqInfoStateInit(device, pFlcn);
}
}
// DEBUG
NVSWITCH_PRINT(device, INFO, "Falcon: %s\n", flcnGetName_HAL(device, pFlcn));
NVSWITCH_ASSERT(pFlcnable != NULL);
flcnableGetExternalConfig(device, pFlcnable, &pFlcn->extConfig);
return NV_OK;
_flcnConstruct_LR10_fail:
// call flcnDestruct to free the memory allocated in this construct function
flcnDestruct_HAL(device, pFlcn);
return status;
}
/**
* @brief set hal function pointers for functions defined in
* LS10 (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] pFlcn The flcn for which to set hals
*/
void
flcnSetupHal_LS10
(
PFLCN pFlcn
)
{
flcn_hal *pHal = pFlcn->pHal;
flcnSetupHal_LR10(pFlcn);
pHal->riscvRegRead = _flcnRiscvRegRead_LS10;
pHal->riscvRegWrite = _flcnRiscvRegWrite_LS10;
pHal->dmemTransfer = _flcnDmemTransfer_LS10;
pHal->setDmemAddr = _flcnSetDmemAddr_LS10;
pHal->imemCopyTo = _flcnImemCopyTo_LS10;
pHal->setImemAddr = _flcnSetImemAddr_LS10;
pHal->dmemSize = _flcnDmemSize_LS10;
pHal->dbgInfoCaptureRiscvPcTrace = _flcnDbgInfoCaptureRiscvPcTrace_LS10;
pHal->debugBufferInit = _flcnDebugBufferInit_LS10;
pHal->debugBufferDestroy = _flcnDebugBufferDestroy_LS10;
pHal->debugBufferDisplay = _flcnDebugBufferDisplay_LS10;
pHal->debugBufferIsEmpty = _flcnDebugBufferIsEmpty_LS10;
pHal->construct = _flcnConstruct_LS10;
}