Files
open-gpu-kernel-modules/src/common/nvswitch/kernel/nvswitch.c
Bernhard Stoeckner 2cca8b3fd5 550.107.02
2024-07-29 10:22:58 +02:00

6543 lines
169 KiB
C

/*
* SPDX-FileCopyrightText: Copyright (c) 2017-2024 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 "rom_nvswitch.h"
#include "error_nvswitch.h"
#include "regkey_nvswitch.h"
#include "bios_nvswitch.h"
#include "haldef_nvswitch.h"
#include "flcn/haldefs_flcnable_nvswitch.h"
#include "flcn/flcn_nvswitch.h"
#include "soe/soe_nvswitch.h"
#include "soe/soeififr.h"
#include "nvVer.h"
#include "nvlink_inband_msg.h"
#include "cci/cci_nvswitch.h"
static NvlStatus _nvswitch_ctrl_inband_flush_data(nvswitch_device *device, NVSWITCH_INBAND_FLUSH_DATA_PARAMS *p);
#define NVSWITCH_DEV_CMD_CHECK_ADMIN NVBIT64(0)
#define NVSWITCH_DEV_CMD_CHECK_FM NVBIT64(1)
#define NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(cmd, function, type, private, flags)\
case cmd: \
{ \
if (sizeof(type) != size) \
{ \
retval = -NVL_BAD_ARGS; \
break; \
} \
\
retval = _nvswitch_lib_validate_privileged_ctrl(private, flags); \
if (retval != NVL_SUCCESS) \
{ \
break; \
} \
\
retval = function(device, params); \
break; \
} \
#define NVSWITCH_DEV_CMD_DISPATCH_RESERVED(cmd) \
case cmd: \
{ \
retval = -NVL_ERR_NOT_SUPPORTED; \
break; \
} \
const static NvU32 nvswitch_lr10_device_ids[] =
{
0x1AE8, 0x1AF0, 0x1AF1, 0x1AF2, 0x1AF3, 0x1AF4, 0x1AF5, 0x1AF6, 0x1AF7,
0x1AF8, 0x1AF9, 0x1AFA, 0x1AFB, 0x1AFC, 0x1AFD, 0x1AFE, 0x1AFF
};
const static NvU32 nvswitch_ls10_device_ids[] =
{
// PCIE endpoint to manage the NVLink switch HW
0x22A0, 0x22A1, 0x22A2, 0x22A3, 0x22A4, 0x22A5, 0x22A6, 0x22A7,
// PCI-PCI Bridge, Laguna Switch Function 0
0x22A8, 0x22A9, 0x22AA, 0x22AB,
// Non-Transparent Bridge, Laguna Switch Function 1
0x22AC, 0x22AD, 0x22AE, 0x22AF
};
nvlink_link_handlers link_handlers;
static NvBool
_nvswitch_is_device_id_present
(
const NvU32 *array,
NvU32 array_len,
NvU32 device_id
)
{
NvU32 i = 0;
for(i = 0; i < array_len; i++)
{
if (array[i] == device_id)
{
return NV_TRUE;
}
}
return NV_FALSE;
}
NvBool
nvswitch_is_lr10_device_id
(
NvU32 device_id
)
{
NvU32 count = (sizeof(nvswitch_lr10_device_ids) /
sizeof(nvswitch_lr10_device_ids[0]));
return _nvswitch_is_device_id_present(nvswitch_lr10_device_ids, count, device_id);
}
NvBool
nvswitch_is_ls10_device_id
(
NvU32 device_id
)
{
NvU32 count = (sizeof(nvswitch_ls10_device_ids) /
sizeof(nvswitch_ls10_device_ids[0]));
return _nvswitch_is_device_id_present(nvswitch_ls10_device_ids, count, device_id);
}
/*
* NVLink corelib callbacks are used by the NVLink library separate from the
* NVSwitch driver, therefore they do not take a device lock and can not modify
* nvswitch_device state or use error logging.
*
* These NVSwitch functions modify link state outside of the corelib:
* _nvswitch_ctrl_inject_link_error - injects asynchronous link errors (MODS-only)
*/
static NV_API_CALL NvlStatus
_nvswitch_corelib_add_link
(
nvlink_link *link
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_add_link(link);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_remove_link
(
nvlink_link *link
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_remove_link(link);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_set_dl_link_mode
(
nvlink_link *link,
NvU64 mode,
NvU32 flags
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_set_dl_link_mode(link, mode, flags);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_get_dl_link_mode
(
nvlink_link *link,
NvU64 *mode
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_get_dl_link_mode(link, mode);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_set_tl_link_mode
(
nvlink_link *link,
NvU64 mode,
NvU32 flags
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_set_tl_link_mode(link, mode, flags);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_get_tl_link_mode
(
nvlink_link *link,
NvU64 *mode
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_get_tl_link_mode(link, mode);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_set_tx_mode
(
nvlink_link *link,
NvU64 mode,
NvU32 flags
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_set_tx_mode(link, mode, flags);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_get_tx_mode
(
nvlink_link *link,
NvU64 *mode,
NvU32 *subMode
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_get_tx_mode(link, mode, subMode);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_set_rx_mode
(
nvlink_link *link,
NvU64 mode,
NvU32 flags
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_set_rx_mode(link, mode, flags);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_get_rx_mode
(
nvlink_link *link,
NvU64 *mode,
NvU32 *subMode
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_get_rx_mode(link, mode, subMode);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_set_rx_detect
(
nvlink_link *link,
NvU32 flags
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_set_rx_detect(link, flags);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_get_rx_detect
(
nvlink_link *link
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_get_rx_detect(link);
}
static NV_API_CALL void
_nvswitch_corelib_training_complete
(
nvlink_link *link
)
{
nvswitch_device *device = link->dev->pDevInfo;
device->hal.nvswitch_corelib_training_complete(link);
}
static NV_API_CALL void
_nvswitch_corelib_get_uphy_load
(
nvlink_link *link,
NvBool *bUnlocked
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_corelib_get_uphy_load(link, bUnlocked);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_write_discovery_token
(
nvlink_link *link,
NvU64 token
)
{
nvswitch_device *device = link->dev->pDevInfo;
if (link->version >= NVLINK_DEVICE_VERSION_40)
{
nvswitch_store_topology_information(device, link);
return NVL_SUCCESS;
}
return NVL_SUCCESS;
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_read_discovery_token
(
nvlink_link *link,
NvU64 *token
)
{
if (link->version >= NVLINK_DEVICE_VERSION_40)
{
return NVL_SUCCESS;
}
return NVL_SUCCESS;
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_get_cci_link_mode
(
nvlink_link *link,
NvU64 *mode
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_cci_get_cci_link_mode(device, link->linkNumber, mode);
}
static NV_API_CALL NvlStatus
_nvswitch_corelib_ali_training
(
nvlink_link *link
)
{
nvswitch_device *device = link->dev->pDevInfo;
return device->hal.nvswitch_launch_ALI_link_training(device, link, NV_FALSE);
}
void
nvswitch_get_link_handlers
(
nvlink_link_handlers *nvswitch_link_handlers
)
{
if (!nvswitch_link_handlers)
{
NVSWITCH_ASSERT(0);
return;
}
nvswitch_link_handlers->add = _nvswitch_corelib_add_link;
nvswitch_link_handlers->remove = _nvswitch_corelib_remove_link;
nvswitch_link_handlers->set_dl_link_mode = _nvswitch_corelib_set_dl_link_mode;
nvswitch_link_handlers->get_dl_link_mode = _nvswitch_corelib_get_dl_link_mode;
nvswitch_link_handlers->set_tl_link_mode = _nvswitch_corelib_set_tl_link_mode;
nvswitch_link_handlers->get_tl_link_mode = _nvswitch_corelib_get_tl_link_mode;
nvswitch_link_handlers->set_tx_mode = _nvswitch_corelib_set_tx_mode;
nvswitch_link_handlers->get_tx_mode = _nvswitch_corelib_get_tx_mode;
nvswitch_link_handlers->set_rx_mode = _nvswitch_corelib_set_rx_mode;
nvswitch_link_handlers->get_rx_mode = _nvswitch_corelib_get_rx_mode;
nvswitch_link_handlers->set_rx_detect = _nvswitch_corelib_set_rx_detect;
nvswitch_link_handlers->get_rx_detect = _nvswitch_corelib_get_rx_detect;
nvswitch_link_handlers->training_complete = _nvswitch_corelib_training_complete;
nvswitch_link_handlers->get_uphy_load = _nvswitch_corelib_get_uphy_load;
nvswitch_link_handlers->write_discovery_token = _nvswitch_corelib_write_discovery_token;
nvswitch_link_handlers->read_discovery_token = _nvswitch_corelib_read_discovery_token;
nvswitch_link_handlers->ali_training = _nvswitch_corelib_ali_training;
nvswitch_link_handlers->get_cci_link_mode = _nvswitch_corelib_get_cci_link_mode;
}
#define NVSWITCH_INIT_REGKEY(_private, _regkey, _string, _default_val) \
do \
{ \
NvU32 data; \
\
device->regkeys._regkey = _default_val; \
if (NV_SWITCH_REGKEY_PRIVATE_ALLOWED || !NV_SWITCH_REGKEY##_private) \
{ \
if (NVL_SUCCESS == \
nvswitch_os_read_registry_dword(device->os_handle, _string, &data)) \
{ \
NVSWITCH_PRINT(device, SETUP, \
"%s: Applying regkey %s=0x%x\n", \
__FUNCTION__, \
_string, data); \
device->regkeys._regkey = data; \
} \
} \
} while(0)
static void
_nvswitch_init_device_regkeys
(
nvswitch_device *device
)
{
//
// Public external use regkeys
//
NVSWITCH_INIT_REGKEY(_PUBLIC, ato_control,
NV_SWITCH_REGKEY_ATO_CONTROL,
NV_SWITCH_REGKEY_ATO_CONTROL_DEFAULT);
NVSWITCH_INIT_REGKEY(_PUBLIC, sto_control,
NV_SWITCH_REGKEY_STO_CONTROL,
NV_SWITCH_REGKEY_STO_CONTROL_DEFAULT);
NVSWITCH_INIT_REGKEY(_PUBLIC, crc_bit_error_rate_short,
NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT,
NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_DEFAULT);
NVSWITCH_INIT_REGKEY(_PUBLIC, crc_bit_error_rate_long,
NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG,
NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_DEFAULT);
NVSWITCH_INIT_REGKEY(_PUBLIC, surpress_link_errors_for_gpu_reset,
NV_SWITCH_REGKEY_SURPRESS_LINK_ERRORS_FOR_GPU_RESET,
NV_SWITCH_REGKEY_SURPRESS_LINK_ERRORS_FOR_GPU_RESET_DISABLE);
NVSWITCH_INIT_REGKEY(_PUBLIC, cci_control,
NV_SWITCH_REGKEY_CCI_CONTROL,
NV_SWITCH_REGKEY_CCI_CONTROL_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, cci_link_train_disable_mask,
NV_SWITCH_REGKEY_CCI_DISABLE_LINK_TRAIN_MASK,
NV_SWITCH_REGKEY_CCI_DISABLE_LINK_TRAIN_MASK_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, cci_link_train_disable_mask2,
NV_SWITCH_REGKEY_CCI_DISABLE_LINK_TRAIN_MASK2,
NV_SWITCH_REGKEY_CCI_DISABLE_LINK_TRAIN_MASK2_DEFAULT);
NVSWITCH_INIT_REGKEY(_PUBLIC, cci_max_onboard_attempts,
NV_SWITCH_REGKEY_CCI_MAX_ONBOARD_ATTEMPTS,
NV_SWITCH_REGKEY_CCI_MAX_ONBOARD_ATTEMPTS_DEFAULT);
NVSWITCH_INIT_REGKEY(_PUBLIC, cci_error_log_enable,
NV_SWITCH_REGKEY_CCI_ERROR_LOG_ENABLE,
NV_SWITCH_REGKEY_CCI_ERROR_LOG_ENABLE_DEFAULT);
//
// Debug use regkeys
// Not available on release build kernel drivers
//
NVSWITCH_INIT_REGKEY(_PRIVATE, external_fabric_mgmt,
NV_SWITCH_REGKEY_EXTERNAL_FABRIC_MGMT,
NV_SWITCH_REGKEY_EXTERNAL_FABRIC_MGMT_ENABLE);
NVSWITCH_INIT_REGKEY(_PRIVATE, txtrain_control,
NV_SWITCH_REGKEY_TXTRAIN_CONTROL,
NV_SWITCH_REGKEY_TXTRAIN_CONTROL_NOP);
NVSWITCH_INIT_REGKEY(_PRIVATE, crossbar_DBI,
NV_SWITCH_REGKEY_CROSSBAR_DBI,
NV_SWITCH_REGKEY_CROSSBAR_DBI_ENABLE);
NVSWITCH_INIT_REGKEY(_PRIVATE, link_DBI,
NV_SWITCH_REGKEY_LINK_DBI,
NV_SWITCH_REGKEY_LINK_DBI_ENABLE);
NVSWITCH_INIT_REGKEY(_PRIVATE, ac_coupled_mask,
NV_SWITCH_REGKEY_AC_COUPLED_MASK,
0);
NVSWITCH_INIT_REGKEY(_PRIVATE, ac_coupled_mask2,
NV_SWITCH_REGKEY_AC_COUPLED_MASK2,
0);
NVSWITCH_INIT_REGKEY(_PRIVATE, swap_clk,
NV_SWITCH_REGKEY_SWAP_CLK_OVERRIDE,
nvswitch_get_swap_clk_default(device));
NVSWITCH_INIT_REGKEY(_PRIVATE, link_enable_mask,
NV_SWITCH_REGKEY_ENABLE_LINK_MASK,
NV_U32_MAX);
NVSWITCH_INIT_REGKEY(_PRIVATE, link_enable_mask2,
NV_SWITCH_REGKEY_ENABLE_LINK_MASK2,
NV_U32_MAX);
NVSWITCH_INIT_REGKEY(_PRIVATE, bandwidth_shaper,
NV_SWITCH_REGKEY_BANDWIDTH_SHAPER,
NV_SWITCH_REGKEY_BANDWIDTH_SHAPER_PROD);
NVSWITCH_INIT_REGKEY(_PRIVATE, ssg_control,
NV_SWITCH_REGKEY_SSG_CONTROL,
0);
NVSWITCH_INIT_REGKEY(_PRIVATE, skip_buffer_ready,
NV_SWITCH_REGKEY_SKIP_BUFFER_READY,
0);
NVSWITCH_INIT_REGKEY(_PUBLIC, enable_pm,
NV_SWITCH_REGKEY_ENABLE_PM,
NV_SWITCH_REGKEY_ENABLE_PM_YES);
NVSWITCH_INIT_REGKEY(_PRIVATE, chiplib_forced_config_link_mask,
NV_SWITCH_REGKEY_CHIPLIB_FORCED_LINK_CONFIG_MASK,
0);
NVSWITCH_INIT_REGKEY(_PRIVATE, chiplib_forced_config_link_mask2,
NV_SWITCH_REGKEY_CHIPLIB_FORCED_LINK_CONFIG_MASK2,
0);
NVSWITCH_INIT_REGKEY(_PRIVATE, soe_dma_self_test,
NV_SWITCH_REGKEY_SOE_DMA_SELFTEST,
NV_SWITCH_REGKEY_SOE_DMA_SELFTEST_ENABLE);
NVSWITCH_INIT_REGKEY(_PRIVATE, soe_disable,
NV_SWITCH_REGKEY_SOE_DISABLE,
NV_SWITCH_REGKEY_SOE_DISABLE_NO);
NVSWITCH_INIT_REGKEY(_PRIVATE, latency_counter,
NV_SWITCH_REGKEY_LATENCY_COUNTER_LOGGING,
NV_SWITCH_REGKEY_LATENCY_COUNTER_LOGGING_ENABLE);
NVSWITCH_INIT_REGKEY(_PRIVATE, nvlink_speed_control,
NV_SWITCH_REGKEY_SPEED_CONTROL,
NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, inforom_bbx_periodic_flush,
NV_SWITCH_REGKEY_INFOROM_BBX_ENABLE_PERIODIC_FLUSHING,
NV_SWITCH_REGKEY_INFOROM_BBX_ENABLE_PERIODIC_FLUSHING_DISABLE);
NVSWITCH_INIT_REGKEY(_PRIVATE, inforom_bbx_write_periodicity,
NV_SWITCH_REGKEY_INFOROM_BBX_WRITE_PERIODICITY,
NV_SWITCH_REGKEY_INFOROM_BBX_WRITE_PERIODICITY_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, inforom_bbx_write_min_duration,
NV_SWITCH_REGKEY_INFOROM_BBX_WRITE_MIN_DURATION,
NV_SWITCH_REGKEY_INFOROM_BBX_WRITE_MIN_DURATION_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, minion_disable,
NV_SWITCH_REGKEY_MINION_DISABLE,
NV_SWITCH_REGKEY_MINION_DISABLE_NO);
NVSWITCH_INIT_REGKEY(_PRIVATE, set_ucode_target,
NV_SWITCH_REGKEY_MINION_SET_UCODE_TARGET,
NV_SWITCH_REGKEY_MINION_SET_UCODE_TARGET_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, set_simmode,
NV_SWITCH_REGKEY_MINION_SET_SIMMODE,
NV_SWITCH_REGKEY_MINION_SET_SIMMODE_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, set_smf_settings,
NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS,
NV_SWITCH_REGKEY_MINION_SET_SMF_SETTINGS_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, select_uphy_tables,
NV_SWITCH_REGKEY_MINION_SELECT_UPHY_TABLES,
NV_SWITCH_REGKEY_MINION_SELECT_UPHY_TABLES_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, link_training_mode,
NV_SWITCH_REGKEY_LINK_TRAINING_SELECT,
NV_SWITCH_REGKEY_LINK_TRAINING_SELECT_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, i2c_access_control,
NV_SWITCH_REGKEY_I2C_ACCESS_CONTROL,
NV_SWITCH_REGKEY_I2C_ACCESS_CONTROL_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, force_kernel_i2c,
NV_SWITCH_REGKEY_FORCE_KERNEL_I2C,
NV_SWITCH_REGKEY_FORCE_KERNEL_I2C_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, link_recal_settings,
NV_SWITCH_REGKEY_LINK_RECAL_SETTINGS,
NV_SWITCH_REGKEY_LINK_RECAL_SETTINGS_NOP);
NVSWITCH_INIT_REGKEY(_PRIVATE, lp_threshold,
NV_SWITCH_REGKEY_SET_LP_THRESHOLD,
NV_SWITCH_REGKEY_SET_LP_THRESHOLD_DEFAULT);
NVSWITCH_INIT_REGKEY(_PUBLIC, minion_intr,
NV_SWITCH_REGKEY_MINION_INTERRUPTS,
NV_SWITCH_REGKEY_MINION_INTERRUPTS_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, block_code_mode,
NV_SWITCH_REGKEY_BLOCK_CODE_MODE,
NV_SWITCH_REGKEY_BLOCK_CODE_MODE_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, reference_clock_mode,
NV_SWITCH_REGKEY_REFERENCE_CLOCK_MODE,
NV_SWITCH_REGKEY_REFERENCE_CLOCK_MODE_DEFAULT);
NVSWITCH_INIT_REGKEY(_PRIVATE, debug_level,
NV_SWITCH_REGKEY_DBG_LEVEL,
NV_SWITCH_REGKEY_DBG_LEVEL_DEFAULT);
}
ct_assert(NVSWITCH_DBG_LEVEL_MMIO == NV_SWITCH_REGKEY_DBG_LEVEL_MMIO);
ct_assert(NVSWITCH_DBG_LEVEL_NOISY == NV_SWITCH_REGKEY_DBG_LEVEL_NOISY);
ct_assert(NVSWITCH_DBG_LEVEL_SETUP == NV_SWITCH_REGKEY_DBG_LEVEL_SETUP);
ct_assert(NVSWITCH_DBG_LEVEL_INFO == NV_SWITCH_REGKEY_DBG_LEVEL_INFO);
ct_assert(NVSWITCH_DBG_LEVEL_WARN == NV_SWITCH_REGKEY_DBG_LEVEL_WARN);
ct_assert(NVSWITCH_DBG_LEVEL_ERROR == NV_SWITCH_REGKEY_DBG_LEVEL_ERROR);
NvU64
nvswitch_lib_deferred_task_dispatcher
(
nvswitch_device *device
)
{
NvU64 time_nsec;
NvU64 time_next_nsec = nvswitch_os_get_platform_time() + 100*NVSWITCH_INTERVAL_1MSEC_IN_NS;
NVSWITCH_TASK_TYPE *task;
NVSWITCH_TASK_TYPE *prev_task;
if (!NVSWITCH_IS_DEVICE_VALID(device))
{
return NV_U64_MAX;
}
prev_task = NULL;
task = device->tasks;
// Walk the task list, executing those whose next execution interval is at hand
while (task)
{
// Get current time (nsec) for scheduling
time_nsec = nvswitch_os_get_platform_time();
if (time_nsec >= task->last_run_nsec + task->period_nsec)
{
//
// The task has never been run or it is time to run
// Mark its last run time
//
task->last_run_nsec = time_nsec;
// Run the task
if (NVSWITCH_IS_DEVICE_INITIALIZED(device) ||
(task->flags & NVSWITCH_TASK_TYPE_FLAGS_RUN_EVEN_IF_DEVICE_NOT_INITIALIZED))
{
if(task->flags & NVSWITCH_TASK_TYPE_FLAGS_VOID_PTR_ARGS)
(*task->task_fn_vdptr)(device, task->task_args); // run task with provided args
else
(*task->task_fn_devptr)(device);
}
}
// Determine its next run time
time_next_nsec = NV_MIN(task->last_run_nsec + task->period_nsec, time_next_nsec);
// Advance pointer. If run once flag is set and task ran, remove task from list.
if((task->flags & NVSWITCH_TASK_TYPE_FLAGS_RUN_ONCE) &&
(task->last_run_nsec == time_nsec))
{
prev_task = task->prev;
// Removing from list head
if (prev_task == NULL)
{
device->tasks = task->next;
if (device->tasks != NULL)
{
device->tasks->prev = NULL;
}
nvswitch_os_free(task);
task = device->tasks;
}
else
{
prev_task->next = task->next;
if (prev_task->next != NULL)
{
prev_task->next->prev = prev_task;
}
nvswitch_os_free(task);
task = prev_task->next;
}
}
else
{
task = task->next;
}
}
time_nsec = nvswitch_os_get_platform_time();
// Return to the OS layer how long to wait before calling again
return(time_next_nsec >= time_nsec ? time_next_nsec - time_nsec : 0);
}
static NvlStatus
_nvswitch_setup_hal
(
nvswitch_device *device,
NvU32 pci_device_id
)
{
if (nvswitch_is_lr10_device_id(pci_device_id))
{
nvswitch_setup_hal_lr10(device);
return NVL_SUCCESS;
}
if (nvswitch_is_ls10_device_id(pci_device_id))
{
nvswitch_setup_hal_ls10(device);
return NVL_SUCCESS;
}
NVSWITCH_PRINT(device, ERROR,
"NVSwitch HAL setup failed - Unrecognized PCI Device ID\n");
return -NVL_ERR_NOT_SUPPORTED;
}
NvlStatus
nvswitch_lib_check_api_version
(
const char *user_version,
char *kernel_version,
NvU32 length
)
{
const NvLength VERSION_LENGTH = nvswitch_os_strlen(NV_VERSION_STRING);
if (kernel_version == NULL || user_version == NULL)
{
return -NVL_BAD_ARGS;
}
if (length < VERSION_LENGTH)
{
return -NVL_NO_MEM;
}
nvswitch_os_memset(kernel_version, 0x0, length);
nvswitch_os_strncpy(kernel_version, NV_VERSION_STRING, VERSION_LENGTH);
kernel_version[length - 1] = '\0';
if (nvswitch_os_strncmp(user_version, kernel_version, VERSION_LENGTH))
{
return -NVL_ERR_NOT_SUPPORTED;
}
return NVL_SUCCESS;
}
NvBool
nvswitch_is_inforom_supported
(
nvswitch_device *device
)
{
return device->hal.nvswitch_is_inforom_supported(device);
}
NvBool
nvswitch_is_spi_supported
(
nvswitch_device *device
)
{
return device->hal.nvswitch_is_spi_supported(device);
}
NvBool
nvswitch_is_bios_supported
(
nvswitch_device *device
)
{
return device->hal.nvswitch_is_bios_supported(device);
}
NvBool
nvswitch_is_smbpbi_supported
(
nvswitch_device *device
)
{
return device->hal.nvswitch_is_smbpbi_supported(device);
}
NvBool
nvswitch_is_soe_supported
(
nvswitch_device *device
)
{
return device->hal.nvswitch_is_soe_supported(device);
}
NvlStatus
nvswitch_init_soe
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_soe(device);
}
void
nvswitch_soe_init_l2_state
(
nvswitch_device *device
)
{
device->hal.nvswitch_soe_init_l2_state(device);
}
void
nvswitch_fsp_update_cmdq_head_tail
(
nvswitch_device *device,
NvU32 queueHead,
NvU32 queueTail
)
{
return device->hal.nvswitch_fsp_update_cmdq_head_tail(device, queueHead, queueTail);
}
void
nvswitch_fsp_get_cmdq_head_tail
(
nvswitch_device *device,
NvU32 *pQueueHead,
NvU32 *pQueueTail
)
{
return device->hal.nvswitch_fsp_get_cmdq_head_tail(device, pQueueHead, pQueueTail);
}
void
nvswitch_fsp_update_msgq_head_tail
(
nvswitch_device *device,
NvU32 msgqHead,
NvU32 msgqTail
)
{
return device->hal.nvswitch_fsp_update_msgq_head_tail(device, msgqHead, msgqTail);
}
void
nvswitch_fsp_get_msgq_head_tail
(
nvswitch_device *device,
NvU32 *pMsgqHead,
NvU32 *pMsgqTail
)
{
return device->hal.nvswitch_fsp_get_msgq_head_tail(device, pMsgqHead, pMsgqTail);
}
NvU32
nvswitch_fsp_get_channel_size
(
nvswitch_device *device
)
{
return device->hal.nvswitch_fsp_get_channel_size(device);
}
NvU8
nvswitch_fsp_nvdm_to_seid
(
nvswitch_device *device,
NvU8 nvdmType
)
{
return device->hal.nvswitch_fsp_nvdm_to_seid(device, nvdmType);
}
NvU32
nvswitch_fsp_create_mctp_header
(
nvswitch_device *device,
NvU8 som,
NvU8 eom,
NvU8 seid,
NvU8 seq
)
{
return device->hal.nvswitch_fsp_create_mctp_header(device, som, eom, seid, seq);
}
NvU32
nvswitch_fsp_create_nvdm_header
(
nvswitch_device *device,
NvU32 nvdmType
)
{
return device->hal.nvswitch_fsp_create_nvdm_header(device, nvdmType);
}
NvlStatus
nvswitch_fsp_get_packet_info
(
nvswitch_device *device,
NvU8 *pBuffer,
NvU32 size,
NvU8 *pPacketState,
NvU8 *pTag
)
{
return device->hal.nvswitch_fsp_get_packet_info(device, pBuffer, size, pPacketState, pTag);
}
NvlStatus
nvswitch_fsp_validate_mctp_payload_header
(
nvswitch_device *device,
NvU8 *pBuffer,
NvU32 size
)
{
return device->hal.nvswitch_fsp_validate_mctp_payload_header(device, pBuffer, size);
}
NvlStatus
nvswitch_fsp_process_nvdm_msg
(
nvswitch_device *device,
NvU8 *pBuffer,
NvU32 size
)
{
return device->hal.nvswitch_fsp_process_nvdm_msg(device, pBuffer, size);
}
NvlStatus
nvswitch_fsp_process_cmd_response
(
nvswitch_device *device,
NvU8 *pBuffer,
NvU32 size
)
{
return device->hal.nvswitch_fsp_process_cmd_response(device, pBuffer, size);
}
NvlStatus
nvswitch_fsp_config_ememc
(
nvswitch_device *device,
NvU32 offset,
NvBool bAincw,
NvBool bAincr
)
{
return device->hal.nvswitch_fsp_config_ememc(device, offset, bAincw, bAincr);
}
NvlStatus
nvswitch_fsp_write_to_emem
(
nvswitch_device *device,
NvU8 *pBuffer,
NvU32 size
)
{
return device->hal.nvswitch_fsp_write_to_emem(device, pBuffer, size);
}
NvlStatus
nvswitch_fsp_read_from_emem
(
nvswitch_device *device,
NvU8 *pBuffer,
NvU32 size
)
{
return device->hal.nvswitch_fsp_read_from_emem(device, pBuffer, size);
}
NvlStatus
nvswitch_fsp_error_code_to_nvlstatus_map
(
nvswitch_device *device,
NvU32 errorCode
)
{
return device->hal.nvswitch_fsp_error_code_to_nvlstatus_map(device, errorCode);
}
static NvlStatus
_nvswitch_ctrl_fsprpc_get_caps
(
nvswitch_device *device,
NVSWITCH_FSPRPC_GET_CAPS_PARAMS *params
)
{
return device->hal.nvswitch_fsprpc_get_caps(device, params);
}
static NvlStatus
_nvswitch_ctrl_get_attestation_certificate_chain
(
nvswitch_device *device,
NVSWITCH_GET_ATTESTATION_CERTIFICATE_CHAIN_PARAMS *params
)
{
return device->hal.nvswitch_tnvl_get_attestation_certificate_chain(device, params);
}
static NvlStatus
_nvswitch_ctrl_get_attestation_report
(
nvswitch_device *device,
NVSWITCH_GET_ATTESTATION_REPORT_PARAMS *params
)
{
return device->hal.nvswitch_tnvl_get_attestation_report(device, params);
}
static NvlStatus
_nvswitch_ctrl_get_tnvl_status
(
nvswitch_device *device,
NVSWITCH_GET_TNVL_STATUS_PARAMS *params
)
{
return device->hal.nvswitch_tnvl_get_status(device, params);
}
void
nvswitch_tnvl_disable_interrupts
(
nvswitch_device *device
)
{
device->hal.nvswitch_tnvl_disable_interrupts(device);
}
static NvlStatus
_nvswitch_construct_soe
(
nvswitch_device *device
)
{
FLCNABLE *pSoe = NULL;
NvlStatus retval;
device->pSoe = pSoe = (PFLCNABLE)soeAllocNew();
if (pSoe == NULL)
{
NVSWITCH_PRINT(device, ERROR, "SOE allocation failed.\n");
return -NVL_NO_MEM;
}
retval = soeInit(device, (PSOE)pSoe, device->nvlink_device->pciInfo.pciDeviceId);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "SOE init failed.\n");
goto soe_init_failed;
}
if (flcnableConstruct_HAL(device, pSoe) != NV_OK)
{
NVSWITCH_PRINT(device, ERROR, "FALCON construct failed.\n");
retval = -NVL_ERR_INVALID_STATE;
goto flcn_construct_failed;
}
return NVL_SUCCESS;
flcn_construct_failed:
soeDestroy(device, (PSOE)pSoe);
soe_init_failed:
nvswitch_os_free(pSoe);
device->pSoe = NULL;
return retval;
}
static void
_nvswitch_destruct_soe
(
nvswitch_device *device
)
{
FLCNABLE *pSoe = device->pSoe;
if (pSoe == NULL)
{
return;
}
flcnableDestruct_HAL(device, pSoe);
soeDestroy(device, (PSOE)pSoe);
nvswitch_os_free(pSoe);
device->pSoe = NULL;
}
static NvlStatus
_nvswitch_construct_cci
(
nvswitch_device *device
)
{
CCI *pCci = NULL;
NvlStatus retval;
device->pCci = pCci = cciAllocNew();
if (pCci == NULL)
{
NVSWITCH_PRINT(device, ERROR, "CCI allocation failed.\n");
return -NVL_NO_MEM;
}
retval = cciInit(device, pCci, device->nvlink_device->pciInfo.pciDeviceId);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "CCI init failed.\n");
goto cci_init_failed;
}
return NVL_SUCCESS;
cci_init_failed:
nvswitch_os_free(pCci);
device->pCci = NULL;
return retval;
}
static void
_nvswitch_destruct_cci
(
nvswitch_device *device
)
{
CCI *pCci = device->pCci;
if (pCci == NULL)
{
return;
}
cciDestroy(device, pCci);
nvswitch_os_free(pCci);
device->pCci = NULL;
}
static void
_nvswitch_update_link_state_led
(
nvswitch_device *device
)
{
device->hal.nvswitch_update_link_state_led(device);
}
static void
_nvswitch_led_shutdown
(
nvswitch_device *device
)
{
device->hal.nvswitch_led_shutdown(device);
}
static NvlStatus
_nvswitch_initialize_device_state
(
nvswitch_device *device
)
{
return device->hal.nvswitch_initialize_device_state(device);
}
static NvlStatus
_nvswitch_post_init_device_setup
(
nvswitch_device *device
)
{
return device->hal.nvswitch_post_init_device_setup(device);
}
static NvlStatus
_nvswitch_setup_system_registers
(
nvswitch_device *device
)
{
return device->hal.nvswitch_setup_system_registers(device);
}
static void
_nvswitch_post_init_blacklist_device_setup
(
nvswitch_device *device
)
{
device->hal.nvswitch_post_init_blacklist_device_setup(device);
}
static void
_nvswitch_set_dma_mask
(
nvswitch_device *device
)
{
NvU32 hw_dma_width, retval;
hw_dma_width = device->hal.nvswitch_get_device_dma_width(device);
if (hw_dma_width == 0)
{
NVSWITCH_PRINT(device, INFO, "DMA is not supported on this device\n");
return;
}
retval = nvswitch_os_set_dma_mask(device->os_handle, hw_dma_width);
if (retval == NVL_SUCCESS)
{
device->dma_addr_width = hw_dma_width;
return;
}
NVSWITCH_PRINT(device, SETUP,
"%s: Failed to set DMA mask, trying 32-bit fallback : %d\n",
__FUNCTION__, retval);
retval = nvswitch_os_set_dma_mask(device->os_handle, 32);
if (retval == NVL_SUCCESS)
{
device->dma_addr_width = 32;
return;
}
// failure is not fatal, the driver will just restrict DMA functionality
NVSWITCH_PRINT(device, ERROR, "Failed to set DMA mask : %d\n", retval);
}
NvlStatus
nvswitch_deassert_link_reset
(
nvswitch_device *device,
nvlink_link *link
)
{
return device->hal.nvswitch_deassert_link_reset(device, link);
}
NvU32
nvswitch_get_sublink_width
(
nvswitch_device *device,
NvU32 linkNumber
)
{
return device->hal.nvswitch_get_sublink_width(device, linkNumber);
}
static void
_nvswitch_unregister_links
(
nvswitch_device *device
)
{
nvlink_link *link = NULL;
NvU32 link_num;
NvBool is_blacklisted;
if (!NVSWITCH_IS_DEVICE_INITIALIZED(device))
return;
device->nvlink_device->initialized = 0;
is_blacklisted = (device->device_fabric_state == NVSWITCH_DEVICE_FABRIC_STATE_BLACKLISTED);
for (link_num = 0; link_num < nvswitch_get_num_links(device); link_num++)
{
if (nvlink_lib_get_link(device->nvlink_device, link_num, &link) == NVL_SUCCESS)
{
nvlink_lib_unregister_link(link);
nvswitch_destroy_link(link);
}
}
if (!is_blacklisted)
nvswitch_inforom_nvlink_flush(device);
}
NvlStatus NV_API_CALL
nvswitch_lib_read_fabric_state
(
nvswitch_device *device,
NVSWITCH_DEVICE_FABRIC_STATE *device_fabric_state,
NVSWITCH_DEVICE_BLACKLIST_REASON *device_blacklist_reason,
NVSWITCH_DRIVER_FABRIC_STATE *driver_fabric_state
)
{
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
return -NVL_BAD_ARGS;
if (device_fabric_state != NULL)
*device_fabric_state = device->device_fabric_state;
if (device_blacklist_reason != NULL)
*device_blacklist_reason = device->device_blacklist_reason;
if (driver_fabric_state != NULL)
*driver_fabric_state = device->driver_fabric_state;
return NVL_SUCCESS;
}
static NvlStatus
nvswitch_lib_blacklist_device
(
nvswitch_device *device,
NVSWITCH_DEVICE_BLACKLIST_REASON device_blacklist_reason
)
{
NvlStatus status;
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
if (device->device_fabric_state == NVSWITCH_DEVICE_FABRIC_STATE_BLACKLISTED)
{
NVSWITCH_PRINT(device, WARN, "Device is already blacklisted\n");
return -NVL_ERR_NOT_SUPPORTED;
}
device->device_fabric_state = NVSWITCH_DEVICE_FABRIC_STATE_BLACKLISTED;
device->device_blacklist_reason = device_blacklist_reason;
status = device->hal.nvswitch_write_fabric_state(device);
if (status != NVL_SUCCESS)
NVSWITCH_PRINT(device, INFO, "Cannot send fabric state to SOE\n");
return NVL_SUCCESS;
}
static NvlStatus
nvswitch_ctrl_blacklist_device(
nvswitch_device *device,
NVSWITCH_BLACKLIST_DEVICE_PARAMS *p
)
{
NvlStatus status;
status = nvswitch_lib_blacklist_device(device, p->deviceReason);
if (status != NVL_SUCCESS)
return status;
nvswitch_lib_disable_interrupts(device);
// Unregister links from NVLinkCoreLib, so that link training is not
// attempted
_nvswitch_unregister_links(device);
// Keep device registered for HAL access and Fabric State updates
return NVL_SUCCESS;
}
static NvlStatus
nvswitch_ctrl_set_fm_driver_state(
nvswitch_device *device,
NVSWITCH_SET_FM_DRIVER_STATE_PARAMS *p
)
{
NvU32 prev_fm_status;
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
prev_fm_status = device->driver_fabric_state;
device->driver_fabric_state = p->driverState;
device->fabric_state_timestamp = nvswitch_os_get_platform_time();
if (prev_fm_status != p->driverState)
{
if (nvswitch_lib_notify_client_events(device,
NVSWITCH_DEVICE_EVENT_FABRIC_STATE) != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify event\n",
__FUNCTION__);
}
}
return NVL_SUCCESS;
}
static NvlStatus
nvswitch_ctrl_set_device_fabric_state(
nvswitch_device *device,
NVSWITCH_SET_DEVICE_FABRIC_STATE_PARAMS *p
)
{
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
if (device->device_fabric_state == NVSWITCH_DEVICE_FABRIC_STATE_BLACKLISTED)
return -NVL_ERR_NOT_SUPPORTED;
device->device_fabric_state = p->deviceState;
device->fabric_state_timestamp = nvswitch_os_get_platform_time();
// If FM had exceeded timeout, reset the status to not timed-out
if (device->driver_fabric_state == NVSWITCH_DRIVER_FABRIC_STATE_MANAGER_TIMEOUT)
device->driver_fabric_state = NVSWITCH_DRIVER_FABRIC_STATE_CONFIGURED;
return NVL_SUCCESS;
}
static NvlStatus
nvswitch_ctrl_set_fm_timeout(
nvswitch_device *device,
NVSWITCH_SET_FM_HEARTBEAT_TIMEOUT_PARAMS *p
)
{
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
device->fm_timeout = p->fmTimeout;
return NVL_SUCCESS;
}
static NvlStatus
_nvswitch_ctrl_register_events(
nvswitch_device *device,
NVSWITCH_REGISTER_EVENTS_PARAMS *p,
void *osPrivate
)
{
NvlStatus status = NVL_SUCCESS;
NvU32 i;
NvBool many_events, os_descriptor;
void *osDescriptor = osPrivate;
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
status = nvswitch_os_get_supported_register_events_params(&many_events,
&os_descriptor);
if (status != NVL_SUCCESS)
{
return status;
}
if ((!many_events && (p->numEvents > 1)) ||
(p->numEvents == 0))
{
return -NVL_BAD_ARGS;
}
if (os_descriptor)
{
osDescriptor = (void *) p->osDescriptor;
}
for (i = 0; i < p->numEvents; i++)
{
status = nvswitch_lib_add_client_event(device, osDescriptor, p->eventIds[i]);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to add client event.\n", __FUNCTION__);
return status;
}
}
return NVL_SUCCESS;
}
static NvlStatus
_nvswitch_ctrl_unregister_events(
nvswitch_device *device,
NVSWITCH_UNREGISTER_EVENTS_PARAMS *p,
void *osPrivate
)
{
NvlStatus status = NVL_SUCCESS;
NvBool many_events, os_descriptor;
void *osDescriptor = osPrivate;
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
status = nvswitch_os_get_supported_register_events_params(&many_events,
&os_descriptor);
if (status != NVL_SUCCESS)
{
return status;
}
if (os_descriptor)
{
osDescriptor = (void *) p->osDescriptor;
}
status = nvswitch_lib_remove_client_events(device, osDescriptor);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to remove client event.\n", __FUNCTION__);
return status;
}
return NVL_SUCCESS;
}
/*
* @Brief : Sends NACK or drops given inband msg based on message type
*
* @Description :
*
* @param[in] device NvSwitch device to contain this link
* @param[in] linkId Link ID
* @param[in] msghdr Header to the message
*
*/
static void
nvswitch_send_nack_or_drop
(
nvswitch_device *device,
NvU32 linkId,
nvlink_inband_msg_header_t *msghdr
)
{
switch(msghdr->type)
{
case NVLINK_INBAND_MSG_TYPE_MC_TEAM_SETUP_REQ:
device->hal.nvswitch_send_inband_nack(device, (NvU32 *)msghdr, linkId);
NVSWITCH_PRINT(device, ERROR,
"Sending NACK for message (type 0x%x)\n", msghdr->type);
return;
default:
// TODO: Add SXid in future if needed.
NVSWITCH_PRINT(device, ERROR,
"Dropping message (type 0x%x)\n", msghdr->type);
return;
}
}
/*
* @Brief : Deletes all the entries in persistent or non-persistent lists.
* Send nacks if requested.
*
* @Description :
*
* @param[in] device NVSwitch device to contain this link
* @param[in] linkId Link number
* @param[in] bSendNack Send nacks if true
* @param[in] bNonPersistentOnly Clear only non-persistent list
*/
static void
_nvswitch_inband_clear_lists
(
nvswitch_device *device,
NvU32 linkId,
NvBool bSendNack,
NvBool bNonPersistentOnly
)
{
nvswitch_inband_data_list *curr = NULL;
nvswitch_inband_data_list *next = NULL;
nvlink_inband_msg_header_t *msghdr = NULL;
nvListForEachEntry_safe(curr, next,
&device->link[linkId].inbandData.nonpersistent_list, entry)
{
if (bSendNack)
{
msghdr = (nvlink_inband_msg_header_t *)curr->data;
nvswitch_send_nack_or_drop(device, linkId, msghdr);
}
nvListDel(&curr->entry);
nvswitch_os_free(curr);
}
if (bNonPersistentOnly)
return;
nvListForEachEntry_safe(curr, next,
&device->link[linkId].inbandData.persistent_list, entry)
{
if (bSendNack)
{
msghdr = (nvlink_inband_msg_header_t *)curr->data;
nvswitch_send_nack_or_drop(device, linkId, msghdr);
}
nvListDel(&curr->entry);
nvswitch_os_free(curr);
}
}
static void
nvswitch_fabric_state_heartbeat(
nvswitch_device *device
)
{
NvU64 age;
NvU32 linkId;
if (!NVSWITCH_IS_DEVICE_VALID(device))
return;
age = nvswitch_os_get_platform_time() - device->fabric_state_timestamp;
// Check to see if we have exceeded the FM timeout
if (device->driver_fabric_state == NVSWITCH_DRIVER_FABRIC_STATE_CONFIGURED &&
age > (NvU64)device->fm_timeout * 1000ULL * 1000ULL)
device->driver_fabric_state = NVSWITCH_DRIVER_FABRIC_STATE_MANAGER_TIMEOUT;
//
// If FM is not running, clear pending non-persistent messages. Persistent
// messages can be processed by the FM when it restarts.
//
if (device->driver_fabric_state != NVSWITCH_DRIVER_FABRIC_STATE_CONFIGURED)
{
for (linkId = 0; linkId < nvswitch_get_num_links(device); linkId++)
_nvswitch_inband_clear_lists(device, linkId,
NV_TRUE /* Nack */,
NV_TRUE /* Non-persistent only */);
}
(void)device->hal.nvswitch_write_fabric_state(device);
}
static NvlStatus
_nvswitch_ctrl_set_training_error_info
(
nvswitch_device *device,
NVSWITCH_SET_TRAINING_ERROR_INFO_PARAMS *p
)
{
return device->hal.nvswitch_set_training_error_info(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_fatal_error_scope
(
nvswitch_device *device,
NVSWITCH_GET_FATAL_ERROR_SCOPE_PARAMS *pParams
)
{
return device->hal.nvswitch_ctrl_get_fatal_error_scope(device, pParams);
}
static NvlStatus
_nvswitch_ctrl_therm_get_temperature_limit
(
nvswitch_device *device,
NVSWITCH_CTRL_GET_TEMPERATURE_LIMIT_PARAMS *pParams
)
{
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
return device->hal.nvswitch_ctrl_therm_get_temperature_limit(device, pParams);
}
//
// Construct an port event log
//
// If port_event_log_size > 0 a circular buffer is created to record port events
//
NvlStatus
_nvswitch_construct_port_event_log
(
NVSWITCH_PORT_EVENT_LOG_TYPE *port_events,
NvU32 port_event_log_size,
NvBool overwritable
)
{
NvlStatus retval = NVL_SUCCESS;
NVSWITCH_ASSERT(port_events != NULL);
port_events->port_event_start = 0;
port_events->port_event_count = 0;
port_events->port_event_total = 0;
port_events->port_event_log_size = 0;
port_events->port_event_log = NULL;
port_events->overwritable = overwritable;
port_events->bOverflow = NV_FALSE;
if (port_event_log_size > 0)
{
port_events->port_event_log = nvswitch_os_malloc(port_event_log_size * sizeof(NVSWITCH_PORT_EVENT_TYPE));
}
if (port_events->port_event_log != NULL)
{
port_events->port_event_log_size = port_event_log_size;
nvswitch_os_memset(port_events->port_event_log, 0, port_events->port_event_log_size * sizeof(NVSWITCH_PORT_EVENT_TYPE));
}
if (port_event_log_size != port_events->port_event_log_size)
{
retval = -NVL_NO_MEM;
}
return retval;
}
//
// Destroy an error log
//
void
_nvswitch_destroy_port_event_log
(
nvswitch_device *device,
NVSWITCH_PORT_EVENT_LOG_TYPE *port_events
)
{
if (port_events == NULL)
return;
port_events->port_event_start = 0;
port_events->port_event_count = 0;
port_events->port_event_log_size = 0;
port_events->bOverflow = NV_FALSE;
if (port_events->port_event_log != NULL)
{
nvswitch_os_free(port_events->port_event_log);
port_events->port_event_log = NULL;
}
}
NvlStatus
nvswitch_lib_initialize_device
(
nvswitch_device *device
)
{
NvlStatus retval = NVL_SUCCESS;
NvU8 link_num;
nvlink_link *link = NULL;
NvBool is_blacklisted_by_os = NV_FALSE;
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
if (NVSWITCH_IS_DEVICE_INITIALIZED(device))
{
NVSWITCH_PRINT(device, SETUP, "Device is already initialized!\n");
return NVL_SUCCESS;
}
NVSWITCH_PRINT(device, SETUP,
"Initializing nvswitch at (%04x:%02x:%02x.%02x)\n",
device->nvlink_device->pciInfo.domain,
device->nvlink_device->pciInfo.bus,
device->nvlink_device->pciInfo.device,
device->nvlink_device->pciInfo.function);
nvListInit(&device->client_events_list);
for (link_num=0; link_num < nvswitch_get_num_links(device); link_num++)
{
nvListInit(&device->link[link_num].inbandData.persistent_list);
nvListInit(&device->link[link_num].inbandData.nonpersistent_list);
}
retval = nvswitch_lib_load_platform_info(device);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Failed to load platform information\n");
return retval;
}
if (nvswitch_is_soe_supported(device))
{
retval = _nvswitch_construct_soe(device);
if (retval != NVL_SUCCESS)
{
return retval;
}
}
else
{
NVSWITCH_PRINT(device, INFO, "SOE is not supported, skipping construct\n");
}
if (nvswitch_is_cci_supported(device))
{
retval = _nvswitch_construct_cci(device);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Failed to construct CCI: %d\n", retval);
goto nvswitch_initialize_cci_fail;
}
}
else
{
NVSWITCH_PRINT(device, INFO, "CCI is not supported, skipping construct\n");
}
_nvswitch_set_dma_mask(device);
retval = _nvswitch_initialize_device_state(device);
if (NVL_SUCCESS != retval)
{
NVSWITCH_PRINT(device, ERROR,
"Failed to initialize device state: %d!\n",
retval);
goto nvswitch_initialize_device_state_fail;
}
device->hal.nvswitch_load_uuid(device);
/*
* Check module parameters for blacklisted device
*/
if (nvswitch_os_is_uuid_in_blacklist(&device->uuid) == NV_TRUE)
{
NVSWITCH_PRINT(device, SETUP,
"Blacklisted nvswitch at (%04x:%02x:%02x.%02x)\n",
device->nvlink_device->pciInfo.domain,
device->nvlink_device->pciInfo.bus,
device->nvlink_device->pciInfo.device,
device->nvlink_device->pciInfo.function);
is_blacklisted_by_os = NV_TRUE;
// initialization continues until we have updated InfoROM...
}
if (nvswitch_is_inforom_supported(device))
{
retval = nvswitch_initialize_inforom(device);
if (NVL_SUCCESS != retval)
{
NVSWITCH_PRINT(device, ERROR,
"Failed to initialize InfoROM rc: %d\n",
retval);
goto nvswitch_initialize_device_state_fail;
}
retval = nvswitch_initialize_inforom_objects(device);
if (NVL_SUCCESS != retval)
{
NVSWITCH_PRINT(device, ERROR,
"Failed to initialize InfoROM objects! rc:%d\n",
retval);
goto nvswitch_initialize_inforom_fail;
}
}
else
{
NVSWITCH_PRINT(device, INFO,
"InfoROM is not supported, skipping init\n");
}
(void)device->hal.nvswitch_read_oob_blacklist_state(device);
(void)device->hal.nvswitch_write_fabric_state(device);
if (!nvswitch_is_tnvl_mode_enabled(device))
{
nvswitch_task_create(device, &nvswitch_fabric_state_heartbeat,
NVSWITCH_HEARTBEAT_INTERVAL_NS,
NVSWITCH_TASK_TYPE_FLAGS_RUN_EVEN_IF_DEVICE_NOT_INITIALIZED);
}
else
{
NVSWITCH_PRINT(device, INFO, "Skipping Fabric state heartbeat background task when TNVL is enabled\n");
}
//
// Blacklisted devices return successfully in order to preserve the fabric state heartbeat
// and ensure OOB utilities don't think the driver has died
//
if (device->device_blacklist_reason == NVSWITCH_DEVICE_BLACKLIST_REASON_MANUAL_OUT_OF_BAND)
{
NVSWITCH_PRINT(device, SETUP,
"Blacklisted nvswitch at (%04x:%02x:%02x.%02x)\n",
device->nvlink_device->pciInfo.domain,
device->nvlink_device->pciInfo.bus,
device->nvlink_device->pciInfo.device,
device->nvlink_device->pciInfo.function);
return NVL_SUCCESS;
}
if (is_blacklisted_by_os)
{
(void)nvswitch_lib_blacklist_device(device, NVSWITCH_DEVICE_BLACKLIST_REASON_MANUAL_IN_BAND);
return NVL_SUCCESS;
}
for (link_num=0; link_num < nvswitch_get_num_links(device); link_num++)
{
if (!nvswitch_is_link_valid(device, link_num))
{
continue;
}
retval = nvswitch_create_link(device, link_num, &link);
if (NVL_SUCCESS != retval)
{
NVSWITCH_PRINT(device, ERROR,
"Failed to create link %d : %d!\n",
link_num,
retval);
goto nvswitch_link_fail;
}
retval = nvlink_lib_register_link(device->nvlink_device, link);
if (NVL_SUCCESS != retval)
{
NVSWITCH_PRINT(device, ERROR,
"Failed to register link %d with the nvlink core : %d!\n",
link_num,
retval);
// Free the single dangling link.
nvswitch_destroy_link(link);
goto nvswitch_link_fail;
}
nvswitch_reset_persistent_link_hw_state(device, link_num);
//
// During Nvswitch initialization, the default L1 thresholds are programmed by the
// BIOS from the BIOS tables. Save these L1 Threshold Values in scratch registers
// for use when resetting the thresholds to default.
//
nvswitch_program_l1_scratch_reg(device, link_num);
//
// WAR : Initializing the L1 threshold registers at this point as a WAR for
// Bug 3963639 where it was discussed that the L1 threshold register should have
// the default value for all available links and not just for active links.
//
nvswitch_init_lpwr_regs(link);
}
retval = nvswitch_set_training_mode(device);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Failed to determine link training mode! rc: %d\n", retval);
goto nvswitch_link_fail;
}
// Initialize select scratch registers to 0x0
device->hal.nvswitch_init_scratch(device);
retval = nvswitch_construct_error_log(&device->log_FATAL_ERRORS, 1024, NV_FALSE);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Failed to construct log_FATAL_ERRORS! rc: %d\n", retval);
goto nvswitch_construct_error_log_fail;
}
retval = nvswitch_construct_error_log(&device->log_NONFATAL_ERRORS, 1024, NV_TRUE);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Failed to construct log_NONFATAL_ERRORS! rc: %d\n", retval);
goto nvswitch_construct_error_log_fail;
}
retval = _nvswitch_construct_port_event_log(&device->log_PORT_EVENTS, NVSWITCH_PORT_EVENT_LOG_SIZE, NV_TRUE);
if (retval != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "Failed to construct log_PORT_EVENTS! rc: %d\n", retval);
goto nvswitch_construct_port_event_log_fail;
}
if (device->regkeys.latency_counter == NV_SWITCH_REGKEY_LATENCY_COUNTER_LOGGING_ENABLE)
{
if (!nvswitch_is_tnvl_mode_enabled(device))
{
nvswitch_task_create(device, &nvswitch_internal_latency_bin_log,
nvswitch_get_latency_sample_interval_msec(device) * NVSWITCH_INTERVAL_1MSEC_IN_NS * 9/10, 0);
}
else
{
NVSWITCH_PRINT(device, INFO, "Skipping Internal latency background task when TNVL is enabled\n");
}
}
if (!nvswitch_is_tnvl_mode_enabled(device))
{
nvswitch_task_create(device, &nvswitch_ecc_writeback_task,
(60 * NVSWITCH_INTERVAL_1SEC_IN_NS), 0);
}
else
{
NVSWITCH_PRINT(device, INFO, "Skipping ECC writeback background task when TNVL is enabled\n");
}
if (IS_RTLSIM(device) || IS_EMULATION(device) || IS_FMODEL(device))
{
NVSWITCH_PRINT(device, WARN,
"%s: Skipping setup of NvSwitch thermal alert monitoring\n",
__FUNCTION__);
}
else
{
if (!nvswitch_is_tnvl_mode_enabled(device))
{
nvswitch_task_create(device, &nvswitch_monitor_thermal_alert,
100*NVSWITCH_INTERVAL_1MSEC_IN_NS, 0);
}
else
{
NVSWITCH_PRINT(device, INFO, "Skipping Thermal alert background task when TNVL is enabled\n");
}
}
device->nvlink_device->initialized = 1;
return NVL_SUCCESS;
nvswitch_construct_error_log_fail:
//free allocated memory to avoid leaking
nvswitch_destroy_error_log(device, &device->log_FATAL_ERRORS);
nvswitch_destroy_error_log(device, &device->log_NONFATAL_ERRORS);
nvswitch_construct_port_event_log_fail:
//free allocated memory to avoid leaking
_nvswitch_destroy_port_event_log(device, &device->log_PORT_EVENTS);
nvswitch_link_fail:
// Track down all links that successfully registered.
for (link_num = 0; link_num < nvswitch_get_num_links(device); link_num++)
{
if (nvlink_lib_get_link(device->nvlink_device, link_num, &link) == NVL_SUCCESS)
{
nvlink_lib_unregister_link(link);
nvswitch_destroy_link(link);
}
}
nvswitch_destroy_inforom_objects(device);
nvswitch_initialize_inforom_fail:
nvswitch_destroy_inforom(device);
nvswitch_initialize_device_state_fail:
_nvswitch_destruct_cci(device);
nvswitch_initialize_cci_fail:
_nvswitch_destruct_soe(device);
nvswitch_tasks_destroy(device);
return retval;
}
NvBool
nvswitch_lib_validate_device_id
(
NvU32 device_id
)
{
if (nvswitch_is_lr10_device_id(device_id))
{
return NV_TRUE;
}
if (nvswitch_is_ls10_device_id(device_id))
{
return NV_TRUE;
}
return NV_FALSE;
}
NvlStatus
nvswitch_lib_post_init_device
(
nvswitch_device *device
)
{
NvlStatus retval;
NvlStatus status;
NvU32 link_num;
NvU64 mode;
nvlink_link *link;
NvU64 enabledLinkMaskNonCci;
if (!NVSWITCH_IS_DEVICE_INITIALIZED(device))
{
return -NVL_ERR_INVALID_STATE;
}
retval = _nvswitch_post_init_device_setup(device);
if (retval != NVL_SUCCESS)
{
return retval;
}
if (nvswitch_is_bios_supported(device))
{
retval = nvswitch_bios_get_image(device);
if (retval != NVL_SUCCESS)
{
return retval;
}
retval = nvswitch_parse_bios_image(device);
if (retval != NVL_SUCCESS)
{
return retval;
}
}
else
{
NVSWITCH_PRINT(device, ERROR,
"%s: Skipping BIOS parsing since BIOS is unsupported.\n",
__FUNCTION__);
}
if (nvswitch_is_cci_supported(device))
{
retval = cciLoad(device);
if (NVL_SUCCESS != retval)
{
NVSWITCH_PRINT(device, ERROR, "%s: Init CCI failed\n",
__FUNCTION__);
return retval;
}
enabledLinkMaskNonCci = nvswitch_get_enabled_link_mask(device);
FOR_EACH_INDEX_IN_MASK(64, link_num, enabledLinkMaskNonCci)
{
if (cciIsLinkManaged(device, link_num))
{
enabledLinkMaskNonCci = enabledLinkMaskNonCci & ~NVBIT64(link_num);
}
}
FOR_EACH_INDEX_IN_MASK_END;
if (enabledLinkMaskNonCci != 0)
{
nvswitch_task_create(device, &_nvswitch_update_link_state_led,
NVSWITCH_INTERVAL_1SEC_IN_NS, 0);
}
}
else
{
NVSWITCH_PRINT(device, INFO, "%s: Skipping CCI init.\n",
__FUNCTION__);
}
retval = _nvswitch_setup_system_registers(device);
if (retval != NVL_SUCCESS)
{
return retval;
}
nvswitch_smbpbi_post_init(device);
// ALI launched by VBIOS on silicon
if (IS_RTLSIM(device) || IS_EMULATION(device) || IS_FMODEL(device))
{
(void)nvswitch_launch_ALI(device);
}
//
// There is an edge case where a hyperisor may not send same number
// of reset to switch and GPUs, so try to re-train links in fault
// if possible
//
for (link_num=0; link_num < nvswitch_get_num_links(device); link_num++)
{
// Sanity check
if (!nvswitch_is_link_valid(device, link_num))
{
continue;
}
// CCI links are trained and managed by SOE, skip any driver based training
if (cciIsLinkManaged(device, link_num))
{
continue;
}
status = nvlink_lib_get_link(device->nvlink_device, link_num, &link);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to get link for LinkId %d\n",
__FUNCTION__, link_num);
continue;
}
// If the link is in fault then re-train
if(_nvswitch_corelib_get_dl_link_mode(link, &mode) != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: nvlipt_lnk_status: Failed to check link mode! LinkId %d\n",
__FUNCTION__, link_num);
}
else if(mode == NVLINK_LINKSTATE_FAULT)
{
NVSWITCH_PRINT(device, INFO, "%s: retraining LinkId %d\n",
__FUNCTION__, link_num);
nvswitch_reset_and_train_link(device, link);
}
}
return NVL_SUCCESS;
}
void
nvswitch_lib_post_init_blacklist_device
(
nvswitch_device *device
)
{
_nvswitch_post_init_blacklist_device_setup(device);
}
void
_nvswitch_check_pending_data_and_notify
(
nvswitch_device *device,
NVSWITCH_CLIENT_EVENT *event
)
{
switch (event->eventId)
{
case NVSWITCH_DEVICE_EVENT_INBAND_DATA:
{
NvU32 i;
for (i = 0; i < nvswitch_get_num_links(device); i++)
{
if (!nvListIsEmpty(&device->link[i].inbandData.persistent_list) ||
!nvListIsEmpty(&device->link[i].inbandData.nonpersistent_list))
{
(void)nvswitch_os_notify_client_event(device->os_handle,
event->private_driver_data,
event->eventId);
}
}
break;
}
default:
return;
}
}
/*!
* @brief: Gets the client event associated with the file descriptor
* if it already exists in the Device's client event list.
*
* If found, and if there is pending data for the event,
* the event is triggered before returning to unblock the
* client right away.
*/
NvlStatus
nvswitch_lib_get_client_event
(
nvswitch_device *device,
void *osPrivate,
NVSWITCH_CLIENT_EVENT **ppClientEvent
)
{
NVSWITCH_CLIENT_EVENT *curr = NULL;
*ppClientEvent = NULL;
if(!NVSWITCH_IS_DEVICE_VALID(device))
{
return -NVL_BAD_ARGS;
}
nvListForEachEntry(curr, &device->client_events_list, entry)
{
if (curr->private_driver_data == osPrivate)
{
*ppClientEvent = curr;
_nvswitch_check_pending_data_and_notify(device, curr);
return NVL_SUCCESS;
}
}
return -NVL_NOT_FOUND;
}
/*!
* @brief: Adds an event to the front of the
* Device's client event list.
*/
NvlStatus
nvswitch_lib_add_client_event
(
nvswitch_device *device,
void *osPrivate,
NvU32 eventId
)
{
NVSWITCH_CLIENT_EVENT *newEvent;
NvlStatus status = NVL_SUCCESS;
if (!NVSWITCH_IS_DEVICE_VALID(device))
{
return -NVL_BAD_ARGS;
}
if (eventId >= NVSWITCH_DEVICE_EVENT_COUNT)
{
NVSWITCH_PRINT(device, ERROR, "%s: Invalid event Id.\n", __FUNCTION__);
return -NVL_BAD_ARGS;
}
// Invoke OS specific API to add event.
status = nvswitch_os_add_client_event(device->os_handle,
osPrivate,
eventId);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to add client event.\n", __FUNCTION__);
return status;
}
newEvent = nvswitch_os_malloc(sizeof(*newEvent));
if (newEvent == NULL)
{
return -NVL_NO_MEM;
}
newEvent->eventId = eventId;
newEvent->private_driver_data = osPrivate;
nvListAdd(&newEvent->entry, &device->client_events_list);
return NVL_SUCCESS;
}
/*!
* @brief: Removes all events corresponding to osPrivate,
* from the Device's client event list.
*/
NvlStatus
nvswitch_lib_remove_client_events
(
nvswitch_device *device,
void *osPrivate
)
{
NVSWITCH_CLIENT_EVENT *curr = NULL;
NVSWITCH_CLIENT_EVENT *next = NULL;
NvlStatus status = NVL_SUCCESS;
//
// Device shutdown may happen before this is called, so return
// if device is gone
//
if (!NVSWITCH_IS_DEVICE_VALID(device))
{
return NVL_SUCCESS;
}
nvListForEachEntry_safe(curr, next, &device->client_events_list, entry)
{
if (curr->private_driver_data == osPrivate)
{
nvListDel(&curr->entry);
nvswitch_os_free(curr);
}
}
// Invoke OS specific API to remove event.
status = nvswitch_os_remove_client_event(device->os_handle,
osPrivate);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to remove client events.\n", __FUNCTION__);
return status;
}
return NVL_SUCCESS;
}
/*!
* @brief: Notifies all events with matching event id in the
* Device's client event list.
*/
NvlStatus
nvswitch_lib_notify_client_events
(
nvswitch_device *device,
NvU32 eventId
)
{
NvlStatus status;
NVSWITCH_CLIENT_EVENT *curr = NULL;
if (!NVSWITCH_IS_DEVICE_VALID(device))
{
return -NVL_BAD_ARGS;
}
if (eventId >= NVSWITCH_DEVICE_EVENT_COUNT)
{
NVSWITCH_PRINT(device, ERROR, "%s: Invalid event Id.\n", __FUNCTION__);
return -NVL_BAD_ARGS;
}
nvListForEachEntry(curr, &device->client_events_list, entry)
{
if (curr->eventId == eventId)
{
// OS specific event notification.
status = nvswitch_os_notify_client_event(device->os_handle,
curr->private_driver_data,
eventId);
if (status != NVL_SUCCESS)
{
return status;
}
}
}
return NVL_SUCCESS;
}
void
nvswitch_record_port_event
(
nvswitch_device *device,
NVSWITCH_PORT_EVENT_LOG_TYPE *port_events,
NvU32 link_id,
NvU8 port_event_type
)
{
NvU32 idx;
NVSWITCH_ASSERT(port_events != NULL);
// If no port events log has been created, then don't log it.
if ((port_events->port_event_log_size != 0) &&
(port_events->port_event_log != NULL))
{
idx = (port_events->port_event_start + port_events->port_event_count)
% port_events->port_event_log_size;
if (port_events->port_event_count == port_events->port_event_log_size)
{
// Error: ring buffer is already full/
if (port_events->overwritable)
{
port_events->port_event_start = (port_events->port_event_start + 1)
% port_events->port_event_log_size;
port_events->bOverflow = NV_TRUE;
}
else
{
// No logging, ring buffer is full
return;
}
}
else
{
port_events->port_event_count++;
}
// Log port event info
port_events->port_event_log[idx].link_id = link_id;
port_events->port_event_log[idx].port_event_type = port_event_type;
// Log tracking info
port_events->port_event_log[idx].time = nvswitch_os_get_platform_time();
port_events->port_event_log[idx].local_port_event_num = port_events->port_event_total;
}
port_events->port_event_total++;
}
/*
* @Brief : Retrives a port event entry by index.
*
* @Description : Retrieves the port_event at index port_event_idx. If index is out
* of range, returns an empty port event entry with port_event_type = 2
*
* @param[in] device NVSwitch device to contain this link
* @param[in] port_events Log of all port events with metadata
* @param[in] port_event_idx Index of entry to retrieve (0 = oldest port event)
* @param[out] port_event_count Clear only non-persistent list
*/
void
nvswitch_get_port_event
(
nvswitch_device *device,
NVSWITCH_PORT_EVENT_LOG_TYPE *port_events,
NVSWITCH_PORT_EVENT_TYPE *port_event_entry,
NvU32 port_event_idx,
NvU32 *port_event_count
)
{
NvU32 idx;
NVSWITCH_ASSERT(port_events != NULL);
if (port_event_entry != NULL)
{
// Index is out of range
if (port_event_idx >= port_events->port_event_count)
{
nvswitch_os_memset(port_event_entry, 0, sizeof(*port_event_entry));
port_event_entry->port_event_type = NVSWITCH_PORT_EVENT_TYPE_INVALID;
port_event_entry->time = nvswitch_os_get_platform_time();
}
else
{
idx = (port_events->port_event_start + port_event_idx) % port_events->port_event_log_size;
*port_event_entry = port_events->port_event_log[idx];
}
}
if (port_event_count)
{
*port_event_count = port_events->port_event_count;
}
}
NvlStatus
nvswitch_ctrl_get_port_events
(
nvswitch_device *device,
NVSWITCH_GET_PORT_EVENTS_PARAMS *p
)
{
NvU32 index = 0;
NvU32 count = 0;
NVSWITCH_PORT_EVENT_LOG_TYPE *port_events = &device->log_PORT_EVENTS;
NVSWITCH_PORT_EVENT_TYPE port_event;
nvswitch_os_memset(p->portEvent, 0, sizeof(NVSWITCH_PORT_EVENT)
*NVSWITCH_PORT_EVENT_COUNT_SIZE);
p->nextPortEventIndex = port_events->port_event_total;
p->portEventCount = 0;
p->bOverflow = port_events->bOverflow;
// Return if there are no more port events to get
nvswitch_get_port_event(device, port_events, &port_event, index, &count);
if (count == 0)
{
return NVL_SUCCESS;
}
// If port event's local_port_Event_num is smaller than the portEventIndex
// passed in by the client, fast-forward index by the difference.
// This will skip over port events that were previously read by the client.
if (port_event.local_port_event_num < p->portEventIndex)
{
index = (NvU32) (p->portEventIndex - port_event.local_port_event_num);
}
// Return if there are no more events after fast-forwarding.
if (index >= count)
{
return NVL_SUCCESS;
}
while ((p->portEventCount < NVSWITCH_PORT_EVENT_COUNT_SIZE) && (index < count))
{
nvswitch_get_port_event(device, port_events, &port_event, index, NULL);
p->portEvent[p->portEventCount].port_event_type = port_event.port_event_type;
p->portEvent[p->portEventCount].link_id = port_event.link_id;
p->portEvent[p->portEventCount].time = port_event.time;
p->portEventCount++;
index++;
}
p->portEventIndex = port_event.local_port_event_num + 1;
return NVL_SUCCESS;
}
/*!
@brief: Release ROM image from memory.
*/
void
_nvswitch_destroy_rom(nvswitch_device *device)
{
if (device->biosImage.pImage != NULL)
{
nvswitch_os_free(device->biosImage.pImage);
device->biosImage.pImage = NULL;
}
}
/*!
* @brief: Free the device's client event list
*/
static void
_nvswitch_destroy_event_list(nvswitch_device *device)
{
NVSWITCH_CLIENT_EVENT *curr = NULL;
NVSWITCH_CLIENT_EVENT *next = NULL;
nvListForEachEntry_safe(curr, next, &device->client_events_list, entry)
{
nvListDel(&curr->entry);
nvswitch_os_free(curr);
}
}
NvlStatus
nvswitch_lib_shutdown_device
(
nvswitch_device *device
)
{
NVSWITCH_INBAND_FLUSH_DATA_PARAMS p;
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
//
// Set fabric state to offline
//
if (device->device_fabric_state != NVSWITCH_DEVICE_FABRIC_STATE_BLACKLISTED)
device->device_fabric_state = NVSWITCH_DEVICE_FABRIC_STATE_OFFLINE;
device->driver_fabric_state = NVSWITCH_DRIVER_FABRIC_STATE_OFFLINE;
(void)device->hal.nvswitch_write_fabric_state(device);
nvswitch_hw_counter_shutdown(device);
// FLUSH any pending messages to avoid memory leaks
p.linkMask = nvswitch_get_enabled_link_mask(device);
_nvswitch_ctrl_inband_flush_data(device, &p);
_nvswitch_destruct_cci(device);
_nvswitch_led_shutdown(device);
_nvswitch_unregister_links(device);
nvswitch_destroy_error_log(device, &device->log_FATAL_ERRORS);
nvswitch_destroy_error_log(device, &device->log_NONFATAL_ERRORS);
_nvswitch_destroy_port_event_log(device, &device->log_PORT_EVENTS);
nvswitch_smbpbi_unload(device);
_nvswitch_destroy_event_list(device);
nvswitch_destroy_inforom_objects(device);
nvswitch_destroy_inforom(device);
nvswitch_smbpbi_destroy(device);
nvswitch_destroy_device_state(device);
_nvswitch_destroy_rom(device);
_nvswitch_destruct_soe(device);
nvswitch_tasks_destroy(device);
return NVL_SUCCESS;
}
NvlStatus
nvswitch_lib_get_log_count
(
nvswitch_device *device,
NvU32 *fatal, NvU32 *nonfatal, NvU32 *portEvent
)
{
if (!NVSWITCH_IS_DEVICE_INITIALIZED(device) ||
fatal == NULL || nonfatal == NULL || portEvent == NULL)
{
return -NVL_BAD_ARGS;
}
*fatal = device->log_FATAL_ERRORS.error_count;
*nonfatal = device->log_NONFATAL_ERRORS.error_count;
*portEvent = device->log_PORT_EVENTS.port_event_count;
// No report of log_INFO currently
return NVL_SUCCESS;
}
NvlStatus
nvswitch_lib_load_platform_info
(
nvswitch_device *device
)
{
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
device->hal.nvswitch_determine_platform(device);
return NVL_SUCCESS;
}
void
nvswitch_lib_get_device_info
(
nvswitch_device *device,
struct nvlink_pci_info **pciInfo
)
{
if (!NVSWITCH_IS_DEVICE_VALID(device) || pciInfo == NULL)
{
NVSWITCH_ASSERT(0);
return;
}
*pciInfo = &device->nvlink_device->pciInfo;
}
NvlStatus
nvswitch_lib_get_bios_version
(
nvswitch_device *device,
NvU64 *version
)
{
NVSWITCH_GET_BIOS_INFO_PARAMS p = { 0 };
NvlStatus ret;
if (!device)
return -NVL_BAD_ARGS;
ret = device->hal.nvswitch_ctrl_get_bios_info(device, &p);
if (version != NULL)
{
*version = p.version;
}
return ret;
}
NvlStatus
nvswitch_lib_use_pin_irq
(
nvswitch_device *device
)
{
return IS_FMODEL(device);
}
NvlStatus
nvswitch_lib_register_device
(
NvU16 pci_domain,
NvU8 pci_bus,
NvU8 pci_device,
NvU8 pci_func,
NvU16 pci_device_id,
void *os_handle,
NvU32 os_instance,
nvswitch_device **return_device
)
{
nvswitch_device *device = NULL;
nvlink_device *coreDev = NULL;
NvlStatus retval = NVL_SUCCESS;
if (!nvlink_lib_is_initialized())
{
NVSWITCH_PRINT(device, ERROR,
"NVLink core lib isn't initialized yet!\n");
return -NVL_INITIALIZATION_TOTAL_FAILURE;
}
if (return_device == NULL || os_handle == NULL)
{
return -NVL_BAD_ARGS;
}
*return_device = NULL;
device = nvswitch_os_malloc(sizeof(*device));
if (NULL == device)
{
NVSWITCH_PRINT(device, ERROR,
"nvswitch_os_malloc during device creation failed!\n");
return -NVL_NO_MEM;
}
nvswitch_os_memset(device, 0, sizeof(*device));
nvswitch_os_snprintf(device->name, sizeof(device->name),
NVSWITCH_DEVICE_NAME "%d", os_instance);
coreDev = nvswitch_os_malloc(sizeof(*coreDev));
if (NULL == coreDev)
{
NVSWITCH_PRINT(device, ERROR,
"nvswitch_os_malloc during device creation failed!\n");
retval = -NVL_NO_MEM;
goto nvlink_lib_register_device_fail;
}
nvswitch_os_memset(coreDev, 0, sizeof(*coreDev));
coreDev->driverName =
nvswitch_os_malloc(sizeof(NVSWITCH_DRIVER_NAME));
if (coreDev->driverName == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"nvswitch_os_malloc during device creation failed!\n");
retval = -NVL_NO_MEM;
goto nvlink_lib_register_device_fail;
}
nvswitch_os_memcpy(coreDev->driverName, NVSWITCH_DRIVER_NAME,
sizeof(NVSWITCH_DRIVER_NAME));
device->os_handle = os_handle;
device->os_instance = os_instance;
device->nvlink_device = coreDev;
device->nvlink_device->deviceName = device->name;
device->nvlink_device->uuid = NULL; // No UUID support for switch
device->nvlink_device->pciInfo.domain = pci_domain;
device->nvlink_device->pciInfo.bus = pci_bus;
device->nvlink_device->pciInfo.device = pci_device;
device->nvlink_device->pciInfo.function = pci_func;
device->nvlink_device->pciInfo.pciDeviceId = pci_device_id;
// nvlink_device has a back pointer to nvswitch_device
device->nvlink_device->pDevInfo = device;
device->nvlink_device->type = NVLINK_DEVICE_TYPE_NVSWITCH;
//
// Initialize the Fabric State
//
device->fm_timeout = NVSWITCH_DEFAULT_FM_HEARTBEAT_TIMEOUT_MSEC;
device->fabric_state_sequence_number = 0;
device->driver_fabric_state = NVSWITCH_DRIVER_FABRIC_STATE_STANDBY;
device->device_fabric_state = NVSWITCH_DEVICE_FABRIC_STATE_STANDBY;
device->device_blacklist_reason = NVSWITCH_DEVICE_BLACKLIST_REASON_NONE;
//
// Initialize TNVL Mode
//
device->tnvl_mode = NVSWITCH_DEVICE_TNVL_MODE_DISABLED;
//
// Initialize HAL connectivity as early as possible so that other lib
// interfaces can work.
//
retval = _nvswitch_setup_hal(device, device->nvlink_device->pciInfo.pciDeviceId);
if (retval != NVL_SUCCESS)
{
goto nvlink_lib_register_device_fail;
}
//
// Initialize regkeys as early as possible so that most routines can take
// advantage of them.
//
_nvswitch_init_device_regkeys(device);
// After regkeys have been set then only set the enableALI field.
device->nvlink_device->enableALI = (device->regkeys.link_training_mode ==
NV_SWITCH_REGKEY_LINK_TRAINING_SELECT_ALI) ? NV_TRUE:NV_FALSE;
retval = nvlink_lib_register_device(device->nvlink_device);
if (NVL_SUCCESS != retval)
{
NVSWITCH_PRINT(device, ERROR,
"nvlinklib register device failed!\n");
goto nvlink_lib_register_device_fail;
}
*return_device = device;
NVSWITCH_PRINT(device, SETUP,
"Successfully registered with nvlinkcore\n");
return retval;
nvlink_lib_register_device_fail:
if (NULL != coreDev)
{
nvswitch_os_free(coreDev->driverName);
nvswitch_os_free(coreDev);
}
if (NULL != device)
nvswitch_os_free(device);
return retval;
}
void
nvswitch_lib_unregister_device
(
nvswitch_device *device
)
{
if (!NVSWITCH_IS_DEVICE_VALID(device))
{
NVSWITCH_ASSERT(0);
return;
}
nvlink_lib_unregister_device(device->nvlink_device);
nvswitch_os_free(device->nvlink_device->driverName);
nvswitch_os_free(device->nvlink_device);
nvswitch_os_free(device);
return;
}
/*!
* @brief: Gets the mask of valid I2C ports on the
* Device.
*/
NvlStatus
nvswitch_lib_get_valid_ports_mask
(
nvswitch_device *device,
NvU32 *validPortsMask
)
{
NvU32 port_info;
NvU32 i;
NvU32 ports_mask = 0;
NvBool is_i2c_access_allowed;
NvBool is_port_allowed;
if (!NVSWITCH_IS_DEVICE_VALID(device) ||
(validPortsMask == NULL))
{
return -NVL_BAD_ARGS;
}
is_i2c_access_allowed = (device->regkeys.i2c_access_control ==
NV_SWITCH_REGKEY_I2C_ACCESS_CONTROL_ENABLE) ?
NV_TRUE : NV_FALSE;
for (i = 0; i < NVSWITCH_MAX_I2C_PORTS; i++)
{
port_info = nvswitch_i2c_get_port_info(device, i);
is_port_allowed = is_i2c_access_allowed ? NV_TRUE :
FLD_TEST_DRF(_I2C, _PORTINFO, _ACCESS_ALLOWED, _TRUE,
port_info);
if (is_port_allowed &&
FLD_TEST_DRF(_I2C, _PORTINFO, _DEFINED, _PRESENT, port_info))
{
ports_mask |= NVBIT(i);
}
}
*validPortsMask = ports_mask;
return NVL_SUCCESS;
}
/*!
* @brief: Returns if the I2C transactions are supported.
*/
NvBool
nvswitch_lib_is_i2c_supported
(
nvswitch_device *device
)
{
if (!NVSWITCH_IS_DEVICE_VALID(device))
{
NVSWITCH_ASSERT(0);
return NV_FALSE;
}
return nvswitch_is_i2c_supported(device);
}
static NvlStatus
_nvswitch_perform_i2c_transfer
(
nvswitch_device *device,
NvU32 client,
NvU8 type,
NvU16 addr,
NvU8 port,
NvU8 cmd,
NvU32 msgLength,
NvU8 *pData
)
{
NvlStatus status;
NvU16 deviceAddr;
NvU32 speedMode;
NvBool bIsRead = NV_FALSE;
NvU32 flags = 0;
NVSWITCH_CTRL_I2C_INDEXED_PARAMS i2c_params = {0};
NvBool is_i2c_access_allowed;
if (!nvswitch_os_is_admin())
{
return -NVL_ERR_INSUFFICIENT_PERMISSIONS;
}
is_i2c_access_allowed = (device->regkeys.i2c_access_control ==
NV_SWITCH_REGKEY_I2C_ACCESS_CONTROL_ENABLE) ?
NV_TRUE : NV_FALSE;
//
// The address needs to be shifted by 1,
// See NVSWITCH_CTRL_I2C_INDEXED_PARAMS
//
deviceAddr = addr << 1;
speedMode = device->pI2c->Ports[port].defaultSpeedMode;
flags = DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _START, _SEND) |
DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _STOP, _SEND) |
DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _ADDRESS_MODE, _7BIT) |
DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _FLAVOR, _HW) |
DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _BLOCK_PROTOCOL, _DISABLED) |
DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _TRANSACTION_MODE, _NORMAL);
switch (speedMode)
{
case NVSWITCH_I2C_SPEED_MODE_1000KHZ:
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _SPEED_MODE, _1000KHZ, flags);
break;
}
case NVSWITCH_I2C_SPEED_MODE_400KHZ:
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _SPEED_MODE, _400KHZ, flags);
break;
}
case NVSWITCH_I2C_SPEED_MODE_300KHZ:
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _SPEED_MODE, _300KHZ, flags);
break;
}
case NVSWITCH_I2C_SPEED_MODE_200KHZ:
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _SPEED_MODE, _200KHZ, flags);
break;
}
case NVSWITCH_I2C_SPEED_MODE_100KHZ:
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _SPEED_MODE, _100KHZ, flags);
break;
}
default:
{
NVSWITCH_PRINT(device, ERROR, "Invalid I2C speed!\n");
status = -NVL_BAD_ARGS;
goto end;
}
}
switch (type)
{
case NVSWITCH_I2C_CMD_READ:
bIsRead = NV_TRUE;
// Fall through
case NVSWITCH_I2C_CMD_WRITE:
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _INDEX_LENGTH, _ZERO, flags);
break;
}
case NVSWITCH_I2C_CMD_SMBUS_READ:
{
bIsRead = NV_TRUE;
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _RESTART, _SEND, flags);
// Fall through
}
case NVSWITCH_I2C_CMD_SMBUS_WRITE:
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _INDEX_LENGTH, _ONE, flags);
break;
}
case NVSWITCH_I2C_CMD_SMBUS_QUICK_READ:
bIsRead = NV_TRUE;
// Fall through
case NVSWITCH_I2C_CMD_SMBUS_QUICK_WRITE:
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _INDEX_LENGTH, _ZERO, flags);
msgLength = 0;
break;
}
default:
{
NVSWITCH_PRINT(device, ERROR, "Invalid SMBUS protocol! Protocol not supported.\n");
status = -NVL_BAD_ARGS;
goto end;
}
}
if (!is_i2c_access_allowed &&
!nvswitch_i2c_is_device_access_allowed(device, port, deviceAddr, bIsRead))
{
return -NVL_BAD_ARGS;
}
if (msgLength > NVSWITCH_CTRL_I2C_MESSAGE_LENGTH_MAX)
{
NVSWITCH_PRINT(device, ERROR,
"Length of buffer (0x%x bytes) provided larger than max (0x%x bytes)\n",
msgLength, NVSWITCH_CTRL_I2C_MESSAGE_LENGTH_MAX);
status = -NVL_BAD_ARGS;
goto end;
}
if (bIsRead)
{
i2c_params.bIsRead = NV_TRUE;
}
else
{
flags = FLD_SET_DRF(SWITCH_CTRL, _I2C_FLAGS, _RESTART, _NONE, flags);
nvswitch_os_memcpy(i2c_params.message, pData, msgLength);
}
if (FLD_TEST_DRF(SWITCH_CTRL, _I2C_FLAGS, _INDEX_LENGTH, _ONE, flags))
{
i2c_params.index[0] = cmd;
}
i2c_params.port = port;
i2c_params.address = deviceAddr;
i2c_params.acquirer = client;
i2c_params.flags = flags;
i2c_params.messageLength = msgLength;
status = nvswitch_ctrl_i2c_indexed(device, &i2c_params);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "I2C transfer Failed!\n");
goto end;
}
if (bIsRead)
{
nvswitch_os_memcpy(pData, i2c_params.message, msgLength);
}
end:
return status;
}
/*!
* @brief: Performs an I2C transaction.
*/
NvlStatus
nvswitch_lib_i2c_transfer
(
nvswitch_device *device,
NvU32 port,
NvU8 type,
NvU8 addr,
NvU8 command,
NvU32 len,
NvU8 *pData
)
{
NvlStatus status;
NvU32 port_info;
NvBool is_i2c_access_allowed;
NvBool is_port_allowed;
if (!NVSWITCH_IS_DEVICE_VALID(device))
{
NVSWITCH_ASSERT(0);
return -NVL_ERR_INVALID_STATE;
}
port_info = nvswitch_i2c_get_port_info(device, port);
is_i2c_access_allowed = (device->regkeys.i2c_access_control ==
NV_SWITCH_REGKEY_I2C_ACCESS_CONTROL_ENABLE) ?
NV_TRUE : NV_FALSE;
is_port_allowed = is_i2c_access_allowed ? NV_TRUE :
FLD_TEST_DRF(_I2C, _PORTINFO, _ACCESS_ALLOWED, _TRUE,
port_info);
if (!is_port_allowed ||
!FLD_TEST_DRF(_I2C, _PORTINFO, _DEFINED, _PRESENT, port_info))
{
NVSWITCH_PRINT(device, INFO,
"%s: Invalid port access %d.\n",
__FUNCTION__, port);
return (-NVL_BAD_ARGS);
}
status = _nvswitch_perform_i2c_transfer(device, NVSWITCH_I2C_ACQUIRER_EXTERNAL,
type, (NvU16)addr, port, command, len, pData);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "I2C transaction failed!\n");
return status;
}
return NVL_SUCCESS;
}
void
nvswitch_timeout_create
(
NvU64 timeout_ns,
NVSWITCH_TIMEOUT *time
)
{
NvU64 time_current;
time_current = nvswitch_os_get_platform_time();
time->timeout_ns = time_current + timeout_ns;
}
NvBool
nvswitch_timeout_check
(
NVSWITCH_TIMEOUT *time
)
{
NvU64 time_current;
time_current = nvswitch_os_get_platform_time();
return (time->timeout_ns <= time_current);
}
NvlStatus
nvswitch_task_create
(
nvswitch_device *device,
void (*task_fn)(nvswitch_device *device),
NvU64 period_nsec,
NvU32 flags
)
{
NVSWITCH_TASK_TYPE *task;
task = nvswitch_os_malloc(sizeof(NVSWITCH_TASK_TYPE));
if (task == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"%s: Unable to allocate task.\n",
__FUNCTION__);
return -NVL_NO_MEM;
}
else
{
task->task_fn_devptr = task_fn;
task->task_args = NULL;
task->period_nsec = period_nsec;
task->last_run_nsec = nvswitch_os_get_platform_time(); // Prevent deferred tasks from being run immediately
task->flags = flags;
task->prev = NULL;
task->next = device->tasks;
if (device->tasks != NULL)
{
device->tasks->prev = task;
}
device->tasks = task;
}
return NVL_SUCCESS;
}
NvlStatus
nvswitch_task_create_args
(
nvswitch_device *device,
void *fn_args,
void (*task_fn)(nvswitch_device* device, void *fn_args),
NvU64 period_nsec,
NvU32 flags
)
{
NVSWITCH_TASK_TYPE *task;
task = nvswitch_os_malloc(sizeof(NVSWITCH_TASK_TYPE));
flags = flags | NVSWITCH_TASK_TYPE_FLAGS_VOID_PTR_ARGS; // ensure dispatcher always executes tasks passed through this function with args
if (task == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"%s: Unable to allocate task.\n",
__FUNCTION__);
return -NVL_NO_MEM;
}
else
{
task->task_fn_vdptr = task_fn;
task->task_args = fn_args;
task->period_nsec = period_nsec;
task->last_run_nsec = nvswitch_os_get_platform_time(); // Prevent deferred tasks from being run immediately
task->flags = flags;
task->prev = NULL;
task->next = device->tasks;
if (device->tasks != NULL)
{
device->tasks->prev = task;
}
device->tasks = task;
}
return NVL_SUCCESS;
}
void
nvswitch_tasks_destroy
(
nvswitch_device *device
)
{
NVSWITCH_TASK_TYPE *task = device->tasks;
NVSWITCH_TASK_TYPE *next_task;
device->tasks = NULL;
while (task)
{
next_task = task->next;
nvswitch_os_free(task);
task = next_task;
}
}
void
nvswitch_destroy_device_state
(
nvswitch_device *device
)
{
device->hal.nvswitch_destroy_device_state(device);
}
static NvlStatus
_nvswitch_ctrl_get_info
(
nvswitch_device *device,
NVSWITCH_GET_INFO *p
)
{
return device->hal.nvswitch_ctrl_get_info(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_nvlink_status
(
nvswitch_device *device,
NVSWITCH_GET_NVLINK_STATUS_PARAMS *ret
)
{
return device->hal.nvswitch_ctrl_get_nvlink_status(device, ret);
}
static NvlStatus
_nvswitch_ctrl_get_counters
(
nvswitch_device *device,
NVSWITCH_NVLINK_GET_COUNTERS_PARAMS *ret
)
{
return device->hal.nvswitch_ctrl_get_counters(device, ret);
}
NvlStatus
nvswitch_set_nport_port_config
(
nvswitch_device *device,
NVSWITCH_SET_SWITCH_PORT_CONFIG *p
)
{
return device->hal.nvswitch_set_nport_port_config(device, p);
}
static NvlStatus
_nvswitch_ctrl_set_switch_port_config
(
nvswitch_device *device,
NVSWITCH_SET_SWITCH_PORT_CONFIG *p
)
{
return device->hal.nvswitch_ctrl_set_switch_port_config(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_ingress_request_table
(
nvswitch_device *device,
NVSWITCH_GET_INGRESS_REQUEST_TABLE_PARAMS *params
)
{
return device->hal.nvswitch_ctrl_get_ingress_request_table(device, params);
}
static NvlStatus
_nvswitch_ctrl_set_ingress_request_table
(
nvswitch_device *device,
NVSWITCH_SET_INGRESS_REQUEST_TABLE *p
)
{
return device->hal.nvswitch_ctrl_set_ingress_request_table(device, p);
}
static NvlStatus
_nvswitch_ctrl_set_ingress_request_valid
(
nvswitch_device *device,
NVSWITCH_SET_INGRESS_REQUEST_VALID *p
)
{
return device->hal.nvswitch_ctrl_set_ingress_request_valid(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_ingress_response_table
(
nvswitch_device *device,
NVSWITCH_GET_INGRESS_RESPONSE_TABLE_PARAMS *params
)
{
return device->hal.nvswitch_ctrl_get_ingress_response_table(device, params);
}
static NvlStatus
_nvswitch_ctrl_set_ingress_response_table
(
nvswitch_device *device,
NVSWITCH_SET_INGRESS_RESPONSE_TABLE *p
)
{
return device->hal.nvswitch_ctrl_set_ingress_response_table(device, p);
}
static NvlStatus
_nvswitch_ctrl_set_ganged_link_table
(
nvswitch_device *device,
NVSWITCH_SET_GANGED_LINK_TABLE *p
)
{
return device->hal.nvswitch_ctrl_set_ganged_link_table(device, p);
}
void
nvswitch_init_npg_multicast
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_npg_multicast(device);
}
void
nvswitch_init_warm_reset
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_warm_reset(device);
}
static NvlStatus
_nvswitch_ctrl_set_remap_policy
(
nvswitch_device *device,
NVSWITCH_SET_REMAP_POLICY *p
)
{
return device->hal.nvswitch_ctrl_set_remap_policy(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_remap_policy
(
nvswitch_device *device,
NVSWITCH_GET_REMAP_POLICY_PARAMS *params
)
{
return device->hal.nvswitch_ctrl_get_remap_policy(device, params);
}
static NvlStatus
_nvswitch_ctrl_set_remap_policy_valid
(
nvswitch_device *device,
NVSWITCH_SET_REMAP_POLICY_VALID *p
)
{
return device->hal.nvswitch_ctrl_set_remap_policy_valid(device, p);
}
static NvlStatus
_nvswitch_ctrl_set_routing_id
(
nvswitch_device *device,
NVSWITCH_SET_ROUTING_ID *p
)
{
return device->hal.nvswitch_ctrl_set_routing_id(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_routing_id
(
nvswitch_device *device,
NVSWITCH_GET_ROUTING_ID_PARAMS *params
)
{
return device->hal.nvswitch_ctrl_get_routing_id(device, params);
}
static NvlStatus
_nvswitch_ctrl_set_routing_id_valid
(
nvswitch_device *device,
NVSWITCH_SET_ROUTING_ID_VALID *p
)
{
return device->hal.nvswitch_ctrl_set_routing_id_valid(device, p);
}
static NvlStatus
_nvswitch_ctrl_set_routing_lan
(
nvswitch_device *device,
NVSWITCH_SET_ROUTING_LAN *p
)
{
return device->hal.nvswitch_ctrl_set_routing_lan(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_routing_lan
(
nvswitch_device *device,
NVSWITCH_GET_ROUTING_LAN_PARAMS *params
)
{
return device->hal.nvswitch_ctrl_get_routing_lan(device, params);
}
static NvlStatus
_nvswitch_ctrl_set_routing_lan_valid
(
nvswitch_device *device,
NVSWITCH_SET_ROUTING_LAN_VALID *p
)
{
return device->hal.nvswitch_ctrl_set_routing_lan_valid(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_internal_latency
(
nvswitch_device *device,
NVSWITCH_GET_INTERNAL_LATENCY *p
)
{
return device->hal.nvswitch_ctrl_get_internal_latency(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_nvlipt_counters
(
nvswitch_device *device,
NVSWITCH_GET_NVLIPT_COUNTERS *p
)
{
//
// This control call is now deprecated.
// New control call to fetch throughput counters is:
// nvswitch_ctrl_get_throughput_counters
//
return -NVL_ERR_NOT_SUPPORTED;
}
static NvlStatus
_nvswitch_ctrl_set_nvlipt_counter_config
(
nvswitch_device *device,
NVSWITCH_SET_NVLIPT_COUNTER_CONFIG *p
)
{
//
// This control call is now deprecated.
// New control call to fetch throughput counters is:
// nvswitch_ctrl_get_throughput_counters_lr10
//
// Setting counter config is not allowed on these
// non-configurable counters. These counters are
// expected to be used by monitoring clients.
//
return -NVL_ERR_NOT_SUPPORTED;
}
static NvlStatus
_nvswitch_ctrl_get_nvlipt_counter_config
(
nvswitch_device *device,
NVSWITCH_GET_NVLIPT_COUNTER_CONFIG *p
)
{
//
// This control call is now deprecated.
// New control call to fetch throughput counters is:
// nvswitch_ctrl_get_throughput_counters_lr10
//
// Getting counter config is useful if counters are
// configurable. These counters are not configurable
// and are expected to be used by monitoring clients.
//
return -NVL_ERR_NOT_SUPPORTED;
}
static NvlStatus
_nvswitch_ctrl_register_read
(
nvswitch_device *device,
NVSWITCH_REGISTER_READ *p
)
{
return device->hal.nvswitch_ctrl_register_read(device, p);
}
static NvlStatus
_nvswitch_ctrl_register_write
(
nvswitch_device *device,
NVSWITCH_REGISTER_WRITE *p
)
{
return device->hal.nvswitch_ctrl_register_write(device, p);
}
NvU32
nvswitch_i2c_get_port_info
(
nvswitch_device *device,
NvU32 port
)
{
return device->hal.nvswitch_i2c_get_port_info(device, port);
}
NvlStatus
nvswitch_ctrl_i2c_indexed
(
nvswitch_device *device,
NVSWITCH_CTRL_I2C_INDEXED_PARAMS *pParams
)
{
return device->hal.nvswitch_ctrl_i2c_indexed(device, pParams);
}
static NvlStatus
_nvswitch_ctrl_therm_read_temperature
(
nvswitch_device *device,
NVSWITCH_CTRL_GET_TEMPERATURE_PARAMS *info
)
{
return device->hal.nvswitch_ctrl_therm_read_temperature(device, info);
}
static NvlStatus
_nvswitch_ctrl_get_bios_info
(
nvswitch_device *device,
NVSWITCH_GET_BIOS_INFO_PARAMS *p
)
{
return device->hal.nvswitch_ctrl_get_bios_info(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_inforom_version
(
nvswitch_device *device,
NVSWITCH_GET_INFOROM_VERSION_PARAMS *p
)
{
return device->hal.nvswitch_ctrl_get_inforom_version(device, p);
}
NvlStatus
nvswitch_ctrl_set_latency_bins
(
nvswitch_device *device,
NVSWITCH_SET_LATENCY_BINS *p
)
{
return device->hal.nvswitch_ctrl_set_latency_bins(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_ingress_reqlinkid
(
nvswitch_device *device,
NVSWITCH_GET_INGRESS_REQLINKID_PARAMS *params
)
{
return device->hal.nvswitch_ctrl_get_ingress_reqlinkid(device, params);
}
NvlStatus
nvswitch_ctrl_get_throughput_counters
(
nvswitch_device *device,
NVSWITCH_GET_THROUGHPUT_COUNTERS_PARAMS *p
)
{
return device->hal.nvswitch_ctrl_get_throughput_counters(device, p);
}
static NvlStatus
_nvswitch_ctrl_unregister_link
(
nvswitch_device *device,
NVSWITCH_UNREGISTER_LINK_PARAMS *params
)
{
nvlink_link *link = nvswitch_get_link(device, (NvU8)params->portNum);
if (link == NULL)
{
return -NVL_BAD_ARGS;
}
// With ALI in FW, links can be unregistered while Active
if (!device->nvlink_device->enableALI)
{
if (device->hal.nvswitch_is_link_in_use(device, params->portNum))
{
return -NVL_ERR_STATE_IN_USE;
}
}
nvlink_lib_unregister_link(link);
nvswitch_destroy_link(link);
return NVL_SUCCESS;
}
static NvlStatus
_nvswitch_ctrl_acquire_capability
(
nvswitch_device *device,
NVSWITCH_ACQUIRE_CAPABILITY_PARAMS *params,
void *osPrivate
)
{
return nvswitch_os_acquire_fabric_mgmt_cap(osPrivate,
params->capDescriptor);
}
static NvlStatus
_nvswitch_ctrl_reset_and_drain_links
(
nvswitch_device *device,
NVSWITCH_RESET_AND_DRAIN_LINKS_PARAMS *params
)
{
return device->hal.nvswitch_reset_and_drain_links(device, params->linkMask, NV_FALSE);
}
static NvlStatus
_nvswitch_ctrl_get_fom_values
(
nvswitch_device *device,
NVSWITCH_GET_FOM_VALUES_PARAMS *ret
)
{
return device->hal.nvswitch_ctrl_get_fom_values(device, ret);
}
static NvlStatus
_nvswitch_ctrl_get_nvlink_ecc_errors
(
nvswitch_device *device,
NVSWITCH_GET_NVLINK_ECC_ERRORS_PARAMS *params
)
{
return device->hal.nvswitch_get_nvlink_ecc_errors(device, params);
}
static NvlStatus
_nvswitch_ctrl_set_mc_rid_table
(
nvswitch_device *device,
NVSWITCH_SET_MC_RID_TABLE_PARAMS *p
)
{
return device->hal.nvswitch_ctrl_set_mc_rid_table(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_mc_rid_table
(
nvswitch_device *device,
NVSWITCH_GET_MC_RID_TABLE_PARAMS *p
)
{
return device->hal.nvswitch_ctrl_get_mc_rid_table(device, p);
}
static NvlStatus
_nvswitch_ctrl_set_residency_bins
(
nvswitch_device *device,
NVSWITCH_SET_RESIDENCY_BINS *p
)
{
return device->hal.nvswitch_ctrl_set_residency_bins(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_residency_bins
(
nvswitch_device *device,
NVSWITCH_GET_RESIDENCY_BINS *p
)
{
return device->hal.nvswitch_ctrl_get_residency_bins(device, p);
}
static NvlStatus
_nvswitch_ctrl_get_rb_stall_busy
(
nvswitch_device *device,
NVSWITCH_GET_RB_STALL_BUSY *p
)
{
return device->hal.nvswitch_ctrl_get_rb_stall_busy(device, p);
}
NvlStatus
nvswitch_ctrl_get_multicast_id_error_vector
(
nvswitch_device *device,
NVSWITCH_GET_MULTICAST_ID_ERROR_VECTOR *p
)
{
return device->hal.nvswitch_ctrl_get_multicast_id_error_vector(device, p);
}
NvlStatus
nvswitch_ctrl_clear_multicast_id_error_vector
(
nvswitch_device *device,
NVSWITCH_CLEAR_MULTICAST_ID_ERROR_VECTOR *p
)
{
return device->hal.nvswitch_ctrl_clear_multicast_id_error_vector(device, p);
}
static NvlStatus
_nvswitch_ctrl_inband_send_data
(
nvswitch_device *device,
NVSWITCH_INBAND_SEND_DATA_PARAMS *p
)
{
return device->hal.nvswitch_ctrl_inband_send_data(device, p);
}
static NvlStatus
_nvswitch_ctrl_inband_read_data
(
nvswitch_device *device,
NVSWITCH_INBAND_READ_DATA_PARAMS *p
)
{
return device->hal.nvswitch_ctrl_inband_read_data(device, p);
}
static NvlStatus
_nvswitch_ctrl_inband_flush_data
(
nvswitch_device *device,
NVSWITCH_INBAND_FLUSH_DATA_PARAMS *p
)
{
NvU32 i;
NvU64 enabledLinkMask;
if (p->linkMask == 0)
{
NVSWITCH_PRINT(device, ERROR, "Nothing to clear\n");
return NVL_SUCCESS;
}
enabledLinkMask = nvswitch_get_enabled_link_mask(device);
FOR_EACH_INDEX_IN_MASK(64, i, p->linkMask)
{
if (nvswitch_is_link_valid(device, i) &&
(enabledLinkMask & NVBIT64(i)))
{
//
// Flush is expected to clear both persistent and non-persistent
// list. FM does flush when it wants to drop (ignore) all pending
// messages w/o any NACKs.
//
_nvswitch_inband_clear_lists(device, i,
NV_FALSE /* Nack */,
NV_FALSE /* Non-persistent only */);
}
}
FOR_EACH_INDEX_IN_MASK_END;
return NVL_SUCCESS;
}
static NvlStatus
_nvswitch_ctrl_inband_pending_data_stats
(
nvswitch_device *device,
NVSWITCH_INBAND_PENDING_DATA_STATS_PARAMS *p
)
{
NvU32 link_num;
NvU64 enabledLinkMask, persistent_mask = 0, nonpersistent_mask = 0;
enabledLinkMask = nvswitch_get_enabled_link_mask(device);
for (link_num = 0; link_num < nvswitch_get_num_links(device); link_num++)
{
if (nvswitch_is_link_valid(device, link_num) &&
(enabledLinkMask & NVBIT64(link_num)))
{
if (!nvListIsEmpty(&device->link[link_num].inbandData.persistent_list))
{
persistent_mask |= NVBIT64(link_num);
}
if (!nvListIsEmpty(&device->link[link_num].inbandData.nonpersistent_list))
{
nonpersistent_mask |= NVBIT64(link_num);
}
}
}
if (persistent_mask > 0)
{
p->linkMask = persistent_mask;
}
else
{
p->linkMask = nonpersistent_mask;
}
return NVL_SUCCESS;
}
static NvlStatus
_nvswitch_ctrl_get_board_part_number
(
nvswitch_device *device,
NVSWITCH_GET_BOARD_PART_NUMBER_VECTOR *p
)
{
if (IS_RTLSIM(device) || IS_EMULATION(device) || IS_FMODEL(device))
{
NVSWITCH_PRINT(device, INFO,
"%s: Skipping retrieval of board part number on FSF\n",
__FUNCTION__);
nvswitch_os_memset(p, 0, sizeof(NVSWITCH_GET_BOARD_PART_NUMBER_VECTOR));
return NVL_SUCCESS;
}
else
{
if (!nvswitch_is_inforom_supported(device))
{
NVSWITCH_PRINT(device, ERROR, "InfoROM is not supported\n");
return -NVL_ERR_NOT_SUPPORTED;
}
return device->hal.nvswitch_ctrl_get_board_part_number(device, p);
}
}
static NvlStatus
_nvswitch_ctrl_i2c_smbus_command
(
nvswitch_device *device,
NVSWITCH_I2C_SMBUS_COMMAND_PARAMS *pParams
)
{
NvU32 port_info;
NvU32 port = pParams->port;
NvU8 msgLen;
NvU8 cmd;
NvU16 addr;
NvU8 cmdType;
NvU8 *pData;
NvBool is_i2c_access_allowed;
NvBool is_port_allowed;
port_info = nvswitch_i2c_get_port_info(device, port);
is_i2c_access_allowed = (device->regkeys.i2c_access_control ==
NV_SWITCH_REGKEY_I2C_ACCESS_CONTROL_ENABLE) ?
NV_TRUE : NV_FALSE;
is_port_allowed = is_i2c_access_allowed ? NV_TRUE :
FLD_TEST_DRF(_I2C, _PORTINFO, _ACCESS_ALLOWED, _TRUE,
port_info);
if (!is_port_allowed ||
!FLD_TEST_DRF(_I2C, _PORTINFO, _DEFINED, _PRESENT, port_info))
{
NVSWITCH_PRINT(device, ERROR, "Invalid port access %d.\n", port);
return NVL_BAD_ARGS;
}
addr = pParams->deviceAddr;
switch (pParams->cmdType)
{
case NVSWITCH_I2C_SMBUS_CMD_QUICK:
{
cmd = 0;
msgLen = 0;
cmdType = pParams->bRead ?
NVSWITCH_I2C_CMD_SMBUS_QUICK_READ :
NVSWITCH_I2C_CMD_SMBUS_QUICK_WRITE;
pData = NULL;
break;
}
case NVSWITCH_I2C_SMBUS_CMD_BYTE:
{
cmd = 0;
msgLen = 1;
cmdType = pParams->bRead ?
NVSWITCH_I2C_CMD_READ :
NVSWITCH_I2C_CMD_WRITE;
pData = (NvU8 *)&pParams->transactionData.smbusByte.message;
break;
}
case NVSWITCH_I2C_SMBUS_CMD_BYTE_DATA:
{
msgLen = 1;
cmd = pParams->transactionData.smbusByteData.cmd;
cmdType = pParams->bRead ?
NVSWITCH_I2C_CMD_SMBUS_READ :
NVSWITCH_I2C_CMD_SMBUS_WRITE;
pData = (NvU8 *)&pParams->transactionData.smbusByteData.message;
break;
}
case NVSWITCH_I2C_SMBUS_CMD_WORD_DATA:
{
msgLen = 2;
cmd = pParams->transactionData.smbusWordData.cmd;
cmdType = pParams->bRead ?
NVSWITCH_I2C_CMD_SMBUS_READ :
NVSWITCH_I2C_CMD_SMBUS_WRITE;
pData = (NvU8 *)&pParams->transactionData.smbusWordData.message;
break;
}
default:
{
NVSWITCH_PRINT(device, ERROR, "Invalid Smbus command: %d.\n", port);
return NVL_BAD_ARGS;
}
}
return _nvswitch_perform_i2c_transfer(device, NVSWITCH_I2C_ACQUIRER_IOCTL,
cmdType, addr, port, cmd, msgLen, pData);
}
NvBool
nvswitch_does_link_need_termination_enabled
(
nvswitch_device *device,
nvlink_link *link
)
{
return device->hal.nvswitch_does_link_need_termination_enabled(device, link);
}
NvlStatus
nvswitch_link_termination_setup
(
nvswitch_device *device,
nvlink_link* link
)
{
return device->hal.nvswitch_link_termination_setup(device, link);
}
static NvlStatus
_nvswitch_ctrl_cci_cmis_presence
(
nvswitch_device *device,
NVSWITCH_CCI_CMIS_PRESENCE_PARAMS *pParams
)
{
nvswitch_os_memset(pParams, 0, sizeof(NVSWITCH_CCI_CMIS_PRESENCE_PARAMS));
if (device->pCci != NULL)
{
(void)cciGetXcvrMask(device, &pParams->cagesMask, &pParams->modulesMask);
}
// IOCTL will always succeed
return NVL_SUCCESS;
}
static NvlStatus
_nvswitch_ctrl_cci_nvlink_mappings
(
nvswitch_device *device,
NVSWITCH_CCI_CMIS_NVLINK_MAPPING_PARAMS *pParams
)
{
if (device->pCci == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"%s: CCI not supported\n",
__FUNCTION__);
return -NVL_ERR_NOT_SUPPORTED;
}
return cciGetCageMapping(device, pParams->cageIndex, &pParams->linkMask, &pParams->encodedValue);
}
static NvlStatus
_nvswitch_ctrl_cci_memory_access_read
(
nvswitch_device *device,
NVSWITCH_CCI_CMIS_MEMORY_ACCESS_READ_PARAMS *pParams
)
{
NvlStatus retVal;
if (device->pCci == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"%s: CCI not supported\n",
__FUNCTION__);
return -NVL_ERR_NOT_SUPPORTED;
}
if (!cciCmisAccessTryLock(device, pParams->cageIndex))
{
return -NVL_ERR_STATE_IN_USE;
}
retVal = cciCmisRead(device, pParams->cageIndex, pParams->bank,
pParams->page, pParams->address, pParams->count,
pParams->data);
if (!pParams->bSequenceLock)
{
cciCmisAccessReleaseLock(device, pParams->cageIndex);
}
return retVal;
}
static NvlStatus
_nvswitch_ctrl_cci_memory_access_write
(
nvswitch_device *device,
NVSWITCH_CCI_CMIS_MEMORY_ACCESS_WRITE_PARAMS *pParams
)
{
NvlStatus retVal;
if (device->pCci == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"%s: CCI not supported\n",
__FUNCTION__);
return -NVL_ERR_NOT_SUPPORTED;
}
if (!cciCmisAccessTryLock(device, pParams->cageIndex))
{
return -NVL_ERR_STATE_IN_USE;
}
retVal = cciCmisWrite(device, pParams->cageIndex, pParams->bank,
pParams->page, pParams->address, pParams->count,
pParams->data);
if (!pParams->bSequenceLock)
{
cciCmisAccessReleaseLock(device, pParams->cageIndex);
}
return retVal;
}
static NvlStatus
_nvswitch_ctrl_cci_cage_bezel_marking
(
nvswitch_device *device,
NVSWITCH_CCI_CMIS_CAGE_BEZEL_MARKING_PARAMS *pParams
)
{
if (device->pCci == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"%s: CCI not supported\n",
__FUNCTION__);
return -NVL_ERR_NOT_SUPPORTED;
}
return cciCmisCageBezelMarking(device, pParams->cageIndex, pParams->bezelMarking);
}
static NvlStatus
_nvswitch_ctrl_get_soe_heartbeat
(
nvswitch_device *device,
NVSWITCH_GET_SOE_HEARTBEAT_PARAMS *pParams
)
{
return device->hal.nvswitch_ctrl_get_soe_heartbeat(device, pParams);
}
static NvlStatus
_nvswitch_ctrl_set_continuous_ali
(
nvswitch_device *device,
NVSWITCH_SET_CONTINUOUS_ALI_PARAMS *pParams
)
{
device->bModeContinuousALI = pParams->bEnable;
NVSWITCH_PRINT(device, INFO,
"%s: Continuous ALI 0x%x\n",
__FUNCTION__, device->bModeContinuousALI);
return NVL_SUCCESS;
}
static NvlStatus
_nvswitch_ctrl_request_ali
(
nvswitch_device *device,
NVSWITCH_REQUEST_ALI_PARAMS *pParams
)
{
nvlink_link *link;
NvU64 linkStateTl;
NvU64 enabledLinkMask;
NvU8 linkId;
if (device->bModeContinuousALI)
{
return -NVL_ERR_INVALID_STATE;
}
// Only process enabled links
enabledLinkMask = nvswitch_get_enabled_link_mask(device);
pParams->linkMaskTrain &= enabledLinkMask;
NVSWITCH_PRINT(device, INFO,
"%s: ALI requested for links 0x%llx\n",
__FUNCTION__, pParams->linkMaskTrain);
// Handle access links
FOR_EACH_INDEX_IN_MASK(64, linkId, pParams->linkMaskTrain)
{
// Only directly launch ALI on non-CCI managed links
if (cciIsLinkManaged(device, linkId))
{
continue;
}
link = nvswitch_get_link(device, linkId);
if ((link == NULL) ||
!NVSWITCH_IS_LINK_ENG_VALID(device, linkId, NVLIPT_LNK) ||
(linkId >= NVSWITCH_NVLINK_MAX_LINKS) ||
(device->hal.nvswitch_corelib_get_tl_link_mode(link, &linkStateTl) != NVL_SUCCESS))
{
continue;
}
if (linkStateTl == NVLINK_LINKSTATE_ACTIVE_PENDING)
{
continue;
}
// Forcibly reset and re-train access links
device->hal.nvswitch_reset_and_drain_links(device,
NVBIT64(linkId), NV_TRUE);
}
FOR_EACH_INDEX_IN_MASK_END;
// Ask CCI to handle trunk links
nvswitch_ctrl_cci_request_ali(device, pParams);
return NVL_SUCCESS;
}
static NvlStatus
_nvswitch_ctrl_get_inforom_nvlink_max_correctable_error_rate
(
nvswitch_device *device,
NVSWITCH_GET_NVLINK_MAX_CORRECTABLE_ERROR_RATES_PARAMS *params
)
{
return nvswitch_inforom_nvlink_get_max_correctable_error_rate(device, params);
}
static NvlStatus
_nvswitch_ctrl_get_inforom_nvlink_errors
(
nvswitch_device *device,
NVSWITCH_GET_NVLINK_ERROR_COUNTS_PARAMS *params
)
{
return nvswitch_inforom_nvlink_get_errors(device, params);
}
static NvlStatus
_nvswitch_ctrl_get_inforom_ecc_errors
(
nvswitch_device *device,
NVSWITCH_GET_ECC_ERROR_COUNTS_PARAMS *params
)
{
return nvswitch_inforom_ecc_get_errors(device, params);
}
static NvlStatus
_nvswitch_ctrl_get_inforom_bbx_sxid
(
nvswitch_device *device,
NVSWITCH_GET_SXIDS_PARAMS *params
)
{
return nvswitch_inforom_bbx_get_sxid(device, params);
}
static NvlStatus
_nvswitch_ctrl_get_inforom_bbx_sys_info
(
nvswitch_device *device,
NVSWITCH_GET_SYS_INFO_PARAMS *params
)
{
return nvswitch_inforom_bbx_get_data(device, RM_SOE_IFR_BBX_GET_SYS_INFO, (void *)params);
}
static NvlStatus
_nvswitch_ctrl_get_inforom_bbx_time_info
(
nvswitch_device *device,
NVSWITCH_GET_TIME_INFO_PARAMS *params
)
{
return nvswitch_inforom_bbx_get_data(device, RM_SOE_IFR_BBX_GET_TIME_INFO, (void *)params);
}
static NvlStatus
_nvswitch_ctrl_get_inforom_bbx_temp_data
(
nvswitch_device *device,
NVSWITCH_GET_TEMP_DATA_PARAMS *params
)
{
return nvswitch_inforom_bbx_get_data(device, RM_SOE_IFR_BBX_GET_TEMP_DATA, (void *)params);
}
static NvlStatus
_nvswitch_ctrl_get_inforom_bbx_temp_samples
(
nvswitch_device *device,
NVSWITCH_GET_TEMP_SAMPLES_PARAMS *params
)
{
return nvswitch_inforom_bbx_get_data(device, RM_SOE_IFR_BBX_GET_TEMP_SAMPLES, (void *)params);
}
static NvlStatus
_nvswitch_ctrl_get_nvlink_lp_counters
(
nvswitch_device *device,
NVSWITCH_GET_NVLINK_LP_COUNTERS_PARAMS *params
)
{
return device->hal.nvswitch_ctrl_get_nvlink_lp_counters(device, params);
}
static NvlStatus
_nvswitch_ctrl_get_sw_info
(
nvswitch_device *device,
NVSWITCH_GET_SW_INFO_PARAMS *params
)
{
return device->hal.nvswitch_ctrl_get_sw_info(device, params);
}
static NvlStatus
_nvswitch_lib_validate_privileged_ctrl
(
void *osPrivate,
NvU64 flags
)
{
if (flags & NVSWITCH_DEV_CMD_CHECK_ADMIN)
{
if (nvswitch_os_is_admin())
{
return NVL_SUCCESS;
}
}
if (flags & NVSWITCH_DEV_CMD_CHECK_FM)
{
if (nvswitch_os_is_fabric_manager(osPrivate))
{
return NVL_SUCCESS;
}
}
return -NVL_ERR_INSUFFICIENT_PERMISSIONS;
}
/*
* @Brief : Copy the data from the persistant or nonpersistant list
*
* @Description :
*
* @param[in] device NvSwitch device to contain this link
* @param[out] data Destination Data
* @param[in] linkId link number of the link
* @param[out] dataSize Size of data copied
*
* @returns NVL_SUCCESS if action succeeded,
* -NVL_NOT_FOUND if link doesnt have data
*/
NvlStatus
nvswitch_inband_read_data
(
nvswitch_device *device,
NvU8 *dest,
NvU32 linkId,
NvU32 *dataSize
)
{
nvswitch_inband_data_list *curr = NULL;
NVListRec *list;
if (nvListIsEmpty(&device->link[linkId].inbandData.persistent_list) &&
nvListIsEmpty(&device->link[linkId].inbandData.nonpersistent_list))
{
NVSWITCH_PRINT(device, ERROR, "%s: LinkId %d doesnt have any data to send\n",
__FUNCTION__, linkId);
*dataSize = 0;
return -NVL_NOT_FOUND;
}
list = nvListIsEmpty(&device->link[linkId].inbandData.persistent_list) ?
&device->link[linkId].inbandData.nonpersistent_list :
&device->link[linkId].inbandData.persistent_list;
nvListForEachEntry(curr, list, entry)
{
*dataSize = curr->dataSize;
nvswitch_os_memcpy(dest, curr->data, curr->dataSize);
nvListDel(&curr->entry);
nvswitch_os_free(curr);
break;
}
return NVL_SUCCESS;
}
/*
* @Brief : Returns NV_TRUE if the given inband msg
* needs to go to persistant list
*
* @Description :
*
* @param[in] device NvSwitch device to contain this link
* @param[in] msghdr Header to the message
*
*/
static NvBool
nvswitch_is_message_persistent
(
nvswitch_device *device,
nvlink_inband_msg_header_t *msghdr
)
{
// We expect only one message per received data
switch(msghdr->type)
{
case NVLINK_INBAND_MSG_TYPE_MC_TEAM_RELEASE_REQ:
return NV_TRUE;
default:
return NV_FALSE;
}
}
/*
* @Brief : Moves the data into persistant or nonpersistant list
*
* @Description :
*
* @param[in] device NvSwitch device to contain this link
* @param[in] linkId link number of the link
*
*/
void
nvswitch_filter_messages
(
nvswitch_device *device,
NvU32 linkId
)
{
NvlStatus status;
nvlink_inband_msg_header_t *msghdr = NULL;
nvswitch_inband_data_list *msg = device->link[linkId].inbandData.message;
NvU8 *buffer = device->link[linkId].inbandData.message->data;
NVSWITCH_DRIVER_FABRIC_STATE driver_fabric_state = 0;
NvBool bSendNackOrDrop = NV_FALSE;
NVSWITCH_ASSERT(nvswitch_lib_read_fabric_state(device, NULL, NULL,
&driver_fabric_state) == NVL_SUCCESS);
msghdr = (nvlink_inband_msg_header_t*)buffer;
if (nvswitch_is_message_persistent(device, msghdr))
{
if (nvListCount(&device->link[linkId].inbandData.persistent_list) <
device->hal.nvswitch_get_max_persistent_message_count(device))
{
nvListAdd(&msg->entry, &device->link[linkId].inbandData.persistent_list);
}
else
{
bSendNackOrDrop = NV_TRUE;
}
}
else
{
if (driver_fabric_state == NVSWITCH_DRIVER_FABRIC_STATE_CONFIGURED)
{
nvListAdd(&msg->entry,
&device->link[linkId].inbandData.nonpersistent_list);
}
else
{
bSendNackOrDrop = NV_TRUE;
}
}
if (bSendNackOrDrop)
{
nvswitch_send_nack_or_drop(device, linkId, msghdr);
nvswitch_os_free(msg);
}
else
{
status = nvswitch_lib_notify_client_events(device,
NVSWITCH_DEVICE_EVENT_INBAND_DATA);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify INBAND_DATA event\n",
__FUNCTION__);
}
}
device->link[linkId].inbandData.message = NULL;
}
/*
* @Brief : Constructs an NVS link struct with the given data
*
* @Description :
*
* @param[in] device NvSwitch device to contain this link
* @param[in] link_num link number of the link
* @param[out] link reference to store the created link into
*
* @returns NVL_SUCCESS if action succeeded,
* -NVL_NO_MEM if memory allocation failed
*/
NvlStatus
nvswitch_create_link
(
nvswitch_device *device,
NvU32 link_number,
nvlink_link **link
)
{
NvlStatus retval = NVL_SUCCESS;
nvlink_link *ret = NULL;
LINK_INFO *link_info = NULL;
NvU64 ac_coupled_mask;
NVSWITCH_ASSERT(nvswitch_get_num_links(device) <= NVSWITCH_MAX_NUM_LINKS);
ret = nvswitch_os_malloc(sizeof(*ret));
if (NULL == ret)
{
NVSWITCH_PRINT(device, ERROR,
"nvswitch_os_malloc during link creation failed!\n");
retval = -NVL_NO_MEM;
goto nvswitch_create_link_cleanup;
}
nvswitch_os_memset(ret, 0, sizeof(*ret));
link_info = nvswitch_os_malloc(sizeof(*link_info));
if (NULL == link_info)
{
NVSWITCH_PRINT(device, ERROR,
"nvswitch_os_malloc during link creation failed!\n");
retval = -NVL_NO_MEM;
goto nvswitch_create_link_cleanup;
}
nvswitch_os_memset(link_info, 0, sizeof(*link_info));
nvswitch_os_snprintf(link_info->name, sizeof(link_info->name), NVSWITCH_LINK_NAME "%d", link_number);
ret->dev = device->nvlink_device;
ret->linkName = link_info->name;
ret->linkNumber = link_number;
ret->state = NVLINK_LINKSTATE_OFF;
ret->ac_coupled = NV_FALSE;
ret->version = nvswitch_get_link_ip_version(device, link_number);
ac_coupled_mask = ((NvU64)device->regkeys.ac_coupled_mask2 << 32 |
(NvU64)device->regkeys.ac_coupled_mask);
if (ac_coupled_mask)
{
if (ac_coupled_mask & NVBIT64(link_number))
{
ret->ac_coupled = NV_TRUE;
}
}
else if (device->firmware.nvlink.link_config_found)
{
if (device->firmware.nvlink.link_ac_coupled_mask & NVBIT64(link_number))
{
ret->ac_coupled = NV_TRUE;
}
}
// Initialize NVLink corelib callbacks for switch
nvswitch_get_link_handlers(&link_handlers);
ret->link_handlers = &link_handlers;
//
// link_info is used to store private link information
//
ret->link_info = link_info;
*link = ret;
return retval;
nvswitch_create_link_cleanup:
if (NULL != ret)
{
nvswitch_os_free(ret);
}
if (NULL != link_info)
{
nvswitch_os_free(link_info);
}
return retval;
}
void
nvswitch_destroy_link
(
nvlink_link *link
)
{
if (NULL != link->link_info)
{
nvswitch_os_free(link->link_info);
}
nvswitch_os_free(link);
}
NvU32
nvswitch_get_num_links
(
nvswitch_device *device
)
{
return device->hal.nvswitch_get_num_links(device);
}
NvBool
nvswitch_is_link_valid
(
nvswitch_device *device,
NvU32 link_id
)
{
return device->hal.nvswitch_is_link_valid(device, link_id);
}
nvlink_link*
nvswitch_get_link(nvswitch_device *device, NvU8 link_id)
{
nvlink_link *link = NULL;
nvlink_lib_get_link(device->nvlink_device, link_id, &link);
return link;
}
NvU64
nvswitch_get_enabled_link_mask
(
nvswitch_device *device
)
{
NvU64 ret;
nvlink_link *link;
NvU32 link_num;
ret = 0x0;
for (link_num = 0; link_num < nvswitch_get_num_links(device); link_num++)
{
if (nvlink_lib_get_link(device->nvlink_device, link_num, &link) == NVL_SUCCESS)
{
ret |= NVBIT64(link_num);
}
}
return ret;
}
void
nvswitch_set_fatal_error
(
nvswitch_device *device,
NvBool device_fatal,
NvU32 link_id
)
{
device->hal.nvswitch_set_fatal_error(device, device_fatal, link_id);
}
NvU32
nvswitch_get_swap_clk_default
(
nvswitch_device *device
)
{
return device->hal.nvswitch_get_swap_clk_default(device);
}
NvU32
nvswitch_get_latency_sample_interval_msec
(
nvswitch_device *device
)
{
return device->hal.nvswitch_get_latency_sample_interval_msec(device);
}
void
nvswitch_internal_latency_bin_log
(
nvswitch_device *device
)
{
device->hal.nvswitch_internal_latency_bin_log(device);
}
void
nvswitch_ecc_writeback_task
(
nvswitch_device *device
)
{
device->hal.nvswitch_ecc_writeback_task(device);
}
void
nvswitch_monitor_thermal_alert
(
nvswitch_device *device
)
{
device->hal.nvswitch_monitor_thermal_alert(device);
}
void
nvswitch_hw_counter_shutdown
(
nvswitch_device *device
)
{
device->hal.nvswitch_hw_counter_shutdown(device);
}
NvlStatus
nvswitch_get_rom_info
(
nvswitch_device *device,
NVSWITCH_EEPROM_TYPE *eeprom
)
{
return device->hal.nvswitch_get_rom_info(device, eeprom);
}
void
nvswitch_lib_enable_interrupts
(
nvswitch_device *device
)
{
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
NVSWITCH_ASSERT(0);
return;
}
device->hal.nvswitch_lib_enable_interrupts(device);
}
void
nvswitch_lib_disable_interrupts
(
nvswitch_device *device
)
{
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
NVSWITCH_ASSERT(0);
return;
}
device->hal.nvswitch_lib_disable_interrupts(device);
}
NvlStatus
nvswitch_lib_check_interrupts
(
nvswitch_device *device
)
{
if (!NVSWITCH_IS_DEVICE_INITIALIZED(device))
{
return -NVL_BAD_ARGS;
}
return device->hal.nvswitch_lib_check_interrupts(device);
}
NvlStatus
nvswitch_lib_service_interrupts
(
nvswitch_device *device
)
{
if (!NVSWITCH_IS_DEVICE_INITIALIZED(device))
{
return -NVL_BAD_ARGS;
}
return device->hal.nvswitch_lib_service_interrupts(device);
}
NvU64
nvswitch_hw_counter_read_counter
(
nvswitch_device *device
)
{
return device->hal.nvswitch_hw_counter_read_counter(device);
}
NvU32
nvswitch_get_link_ip_version
(
nvswitch_device *device,
NvU32 link_id
)
{
return device->hal.nvswitch_get_link_ip_version(device, link_id);
}
NvU32
nvswitch_reg_read_32
(
nvswitch_device *device,
NvU32 offset
)
{
NvU32 val;
if (device->nvlink_device->pciInfo.bars[0].pBar == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"register read failed at offset 0x%x\n", offset);
return 0xFFFFFFFF;
}
val = nvswitch_os_mem_read32((NvU8 *)device->nvlink_device->pciInfo.bars[0].pBar + offset);
if ((val & 0xFFFF0000) == 0xBADF0000)
{
NvU32 boot_0;
NVSWITCH_PRINT(device, WARN,
"Potential IO failure reading 0x%x (0x%x)\n", offset, val);
boot_0 = nvswitch_os_mem_read32((NvU8 *)device->nvlink_device->pciInfo.bars[0].pBar + 0x0);
if ((boot_0 & 0xFFFF0000) == 0xBADF0000)
{
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_IO_FAILURE,
"IO failure\n");
NVSWITCH_PRINT(device, ERROR,
"IO failure reading 0x%x (0x%x)\n", offset, val);
}
}
#ifdef _VERBOSE_REG_ACCESS
NVSWITCH_PRINT(device, SETUP,
"NVSWITCH read 0x%6x+%6x = 0x%08x\n",
device->nvlink_device->pciInfo.bars[0].baseAddr, offset, val);
#endif
return val;
}
void
nvswitch_reg_write_32
(
nvswitch_device *device,
NvU32 offset,
NvU32 data
)
{
if (device->nvlink_device->pciInfo.bars[0].pBar == NULL)
{
NVSWITCH_PRINT(device, ERROR,
"register write failed at offset 0x%x\n", offset);
return;
}
#ifdef _VERBOSE_REG_ACCESS
NVSWITCH_PRINT(device, SETUP,
"NVSWITCH write 0x%6x+%6x = 0x%08x\n",
device->nvlink_device->pciInfo.bars[0].baseAddr, offset, data);
#endif
// Write the register
nvswitch_os_mem_write32((NvU8 *)device->nvlink_device->pciInfo.bars[0].pBar + offset, data);
return;
}
NvU64
nvswitch_read_64bit_counter
(
nvswitch_device *device,
NvU32 lo_offset,
NvU32 hi_offset
)
{
NvU32 hi0;
NvU32 hi1;
NvU32 lo;
hi0 = nvswitch_reg_read_32(device, hi_offset);
do
{
hi1 = hi0;
lo = nvswitch_reg_read_32(device, lo_offset);
hi0 = nvswitch_reg_read_32(device, hi_offset);
} while (hi0 != hi1);
return (lo | ((NvU64)hi0 << 32));
}
NvlStatus
nvswitch_validate_pll_config
(
nvswitch_device *device,
NVSWITCH_PLL_INFO *switch_pll,
NVSWITCH_PLL_LIMITS default_pll_limits
)
{
NvU32 update_rate_khz;
NvU32 vco_freq_khz;
NVSWITCH_PLL_LIMITS pll_limits;
NVSWITCH_PRINT(device, SETUP,
"%s: Validating PLL: %dkHz * %d / (%d * %d * (1 << %d))\n",
__FUNCTION__,
switch_pll->src_freq_khz,
switch_pll->N,
switch_pll->M,
switch_pll->PL,
switch_pll->dist_mode);
//
// These parameters could come from schmoo'ing API, settings file or a ROM.
// For now, hard code with POR.
//
if (device->firmware.firmware_size > 0 &&
device->firmware.clocks.clocks_found &&
device->firmware.clocks.sys_pll.valid)
{
pll_limits = device->firmware.clocks.sys_pll;
}
else
{
pll_limits = default_pll_limits;
}
NVSWITCH_ASSERT(switch_pll->M != 0);
NVSWITCH_ASSERT(switch_pll->PL != 0);
if ((switch_pll->src_freq_khz < pll_limits.ref_min_mhz * 1000) ||
(switch_pll->src_freq_khz > pll_limits.ref_max_mhz * 1000))
{
NVSWITCH_PRINT(device, ERROR,
"%s: ERROR: Ref(%d) out-of-range\n",
__FUNCTION__,
switch_pll->src_freq_khz);
return -NVL_ERR_INVALID_STATE;
}
if ((switch_pll->M < pll_limits.m_min) ||
(switch_pll->M > pll_limits.m_max))
{
NVSWITCH_PRINT(device, ERROR,
"%s: ERROR: M(%d) out-of-range\n",
__FUNCTION__,
switch_pll->M);
return -NVL_ERR_INVALID_STATE;
}
if ((switch_pll->N < pll_limits.n_min) ||
(switch_pll->N > pll_limits.n_max))
{
NVSWITCH_PRINT(device, ERROR,
"%s: ERROR: N(%d) out-of-range\n",
__FUNCTION__,
switch_pll->N);
return -NVL_ERR_INVALID_STATE;
}
if ((switch_pll->PL < pll_limits.pl_min) ||
(switch_pll->PL > pll_limits.pl_max))
{
NVSWITCH_PRINT(device, ERROR,
"%s: ERROR: PL(%d) out-of-range\n",
__FUNCTION__,
switch_pll->PL);
return -NVL_ERR_INVALID_STATE;
}
vco_freq_khz = switch_pll->src_freq_khz * switch_pll->N
/ switch_pll->M;
if ((vco_freq_khz < pll_limits.vco_min_mhz * 1000) ||
(vco_freq_khz > pll_limits.vco_max_mhz * 1000))
{
NVSWITCH_PRINT(device, ERROR,
"%s: ERROR: VCO(%d) freq out-of-range\n",
__FUNCTION__,
vco_freq_khz);
return -NVL_ERR_INVALID_STATE;
}
update_rate_khz = switch_pll->src_freq_khz / switch_pll->M;
if ((update_rate_khz < pll_limits.update_min_mhz * 1000) ||
(update_rate_khz > pll_limits.update_max_mhz * 1000))
{
NVSWITCH_PRINT(device, ERROR,
"%s: ERROR: update rate(%d) out-of-range\n",
__FUNCTION__,
update_rate_khz);
return -NVL_ERR_INVALID_STATE;
}
switch_pll->vco_freq_khz = vco_freq_khz;
switch_pll->freq_khz =
switch_pll->src_freq_khz * switch_pll->N /
(switch_pll->M * switch_pll->PL * (1 << switch_pll->dist_mode));
NVSWITCH_PRINT(device, SETUP,
"%s: Validated PLL: %dkHz * %d / (%d * %d * (1 << %d)) = %dkHz\n",
__FUNCTION__,
switch_pll->src_freq_khz,
switch_pll->N,
switch_pll->M,
switch_pll->PL,
switch_pll->dist_mode,
switch_pll->freq_khz);
return NVL_SUCCESS;
}
NvlStatus
nvswitch_init_pll_config
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_pll_config(device);
}
NvlStatus
nvswitch_init_pll
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_pll(device);
}
void
nvswitch_init_clock_gating
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_clock_gating(device);
}
void
nvswitch_lib_get_uuid
(
nvswitch_device *device,
NvUuid *uuid
)
{
if (!NVSWITCH_IS_DEVICE_INITIALIZED(device) || (uuid == NULL))
{
return;
}
nvswitch_os_memcpy(uuid, &device->uuid, sizeof(device->uuid));
}
NvlStatus
nvswitch_lib_get_physid
(
nvswitch_device *device,
NvU32 *phys_id
)
{
NVSWITCH_GET_INFO get_info;
NvlStatus ret;
if (phys_id == NULL || !NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
get_info.count=1;
get_info.index[0] = NVSWITCH_GET_INFO_INDEX_PHYSICAL_ID;
ret = _nvswitch_ctrl_get_info(device, &get_info);
if (ret != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR,
"Failed to get physical ID\n");
return ret;
}
*phys_id = get_info.info[0];
return NVL_SUCCESS;
}
void
nvswitch_i2c_set_hw_speed_mode
(
nvswitch_device *device,
NvU32 port,
NvU32 speedMode
)
{
device->hal.nvswitch_i2c_set_hw_speed_mode(device, port, speedMode);
return;
}
void
nvswitch_lib_smbpbi_log_sxid
(
nvswitch_device *device,
NvU32 sxid,
const char *pFormat,
...
)
{
va_list arglist;
int msglen;
char string[RM_SOE_SMBPBI_CMD_LOG_MESSAGE_MAX_STRING + 1];
nvswitch_os_memset(string, 0, (NvLength)sizeof(string));
va_start(arglist, pFormat);
msglen = nvswitch_os_vsnprintf(string, sizeof(string), pFormat, arglist);
va_end(arglist);
if (!(msglen < 0))
{
//
// HALs will know that the string is being truncated by seeing that the
// last byte in the buffer is not nul.
//
msglen = NV_MIN(msglen + 1, (int)RM_SOE_SMBPBI_CMD_LOG_MESSAGE_MAX_STRING);
device->hal.nvswitch_smbpbi_log_message(device, sxid, msglen, (NvU8 *) string);
}
}
NvlStatus
nvswitch_set_minion_initialized
(
nvswitch_device *device,
NvU32 idx_minion,
NvBool initialized
)
{
return device->hal.nvswitch_set_minion_initialized(device, idx_minion, initialized);
}
NvBool
nvswitch_is_minion_initialized
(
nvswitch_device *device,
NvU32 idx_minion
)
{
return device->hal.nvswitch_is_minion_initialized(device, idx_minion);
}
NvlStatus
nvswitch_device_discovery
(
nvswitch_device *device,
NvU32 discovery_offset
)
{
return device->hal.nvswitch_device_discovery(device, discovery_offset);
}
void
nvswitch_filter_discovery
(
nvswitch_device *device
)
{
device->hal.nvswitch_filter_discovery(device);
}
NvlStatus
nvswitch_process_discovery
(
nvswitch_device *device
)
{
return device->hal.nvswitch_process_discovery(device);
}
NvlStatus
nvswitch_init_minion
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_minion(device);
}
NvU32
nvswitch_get_link_eng_inst
(
nvswitch_device *device,
NvU32 link_id,
NVSWITCH_ENGINE_ID eng_id
)
{
return device->hal.nvswitch_get_link_eng_inst(device, link_id, eng_id);
}
void *
nvswitch_alloc_chipdevice
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_alloc_chipdevice(device));
}
void
nvswitch_free_chipdevice
(
nvswitch_device *device
)
{
if (device->chip_device)
{
nvswitch_os_free(device->chip_device);
device->chip_device = NULL;
}
}
NvlStatus
nvswitch_init_thermal
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_init_thermal(device));
}
NvU32
nvswitch_read_physical_id
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_read_physical_id(device));
}
NvU32
nvswitch_get_caps_nvlink_version
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_get_caps_nvlink_version(device));
}
void
nvswitch_initialize_interrupt_tree
(
nvswitch_device *device
)
{
device->hal.nvswitch_initialize_interrupt_tree(device);
}
void
nvswitch_init_dlpl_interrupts
(
nvlink_link *link
)
{
nvswitch_device *device = link->dev->pDevInfo;
device->hal.nvswitch_init_dlpl_interrupts(link);
}
NvlStatus
nvswitch_initialize_pmgr
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_initialize_pmgr(device));
}
NvlStatus
nvswitch_initialize_ip_wrappers
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_initialize_ip_wrappers(device));
}
NvlStatus
nvswitch_initialize_route
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_initialize_route(device));
}
void
nvswitch_soe_unregister_events
(
nvswitch_device *device
)
{
device->hal.nvswitch_soe_unregister_events(device);
}
NvlStatus
nvswitch_soe_register_event_callbacks
(
nvswitch_device *device
)
{
return device->hal.nvswitch_soe_register_event_callbacks(device);
}
NVSWITCH_BIOS_NVLINK_CONFIG *
nvswitch_get_bios_nvlink_config
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_get_bios_nvlink_config(device));
}
NvlStatus
nvswitch_minion_send_command
(
nvswitch_device *device,
NvU32 linkNumber,
NvU32 command,
NvU32 scratch0
)
{
return(device->hal.nvswitch_minion_send_command(device, linkNumber,
command, scratch0));
}
NvlStatus
nvswitch_init_nport
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_nport(device);
}
NvlStatus
nvswitch_init_nxbar
(
nvswitch_device *device
)
{
return device->hal.nvswitch_init_nxbar(device);
}
NvlStatus
nvswitch_clear_nport_rams
(
nvswitch_device *device
)
{
return device->hal.nvswitch_clear_nport_rams(device);
}
NvlStatus
nvswitch_pri_ring_init
(
nvswitch_device *device
)
{
return(device->hal.nvswitch_pri_ring_init(device));
}
NvlStatus
nvswitch_get_remap_table_selector
(
nvswitch_device *device,
NVSWITCH_TABLE_SELECT_REMAP table_selector,
NvU32 *remap_ram_sel
)
{
return device->hal.nvswitch_get_remap_table_selector(device, table_selector, remap_ram_sel);
}
NvU32
nvswitch_get_ingress_ram_size
(
nvswitch_device *device,
NvU32 ingress_ram_selector // NV_INGRESS_REQRSPMAPADDR_RAM_ADDRESS_*
)
{
return device->hal.nvswitch_get_ingress_ram_size(device, ingress_ram_selector);
}
NvlStatus
nvswitch_minion_get_dl_status
(
nvswitch_device *device,
NvU32 linkId,
NvU32 statusIdx,
NvU32 statusArgs,
NvU32 *statusData
)
{
return device->hal.nvswitch_minion_get_dl_status(device, linkId, statusIdx, statusArgs, statusData);
}
NvBool
nvswitch_is_i2c_supported
(
nvswitch_device *device
)
{
return device->hal.nvswitch_is_i2c_supported(device);
}
NvlStatus
nvswitch_poll_sublink_state
(
nvswitch_device *device,
nvlink_link *link
)
{
return device->hal.nvswitch_poll_sublink_state(device, link);
}
void
nvswitch_setup_link_loopback_mode
(
nvswitch_device *device,
NvU32 linkNumber
)
{
return device->hal.nvswitch_setup_link_loopback_mode(device, linkNumber);
}
void
nvswitch_reset_persistent_link_hw_state
(
nvswitch_device *device,
NvU32 linkNumber
)
{
return device->hal.nvswitch_reset_persistent_link_hw_state(device, linkNumber);
}
void
nvswitch_store_topology_information
(
nvswitch_device *device,
nvlink_link *link
)
{
return device->hal.nvswitch_store_topology_information(device, link);
}
void
nvswitch_init_lpwr_regs
(
nvlink_link *link
)
{
nvswitch_device *device = link->dev->pDevInfo;
device->hal.nvswitch_init_lpwr_regs(link);
}
void
nvswitch_program_l1_scratch_reg
(
nvswitch_device *device,
NvU32 linkNumber
)
{
device->hal.nvswitch_program_l1_scratch_reg(device, linkNumber);
}
NvlStatus
nvswitch_check_io_sanity
(
nvswitch_device *device
)
{
return device->hal.nvswitch_check_io_sanity(device);
}
NvlStatus
nvswitch_launch_ALI
(
nvswitch_device *device
)
{
return device->hal.nvswitch_launch_ALI(device);
}
NvlStatus
nvswitch_set_training_mode
(
nvswitch_device *device
)
{
return device->hal.nvswitch_set_training_mode(device);
}
NvBool
nvswitch_is_link_in_reset
(
nvswitch_device *device,
nvlink_link *link
)
{
return device->hal.nvswitch_is_link_in_reset(device, link);
}
NvBool
nvswitch_i2c_is_device_access_allowed
(
nvswitch_device *device,
NvU32 port,
NvU8 addr,
NvBool bIsRead
)
{
return device->hal.nvswitch_i2c_is_device_access_allowed(device, port, addr, bIsRead);
}
NvlStatus
nvswitch_parse_bios_image
(
nvswitch_device *device
)
{
return device->hal.nvswitch_parse_bios_image(device);
}
void
nvswitch_init_buffer_ready
(
nvswitch_device *device,
nvlink_link *link,
NvBool bNportBufferReady
)
{
return device->hal.nvswitch_init_buffer_ready(device, link, bNportBufferReady);
}
void
nvswitch_apply_recal_settings
(
nvswitch_device *device,
nvlink_link *link
)
{
return device->hal.nvswitch_apply_recal_settings(device, link);
}
NvlStatus
nvswitch_launch_ALI_link_training
(
nvswitch_device *device,
nvlink_link *link,
NvBool bSync
)
{
return device->hal.nvswitch_launch_ALI_link_training(device, link, bSync);
}
NvlStatus
nvswitch_reset_and_train_link
(
nvswitch_device *device,
nvlink_link *link
)
{
return device->hal.nvswitch_reset_and_train_link(device, link);
}
static NvlStatus
_nvswitch_ctrl_get_err_info
(
nvswitch_device *device,
NVSWITCH_NVLINK_GET_ERR_INFO_PARAMS *ret
)
{
return device->hal.nvswitch_ctrl_get_err_info(device, ret);
}
static NvlStatus
_nvswitch_ctrl_clear_counters
(
nvswitch_device *device,
NVSWITCH_NVLINK_CLEAR_COUNTERS_PARAMS *ret
)
{
return device->hal.nvswitch_ctrl_clear_counters(device, ret);
}
void
nvswitch_setup_link_system_registers
(
nvswitch_device *device,
nvlink_link *link
)
{
device->hal.nvswitch_setup_link_system_registers(device, link);
}
void
nvswitch_load_link_disable_settings
(
nvswitch_device *device,
nvlink_link *link
)
{
device->hal.nvswitch_load_link_disable_settings(device, link);
}
static NvlStatus
_nvswitch_ctrl_set_nvlink_error_threshold
(
nvswitch_device *device,
NVSWITCH_SET_NVLINK_ERROR_THRESHOLD_PARAMS *pParams
)
{
return device->hal.nvswitch_ctrl_set_nvlink_error_threshold(device, pParams);
}
static NvlStatus
_nvswitch_ctrl_get_nvlink_error_threshold
(
nvswitch_device *device,
NVSWITCH_GET_NVLINK_ERROR_THRESHOLD_PARAMS *pParams
)
{
return device->hal.nvswitch_ctrl_get_nvlink_error_threshold(device, pParams);
}
static NvlStatus
_nvswitch_ctrl_therm_read_voltage
(
nvswitch_device *device,
NVSWITCH_CTRL_GET_VOLTAGE_PARAMS *info
)
{
return device->hal.nvswitch_ctrl_therm_read_voltage(device, info);
}
static NvlStatus
_nvswitch_ctrl_therm_read_power
(
nvswitch_device *device,
NVSWITCH_GET_POWER_PARAMS *info
)
{
return device->hal.nvswitch_ctrl_therm_read_power(device, info);
}
NvlStatus
nvswitch_get_board_id
(
nvswitch_device *device,
NvU16 *boardId
)
{
return device->hal.nvswitch_get_board_id(device, boardId);
}
NvlStatus
_nvswitch_ctrl_get_link_l1_capability
(
nvswitch_device *device,
NVSWITCH_GET_NVLINK_L1_CAPABILITY_PARAMS *p
)
{
NvlStatus status;
nvlink_link *link;
NvU8 i;
if (p->linkMask == 0)
{
NVSWITCH_PRINT(device, ERROR, "%s: No links in linkMask\n", __FUNCTION__);
return -NVL_BAD_ARGS;
}
FOR_EACH_INDEX_IN_MASK(64, i, p->linkMask)
{
NvU32 linkNum;
NVSWITCH_ASSERT(i < NVSWITCH_LINK_COUNT(device));
link = nvswitch_get_link(device, i);
if ((link == NULL) ||
(i >= NVSWITCH_NVLINK_MAX_LINKS))
{
NVSWITCH_PRINT(device, ERROR, "%s: Invalid input link %d set in linkMask\n",
__FUNCTION__, i);
return -NVL_BAD_ARGS;
}
linkNum = link->linkNumber;
status = device->hal.nvswitch_ctrl_get_link_l1_capability(device, linkNum, &(p->l1Capable[linkNum]));
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to get l1 capability for link %d\n",
__FUNCTION__, linkNum);
return status;
}
}
FOR_EACH_INDEX_IN_MASK_END;
return NVL_SUCCESS;
}
NvlStatus
_nvswitch_ctrl_get_link_l1_threshold
(
nvswitch_device *device,
NVSWITCH_GET_NVLINK_L1_THRESHOLD_PARAMS *p
)
{
NvlStatus status;
nvlink_link *link;
NvBool isL1Capable;
NvU8 i;
if (device->regkeys.enable_pm == NV_SWITCH_REGKEY_ENABLE_PM_NO)
{
NVSWITCH_PRINT(device, INFO, "%s: L1 Threshold is disabled\n", __FUNCTION__);
return -NVL_ERR_NOT_SUPPORTED;
}
if (p->linkMask == 0)
{
NVSWITCH_PRINT(device, ERROR, "%s: No links in linkMask\n", __FUNCTION__);
return -NVL_BAD_ARGS;
}
FOR_EACH_INDEX_IN_MASK(64, i, p->linkMask)
{
NvU32 linkNum;
NVSWITCH_ASSERT(i < NVSWITCH_LINK_COUNT(device));
link = nvswitch_get_link(device, i);
if ((link == NULL) ||
(i >= NVSWITCH_NVLINK_MAX_LINKS))
{
NVSWITCH_PRINT(device, ERROR, "%s: Invalid input link %d set in linkMask\n",
__FUNCTION__, i);
return -NVL_BAD_ARGS;
}
linkNum = link->linkNumber;
status = device->hal.nvswitch_ctrl_get_link_l1_capability(device, linkNum, &isL1Capable);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to get l1 capability for link %d\n",
__FUNCTION__, linkNum);
return status;
}
if (!isL1Capable)
{
NVSWITCH_PRINT(device, ERROR, "%s: Input link %d does not support L1\n",
__FUNCTION__, i);
return -NVL_ERR_NOT_SUPPORTED;
}
// Get HAL
status = device->hal.nvswitch_ctrl_get_link_l1_threshold(device, linkNum, &(p->l1Threshold[linkNum]));
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to get L1 Threshold for link %d\n",
__FUNCTION__, linkNum);
return status;
}
}
FOR_EACH_INDEX_IN_MASK_END;
return NVL_SUCCESS;
}
NvlStatus
_nvswitch_ctrl_set_link_l1_threshold
(
nvswitch_device *device,
NVSWITCH_SET_NVLINK_L1_THRESHOLD_PARAMS *p
)
{
NvlStatus status;
nvlink_link *link;
NvBool isL1Capable;
NvU8 i;
if (device->regkeys.enable_pm == NV_SWITCH_REGKEY_ENABLE_PM_NO)
{
NVSWITCH_PRINT(device, INFO, "%s: L1 Threshold is disabled\n", __FUNCTION__);
return -NVL_ERR_NOT_SUPPORTED;
}
if (p->linkMask == 0)
{
NVSWITCH_PRINT(device, ERROR, "%s: No links in linkMask\n", __FUNCTION__);
return -NVL_BAD_ARGS;
}
FOR_EACH_INDEX_IN_MASK(64, i, p->linkMask)
{
NvU32 linkNum;
NvU32 l1Threshold;
NVSWITCH_ASSERT(i < NVSWITCH_LINK_COUNT(device));
link = nvswitch_get_link(device, i);
if ((link == NULL) ||
(i >= NVSWITCH_NVLINK_MAX_LINKS))
{
NVSWITCH_PRINT(device, ERROR, "%s: Invalid input link %d set in linkMask\n",
__FUNCTION__, i);
return -NVL_BAD_ARGS;
}
linkNum = link->linkNumber;
l1Threshold = p->l1Threshold[linkNum];
status = device->hal.nvswitch_ctrl_get_link_l1_capability(device, linkNum, &isL1Capable);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to get l1 capability for link %d\n",
__FUNCTION__, linkNum);
return status;
}
if (!isL1Capable)
{
NVSWITCH_PRINT(device, ERROR, "%s: Input link %d does not support L1\n",
__FUNCTION__, i);
return -NVL_ERR_NOT_SUPPORTED;
}
if (((l1Threshold < NVSWITCH_SET_NVLINK_L1_THRESHOLD_MIN) ||
(l1Threshold > NVSWITCH_SET_NVLINK_L1_THRESHOLD_MAX)) &&
(l1Threshold != NVSWITCH_SET_NVLINK_L1_THRESHOLD_DEFAULT))
{
return -NVL_BAD_ARGS;
}
status = device->hal.nvswitch_ctrl_set_link_l1_threshold(link,
p->l1Threshold[linkNum]);
if (status != NVL_SUCCESS)
{
NVSWITCH_PRINT(device, ERROR, "%s: Failed to set L1 Threshold for link %d\n",
__FUNCTION__, linkNum);
return status;
}
}
FOR_EACH_INDEX_IN_MASK_END
return NVL_SUCCESS;
}
NvlStatus
nvswitch_detect_tnvl_mode
(
nvswitch_device *device
)
{
return device->hal.nvswitch_detect_tnvl_mode(device);
}
NvBool
nvswitch_is_tnvl_mode_enabled
(
nvswitch_device *device
)
{
return device->hal.nvswitch_is_tnvl_mode_enabled(device);
}
NvBool
nvswitch_is_tnvl_mode_locked
(
nvswitch_device *device
)
{
return device->hal.nvswitch_is_tnvl_mode_locked(device);
}
NvBool NV_API_CALL
nvswitch_lib_is_tnvl_enabled
(
nvswitch_device *device
)
{
return nvswitch_is_tnvl_mode_enabled(device);
}
NvlStatus
nvswitch_tnvl_send_fsp_lock_config
(
nvswitch_device *device
)
{
return device->hal.nvswitch_tnvl_send_fsp_lock_config(device);
}
NvlStatus
nvswitch_send_tnvl_prelock_cmd
(
nvswitch_device *device
)
{
return device->hal.nvswitch_send_tnvl_prelock_cmd(device);
}
static NvlStatus
_nvswitch_ctrl_set_device_tnvl_lock
(
nvswitch_device *device,
NVSWITCH_SET_DEVICE_TNVL_LOCK_PARAMS *p
)
{
NvlStatus status = NVL_SUCCESS;
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device))
{
return -NVL_BAD_ARGS;
}
if (!nvswitch_is_tnvl_mode_enabled(device))
{
NVSWITCH_PRINT(device, ERROR,
"%s: TNVL is not enabled\n",
__FUNCTION__);
return -NVL_ERR_NOT_SUPPORTED;
}
// Return failure if FM is not yet configured
if (device->device_fabric_state != NVSWITCH_DEVICE_FABRIC_STATE_CONFIGURED)
{
NVSWITCH_PRINT(device, ERROR,
"%s: FM is not configured yet\n",
__FUNCTION__);
return -NVL_ERR_INVALID_STATE;
}
//
// Disable non-fatal and legacy interrupts
//
nvswitch_tnvl_disable_interrupts(device);
//
//
// Send Pre-Lock sequence command to SOE
//
status = nvswitch_send_tnvl_prelock_cmd(device);
if (status != NVL_SUCCESS)
{
return status;
}
// Send lock-config command to FSP
status = nvswitch_tnvl_send_fsp_lock_config(device);
if (status == NVL_SUCCESS)
{
device->tnvl_mode = NVSWITCH_DEVICE_TNVL_MODE_LOCKED;
}
else
{
device->tnvl_mode = NVSWITCH_DEVICE_TNVL_MODE_FAILURE;
}
return status;
}
NvlStatus
nvswitch_lib_ctrl
(
nvswitch_device *device,
NvU32 cmd,
void *params,
NvU64 size,
void *osPrivate
)
{
NvlStatus retval;
NvU64 flags = 0;
if (!NVSWITCH_IS_DEVICE_ACCESSIBLE(device) || params == NULL)
{
return -NVL_BAD_ARGS;
}
flags = NVSWITCH_DEV_CMD_CHECK_ADMIN | NVSWITCH_DEV_CMD_CHECK_FM;
switch (cmd)
{
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_INFO,
_nvswitch_ctrl_get_info,
NVSWITCH_GET_INFO);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_INTERNAL_LATENCY,
_nvswitch_ctrl_get_internal_latency,
NVSWITCH_GET_INTERNAL_LATENCY);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_NVLIPT_COUNTERS,
_nvswitch_ctrl_get_nvlipt_counters,
NVSWITCH_GET_NVLIPT_COUNTERS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_ERRORS,
nvswitch_ctrl_get_errors,
NVSWITCH_GET_ERRORS_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_PORT_EVENTS,
nvswitch_ctrl_get_port_events,
NVSWITCH_GET_PORT_EVENTS_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_NVLINK_STATUS,
_nvswitch_ctrl_get_nvlink_status,
NVSWITCH_GET_NVLINK_STATUS_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH_WITH_PRIVATE_DATA(
CTRL_NVSWITCH_ACQUIRE_CAPABILITY,
_nvswitch_ctrl_acquire_capability,
NVSWITCH_ACQUIRE_CAPABILITY_PARAMS,
osPrivate);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_TEMPERATURE,
_nvswitch_ctrl_therm_read_temperature,
NVSWITCH_CTRL_GET_TEMPERATURE_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_THROUGHPUT_COUNTERS,
nvswitch_ctrl_get_throughput_counters,
NVSWITCH_GET_THROUGHPUT_COUNTERS_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_FATAL_ERROR_SCOPE,
_nvswitch_ctrl_get_fatal_error_scope,
NVSWITCH_GET_FATAL_ERROR_SCOPE_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_SWITCH_PORT_CONFIG,
_nvswitch_ctrl_set_switch_port_config,
NVSWITCH_SET_SWITCH_PORT_CONFIG,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_INGRESS_REQUEST_TABLE,
_nvswitch_ctrl_get_ingress_request_table,
NVSWITCH_GET_INGRESS_REQUEST_TABLE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_INGRESS_REQUEST_TABLE,
_nvswitch_ctrl_set_ingress_request_table,
NVSWITCH_SET_INGRESS_REQUEST_TABLE,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_INGRESS_REQUEST_VALID,
_nvswitch_ctrl_set_ingress_request_valid,
NVSWITCH_SET_INGRESS_REQUEST_VALID,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_INGRESS_RESPONSE_TABLE,
_nvswitch_ctrl_get_ingress_response_table,
NVSWITCH_GET_INGRESS_RESPONSE_TABLE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_INGRESS_RESPONSE_TABLE,
_nvswitch_ctrl_set_ingress_response_table,
NVSWITCH_SET_INGRESS_RESPONSE_TABLE,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_GANGED_LINK_TABLE,
_nvswitch_ctrl_set_ganged_link_table,
NVSWITCH_SET_GANGED_LINK_TABLE,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_SET_LATENCY_BINS,
nvswitch_ctrl_set_latency_bins,
NVSWITCH_SET_LATENCY_BINS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_NVLIPT_COUNTER_CONFIG,
_nvswitch_ctrl_set_nvlipt_counter_config,
NVSWITCH_SET_NVLIPT_COUNTER_CONFIG,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_NVLIPT_COUNTER_CONFIG,
_nvswitch_ctrl_get_nvlipt_counter_config,
NVSWITCH_GET_NVLIPT_COUNTER_CONFIG,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_SET_REMAP_POLICY,
_nvswitch_ctrl_set_remap_policy,
NVSWITCH_SET_REMAP_POLICY,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_GET_REMAP_POLICY,
_nvswitch_ctrl_get_remap_policy,
NVSWITCH_GET_REMAP_POLICY_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_REMAP_POLICY_VALID,
_nvswitch_ctrl_set_remap_policy_valid,
NVSWITCH_SET_REMAP_POLICY_VALID,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_SET_ROUTING_ID,
_nvswitch_ctrl_set_routing_id,
NVSWITCH_SET_ROUTING_ID,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_GET_ROUTING_ID,
_nvswitch_ctrl_get_routing_id,
NVSWITCH_GET_ROUTING_ID_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_SET_ROUTING_ID_VALID,
_nvswitch_ctrl_set_routing_id_valid,
NVSWITCH_SET_ROUTING_LAN_VALID,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_SET_ROUTING_LAN,
_nvswitch_ctrl_set_routing_lan,
NVSWITCH_SET_ROUTING_LAN,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_GET_ROUTING_LAN,
_nvswitch_ctrl_get_routing_lan,
NVSWITCH_GET_ROUTING_LAN_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_ROUTING_LAN_VALID,
_nvswitch_ctrl_set_routing_lan_valid,
NVSWITCH_SET_ROUTING_LAN_VALID,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_INGRESS_REQLINKID,
_nvswitch_ctrl_get_ingress_reqlinkid,
NVSWITCH_GET_INGRESS_REQLINKID_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_UNREGISTER_LINK,
_nvswitch_ctrl_unregister_link,
NVSWITCH_UNREGISTER_LINK_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_RESET_AND_DRAIN_LINKS,
_nvswitch_ctrl_reset_and_drain_links,
NVSWITCH_RESET_AND_DRAIN_LINKS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_BIOS_INFO,
_nvswitch_ctrl_get_bios_info,
NVSWITCH_GET_BIOS_INFO_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_INFOROM_VERSION,
_nvswitch_ctrl_get_inforom_version,
NVSWITCH_GET_INFOROM_VERSION_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_BLACKLIST_DEVICE,
nvswitch_ctrl_blacklist_device,
NVSWITCH_BLACKLIST_DEVICE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_FM_DRIVER_STATE,
nvswitch_ctrl_set_fm_driver_state,
NVSWITCH_SET_FM_DRIVER_STATE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_DEVICE_FABRIC_STATE,
nvswitch_ctrl_set_device_fabric_state,
NVSWITCH_SET_DEVICE_FABRIC_STATE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_FM_HEARTBEAT_TIMEOUT,
nvswitch_ctrl_set_fm_timeout,
NVSWITCH_SET_FM_HEARTBEAT_TIMEOUT_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_WITH_PRIVATE_DATA(
CTRL_NVSWITCH_REGISTER_EVENTS,
_nvswitch_ctrl_register_events,
NVSWITCH_REGISTER_EVENTS_PARAMS,
osPrivate);
NVSWITCH_DEV_CMD_DISPATCH_WITH_PRIVATE_DATA(
CTRL_NVSWITCH_UNREGISTER_EVENTS,
_nvswitch_ctrl_unregister_events,
NVSWITCH_UNREGISTER_EVENTS_PARAMS,
osPrivate);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_TRAINING_ERROR_INFO,
_nvswitch_ctrl_set_training_error_info,
NVSWITCH_SET_TRAINING_ERROR_INFO_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_MC_RID_TABLE,
_nvswitch_ctrl_set_mc_rid_table,
NVSWITCH_SET_MC_RID_TABLE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_MC_RID_TABLE,
_nvswitch_ctrl_get_mc_rid_table,
NVSWITCH_GET_MC_RID_TABLE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_COUNTERS,
_nvswitch_ctrl_get_counters,
NVSWITCH_NVLINK_GET_COUNTERS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_NVLINK_ECC_ERRORS,
_nvswitch_ctrl_get_nvlink_ecc_errors,
NVSWITCH_GET_NVLINK_ECC_ERRORS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_I2C_SMBUS_COMMAND,
_nvswitch_ctrl_i2c_smbus_command,
NVSWITCH_I2C_SMBUS_COMMAND_PARAMS,
osPrivate, NVSWITCH_DEV_CMD_CHECK_ADMIN);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_CMIS_PRESENCE,
_nvswitch_ctrl_cci_cmis_presence,
NVSWITCH_CCI_CMIS_PRESENCE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_CMIS_NVLINK_MAPPING,
_nvswitch_ctrl_cci_nvlink_mappings,
NVSWITCH_CCI_CMIS_NVLINK_MAPPING_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_CMIS_MEMORY_ACCESS_READ,
_nvswitch_ctrl_cci_memory_access_read,
NVSWITCH_CCI_CMIS_MEMORY_ACCESS_READ_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_CMIS_MEMORY_ACCESS_WRITE,
_nvswitch_ctrl_cci_memory_access_write,
NVSWITCH_CCI_CMIS_MEMORY_ACCESS_WRITE_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_CMIS_CAGE_BEZEL_MARKING,
_nvswitch_ctrl_cci_cage_bezel_marking,
NVSWITCH_CCI_CMIS_CAGE_BEZEL_MARKING_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_GET_GRADING_VALUES,
nvswitch_ctrl_get_grading_values,
NVSWITCH_CCI_GET_GRADING_VALUES_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_GET_PORTS_CPLD_INFO,
nvswitch_ctrl_get_ports_cpld_info,
NVSWITCH_CCI_GET_PORTS_CPLD_INFO_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_GET_FW_REVISIONS,
nvswitch_ctrl_get_cci_fw_revisions,
NVSWITCH_CCI_GET_FW_REVISION_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_CCI_SET_LOCATE_LED,
nvswitch_ctrl_set_locate_led,
NVSWITCH_CCI_SET_LOCATE_LED_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_SOE_HEARTBEAT,
_nvswitch_ctrl_get_soe_heartbeat,
NVSWITCH_GET_SOE_HEARTBEAT_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_CONTINUOUS_ALI,
_nvswitch_ctrl_set_continuous_ali,
NVSWITCH_SET_CONTINUOUS_ALI_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_REQUEST_ALI,
_nvswitch_ctrl_request_ali,
NVSWITCH_REQUEST_ALI_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH(
CTRL_NVSWITCH_GET_TEMPERATURE_LIMIT,
_nvswitch_ctrl_therm_get_temperature_limit,
NVSWITCH_CTRL_GET_TEMPERATURE_LIMIT_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_NVLINK_MAX_ERROR_RATES,
_nvswitch_ctrl_get_inforom_nvlink_max_correctable_error_rate,
NVSWITCH_GET_NVLINK_MAX_CORRECTABLE_ERROR_RATES_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_NVLINK_ERROR_COUNTS,
_nvswitch_ctrl_get_inforom_nvlink_errors,
NVSWITCH_GET_NVLINK_ERROR_COUNTS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_ECC_ERROR_COUNTS,
_nvswitch_ctrl_get_inforom_ecc_errors,
NVSWITCH_GET_ECC_ERROR_COUNTS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_SXIDS,
_nvswitch_ctrl_get_inforom_bbx_sxid,
NVSWITCH_GET_SXIDS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_FOM_VALUES,
_nvswitch_ctrl_get_fom_values,
NVSWITCH_GET_FOM_VALUES_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_NVLINK_LP_COUNTERS,
_nvswitch_ctrl_get_nvlink_lp_counters,
NVSWITCH_GET_NVLINK_LP_COUNTERS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_RESIDENCY_BINS,
_nvswitch_ctrl_get_residency_bins,
NVSWITCH_GET_RESIDENCY_BINS);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_SET_RESIDENCY_BINS,
_nvswitch_ctrl_set_residency_bins,
NVSWITCH_SET_RESIDENCY_BINS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_RB_STALL_BUSY,
_nvswitch_ctrl_get_rb_stall_busy,
NVSWITCH_GET_RB_STALL_BUSY);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_MULTICAST_ID_ERROR_VECTOR,
nvswitch_ctrl_get_multicast_id_error_vector,
NVSWITCH_GET_MULTICAST_ID_ERROR_VECTOR);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_CLEAR_MULTICAST_ID_ERROR_VECTOR,
nvswitch_ctrl_clear_multicast_id_error_vector,
NVSWITCH_CLEAR_MULTICAST_ID_ERROR_VECTOR);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_INBAND_SEND_DATA,
_nvswitch_ctrl_inband_send_data,
NVSWITCH_INBAND_SEND_DATA_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_INBAND_READ_DATA,
_nvswitch_ctrl_inband_read_data,
NVSWITCH_INBAND_READ_DATA_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_INBAND_FLUSH_DATA,
_nvswitch_ctrl_inband_flush_data,
NVSWITCH_INBAND_FLUSH_DATA_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_INBAND_PENDING_DATA_STATS,
_nvswitch_ctrl_inband_pending_data_stats,
NVSWITCH_INBAND_PENDING_DATA_STATS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_BOARD_PART_NUMBER,
_nvswitch_ctrl_get_board_part_number,
NVSWITCH_GET_BOARD_PART_NUMBER_VECTOR);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_SW_INFO,
_nvswitch_ctrl_get_sw_info,
NVSWITCH_GET_SW_INFO_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_REGISTER_READ,
_nvswitch_ctrl_register_read,
NVSWITCH_REGISTER_READ,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_REGISTER_WRITE,
_nvswitch_ctrl_register_write,
NVSWITCH_REGISTER_WRITE,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_GET_ERR_INFO,
_nvswitch_ctrl_get_err_info,
NVSWITCH_NVLINK_GET_ERR_INFO_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_CLEAR_COUNTERS,
_nvswitch_ctrl_clear_counters,
NVSWITCH_NVLINK_CLEAR_COUNTERS_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_SET_NVLINK_ERROR_THRESHOLD,
_nvswitch_ctrl_set_nvlink_error_threshold,
NVSWITCH_SET_NVLINK_ERROR_THRESHOLD_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_NVLINK_ERROR_THRESHOLD,
_nvswitch_ctrl_get_nvlink_error_threshold,
NVSWITCH_GET_NVLINK_ERROR_THRESHOLD_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_VOLTAGE,
_nvswitch_ctrl_therm_read_voltage,
NVSWITCH_CTRL_GET_VOLTAGE_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_POWER,
_nvswitch_ctrl_therm_read_power,
NVSWITCH_GET_POWER_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_SYS_INFO,
_nvswitch_ctrl_get_inforom_bbx_sys_info,
NVSWITCH_GET_SYS_INFO_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_TIME_INFO,
_nvswitch_ctrl_get_inforom_bbx_time_info,
NVSWITCH_GET_TIME_INFO_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_TEMP_DATA,
_nvswitch_ctrl_get_inforom_bbx_temp_data,
NVSWITCH_GET_TEMP_DATA_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_TEMP_SAMPLES,
_nvswitch_ctrl_get_inforom_bbx_temp_samples,
NVSWITCH_GET_TEMP_SAMPLES_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_NVLINK_L1_CAPABILITY,
_nvswitch_ctrl_get_link_l1_capability,
NVSWITCH_GET_NVLINK_L1_CAPABILITY_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_GET_NVLINK_L1_THRESHOLD,
_nvswitch_ctrl_get_link_l1_threshold,
NVSWITCH_GET_NVLINK_L1_THRESHOLD_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(CTRL_NVSWITCH_SET_NVLINK_L1_THRESHOLD,
_nvswitch_ctrl_set_link_l1_threshold,
NVSWITCH_SET_NVLINK_L1_THRESHOLD_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH(CTRL_NVSWITCH_FSPRPC_GET_CAPS,
_nvswitch_ctrl_fsprpc_get_caps,
NVSWITCH_FSPRPC_GET_CAPS_PARAMS);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_SET_DEVICE_TNVL_LOCK,
_nvswitch_ctrl_set_device_tnvl_lock,
NVSWITCH_SET_DEVICE_TNVL_LOCK_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_ATTESTATION_CERTIFICATE_CHAIN,
_nvswitch_ctrl_get_attestation_certificate_chain,
NVSWITCH_GET_ATTESTATION_CERTIFICATE_CHAIN_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_ATTESTATION_REPORT,
_nvswitch_ctrl_get_attestation_report,
NVSWITCH_GET_ATTESTATION_REPORT_PARAMS,
osPrivate, flags);
NVSWITCH_DEV_CMD_DISPATCH_PRIVILEGED(
CTRL_NVSWITCH_GET_TNVL_STATUS,
_nvswitch_ctrl_get_tnvl_status,
NVSWITCH_GET_TNVL_STATUS_PARAMS,
osPrivate, flags);
default:
nvswitch_os_print(NVSWITCH_DBG_LEVEL_INFO, "unknown ioctl %x\n", cmd);
retval = -NVL_BAD_ARGS;
break;
}
return retval;
}
#if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
void nvswitch_assert_log
(
const char *function,
const char *file,
NvU32 line
)
{
nvswitch_os_assert_log("NVSwitch: Assertion failed in %s() at %s:%d\n",
function, file, line);
}
#else
void nvswitch_assert_log(void)
{
nvswitch_os_assert_log("NVSwitch: Assertion failed\n");
}
#endif