mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-03-12 08:39:53 +00:00
515.43.04
This commit is contained in:
734
src/common/nvswitch/kernel/smbpbi_nvswitch.c
Normal file
734
src/common/nvswitch/kernel/smbpbi_nvswitch.c
Normal file
@@ -0,0 +1,734 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2020-2021 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 "nvfixedtypes.h"
|
||||
#include "common_nvswitch.h"
|
||||
#include "error_nvswitch.h"
|
||||
#include "rmsoecmdif.h"
|
||||
#include "smbpbi_nvswitch.h"
|
||||
#include "nvswitch/lr10/dev_ext_devices.h"
|
||||
|
||||
#include "flcn/flcn_nvswitch.h"
|
||||
|
||||
#include "rmflcncmdif_nvswitch.h"
|
||||
|
||||
#define GET_PFIFO_FROM_DEVICE(dev) (&(dev)->pSmbpbi->sharedSurface->inforomObjects.DEM.object.v1)
|
||||
|
||||
#define DEM_FIFO_SIZE INFOROM_DEM_OBJECT_V1_00_FIFO_SIZE
|
||||
#define DEM_FIFO_PTR(x) ((x) % DEM_FIFO_SIZE)
|
||||
#define DEM_PTR_DIFF(cur, next) (((next) > (cur)) ? ((next) - (cur)) : \
|
||||
(DEM_FIFO_SIZE - ((cur) - (next))))
|
||||
#define DEM_BYTES_OCCUPIED(pf) DEM_PTR_DIFF((pf)->readOffset, (pf)->writeOffset)
|
||||
//
|
||||
// See how much space is available in the FIFO.
|
||||
// Must leave 1 word free so the write pointer does not
|
||||
// catch up with the read pointer. That would be indistinguishable
|
||||
// from an empty FIFO.
|
||||
//
|
||||
#define DEM_BYTES_AVAILABLE(pf) (DEM_PTR_DIFF((pf)->writeOffset, (pf)->readOffset) - \
|
||||
sizeof(NvU32))
|
||||
#define DEM_RECORD_SIZE_MAX (sizeof(NV_MSGBOX_DEM_RECORD) \
|
||||
+ NV_MSGBOX_MAX_DRIVER_EVENT_MSG_TXT_SIZE)
|
||||
#define DEM_RECORD_SIZE_MIN (sizeof(NV_MSGBOX_DEM_RECORD) + 1)
|
||||
|
||||
#define FIFO_REC_LOOP_ITERATOR _curPtr
|
||||
#define FIFO_REC_LOOP_REC_PTR _recPtr
|
||||
#define FIFO_REC_LOOP_REC_SIZE _recSize
|
||||
#define FIFO_REC_LOOP_START(pf, cond) \
|
||||
{ \
|
||||
NvU16 _nextPtr; \
|
||||
for (FIFO_REC_LOOP_ITERATOR = (pf)->readOffset; cond; FIFO_REC_LOOP_ITERATOR = _nextPtr) \
|
||||
{ \
|
||||
NV_MSGBOX_DEM_RECORD *FIFO_REC_LOOP_REC_PTR = (NV_MSGBOX_DEM_RECORD *) \
|
||||
((pf)->fifoBuffer + FIFO_REC_LOOP_ITERATOR); \
|
||||
NvU16 FIFO_REC_LOOP_REC_SIZE = \
|
||||
FIFO_REC_LOOP_REC_PTR->recordSize * sizeof(NvU32);
|
||||
|
||||
#define FIFO_REC_LOOP_END \
|
||||
_nextPtr = DEM_FIFO_PTR(FIFO_REC_LOOP_ITERATOR + FIFO_REC_LOOP_REC_SIZE); \
|
||||
} \
|
||||
}
|
||||
|
||||
static void _smbpbiDemInit(nvswitch_device *device, struct smbpbi *pSmbpbi, struct INFOROM_DEM_OBJECT_V1_00 *pFifo);
|
||||
static void _nvswitch_smbpbi_dem_flush(nvswitch_device *device);
|
||||
|
||||
|
||||
NvlStatus
|
||||
nvswitch_smbpbi_init
|
||||
(
|
||||
nvswitch_device *device
|
||||
)
|
||||
{
|
||||
NV_STATUS status;
|
||||
NvU64 dmaHandle;
|
||||
void *cpuAddr;
|
||||
|
||||
if (!device->pSoe)
|
||||
{
|
||||
return -NVL_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// Create DMA mapping for SMBPBI transactions
|
||||
status = nvswitch_os_alloc_contig_memory(device->os_handle, &cpuAddr,
|
||||
sizeof(SOE_SMBPBI_SHARED_SURFACE),
|
||||
(device->dma_addr_width == 32));
|
||||
if (status != NVL_SUCCESS)
|
||||
{
|
||||
NVSWITCH_PRINT(device, ERROR, "Failed to allocate contig memory, rc:%d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
nvswitch_os_memset(cpuAddr, 0, sizeof(SOE_SMBPBI_SHARED_SURFACE));
|
||||
|
||||
status = nvswitch_os_map_dma_region(device->os_handle, cpuAddr, &dmaHandle,
|
||||
sizeof(SOE_SMBPBI_SHARED_SURFACE),
|
||||
NVSWITCH_DMA_DIR_BIDIRECTIONAL);
|
||||
if (status != NVL_SUCCESS)
|
||||
{
|
||||
NVSWITCH_PRINT(device, ERROR,
|
||||
"Failed to map dma region for SMBPBI shared surface, rc:%d\n",
|
||||
status);
|
||||
goto os_map_dma_region_fail;
|
||||
}
|
||||
|
||||
device->pSmbpbi = nvswitch_os_malloc(sizeof(struct smbpbi));
|
||||
if (!device->pSmbpbi)
|
||||
{
|
||||
status = -NVL_NO_MEM;
|
||||
goto smbpbi_init_fail;
|
||||
}
|
||||
|
||||
device->pSmbpbi->sharedSurface = cpuAddr;
|
||||
device->pSmbpbi->dmaHandle = dmaHandle;
|
||||
|
||||
return NVL_SUCCESS;
|
||||
|
||||
smbpbi_init_fail:
|
||||
nvswitch_os_unmap_dma_region(device->os_handle, cpuAddr, dmaHandle,
|
||||
sizeof(SOE_SMBPBI_SHARED_SURFACE), NVSWITCH_DMA_DIR_BIDIRECTIONAL);
|
||||
os_map_dma_region_fail:
|
||||
nvswitch_os_free_contig_memory(device->os_handle, cpuAddr, sizeof(SOE_SMBPBI_SHARED_SURFACE));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NvlStatus
|
||||
nvswitch_smbpbi_post_init
|
||||
(
|
||||
nvswitch_device * device
|
||||
)
|
||||
{
|
||||
struct smbpbi *pSmbpbi = device->pSmbpbi;
|
||||
FLCN *pFlcn;
|
||||
NvU64 dmaHandle;
|
||||
RM_FLCN_CMD_SOE cmd;
|
||||
NVSWITCH_TIMEOUT timeout;
|
||||
NvU32 cmdSeqDesc;
|
||||
RM_SOE_SMBPBI_CMD_INIT *pInitCmd = &cmd.cmd.smbpbiCmd.init;
|
||||
NvlStatus status;
|
||||
|
||||
if (!device->pSmbpbi || !device->pInforom)
|
||||
{
|
||||
return -NVL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
// Populate shared surface with static InfoROM data
|
||||
nvswitch_inforom_read_static_data(device, device->pInforom,
|
||||
&device->pSmbpbi->sharedSurface->inforomObjects);
|
||||
|
||||
pFlcn = device->pSoe->pFlcn;
|
||||
dmaHandle = pSmbpbi->dmaHandle;
|
||||
|
||||
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.unitId = RM_SOE_UNIT_SMBPBI;
|
||||
cmd.hdr.size = RM_SOE_CMD_SIZE(SMBPBI, INIT);
|
||||
cmd.cmd.smbpbiCmd.cmdType = RM_SOE_SMBPBI_CMD_ID_INIT;
|
||||
RM_FLCN_U64_PACK(&pInitCmd->dmaHandle, &dmaHandle);
|
||||
|
||||
//
|
||||
// Make the interval twice the heartbeat period to avoid
|
||||
// skew between driver and soe threads
|
||||
//
|
||||
pInitCmd->driverPollingPeriodUs = (NVSWITCH_HEARTBEAT_INTERVAL_NS / 1000) * 2;
|
||||
|
||||
nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS, &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);
|
||||
if (status != NV_OK)
|
||||
{
|
||||
NVSWITCH_PRINT(device, ERROR, "%s: SMBPBI Init command failed. rc:%d\n",
|
||||
__FUNCTION__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
nvswitch_lib_smbpbi_log_sxid(device, NVSWITCH_ERR_NO_ERROR,
|
||||
"NVSWITCH SMBPBI server is online.");
|
||||
|
||||
NVSWITCH_PRINT(device, INFO, "%s: SMBPBI POST INIT completed\n", __FUNCTION__);
|
||||
|
||||
return NVL_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_nvswitch_smbpbi_send_unload
|
||||
(
|
||||
nvswitch_device *device
|
||||
)
|
||||
{
|
||||
FLCN *pFlcn;
|
||||
RM_FLCN_CMD_SOE cmd;
|
||||
NVSWITCH_TIMEOUT timeout;
|
||||
NvU32 cmdSeqDesc;
|
||||
NvlStatus status;
|
||||
|
||||
pFlcn = device->pSoe->pFlcn;
|
||||
|
||||
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.unitId = RM_SOE_UNIT_SMBPBI;
|
||||
cmd.hdr.size = RM_SOE_CMD_SIZE(SMBPBI, UNLOAD);
|
||||
cmd.cmd.smbpbiCmd.cmdType = RM_SOE_SMBPBI_CMD_ID_UNLOAD;
|
||||
|
||||
nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS, &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);
|
||||
if (status != NV_OK)
|
||||
{
|
||||
NVSWITCH_PRINT(device, ERROR, "%s: SMBPBI unload command failed. rc:%d\n",
|
||||
__FUNCTION__, status);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvswitch_smbpbi_unload
|
||||
(
|
||||
nvswitch_device *device
|
||||
)
|
||||
{
|
||||
if (device->pSmbpbi)
|
||||
{
|
||||
_nvswitch_smbpbi_send_unload(device);
|
||||
_nvswitch_smbpbi_dem_flush(device);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvswitch_smbpbi_destroy
|
||||
(
|
||||
nvswitch_device *device
|
||||
)
|
||||
{
|
||||
if (device->pSmbpbi)
|
||||
{
|
||||
nvswitch_os_unmap_dma_region(device->os_handle,
|
||||
device->pSmbpbi->sharedSurface,
|
||||
device->pSmbpbi->dmaHandle,
|
||||
sizeof(SOE_SMBPBI_SHARED_SURFACE),
|
||||
NVSWITCH_DMA_DIR_BIDIRECTIONAL);
|
||||
nvswitch_os_free_contig_memory(device->os_handle, device->pSmbpbi->sharedSurface,
|
||||
sizeof(SOE_SMBPBI_SHARED_SURFACE));
|
||||
nvswitch_os_free(device->pSmbpbi);
|
||||
device->pSmbpbi = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
NvlStatus
|
||||
nvswitch_smbpbi_refresh_ecc_counts
|
||||
(
|
||||
nvswitch_device *device
|
||||
)
|
||||
{
|
||||
PRM_SOE_SMBPBI_INFOROM_DATA pObjs;
|
||||
struct inforom *pInforom = device->pInforom;
|
||||
NvU64 corCnt;
|
||||
NvU64 uncCnt;
|
||||
|
||||
if ((device->pSmbpbi == NULL) || (device->pSmbpbi->sharedSurface == NULL))
|
||||
{
|
||||
return -NVL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (pInforom == NULL || pInforom->pEccState == NULL)
|
||||
{
|
||||
return -NVL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
device->hal.nvswitch_inforom_ecc_get_total_errors(device, pInforom->pEccState->pEcc,
|
||||
&corCnt, &uncCnt);
|
||||
|
||||
pObjs = &device->pSmbpbi->sharedSurface->inforomObjects;
|
||||
NvU64_ALIGN32_PACK(&(pObjs->ECC.correctedTotal), &corCnt);
|
||||
NvU64_ALIGN32_PACK(&(pObjs->ECC.uncorrectedTotal), &uncCnt);
|
||||
|
||||
return NVL_SUCCESS;
|
||||
}
|
||||
|
||||
NvlStatus
|
||||
nvswitch_inforom_dem_load
|
||||
(
|
||||
nvswitch_device *device
|
||||
)
|
||||
{
|
||||
NvlStatus status;
|
||||
NvU8 version = 0;
|
||||
NvU8 subversion = 0;
|
||||
struct inforom *pInforom = device->pInforom;
|
||||
NvU8 *pPackedObject = NULL;
|
||||
struct INFOROM_DEM_OBJECT_V1_00 *pFifo;
|
||||
|
||||
if ((pInforom == NULL) || (device->pSmbpbi == NULL) ||
|
||||
(device->pSmbpbi->sharedSurface == NULL))
|
||||
{
|
||||
return -NVL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
pFifo = GET_PFIFO_FROM_DEVICE(device);
|
||||
|
||||
status = nvswitch_inforom_get_object_version_info(device, "DEM", &version,
|
||||
&subversion);
|
||||
if (status != NVL_SUCCESS)
|
||||
{
|
||||
NVSWITCH_PRINT(device, INFO, "no DEM object found, rc:%d\n", status);
|
||||
goto nvswitch_inforom_dem_load_fail;
|
||||
}
|
||||
|
||||
if (!INFOROM_OBJECT_SUBVERSION_SUPPORTS_NVSWITCH(subversion))
|
||||
{
|
||||
NVSWITCH_PRINT(device, WARN, "DEM v%u.%u not supported\n",
|
||||
version, subversion);
|
||||
status = -NVL_ERR_NOT_SUPPORTED;
|
||||
goto nvswitch_inforom_dem_load_fail;
|
||||
}
|
||||
|
||||
NVSWITCH_PRINT(device, INFO, "DEM v%u.%u found\n", version, subversion);
|
||||
|
||||
if (version != 1)
|
||||
{
|
||||
NVSWITCH_PRINT(device, WARN, "DEM v%u.%u not supported\n",
|
||||
version, subversion);
|
||||
status = -NVL_ERR_NOT_SUPPORTED;
|
||||
goto nvswitch_inforom_dem_load_fail;
|
||||
}
|
||||
|
||||
pPackedObject = nvswitch_os_malloc(INFOROM_DEM_OBJECT_V1_00_PACKED_SIZE);
|
||||
|
||||
if (pPackedObject == NULL)
|
||||
{
|
||||
status = -NVL_NO_MEM;
|
||||
goto nvswitch_inforom_dem_load_fail;
|
||||
}
|
||||
|
||||
status = nvswitch_inforom_load_object(device, pInforom, "DEM",
|
||||
INFOROM_DEM_OBJECT_V1_00_FMT,
|
||||
pPackedObject,
|
||||
pFifo);
|
||||
if (status != NVL_SUCCESS)
|
||||
{
|
||||
NVSWITCH_PRINT(device, ERROR, "Failed to load DEM object, rc: %d\n",
|
||||
status);
|
||||
goto nvswitch_inforom_dem_load_fail;
|
||||
}
|
||||
|
||||
nvswitch_inforom_dem_load_fail:
|
||||
|
||||
if (pPackedObject)
|
||||
{
|
||||
nvswitch_os_free(pPackedObject);
|
||||
}
|
||||
|
||||
//
|
||||
// Mark the cached DEM as usable for Xid logging, even if we were
|
||||
// unable to find it in the InfoROM image.
|
||||
//
|
||||
|
||||
device->pSmbpbi->sharedSurface->inforomObjects.DEM.bValid = NV_TRUE;
|
||||
|
||||
_smbpbiDemInit(device, device->pSmbpbi, pFifo);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Validate/Initialize the Driver Event Message (SXid) FIFO buffer
|
||||
*
|
||||
* @param[in] device device object pointer
|
||||
* @param[in] pSmbpbi SMBPBI object pointer
|
||||
* @param[in,out] pFifo DEM object pointer
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static void
|
||||
_smbpbiDemInit
|
||||
(
|
||||
nvswitch_device *device,
|
||||
struct smbpbi *pSmbpbi,
|
||||
struct INFOROM_DEM_OBJECT_V1_00 *pFifo
|
||||
)
|
||||
{
|
||||
NvU8 msgLeft;
|
||||
unsigned recordsHeld = 0;
|
||||
NvU16 FIFO_REC_LOOP_ITERATOR;
|
||||
NvU16 bytesOccupied;
|
||||
NvU16 bytesSeen;
|
||||
NvBool status = NV_FALSE;
|
||||
|
||||
// validate the FIFO buffer
|
||||
|
||||
if ((DEM_FIFO_PTR(pFifo->writeOffset) != pFifo->writeOffset) ||
|
||||
(DEM_FIFO_PTR(pFifo->readOffset) != pFifo->readOffset) ||
|
||||
((pFifo->writeOffset % sizeof(NvU32)) != 0) ||
|
||||
((pFifo->readOffset % sizeof(NvU32)) != 0))
|
||||
{
|
||||
goto smbpbiDemInit_exit;
|
||||
}
|
||||
|
||||
if (pFifo->writeOffset == pFifo->readOffset)
|
||||
{
|
||||
// The FIFO is empty
|
||||
status = NV_TRUE;
|
||||
goto smbpbiDemInit_exit;
|
||||
}
|
||||
|
||||
//
|
||||
// This HAL extracts from a scratch register the count of DEM messages
|
||||
// in the FIFO that has not yet been requested by the SMBPBI client.
|
||||
// If the FIFO holds more messages than that, it means those in excess
|
||||
// of this count have been delivered to the client by PreOS app.
|
||||
//
|
||||
if (device->hal.nvswitch_smbpbi_get_dem_num_messages(device, &msgLeft) != NVL_SUCCESS)
|
||||
{
|
||||
// assume the maximum
|
||||
msgLeft = ~0;
|
||||
}
|
||||
|
||||
if (msgLeft == 0)
|
||||
{
|
||||
// Nothing of value in the FIFO. Lets reset it explicitly.
|
||||
status = NV_TRUE;
|
||||
pFifo->writeOffset = 0;
|
||||
pFifo->readOffset = 0;
|
||||
goto smbpbiDemInit_exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Count the messages in the FIFO, while also checking the structure
|
||||
// for integrity. Reset the FIFO in case any corruption is found.
|
||||
//
|
||||
bytesOccupied = DEM_BYTES_OCCUPIED(pFifo);
|
||||
|
||||
bytesSeen = 0;
|
||||
FIFO_REC_LOOP_START(pFifo, bytesSeen < bytesOccupied)
|
||||
if ((_recSize > DEM_RECORD_SIZE_MAX) ||
|
||||
(FIFO_REC_LOOP_REC_SIZE < DEM_RECORD_SIZE_MIN))
|
||||
{
|
||||
goto smbpbiDemInit_exit;
|
||||
}
|
||||
|
||||
bytesSeen += FIFO_REC_LOOP_REC_SIZE;
|
||||
++recordsHeld;
|
||||
FIFO_REC_LOOP_END
|
||||
|
||||
if ((bytesSeen != bytesOccupied) || (msgLeft > recordsHeld))
|
||||
{
|
||||
goto smbpbiDemInit_exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Advance the FIFO read ptr in order to remove those messages that
|
||||
// have already been delivered to the client.
|
||||
//
|
||||
FIFO_REC_LOOP_START(pFifo, recordsHeld > msgLeft)
|
||||
--recordsHeld;
|
||||
FIFO_REC_LOOP_END
|
||||
|
||||
pFifo->readOffset = FIFO_REC_LOOP_ITERATOR;
|
||||
status = NV_TRUE;
|
||||
|
||||
smbpbiDemInit_exit:
|
||||
|
||||
if (!status)
|
||||
{
|
||||
// Reset the FIFO
|
||||
pFifo->writeOffset = 0;
|
||||
pFifo->readOffset = 0;
|
||||
pFifo->seqNumber = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_nvswitch_smbpbi_dem_flush(nvswitch_device *device)
|
||||
{
|
||||
NvU8 *pPackedObject = NULL;
|
||||
struct INFOROM_DEM_OBJECT_V1_00 *pFifo;
|
||||
NvlStatus status = NVL_SUCCESS;
|
||||
|
||||
pPackedObject = nvswitch_os_malloc(INFOROM_DEM_OBJECT_V1_00_PACKED_SIZE);
|
||||
|
||||
if (pPackedObject == NULL)
|
||||
{
|
||||
status = -NVL_NO_MEM;
|
||||
goto _nvswitch_smbpbi_dem_flush_exit;
|
||||
}
|
||||
|
||||
pFifo = GET_PFIFO_FROM_DEVICE(device);
|
||||
|
||||
status = nvswitch_inforom_write_object(device, "DEM",
|
||||
INFOROM_DEM_OBJECT_V1_00_FMT,
|
||||
pFifo,
|
||||
pPackedObject);
|
||||
|
||||
_nvswitch_smbpbi_dem_flush_exit:
|
||||
nvswitch_os_free(pPackedObject);
|
||||
|
||||
if (status != NVL_SUCCESS)
|
||||
{
|
||||
NVSWITCH_PRINT(device, ERROR, "DEM object write failed, status=%d\n",
|
||||
status);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* A helper to create a new DEM FIFO record
|
||||
*
|
||||
* @param[in,out] pFifo DEM object pointer
|
||||
* @param[in] num Xid number
|
||||
* @param[in] osErrorString text message to store
|
||||
* @param[in] msglen message size
|
||||
* @param[out] pRecSize new record size in bytes
|
||||
*
|
||||
* @return ptr to the new record
|
||||
* @return NULL if there's no room in the FIFO
|
||||
* or dynamic allocation error
|
||||
*/
|
||||
static NV_MSGBOX_DEM_RECORD *
|
||||
_makeNewRecord
|
||||
(
|
||||
INFOROM_DEM_OBJECT_V1_00 *pFifo,
|
||||
NvU32 num,
|
||||
NvU8 *osErrorString,
|
||||
NvU32 msglen,
|
||||
NvU32 *pRecSize
|
||||
)
|
||||
{
|
||||
NV_MSGBOX_DEM_RECORD *pNewRec;
|
||||
|
||||
*pRecSize = NV_MIN(sizeof(NV_MSGBOX_DEM_RECORD) + msglen,
|
||||
DEM_RECORD_SIZE_MAX);
|
||||
|
||||
if ((*pRecSize > DEM_BYTES_AVAILABLE(pFifo)) ||
|
||||
((pNewRec = nvswitch_os_malloc(*pRecSize)) == NULL))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fill the new record.
|
||||
nvswitch_os_memset(pNewRec, 0, *pRecSize);
|
||||
pNewRec->recordSize = NV_UNSIGNED_DIV_CEIL(*pRecSize, sizeof(NvU32));
|
||||
pNewRec->xidId = num;
|
||||
pNewRec->seqNumber = pFifo->seqNumber++;
|
||||
pNewRec->timeStamp = nvswitch_os_get_platform_time() / NVSWITCH_NSEC_PER_SEC;
|
||||
|
||||
if (msglen > NV_MSGBOX_MAX_DRIVER_EVENT_MSG_TXT_SIZE)
|
||||
{
|
||||
// The text string is too long. Truncate and notify the client.
|
||||
pNewRec->flags = FLD_SET_DRF(_MSGBOX, _DEM_RECORD_FLAGS,
|
||||
_TRUNC, _SET, pNewRec->flags);
|
||||
msglen = NV_MSGBOX_MAX_DRIVER_EVENT_MSG_TXT_SIZE - 1;
|
||||
}
|
||||
|
||||
nvswitch_os_memcpy(pNewRec->textMessage, osErrorString, msglen);
|
||||
|
||||
return pNewRec;
|
||||
}
|
||||
|
||||
/*!
|
||||
* A helper to add the new record to the DEM FIFO
|
||||
*
|
||||
* @param[in,out] pFifo DEM object pointer
|
||||
* @param[in] pNewRec the new record
|
||||
* @param[in] recSize new record size in bytes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static void
|
||||
_addNewRecord
|
||||
(
|
||||
INFOROM_DEM_OBJECT_V1_00 *pFifo,
|
||||
NV_MSGBOX_DEM_RECORD *pNewRec,
|
||||
NvU32 recSize
|
||||
)
|
||||
{
|
||||
NvU16 rem;
|
||||
NvU16 curPtr;
|
||||
NvU16 copySz;
|
||||
NvU8 *srcPtr;
|
||||
|
||||
// Copy the new record into the FIFO, handling a possible wrap-around.
|
||||
rem = recSize;
|
||||
curPtr = pFifo->writeOffset;
|
||||
srcPtr = (NvU8 *)pNewRec;
|
||||
while (rem > 0)
|
||||
{
|
||||
copySz = NV_MIN(rem, DEM_FIFO_SIZE - curPtr);
|
||||
nvswitch_os_memcpy(pFifo->fifoBuffer + curPtr, srcPtr, copySz);
|
||||
rem -= copySz;
|
||||
srcPtr += copySz;
|
||||
curPtr = DEM_FIFO_PTR(curPtr + copySz);
|
||||
}
|
||||
|
||||
// Advance the FIFO write ptr.
|
||||
pFifo->writeOffset = DEM_FIFO_PTR(pFifo->writeOffset +
|
||||
(pNewRec->recordSize * sizeof(NvU32)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Add a Driver Event Message (SXid) to the InfoROM DEM FIFO buffer
|
||||
*
|
||||
* @param[in] device device object pointer
|
||||
* @param[in] num Xid number
|
||||
* @param[in] msglen message size
|
||||
* @param[in] osErrorString text message to store
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void
|
||||
nvswitch_smbpbi_log_message
|
||||
(
|
||||
nvswitch_device *device,
|
||||
NvU32 num,
|
||||
NvU32 msglen,
|
||||
NvU8 *osErrorString
|
||||
)
|
||||
{
|
||||
INFOROM_DEM_OBJECT_V1_00 *pFifo;
|
||||
NvU32 recSize;
|
||||
NvU16 FIFO_REC_LOOP_ITERATOR;
|
||||
NV_MSGBOX_DEM_RECORD *pNewRec;
|
||||
|
||||
if ((device->pSmbpbi == NULL) ||
|
||||
(device->pSmbpbi->sharedSurface == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pFifo = GET_PFIFO_FROM_DEVICE(device);
|
||||
|
||||
pNewRec = _makeNewRecord(pFifo, num, osErrorString, msglen, &recSize);
|
||||
|
||||
if (pNewRec != NULL)
|
||||
{
|
||||
_addNewRecord(pFifo, pNewRec, recSize);
|
||||
nvswitch_os_free(pNewRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// We are unable to log this message. Mark the latest record
|
||||
// with a flag telling the client that message(s) were dropped.
|
||||
//
|
||||
|
||||
NvU16 bytesOccupied = DEM_BYTES_OCCUPIED(pFifo);
|
||||
NvU16 bytesSeen;
|
||||
NV_MSGBOX_DEM_RECORD *pLastRec = NULL;
|
||||
|
||||
// Find the newest record
|
||||
bytesSeen = 0;
|
||||
FIFO_REC_LOOP_START(pFifo, bytesSeen < bytesOccupied)
|
||||
pLastRec = FIFO_REC_LOOP_REC_PTR;
|
||||
bytesSeen += FIFO_REC_LOOP_REC_SIZE;
|
||||
FIFO_REC_LOOP_END
|
||||
|
||||
if (pLastRec != NULL)
|
||||
{
|
||||
pLastRec->flags = FLD_SET_DRF(_MSGBOX, _DEM_RECORD_FLAGS,
|
||||
_OVFL, _SET, pLastRec->flags);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NvlStatus
|
||||
nvswitch_smbpbi_set_link_error_info
|
||||
(
|
||||
nvswitch_device *device,
|
||||
NVSWITCH_LINK_TRAINING_ERROR_INFO *pLinkTrainingErrorInfo,
|
||||
NVSWITCH_LINK_RUNTIME_ERROR_INFO *pLinkRuntimeErrorInfo
|
||||
)
|
||||
{
|
||||
FLCN *pFlcn;
|
||||
RM_FLCN_CMD_SOE cmd;
|
||||
NVSWITCH_TIMEOUT timeout;
|
||||
NvU32 cmdSeqDesc;
|
||||
RM_SOE_SMBPBI_CMD_SET_LINK_ERROR_INFO *pSetCmd = &cmd.cmd.smbpbiCmd.linkErrorInfo;
|
||||
NvlStatus status;
|
||||
|
||||
if (!device->pSmbpbi)
|
||||
{
|
||||
return -NVL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
pFlcn = device->pSoe->pFlcn;
|
||||
|
||||
nvswitch_os_memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.unitId = RM_SOE_UNIT_SMBPBI;
|
||||
cmd.hdr.size = RM_SOE_CMD_SIZE(SMBPBI, SET_LINK_ERROR_INFO);
|
||||
cmd.cmd.smbpbiCmd.cmdType = RM_SOE_SMBPBI_CMD_ID_SET_LINK_ERROR_INFO;
|
||||
|
||||
pSetCmd->trainingErrorInfo.isValid = pLinkTrainingErrorInfo->isValid;
|
||||
pSetCmd->runtimeErrorInfo.isValid = pLinkRuntimeErrorInfo->isValid;
|
||||
|
||||
RM_FLCN_U64_PACK(&pSetCmd->trainingErrorInfo.attemptedTrainingMask0,
|
||||
&pLinkTrainingErrorInfo->attemptedTrainingMask0);
|
||||
RM_FLCN_U64_PACK(&pSetCmd->trainingErrorInfo.trainingErrorMask0,
|
||||
&pLinkTrainingErrorInfo->trainingErrorMask0);
|
||||
RM_FLCN_U64_PACK(&pSetCmd->runtimeErrorInfo.mask0, &pLinkRuntimeErrorInfo->mask0);
|
||||
|
||||
nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS, &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);
|
||||
if (status != NV_OK)
|
||||
{
|
||||
NVSWITCH_PRINT(device, ERROR, "%s SMBPBI Set Link Error Info command failed. rc:%d\n",
|
||||
__FUNCTION__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return NVL_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user