mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-01-26 19:19:47 +00:00
2585 lines
89 KiB
C
2585 lines
89 KiB
C
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2018-2023 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 "nvlink_export.h"
|
|
|
|
#include "export_nvswitch.h"
|
|
#include "common_nvswitch.h"
|
|
#include "regkey_nvswitch.h"
|
|
#include "lr10/lr10.h"
|
|
#include "lr10/minion_lr10.h"
|
|
#include "lr10/pmgr_lr10.h"
|
|
|
|
#include "nvswitch/lr10/dev_nvldl_ip.h"
|
|
#include "nvswitch/lr10/dev_nvldl_ip_addendum.h"
|
|
#include "nvswitch/lr10/dev_minion_ip_addendum.h"
|
|
#include "nvswitch/lr10/dev_nvlipt_lnk_ip.h"
|
|
#include "nvswitch/lr10/dev_nvlphyctl_ip.h"
|
|
#include "nvswitch/lr10/dev_nvltlc_ip.h"
|
|
#include "nvswitch/lr10/dev_minion_ip.h"
|
|
#include "nvswitch/lr10/dev_trim.h"
|
|
#include "nvswitch/lr10/dev_pri_ringstation_sys.h"
|
|
#include "nvswitch/lr10/dev_nvlperf_ip.h"
|
|
#include "nvswitch/lr10/dev_nvlipt_ip.h"
|
|
#include "nvswitch/lr10/dev_nport_ip.h"
|
|
|
|
#define NUM_SWITCH_WITH_DISCONNETED_REMOTE_LINK 8 // This must be incremented if any entries are added to the array below
|
|
lr10_links_connected_to_disabled_remote_end nvswitchDisconnetedRemoteLinkMasks[] =
|
|
{
|
|
{
|
|
0x8, // switchPhysicalId
|
|
0x56A000500 //linkMask
|
|
},
|
|
{
|
|
0x9, // switchPhysicalId
|
|
0x509009900 //linkMask
|
|
},
|
|
{
|
|
0xb, // switchPhysicalId
|
|
0x56A000600 //linkMask
|
|
},
|
|
{
|
|
0xc, // switchPhysicalId
|
|
0x4A9009400 //linkMask
|
|
},
|
|
{
|
|
0x18, // switchPhysicalId
|
|
0x56A000500 //linkMask
|
|
},
|
|
{
|
|
0x19, // switchPhysicalId
|
|
0x509009900 //linkMask
|
|
},
|
|
{
|
|
0x1b, // switchPhysicalId
|
|
0x56A000600 //linkMask
|
|
},
|
|
{
|
|
0x1c, // switchPhysicalId
|
|
0x4A9009400 //linkMask
|
|
},
|
|
};
|
|
ct_assert(sizeof(nvswitchDisconnetedRemoteLinkMasks)/sizeof(lr10_links_connected_to_disabled_remote_end) == NUM_SWITCH_WITH_DISCONNETED_REMOTE_LINK);
|
|
|
|
|
|
void
|
|
nvswitch_setup_link_loopback_mode_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 linkNumber
|
|
)
|
|
{
|
|
nvlink_link *link;
|
|
NV_STATUS status;
|
|
|
|
link = nvswitch_get_link(device, linkNumber);
|
|
|
|
if ((link == NULL) ||
|
|
!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber) ||
|
|
(linkNumber >= NVSWITCH_NVLINK_MAX_LINKS))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (device->link[link->linkNumber].nea)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Setting NEA on link %d\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_SETNEA, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: SETNEA CMD failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
}
|
|
}
|
|
|
|
if (device->link[link->linkNumber].nedr)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Setting NEDR on link %d\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
|
|
// setting NEDR
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_SETNEDR, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: SETNEDR CMD failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
}
|
|
}
|
|
|
|
if (device->link[link->linkNumber].nedw)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Setting NEDW on link %d\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
|
|
// setting NEDW
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_SETNEDW, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: SETNEDW CMD failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
}
|
|
}
|
|
}
|
|
|
|
static NV_STATUS
|
|
_nvswitch_ioctrl_setup_link_plls_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
NV_STATUS status = NV_OK;
|
|
NvU32 linkId, tempRegVal;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
NvBool keepPolling;
|
|
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
linkId = link->linkNumber;
|
|
|
|
if (IS_EMULATION(device))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,"Skipping PLL init on emulation. \n");
|
|
return status;
|
|
}
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_1MSEC_IN_NS * 400, &timeout);
|
|
|
|
do
|
|
{
|
|
keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
|
|
tempRegVal = NVSWITCH_LINK_RD32_LR10(device, linkId, NVLIPT_LNK , _NVLIPT_LNK , _CTRL_CLK_CTRL);
|
|
|
|
if (FLD_TEST_DRF(_NVLIPT_LNK, _CTRL_CLK_CTRL, _PLL_PWR_STS, _ON, tempRegVal))
|
|
break;
|
|
|
|
nvswitch_os_sleep(1);
|
|
} while (keepPolling == NV_TRUE);
|
|
|
|
if (FLD_TEST_DRF(_NVLIPT_LNK, _CTRL_CLK_CTRL, _PLL_PWR_STS, _OFF, tempRegVal))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"PLL_PWR_STS did not turn _ON for linkId = 0x%x!!\n", linkId);
|
|
return NV_ERR_TIMEOUT;
|
|
}
|
|
|
|
// Request Minion to setup the NVLink clocks
|
|
status = nvswitch_minion_send_command(device, linkId,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_TXCLKSWITCH_PLL, 0);
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"Error sending TXCLKSWITCH_PLL command to MINION. Link = %d\n", linkId);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_CLOCK_ERROR, NVBIT32(link->linkNumber), TXCLKSWITCH_PLL_ERROR);
|
|
return NV_ERR_NVLINK_CLOCK_ERROR;
|
|
}
|
|
|
|
// Poll for the links to switch to NVLink clocks
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_1MSEC_IN_NS * 400, &timeout);
|
|
|
|
do
|
|
{
|
|
keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
|
|
tempRegVal = NVSWITCH_LINK_RD32_LR10(device, linkId, NVLIPT_LNK , _NVLIPT_LNK , _CTRL_CLK_CTRL);
|
|
if (FLD_TEST_DRF(_NVLIPT_LNK, _CTRL_CLK_CTRL, _TXCLK_STS, _PLL_CLK, tempRegVal))
|
|
break;
|
|
|
|
nvswitch_os_sleep(1);
|
|
} while (keepPolling == NV_TRUE);
|
|
|
|
if (!FLD_TEST_DRF(_NVLIPT_LNK, _CTRL_CLK_CTRL, _TXCLK_STS, _PLL_CLK, tempRegVal))
|
|
{
|
|
// Print the links for which we were unable to switch to PLL clock
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"TXCLK_STS did not switch to _PLL_CLOCK for linkId = 0x%x!!\n", linkId);
|
|
return NV_ERR_TIMEOUT;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NvBool
|
|
nvswitch_is_link_in_reset_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
NvU32 val;
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK, _NVLIPT_LNK, _RESET_RSTSEQ_LINK_RESET);
|
|
|
|
return (FLD_TEST_DRF(_NVLIPT_LNK, _RESET_RSTSEQ_LINK_RESET, _LINK_RESET_STATUS,
|
|
_ASSERTED, val)) ? NV_TRUE : NV_FALSE;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_poll_sublink_state_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
NVSWITCH_TIMEOUT timeout;
|
|
NvBool keepPolling;
|
|
NvU32 val;
|
|
NvBool bPreSiPlatform = (IS_RTLSIM(device) || IS_EMULATION(device) || IS_FMODEL(device));
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_1MSEC_IN_NS * (bPreSiPlatform ? 2000: 200), &timeout);
|
|
|
|
do
|
|
{
|
|
keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _SUBLINK_CHANGE);
|
|
|
|
if (FLD_TEST_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _STATUS, _FAULT, val))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Fault while changing sublink state (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
if (FLD_TEST_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _STATUS, _DONE, val))
|
|
{
|
|
break;
|
|
}
|
|
|
|
nvswitch_os_sleep(1);
|
|
}
|
|
while (keepPolling);
|
|
|
|
if ((!FLD_TEST_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _STATUS, _DONE, val)))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Timeout while waiting sublink state (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return -NVL_ERR_GENERIC;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
static NvlStatus
|
|
_nvswitch_init_dl_pll
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvlStatus status;
|
|
|
|
status = nvswitch_minion_send_command(device, link->linkNumber, NV_MINION_NVLINK_DL_CMD_COMMAND_INITPLL, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: INITPLL failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_CLOCK_ERROR, NVBIT32(link->linkNumber), INITPLL_ERROR);
|
|
return NV_ERR_NVLINK_CLOCK_ERROR;
|
|
}
|
|
|
|
status = _nvswitch_ioctrl_setup_link_plls_lr10(link);
|
|
if (status != NV_OK){
|
|
return status;
|
|
}
|
|
|
|
status = nvswitch_minion_send_command(device, link->linkNumber, NV_MINION_NVLINK_DL_CMD_COMMAND_INITPHY, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: INITPHY failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_INIT_ERROR, NVBIT32(link->linkNumber), INITPHY_ERROR);
|
|
return NV_ERR_NVLINK_INIT_ERROR;
|
|
}
|
|
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvU32
|
|
nvswitch_get_sublink_width_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 linkNumber
|
|
)
|
|
{
|
|
return NVSWITCH_NUM_LANES_LR10;
|
|
}
|
|
|
|
void
|
|
nvswitch_init_dlpl_interrupts_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 linkNumber = link->linkNumber;
|
|
NvU32 crcShortRegkeyVal = device->regkeys.crc_bit_error_rate_short;
|
|
NvU32 crcLongRegkeyVal = device->regkeys.crc_bit_error_rate_long;
|
|
NvU32 intrRegVal;
|
|
NvU32 crcRegVal;
|
|
NvU32 shortRateMask;
|
|
NvU32 longRateMask;
|
|
|
|
ct_assert(DRF_BASE(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_THRESHOLD_MAN) ==
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_SHORT_THRESHOLD_MAN));
|
|
ct_assert(DRF_EXTENT(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_THRESHOLD_MAN) ==
|
|
DRF_EXTENT(NV_NVLDL_RX_ERROR_RATE_CTRL_SHORT_THRESHOLD_MAN));
|
|
ct_assert(DRF_BASE(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_THRESHOLD_EXP) ==
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_SHORT_THRESHOLD_EXP));
|
|
ct_assert(DRF_EXTENT(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_THRESHOLD_EXP) ==
|
|
DRF_EXTENT(NV_NVLDL_RX_ERROR_RATE_CTRL_SHORT_THRESHOLD_EXP));
|
|
ct_assert(DRF_BASE(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_TIMESCALE_MAN) ==
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_SHORT_TIMESCALE_MAN));
|
|
ct_assert(DRF_EXTENT(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_TIMESCALE_MAN) ==
|
|
DRF_EXTENT(NV_NVLDL_RX_ERROR_RATE_CTRL_SHORT_TIMESCALE_MAN));
|
|
ct_assert(DRF_BASE(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_TIMESCALE_EXP) ==
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_SHORT_TIMESCALE_EXP));
|
|
ct_assert(DRF_EXTENT(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_TIMESCALE_EXP) ==
|
|
DRF_EXTENT(NV_NVLDL_RX_ERROR_RATE_CTRL_SHORT_TIMESCALE_EXP));
|
|
|
|
ct_assert(DRF_BASE(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_THRESHOLD_MAN) ==
|
|
(DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN) -
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN)));
|
|
ct_assert(DRF_EXTENT(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_THRESHOLD_MAN) ==
|
|
(DRF_EXTENT(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN) -
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN)));
|
|
ct_assert(DRF_BASE(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_THRESHOLD_EXP) ==
|
|
(DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_EXP) -
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN)));
|
|
ct_assert(DRF_EXTENT(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_THRESHOLD_EXP) ==
|
|
(DRF_EXTENT(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_EXP) -
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN)));
|
|
ct_assert(DRF_BASE(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_TIMESCALE_MAN) ==
|
|
(DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_TIMESCALE_MAN) -
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN)));
|
|
ct_assert(DRF_EXTENT(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_TIMESCALE_MAN) ==
|
|
(DRF_EXTENT(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_TIMESCALE_MAN) -
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN)));
|
|
ct_assert(DRF_BASE(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_TIMESCALE_EXP) ==
|
|
(DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_TIMESCALE_EXP) -
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN)));
|
|
ct_assert(DRF_EXTENT(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_TIMESCALE_EXP) ==
|
|
(DRF_EXTENT(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_TIMESCALE_EXP) -
|
|
DRF_BASE(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN)));
|
|
|
|
// W1C any stale state.
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNumber, NVLDL, _NVLDL_TOP, _INTR, 0xffffffff);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNumber, NVLDL, _NVLDL_TOP, _INTR_SW2, 0xffffffff);
|
|
|
|
// Stall tree routes to INTR_A which is connected to NVLIPT fatal tree
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNumber, NVLDL, _NVLDL_TOP, _INTR_STALL_EN,
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _TX_REPLAY, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _TX_RECOVERY_SHORT, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _LTSSM_FAULT_UP, _ENABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _TX_FAULT_RAM, _ENABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _TX_FAULT_INTERFACE, _ENABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _TX_FAULT_SUBLINK_CHANGE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _RX_FAULT_SUBLINK_CHANGE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _RX_FAULT_DL_PROTOCOL, _ENABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _RX_SHORT_ERROR_RATE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _RX_LONG_ERROR_RATE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _RX_ILA_TRIGGER, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _RX_CRC_COUNTER, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _LTSSM_PROTOCOL, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_STALL_EN, _MINION_REQUEST, _DISABLE));
|
|
|
|
// NONSTALL -> NONFATAL
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNumber, NVLDL, _NVLDL_TOP, _INTR_NONSTALL_EN,
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _TX_REPLAY, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _TX_RECOVERY_SHORT, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _LTSSM_FAULT_UP, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _TX_FAULT_RAM, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _TX_FAULT_INTERFACE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _TX_FAULT_SUBLINK_CHANGE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_FAULT_SUBLINK_CHANGE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_FAULT_DL_PROTOCOL, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_SHORT_ERROR_RATE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_LONG_ERROR_RATE, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_ILA_TRIGGER, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_CRC_COUNTER, _ENABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _LTSSM_PROTOCOL, _DISABLE) |
|
|
DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _MINION_REQUEST, _DISABLE));
|
|
|
|
intrRegVal = NVSWITCH_LINK_RD32_LR10(device, linkNumber, NVLDL,
|
|
_NVLDL_TOP, _INTR_NONSTALL_EN);
|
|
crcRegVal = NVSWITCH_LINK_RD32_LR10(device, linkNumber, NVLDL,
|
|
_NVLDL_RX, _ERROR_RATE_CTRL);
|
|
|
|
// Enable RX error rate short interrupt if the regkey is set
|
|
if (crcShortRegkeyVal != NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_DEFAULT)
|
|
{
|
|
shortRateMask = DRF_SHIFTMASK(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_THRESHOLD_MAN) |
|
|
DRF_SHIFTMASK(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_THRESHOLD_EXP) |
|
|
DRF_SHIFTMASK(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_TIMESCALE_MAN) |
|
|
DRF_SHIFTMASK(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_SHORT_TIMESCALE_EXP);
|
|
|
|
intrRegVal |= DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_SHORT_ERROR_RATE, _ENABLE);
|
|
crcRegVal &= ~shortRateMask;
|
|
crcRegVal |= crcShortRegkeyVal;
|
|
}
|
|
// Enable RX error rate long interrupt if the regkey is set
|
|
if (crcLongRegkeyVal != NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_DEFAULT)
|
|
{
|
|
longRateMask = DRF_SHIFTMASK(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_THRESHOLD_MAN) |
|
|
DRF_SHIFTMASK(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_THRESHOLD_EXP) |
|
|
DRF_SHIFTMASK(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_TIMESCALE_MAN) |
|
|
DRF_SHIFTMASK(NV_SWITCH_REGKEY_CRC_BIT_ERROR_RATE_LONG_TIMESCALE_EXP);
|
|
|
|
intrRegVal |= DRF_DEF(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_LONG_ERROR_RATE, _ENABLE);
|
|
crcRegVal &= ~longRateMask;
|
|
crcRegVal |= crcLongRegkeyVal << DRF_SHIFT(NV_NVLDL_RX_ERROR_RATE_CTRL_LONG_THRESHOLD_MAN);
|
|
}
|
|
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNumber, NVLDL,
|
|
_NVLDL_TOP, _INTR_NONSTALL_EN, intrRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNumber, NVLDL,
|
|
_NVLDL_RX, _ERROR_RATE_CTRL, crcRegVal);
|
|
}
|
|
|
|
static void
|
|
_nvswitch_disable_dlpl_interrupts
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 linkNumber = link->linkNumber;
|
|
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNumber, NVLDL, _NVLDL_TOP, _INTR_STALL_EN, 0x0);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNumber, NVLDL, _NVLDL_TOP, _INTR_NONSTALL_EN, 0x0);
|
|
}
|
|
|
|
void
|
|
nvswitch_store_topology_information_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
NvU32 tempval;
|
|
|
|
link->bInitnegotiateConfigGood = NV_TRUE;
|
|
link->remoteSid = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT_LNK,
|
|
_NVLIPT_LNK, _TOPOLOGY_REMOTE_CHIP_SID_HI);
|
|
link->remoteSid = link->remoteSid << 32;
|
|
link->remoteSid |= NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT_LNK,
|
|
_NVLIPT_LNK, _TOPOLOGY_REMOTE_CHIP_SID_LO);
|
|
|
|
tempval = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT_LNK, _NVLIPT_LNK, _TOPOLOGY_REMOTE_LINK_INFO);
|
|
link->remoteLinkId = DRF_VAL(_NVLIPT_LNK, _TOPOLOGY_REMOTE_LINK_INFO, _LINK_NUMBER, tempval);
|
|
|
|
link->localSid = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT,
|
|
_NVLIPT_COMMON, _TOPOLOGY_LOCAL_CHIP_SID_HI);
|
|
link->localSid = link->localSid << 32;
|
|
link->localSid |= NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT,
|
|
_NVLIPT_COMMON, _TOPOLOGY_LOCAL_CHIP_SID_LO);
|
|
|
|
tempval = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT_LNK,
|
|
_NVLIPT_LNK, _TOPOLOGY_REMOTE_CHIP_TYPE);
|
|
|
|
// Update the remoteDeviceType with NV2080_CTRL_NVLINK_DEVICE_INFO_DEVICE_TYPE values.
|
|
switch(tempval)
|
|
{
|
|
case NV_NVLIPT_LNK_TOPOLOGY_REMOTE_CHIP_TYPE_TYPE_NV3P0AMP:
|
|
link->remoteDeviceType = NVSWITCH_NVLINK_DEVICE_INFO_DEVICE_TYPE_GPU;
|
|
break;
|
|
case NV_NVLIPT_LNK_TOPOLOGY_REMOTE_CHIP_TYPE_TYPE_NV3P0LRK:
|
|
link->remoteDeviceType = NVSWITCH_NVLINK_DEVICE_INFO_DEVICE_TYPE_SWITCH;
|
|
break;
|
|
default:
|
|
link->remoteDeviceType = NVSWITCH_NVLINK_DEVICE_INFO_DEVICE_TYPE_NONE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
nvswitch_init_lpwr_regs_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 linkNum = link->linkNumber;
|
|
NvU32 tempRegVal, icLimit, fbIcInc, lpIcInc, fbIcDec, lpIcDec, lpEntryThreshold;
|
|
NvU32 lpExitThreshold;
|
|
NvU8 softwareDesired, hardwareDisable;
|
|
NvBool bLpEnable;
|
|
|
|
if (device->regkeys.enable_pm == NV_SWITCH_REGKEY_ENABLE_PM_NO)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Power Management threshold settings
|
|
// These settings are currently being hard coded.
|
|
// They will be parsed from the VBIOS NVLink LPWR table once bug 2767390 is
|
|
// implemented
|
|
//
|
|
|
|
// IC Limit
|
|
icLimit = 16110000;
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_LIMIT, _LIMIT, icLimit,
|
|
tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _PWRM_IC_LIMIT,
|
|
tempRegVal);
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK,_PWRM_IC_LIMIT, _LIMIT, icLimit,
|
|
tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _PWRM_IC_LIMIT,
|
|
tempRegVal);
|
|
|
|
//IC Inc
|
|
fbIcInc = 1;
|
|
lpIcInc = 1;
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_INC, _FBINC, fbIcInc, tempRegVal);
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_INC, _LPINC, lpIcInc, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _PWRM_IC_INC,
|
|
tempRegVal);
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK, _PWRM_IC_INC, _FBINC, fbIcInc, tempRegVal);
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK, _PWRM_IC_INC, _LPINC, lpIcInc, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _PWRM_IC_INC,
|
|
tempRegVal);
|
|
|
|
//IC Dec
|
|
fbIcDec = 1;
|
|
lpIcDec = 65535;
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_DEC, _FBDEC, fbIcDec, tempRegVal);
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_DEC, _LPDEC, lpIcDec, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _PWRM_IC_DEC,
|
|
tempRegVal);
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK, _PWRM_IC_DEC, _FBDEC, fbIcDec, tempRegVal);
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK, _PWRM_IC_DEC, _LPDEC, lpIcDec, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _PWRM_IC_DEC,
|
|
tempRegVal);
|
|
|
|
//IC Enter Threshold
|
|
if (device->regkeys.lp_threshold == NV_SWITCH_REGKEY_SET_LP_THRESHOLD_DEFAULT)
|
|
{
|
|
// TODO: get from bios. Refer Bug 3626523 for more info.
|
|
lpEntryThreshold = 16110000;
|
|
}
|
|
else
|
|
{
|
|
lpEntryThreshold = device->regkeys.lp_threshold;
|
|
}
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_LP_ENTER_THRESHOLD, _THRESHOLD, lpEntryThreshold, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _PWRM_IC_LP_ENTER_THRESHOLD,
|
|
tempRegVal);
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK, _PWRM_IC_LP_ENTER_THRESHOLD, _THRESHOLD, lpEntryThreshold, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _PWRM_IC_LP_ENTER_THRESHOLD,
|
|
tempRegVal);
|
|
|
|
//IC Exit Threshold
|
|
lpExitThreshold = 16044465;
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_LP_EXIT_THRESHOLD, _THRESHOLD, lpExitThreshold, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _PWRM_IC_LP_EXIT_THRESHOLD,
|
|
tempRegVal);
|
|
|
|
tempRegVal = 0;
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK, _PWRM_IC_LP_EXIT_THRESHOLD, _THRESHOLD, lpExitThreshold, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _PWRM_IC_LP_EXIT_THRESHOLD,
|
|
tempRegVal);
|
|
|
|
//LP Entry Enable
|
|
bLpEnable = NV_TRUE;
|
|
softwareDesired = (bLpEnable) ? 0x1 : 0x0;
|
|
hardwareDisable = (bLpEnable) ? 0x0 : 0x1;
|
|
|
|
tempRegVal = NVSWITCH_LINK_RD32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _PWRM_IC_SW_CTRL);
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_SW_CTRL, _SOFTWAREDESIRED,
|
|
softwareDesired, tempRegVal);
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_TX_LNK, _PWRM_IC_SW_CTRL, _HARDWAREDISABLE,
|
|
hardwareDisable, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _PWRM_IC_SW_CTRL,
|
|
tempRegVal);
|
|
|
|
tempRegVal = NVSWITCH_LINK_RD32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _PWRM_IC_SW_CTRL);
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK, _PWRM_IC_SW_CTRL, _SOFTWAREDESIRED,
|
|
softwareDesired, tempRegVal);
|
|
tempRegVal = FLD_SET_DRF_NUM(_NVLTLC_RX_LNK, _PWRM_IC_SW_CTRL, _HARDWAREDISABLE,
|
|
hardwareDisable, tempRegVal);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _PWRM_IC_SW_CTRL,
|
|
tempRegVal);
|
|
}
|
|
|
|
|
|
void
|
|
nvswitch_init_buffer_ready_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link,
|
|
NvBool bNportBufferReady
|
|
)
|
|
{
|
|
NvU32 val;
|
|
NvU32 linkNum = link->linkNumber;
|
|
|
|
if (FLD_TEST_DRF(_SWITCH_REGKEY, _SKIP_BUFFER_READY, _TLC, _NO,
|
|
device->regkeys.skip_buffer_ready))
|
|
{
|
|
val = DRF_NUM(_NVLTLC_RX_SYS, _CTRL_BUFFER_READY, _BUFFERRDY, 0x1);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_SYS, _CTRL_BUFFER_READY, val);
|
|
val = DRF_NUM(_NVLTLC_TX_SYS, _CTRL_BUFFER_READY, _BUFFERRDY, 0x1);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_SYS, _CTRL_BUFFER_READY, val);
|
|
}
|
|
|
|
if (bNportBufferReady &&
|
|
FLD_TEST_DRF(_SWITCH_REGKEY, _SKIP_BUFFER_READY, _NPORT, _NO,
|
|
device->regkeys.skip_buffer_ready))
|
|
{
|
|
val = DRF_NUM(_NPORT, _CTRL_BUFFER_READY, _BUFFERRDY, 0x1);
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NPORT, _NPORT, _CTRL_BUFFER_READY, val);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_nvswitch_configure_reserved_throughput_counters
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 linkNum = link->linkNumber;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLTLC, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"Invalid link, skipping NVLink throughput counter config for link %d\n",
|
|
link->linkNumber);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Counters 0 and 2 will be reserved for monitoring tools
|
|
// Counters 1 and 3 will be user-configurable and used by devtools
|
|
//
|
|
|
|
// Rx0 config
|
|
NVSWITCH_LINK_WR32_IDX_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, 0,
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _UNIT, _FLITS) |
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _DATA) |
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _VCSETFILTERMODE, _INIT));
|
|
|
|
// Tx0 config
|
|
NVSWITCH_LINK_WR32_IDX_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, 0,
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _UNIT, _FLITS) |
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _DATA) |
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _VCSETFILTERMODE, _INIT));
|
|
|
|
// Rx2 config
|
|
NVSWITCH_LINK_WR32_IDX_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, 2,
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _UNIT, _FLITS) |
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _HEAD) |
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _AE) |
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _BE) |
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _DATA) |
|
|
DRF_DEF(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL_0, _VCSETFILTERMODE, _INIT));
|
|
|
|
// Tx2 config
|
|
NVSWITCH_LINK_WR32_IDX_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, 2,
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _UNIT, _FLITS) |
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _HEAD) |
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _AE) |
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _BE) |
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _FLITFILTER, _DATA) |
|
|
DRF_DEF(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL_0, _VCSETFILTERMODE, _INIT));
|
|
|
|
// Enable Rx for counters 0, 2
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL,
|
|
DRF_NUM(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL, _ENRX0, 0x1) |
|
|
DRF_NUM(_NVLTLC_RX_LNK, _DEBUG_TP_CNTR_CTRL, _ENRX2, 0x1));
|
|
|
|
// Enable Tx for counters 0, 2
|
|
NVSWITCH_LINK_WR32_LR10(device, linkNum, NVLTLC, _NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL,
|
|
DRF_NUM(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL, _ENTX0, 0x1) |
|
|
DRF_NUM(_NVLTLC_TX_LNK, _DEBUG_TP_CNTR_CTRL, _ENTX2, 0x1));
|
|
}
|
|
|
|
static NvlStatus
|
|
_nvswitch_init_link_post_active
|
|
(
|
|
nvlink_link *link,
|
|
NvU32 flags
|
|
)
|
|
{
|
|
NvlStatus status = NVL_SUCCESS;
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
|
|
nvswitch_init_lpwr_regs(link);
|
|
status = nvswitch_request_tl_link_state_lr10(link,
|
|
NV_NVLIPT_LNK_CTRL_LINK_STATE_REQUEST_REQUEST_ACTIVE,
|
|
flags == NVLINK_STATE_CHANGE_SYNC);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
// Note: buffer_rdy should be asserted last!
|
|
nvswitch_init_buffer_ready(device, link, NV_TRUE);
|
|
|
|
return status;
|
|
}
|
|
|
|
static void
|
|
_nvswitch_power_down_link_plls
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
NvlStatus status = NVL_SUCCESS;
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
|
|
if (IS_EMULATION(device))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,"Skipping PLL init on emulation. \n");
|
|
return;
|
|
}
|
|
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_TXCLKSWITCH_ALT, 0);
|
|
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: TXCLKSWITCH_ALT CMD failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_add_link_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_remove_link_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_set_dl_link_mode_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU64 mode,
|
|
NvU32 flags
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 val;
|
|
NvU32 link_state;
|
|
NvlStatus status = NVL_SUCCESS;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
if (nvswitch_does_link_need_termination_enabled(device, link))
|
|
{
|
|
|
|
if (mode == NVLINK_LINKSTATE_INITPHASE1)
|
|
{
|
|
status = nvswitch_link_termination_setup(device, link);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Failed to enable termination on link #%d\n", __FUNCTION__, link->linkNumber);
|
|
}
|
|
}
|
|
|
|
// return SUCCESS to avoid errors being propogated
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case NVLINK_LINKSTATE_SAFE:
|
|
{
|
|
// check if link is in reset
|
|
if (nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d is still in reset, cannot change link state\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_STATE);
|
|
link_state = DRF_VAL(_NVLDL_TOP, _LINK_STATE, _STATE, val);
|
|
|
|
if (link_state == NV_NVLDL_TOP_LINK_STATE_STATE_SWCFG)
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : Link is already in Safe mode for (%s).\n",
|
|
__FUNCTION__, link->linkName);
|
|
break;
|
|
}
|
|
else if (link_state == NV_NVLDL_TOP_LINK_STATE_STATE_HWCFG)
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : Link already transitioning to Safe mode for (%s).\n",
|
|
__FUNCTION__, link->linkName);
|
|
break;
|
|
}
|
|
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"NVRM: %s : Changing Link state to Safe for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
|
|
if (link_state == NV_NVLDL_TOP_LINK_STATE_STATE_INIT)
|
|
{
|
|
val = 0;
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_CHANGE);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _NEWSTATE, _HWCFG, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _OLDSTATE_MASK, _DONTCARE, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _ACTION, _LTSSM_CHANGE, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_CHANGE, val);
|
|
}
|
|
else if (link_state == NV_NVLDL_TOP_LINK_STATE_STATE_ACTIVE)
|
|
{
|
|
val = 0;
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_CHANGE);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _NEWSTATE, _SWCFG, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _OLDSTATE_MASK, _DONTCARE, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _ACTION, _LTSSM_CHANGE, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_CHANGE, val);
|
|
}
|
|
else
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Link is in invalid state"
|
|
" cannot set to safe state (%s):(%s). (%x) (%x)\n",
|
|
__FUNCTION__, device->name, link->linkName, val, link_state);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_HS:
|
|
{
|
|
// check if link is in reset
|
|
if (nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d is still in reset, cannot change link state\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_STATE);
|
|
link_state = DRF_VAL(_NVLDL_TOP, _LINK_STATE, _STATE, val);
|
|
|
|
if (link_state == NV_NVLDL_TOP_LINK_STATE_STATE_ACTIVE)
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : Link is already in Active mode (%s).\n",
|
|
__FUNCTION__, link->linkName);
|
|
break;
|
|
}
|
|
else if (link_state == NV_NVLDL_TOP_LINK_STATE_STATE_INIT)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Link cannot be taken from INIT state to"
|
|
" Active mode for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
else if (link_state == NV_NVLDL_TOP_LINK_STATE_STATE_SWCFG)
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : Changing Link state to Active for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_CHANGE);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _NEWSTATE, _ACTIVE, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _OLDSTATE_MASK, _DONTCARE, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _LINK_CHANGE, _ACTION, _LTSSM_CHANGE, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_CHANGE, val);
|
|
}
|
|
else
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Link is in invalid state"
|
|
" cannot set to active state (%s):(%s). (%x) (%x)\n",
|
|
__FUNCTION__, device->name, link->linkName, val, link_state);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_OFF:
|
|
{
|
|
_nvswitch_power_down_link_plls(link);
|
|
|
|
if (nvswitch_lib_notify_client_events(device,
|
|
NVSWITCH_DEVICE_EVENT_PORT_DOWN) != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify PORT_DOWN event\n",
|
|
__FUNCTION__);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_RESET:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_ENABLE_PM:
|
|
{
|
|
if (device->regkeys.enable_pm == NV_SWITCH_REGKEY_ENABLE_PM_YES)
|
|
{
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_ENABLEPM, 0);
|
|
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: ENABLEPM CMD failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return status;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_DISABLE_PM:
|
|
{
|
|
if (device->regkeys.enable_pm == NV_SWITCH_REGKEY_ENABLE_PM_YES)
|
|
{
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_DISABLEPM, 0);
|
|
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: DISABLEPM CMD failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return status;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_DISABLE_HEARTBEAT:
|
|
{
|
|
// NOP
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_PRE_HS:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_TRAFFIC_SETUP:
|
|
{
|
|
status = _nvswitch_init_link_post_active(link, flags);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_DISABLE_ERR_DETECT:
|
|
{
|
|
// Disable DL/PL interrupts
|
|
_nvswitch_disable_dlpl_interrupts(link);
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_LANE_DISABLE:
|
|
{
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_LANEDISABLE, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : LANEDISABLE CMD failed for link (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_LANE_SHUTDOWN:
|
|
{
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_LANESHUTDOWN, 0);
|
|
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : SHUTDOWN CMD failed for link (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_INITPHASE1:
|
|
{
|
|
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_INITPHASE1, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : INITPHASE1 failed for link (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_CONFIGURATION_ERROR,
|
|
NVBIT32(link->linkNumber), INITPHASE1_ERROR);
|
|
return NV_ERR_NVLINK_CONFIGURATION_ERROR;
|
|
}
|
|
|
|
// After INITPHASE1, apply NEA setting
|
|
nvswitch_setup_link_loopback_mode(device, link->linkNumber);
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_INITOPTIMIZE:
|
|
{
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_INITOPTIMIZE, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : INITOPTIMIZE failed for link (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_POST_INITOPTIMIZE:
|
|
{
|
|
// Poll for TRAINING_GOOD
|
|
status = nvswitch_minion_get_initoptimize_status_lr10(device, link->linkNumber);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s Error polling for INITOPTIMIZE TRAINING_GOOD. Link (%s):(%s)\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_TRAINING_ERROR, NVBIT32(link->linkNumber), INITOPTIMIZE_ERROR);
|
|
return NV_ERR_NVLINK_TRAINING_ERROR;
|
|
}
|
|
|
|
// Send INITTL DLCMD
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_INITTL, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : INITTL failed for link (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_TRAINING_ERROR, NVBIT32(link->linkNumber), INITTL_ERROR);
|
|
return NV_ERR_NVLINK_TRAINING_ERROR;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_INITNEGOTIATE:
|
|
{
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_INITNEGOTIATE, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : INITNEGOTIATE failed for link (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_LINKSTATE_POST_INITNEGOTIATE:
|
|
{
|
|
// Poll for CONFIG_GOOD
|
|
status = nvswitch_minion_get_initnegotiate_status_lr10(device, link->linkNumber);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s Error polling for INITNEGOTIATE CONFIG_GOOD. Link (%s):(%s)\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_CONFIGURATION_ERROR,
|
|
NVBIT32(link->linkNumber), INITNEGOTIATE_ERROR);
|
|
return NV_ERR_NVLINK_CONFIGURATION_ERROR;
|
|
}
|
|
else
|
|
{
|
|
nvswitch_store_topology_information(device, link);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Invalid mode specified.\n",
|
|
__FUNCTION__);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_get_dl_link_mode_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU64 *mode
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 link_state;
|
|
NvU32 val = 0;
|
|
|
|
*mode = NVLINK_LINKSTATE_OFF;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
// check if links are in reset
|
|
if (nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
*mode = NVLINK_LINKSTATE_RESET;
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _LINK_STATE);
|
|
|
|
link_state = DRF_VAL(_NVLDL_TOP, _LINK_STATE, _STATE, val);
|
|
|
|
switch (link_state)
|
|
{
|
|
case NV_NVLDL_TOP_LINK_STATE_STATE_INIT:
|
|
*mode = NVLINK_LINKSTATE_OFF;
|
|
break;
|
|
case NV_NVLDL_TOP_LINK_STATE_STATE_HWCFG:
|
|
*mode = NVLINK_LINKSTATE_DETECT;
|
|
break;
|
|
case NV_NVLDL_TOP_LINK_STATE_STATE_SWCFG:
|
|
*mode = NVLINK_LINKSTATE_SAFE;
|
|
break;
|
|
case NV_NVLDL_TOP_LINK_STATE_STATE_ACTIVE:
|
|
*mode = NVLINK_LINKSTATE_HS;
|
|
break;
|
|
case NV_NVLDL_TOP_LINK_STATE_STATE_FAULT:
|
|
*mode = NVLINK_LINKSTATE_FAULT;
|
|
break;
|
|
case NV_NVLDL_TOP_LINK_STATE_STATE_RCVY_AC:
|
|
case NV_NVLDL_TOP_LINK_STATE_STATE_RCVY_RX:
|
|
*mode = NVLINK_LINKSTATE_RECOVERY;
|
|
break;
|
|
default:
|
|
*mode = NVLINK_LINKSTATE_OFF;
|
|
break;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
void
|
|
nvswitch_corelib_get_uphy_load_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvBool *bUnlocked
|
|
)
|
|
{
|
|
*bUnlocked = NV_FALSE;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_set_tl_link_mode_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU64 mode,
|
|
NvU32 flags
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvlStatus status = NVL_SUCCESS;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
if (nvswitch_does_link_need_termination_enabled(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s: link #% is connected to a disabled remote end. Skipping TL link mode request!\n", __FUNCTION__, link->linkNumber);
|
|
|
|
// return SUCCESS to avoid errors being propogated
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case NVLINK_LINKSTATE_RESET:
|
|
{
|
|
// perform TL reset
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s: Performing TL Reset on link %d\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
|
|
status = nvswitch_request_tl_link_state_lr10(link,
|
|
NV_NVLIPT_LNK_CTRL_LINK_STATE_REQUEST_REQUEST_RESET,
|
|
flags == NVLINK_STATE_CHANGE_SYNC);
|
|
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: NvLink Reset has failed for link %d\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return status;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Invalid mode specified.\n",
|
|
__FUNCTION__);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_get_tl_link_mode_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU64 *mode
|
|
)
|
|
{
|
|
#if defined(INCLUDE_NVLINK_LIB)
|
|
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 link_state;
|
|
NvU32 val = 0;
|
|
|
|
*mode = NVLINK_LINKSTATE_OFF;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
// check if links are in reset
|
|
if (nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
*mode = NVLINK_LINKSTATE_RESET;
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
// Read state from NVLIPT HW
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT_LNK,
|
|
_NVLIPT_LNK, _CTRL_LINK_STATE_STATUS);
|
|
|
|
link_state = DRF_VAL(_NVLIPT_LNK, _CTRL_LINK_STATE_STATUS, _CURRENTLINKSTATE,
|
|
val);
|
|
|
|
switch(link_state)
|
|
{
|
|
case NV_NVLIPT_LNK_CTRL_LINK_STATE_STATUS_CURRENTLINKSTATE_ACTIVE:
|
|
*mode = NVLINK_LINKSTATE_HS;
|
|
break;
|
|
|
|
case NV_NVLIPT_LNK_CTRL_LINK_STATE_STATUS_CURRENTLINKSTATE_L2:
|
|
*mode = NVLINK_LINKSTATE_SLEEP;
|
|
break;
|
|
|
|
case NV_NVLIPT_LNK_CTRL_LINK_STATE_STATUS_CURRENTLINKSTATE_CONTAIN:
|
|
*mode = NVLINK_LINKSTATE_CONTAIN;
|
|
break;
|
|
|
|
default:
|
|
// Currently, only ACTIVE, L2 and CONTAIN states are supported
|
|
return NVL_ERR_INVALID_STATE;
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_set_tx_mode_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU64 mode,
|
|
NvU32 flags
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 tx_sublink_state;
|
|
NvU32 val;
|
|
NvlStatus status = NVL_SUCCESS;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
if (nvswitch_does_link_need_termination_enabled(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s: link #% is connected to a disabled remote end. Skipping TX mode request!\n", __FUNCTION__, link->linkNumber);
|
|
|
|
// return SUCCESS to avoid errors being propogated
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
// check if link is in reset
|
|
if (nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d is still in reset, cannot change sub-link state\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TX, _SLSM_STATUS_TX);
|
|
|
|
tx_sublink_state = DRF_VAL(_NVLDL_TX, _SLSM_STATUS_TX, _PRIMARY_STATE, val);
|
|
|
|
// Check if Sublink State Machine is ready to accept a sublink change request.
|
|
status = nvswitch_poll_sublink_state(device, link);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : SLSM not ready to accept a state change request for(%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case NVLINK_SUBLINK_STATE_TX_COMMON_MODE:
|
|
{
|
|
val = _nvswitch_init_dl_pll(link);
|
|
if (val != NVL_SUCCESS)
|
|
{
|
|
return val;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_TX_COMMON_MODE_DISABLE:
|
|
{
|
|
// Not applicable for NV IP
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_TX_DATA_READY:
|
|
{
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_INITDLPL, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: INITNVLDL CMD failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_INIT_ERROR,
|
|
NVBIT32(link->linkNumber), INITDLPL_ERROR);
|
|
return NV_ERR_NVLINK_INIT_ERROR;
|
|
}
|
|
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_INITLANEENABLE, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: INITLANEENABLE CMD failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
NVSWITCH_ASSERT_INFO(NV_ERR_NVLINK_INIT_ERROR, NVBIT32(link->linkNumber), INITLANEENABLE_ERROR);
|
|
return NV_ERR_NVLINK_INIT_ERROR;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_TX_PRBS_EN:
|
|
{
|
|
// Not needed with ALT
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_TX_POST_HS:
|
|
{
|
|
// NOP: In general, there is no point to downgrade *_PRBS_* and *_SCRAM_* values.
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_TX_EQ:
|
|
{
|
|
//TODO: To be implemented
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_TX_HS:
|
|
{
|
|
// Not needed with ALT
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_TX_SAFE:
|
|
{
|
|
if (tx_sublink_state == NV_NVLDL_TX_SLSM_STATUS_TX_PRIMARY_STATE_SAFE)
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : TX already in Safe mode for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
break;
|
|
}
|
|
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : Changing TX sublink state to Safe mode for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _SUBLINK_CHANGE);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _NEWSTATE, _SAFE, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _SUBLINK, _TX, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _ACTION, _SLSM_CHANGE, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _SUBLINK_CHANGE, val);
|
|
|
|
status = nvswitch_poll_sublink_state(device, link);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Error while changing TX sublink to Safe Mode for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_TX_OFF:
|
|
{
|
|
if (tx_sublink_state == NV_NVLDL_TX_SLSM_STATUS_TX_PRIMARY_STATE_OFF)
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : TX already OFF (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
break;
|
|
}
|
|
else if (tx_sublink_state == NV_NVLDL_TX_SLSM_STATUS_TX_PRIMARY_STATE_HS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : TX cannot be taken from HS to OFF directly for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return -NVL_ERR_GENERIC;
|
|
}
|
|
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : Changing TX sublink state to OFF for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _SUBLINK_CHANGE);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _COUNTDOWN, _IMMEDIATE, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _NEWSTATE, _OFF, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _SUBLINK, _TX, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _ACTION, _SLSM_CHANGE, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _SUBLINK_CHANGE, val);
|
|
|
|
status = nvswitch_poll_sublink_state(device, link);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Error while changing TX sublink to off Mode for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Invalid TX sublink mode specified.\n",
|
|
__FUNCTION__);
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_get_tx_mode_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU64 *mode,
|
|
NvU32 *subMode
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 tx_sublink_state;
|
|
NvU32 data = 0;
|
|
|
|
*mode = NVLINK_SUBLINK_STATE_TX_OFF;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
// check if link is in reset
|
|
if (nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
*mode = NVLINK_SUBLINK_STATE_TX_OFF;
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
data = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TX, _SLSM_STATUS_TX);
|
|
|
|
tx_sublink_state = DRF_VAL(_NVLDL_TX, _SLSM_STATUS_TX, _PRIMARY_STATE, data);
|
|
|
|
// Return NVLINK_SUBLINK_SUBSTATE_TX_STABLE for sub-state
|
|
*subMode = NVLINK_SUBLINK_SUBSTATE_TX_STABLE;
|
|
|
|
switch (tx_sublink_state)
|
|
{
|
|
case NV_NVLDL_TX_SLSM_STATUS_TX_PRIMARY_STATE_EIGHTH:
|
|
*mode = NVLINK_SUBLINK_STATE_TX_SINGLE_LANE;
|
|
break;
|
|
|
|
case NV_NVLDL_TX_SLSM_STATUS_TX_PRIMARY_STATE_HS:
|
|
*mode = NVLINK_SUBLINK_STATE_TX_HS;
|
|
break;
|
|
|
|
case NV_NVLDL_TX_SLSM_STATUS_TX_PRIMARY_STATE_TRAIN:
|
|
*mode = NVLINK_SUBLINK_STATE_TX_TRAIN;
|
|
break;
|
|
|
|
case NV_NVLDL_TX_SLSM_STATUS_TX_PRIMARY_STATE_SAFE:
|
|
*mode = NVLINK_SUBLINK_STATE_TX_SAFE;
|
|
break;
|
|
|
|
case NV_NVLDL_TX_SLSM_STATUS_TX_PRIMARY_STATE_OFF:
|
|
*mode = NVLINK_SUBLINK_STATE_TX_OFF;
|
|
break;
|
|
|
|
default:
|
|
*mode = NVLINK_SUBLINK_STATE_TX_OFF;
|
|
break;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_set_rx_mode_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU64 mode,
|
|
NvU32 flags
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 rx_sublink_state;
|
|
NvU32 val;
|
|
NvlStatus status = NVL_SUCCESS;
|
|
NvU32 delay_ns;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
if (nvswitch_does_link_need_termination_enabled(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s: link #% is connected to a disabled remote end. Skipping RX mode request!\n", __FUNCTION__, link->linkNumber);
|
|
|
|
// return SUCCESS to avoid errors being propogated
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
// check if link is in reset
|
|
if (nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d is still in reset, cannot change sub-link state\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_RX, _SLSM_STATUS_RX);
|
|
|
|
rx_sublink_state = DRF_VAL(_NVLDL_RX, _SLSM_STATUS_RX, _PRIMARY_STATE, val);
|
|
|
|
// Check if Sublink State Machine is ready to accept a sublink change request.
|
|
status = nvswitch_poll_sublink_state(device, link);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : SLSM not ready to accept a state change request for(%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case NVLINK_SUBLINK_STATE_RX_HS:
|
|
break;
|
|
|
|
case NVLINK_SUBLINK_STATE_RX_SAFE:
|
|
break;
|
|
|
|
case NVLINK_SUBLINK_STATE_RX_OFF:
|
|
{
|
|
if (rx_sublink_state == NV_NVLDL_RX_SLSM_STATUS_RX_PRIMARY_STATE_OFF)
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : RX already OFF (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
break;
|
|
}
|
|
else if (rx_sublink_state == NV_NVLDL_RX_SLSM_STATUS_RX_PRIMARY_STATE_HS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : RX cannot be taken from HS to OFF directly for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
status = -NVL_ERR_GENERIC;
|
|
return status;
|
|
}
|
|
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : Changing RX sublink state to OFF for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _SUBLINK_CHANGE);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _COUNTDOWN, _IMMEDIATE, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _OLDSTATE_MASK, _DONTCARE, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _NEWSTATE, _OFF, val);
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _SUBLINK, _RX, val);
|
|
|
|
// When changing RX sublink state use FORCE, otherwise it will fault.
|
|
val = FLD_SET_DRF(_NVLDL_TOP, _SUBLINK_CHANGE, _ACTION, _SLSM_FORCE, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLDL, _NVLDL_TOP, _SUBLINK_CHANGE, val);
|
|
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s : NV_NVLDL_TOP_SUBLINK_CHANGE = 0x%08x\n", __FUNCTION__, val);
|
|
|
|
status = nvswitch_poll_sublink_state(device, link);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Error while changing RX sublink to Off Mode for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_RX_RXCAL:
|
|
{
|
|
// Enable RXCAL in CFG_CTL_6, Delay 200us (bug 2551877), and check CFG_STATUS_0 for RXCAL_DONE=1.
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLPHYCTL_COMMON, _CFG_CTL_6);
|
|
val = FLD_SET_DRF(_NVLPHYCTL_COMMON, _CFG_CTL_6, _RXCAL , _ON, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLDL, _NVLPHYCTL_COMMON, _CFG_CTL_6, val);
|
|
|
|
if (IS_FMODEL(device) || IS_EMULATION(device) || IS_RTLSIM(device))
|
|
{
|
|
delay_ns = NVSWITCH_INTERVAL_1SEC_IN_NS;
|
|
}
|
|
else
|
|
{
|
|
delay_ns = 200 * NVSWITCH_INTERVAL_1USEC_IN_NS;
|
|
}
|
|
|
|
NVSWITCH_NSEC_DELAY(delay_ns);
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLPHYCTL_COMMON, _CFG_STATUS_0);
|
|
if (!FLD_TEST_DRF_NUM(_NVLPHYCTL_COMMON, _CFG_STATUS_0, _RXCAL_DONE, 0x1, val))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Timeout while waiting for RXCAL_DONE on link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_ERR_GENERIC;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case NVLINK_SUBLINK_STATE_RX_INIT_TERM:
|
|
{
|
|
// Invoke MINION routine to enable RX Termination
|
|
status = nvswitch_minion_set_rx_term_lr10(device, link->linkNumber);
|
|
|
|
if (status != NV_OK)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Error while setting RX INIT_TERM for (%s):(%s).\n",
|
|
__FUNCTION__, device->name, link->linkName);
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
default:
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s : Invalid RX sublink mode specified.\n",
|
|
__FUNCTION__);
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_get_rx_mode_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU64 *mode,
|
|
NvU32 *subMode
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvU32 rx_sublink_state;
|
|
NvU32 data = 0;
|
|
|
|
*mode = NVLINK_SUBLINK_STATE_RX_OFF;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
// check if link is in reset
|
|
if (nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
*mode = NVLINK_SUBLINK_STATE_RX_OFF;
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
data = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLDL, _NVLDL_RX, _SLSM_STATUS_RX);
|
|
|
|
rx_sublink_state = DRF_VAL(_NVLDL_RX, _SLSM_STATUS_RX, _PRIMARY_STATE, data);
|
|
|
|
// Return NVLINK_SUBLINK_SUBSTATE_RX_STABLE for sub-state
|
|
*subMode = NVLINK_SUBLINK_SUBSTATE_RX_STABLE;
|
|
|
|
switch (rx_sublink_state)
|
|
{
|
|
case NV_NVLDL_RX_SLSM_STATUS_RX_PRIMARY_STATE_HS:
|
|
*mode = NVLINK_SUBLINK_STATE_RX_HS;
|
|
break;
|
|
|
|
case NV_NVLDL_RX_SLSM_STATUS_RX_PRIMARY_STATE_TRAIN:
|
|
*mode = NVLINK_SUBLINK_STATE_RX_TRAIN;
|
|
break;
|
|
|
|
case NV_NVLDL_RX_SLSM_STATUS_RX_PRIMARY_STATE_SAFE:
|
|
*mode = NVLINK_SUBLINK_STATE_RX_SAFE;
|
|
break;
|
|
|
|
case NV_NVLDL_RX_SLSM_STATUS_RX_PRIMARY_STATE_EIGHTH:
|
|
*mode = NVLINK_SUBLINK_STATE_RX_SINGLE_LANE;
|
|
break;
|
|
|
|
case NV_NVLDL_RX_SLSM_STATUS_RX_PRIMARY_STATE_OFF:
|
|
*mode = NVLINK_SUBLINK_STATE_RX_OFF;
|
|
break;
|
|
|
|
default:
|
|
*mode = NVLINK_SUBLINK_STATE_RX_OFF;
|
|
break;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_set_rx_detect_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU32 flags
|
|
)
|
|
{
|
|
NvlStatus status;
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
|
|
if (nvswitch_does_link_need_termination_enabled(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s: link #% is connected to a disabled remote end. Skipping RxDet request!\n", __FUNCTION__, link->linkNumber);
|
|
|
|
// return SUCCESS to avoid errors being propogated
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
status = nvswitch_minion_send_command(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_TURING_RXDET, 0);
|
|
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Set RXDET failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return status;
|
|
}
|
|
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_corelib_get_rx_detect_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
NvlStatus status;
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
|
|
status = nvswitch_minion_get_rxdet_status_lr10(device, link->linkNumber);
|
|
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, WARN,
|
|
"%s: Get RXDET failed for link %d.\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return status;
|
|
}
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
void
|
|
nvswitch_corelib_training_complete_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
|
|
nvswitch_init_dlpl_interrupts(link);
|
|
|
|
_nvswitch_configure_reserved_throughput_counters(link);
|
|
|
|
if (nvswitch_lib_notify_client_events(device,
|
|
NVSWITCH_DEVICE_EVENT_PORT_UP) != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify PORT_UP event\n",
|
|
__FUNCTION__);
|
|
}
|
|
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_wait_for_tl_request_ready_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NVSWITCH_TIMEOUT timeout;
|
|
NvBool keepPolling;
|
|
NvU32 linkRequest;
|
|
#if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
|
|
NvU32 linkStatus, linkErr;
|
|
#endif
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLIPT_LNK, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_BAD_ARGS;
|
|
}
|
|
|
|
nvswitch_timeout_create(NVSWITCH_INTERVAL_1MSEC_IN_NS * 400, &timeout);
|
|
|
|
do
|
|
{
|
|
keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE;
|
|
|
|
linkRequest = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK , _NVLIPT_LNK , _CTRL_LINK_STATE_REQUEST);
|
|
|
|
if (FLD_TEST_DRF_NUM(_NVLIPT_LNK, _CTRL_LINK_STATE_REQUEST, _READY, 1, linkRequest))
|
|
{
|
|
return NVL_SUCCESS;
|
|
}
|
|
|
|
nvswitch_os_sleep(1);
|
|
}
|
|
while(keepPolling);
|
|
|
|
//
|
|
// NVSWITCH_PRINT is not defined for release builds,
|
|
// so this keeps compiler happy
|
|
//
|
|
#if defined(DEVELOP) || defined(DEBUG) || defined(NV_MODS)
|
|
linkStatus = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK , _NVLIPT_LNK , _CTRL_LINK_STATE_STATUS);
|
|
linkErr = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK , _NVLIPT_LNK , _ERR_STATUS_0);
|
|
#endif
|
|
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Timeout waiting for TL link state ready on link #%d! "
|
|
"NV_NVLIPT_LNK_CTRL_LINK_STATE_REQUEST = 0x%x, "
|
|
"NV_NVLIPT_LNK_CTRL_LINK_STATE_STATUS = 0x%x, "
|
|
"NV_NVLIPT_LNK_ERR_STATUS_0 = 0x%x\n",
|
|
__FUNCTION__, link->linkNumber, linkRequest, linkStatus, linkErr);
|
|
|
|
return -NVL_ERR_GENERIC;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_request_tl_link_state_lr10
|
|
(
|
|
nvlink_link *link,
|
|
NvU32 tlLinkState,
|
|
NvBool bSync
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
NvlStatus status = NVL_SUCCESS;
|
|
NvU32 linkStatus;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLIPT_LNK, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return -NVL_UNBOUND_DEVICE;
|
|
}
|
|
|
|
// Wait for the TL link state register to report ready
|
|
status = nvswitch_wait_for_tl_request_ready_lr10(link);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
// Request RESET state through CTRL_LINK_STATE_REQUEST
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK, _NVLIPT_LNK, _CTRL_LINK_STATE_REQUEST,
|
|
DRF_NUM(_NVLIPT_LNK, _CTRL_LINK_STATE_REQUEST, _REQUEST, tlLinkState));
|
|
|
|
if (bSync)
|
|
{
|
|
// Wait for the TL link state register to complete
|
|
status = nvswitch_wait_for_tl_request_ready_lr10(link);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
// Check for state requested
|
|
linkStatus = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK , _NVLIPT_LNK , _CTRL_LINK_STATE_STATUS);
|
|
|
|
if (DRF_VAL(_NVLIPT_LNK, _CTRL_LINK_STATE_STATUS, _CURRENTLINKSTATE, linkStatus) !=
|
|
tlLinkState)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: TL link state request to state 0x%x for link #%d did not complete!\n",
|
|
__FUNCTION__, tlLinkState, link->linkNumber);
|
|
return -NVL_ERR_GENERIC;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
void
|
|
nvswitch_execute_unilateral_link_shutdown_lr10
|
|
(
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
nvswitch_device *device = link->dev->pDevInfo;
|
|
|
|
if (!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, link->linkNumber))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d invalid\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Perform unilateral shutdown
|
|
// This follows "Unilateral variant" from
|
|
// NVLink 3.x Shutdown (confluence page ID: 164573291)
|
|
//
|
|
// Status is explicitly ignored here since we are required to soldier-on
|
|
// in this scenario
|
|
//
|
|
nvswitch_corelib_set_dl_link_mode_lr10(link, NVLINK_LINKSTATE_DISABLE_PM, 0);
|
|
nvswitch_corelib_set_dl_link_mode_lr10(link, NVLINK_LINKSTATE_DISABLE_ERR_DETECT, 0);
|
|
nvswitch_corelib_set_dl_link_mode_lr10(link, NVLINK_LINKSTATE_LANE_DISABLE, 0);
|
|
nvswitch_corelib_set_dl_link_mode_lr10(link, NVLINK_LINKSTATE_OFF, 0);
|
|
}
|
|
|
|
static NvU32
|
|
_nvswitch_get_nvlink_linerate_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 val
|
|
)
|
|
{
|
|
NvU32 lineRate = 0;
|
|
switch (val)
|
|
{
|
|
case NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_16G:
|
|
lineRate = NV_NVLIPT_LNK_CTRL_SYSTEM_LINK_CLK_CTRL_LINE_RATE_16_00000_GBPS;
|
|
break;
|
|
case NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_20G:
|
|
lineRate = NV_NVLIPT_LNK_CTRL_SYSTEM_LINK_CLK_CTRL_LINE_RATE_20_00000_GBPS;
|
|
break;
|
|
case NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_25G:
|
|
lineRate = NV_NVLIPT_LNK_CTRL_SYSTEM_LINK_CLK_CTRL_LINE_RATE_25_00000_GBPS;
|
|
break;
|
|
case NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_32G:
|
|
lineRate = NV_NVLIPT_LNK_CTRL_SYSTEM_LINK_CLK_CTRL_LINE_RATE_32_00000_GBPS;
|
|
break;
|
|
case NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_40G:
|
|
lineRate = NV_NVLIPT_LNK_CTRL_SYSTEM_LINK_CLK_CTRL_LINE_RATE_40_00000_GBPS;
|
|
break;
|
|
case NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_50G:
|
|
lineRate = NV_NVLIPT_LNK_CTRL_SYSTEM_LINK_CLK_CTRL_LINE_RATE_50_00000_GBPS;
|
|
break;
|
|
case NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_53_12500G:
|
|
lineRate = NV_NVLIPT_LNK_CTRL_SYSTEM_LINK_CLK_CTRL_LINE_RATE_53_12500_GBPS;
|
|
break;
|
|
default:
|
|
NVSWITCH_PRINT(device, SETUP, "%s:ERROR LINE_RATE = 0x%x requested by regkey\n",
|
|
__FUNCTION__, lineRate);
|
|
lineRate = NV_NVLIPT_LNK_CTRL_SYSTEM_LINK_CLK_CTRL_LINE_RATE_ILLEGAL_LINE_RATE;
|
|
}
|
|
return lineRate;
|
|
}
|
|
|
|
void
|
|
nvswitch_setup_link_system_registers_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
NvU32 regval = 0;
|
|
NvU32 fldval = 0;
|
|
NvU32 lineRate = 0;
|
|
NVLINK_CONFIG_DATA_LINKENTRY *vbios_link_entry = NULL;
|
|
NVSWITCH_BIOS_NVLINK_CONFIG *bios_config;
|
|
NvU32 base_entry;
|
|
|
|
bios_config = nvswitch_get_bios_nvlink_config(device);
|
|
if ((bios_config == NULL) || (bios_config->bit_address == 0))
|
|
{
|
|
NVSWITCH_PRINT(device, WARN,
|
|
"%s: VBIOS NvLink configuration table not found\n",
|
|
__FUNCTION__);
|
|
}
|
|
|
|
//
|
|
// Identify the valid link entry to update. If not, proceed with the default settings
|
|
//
|
|
if ((bios_config == NULL) || (bios_config->bit_address == 0))
|
|
{
|
|
NVSWITCH_PRINT(device, SETUP,
|
|
"%s: No override with VBIOS - VBIOS NvLink configuration table not found\n",
|
|
__FUNCTION__);
|
|
}
|
|
else
|
|
{
|
|
base_entry = bios_config->link_base_entry_assigned;
|
|
|
|
vbios_link_entry = &bios_config->link_vbios_entry[base_entry][link->linkNumber];
|
|
}
|
|
|
|
regval = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT_LNK,
|
|
_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CLK_CTRL);
|
|
|
|
// LINE_RATE SYSTEM register
|
|
if (device->regkeys.nvlink_speed_control != NV_SWITCH_REGKEY_SPEED_CONTROL_SPEED_DEFAULT)
|
|
{
|
|
lineRate = _nvswitch_get_nvlink_linerate_lr10(device, device->regkeys.nvlink_speed_control);
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CLK_CTRL,
|
|
_LINE_RATE, lineRate, regval);
|
|
NVSWITCH_PRINT(device, SETUP, "%s: LINE_RATE = 0x%x requested by regkey\n",
|
|
__FUNCTION__, lineRate);
|
|
}
|
|
|
|
// REFERENCE_CLOCK_MODE SYSTEM register
|
|
if (device->regkeys.reference_clock_mode != NV_SWITCH_REGKEY_REFERENCE_CLOCK_MODE_DEFAULT)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CLK_CTRL,
|
|
_REFERENCE_CLOCK_MODE, device->regkeys.reference_clock_mode, regval);
|
|
NVSWITCH_PRINT(device, SETUP, "%s: REFERENCE_CLOCK_MODE = 0x%x requested by regkey\n",
|
|
__FUNCTION__, device->regkeys.reference_clock_mode);
|
|
}
|
|
else if (vbios_link_entry != NULL)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CLK_CTRL, _REFERENCE_CLOCK_MODE,
|
|
DRF_VAL(_NVLINK_VBIOS,_PARAM3,_REFERENCE_CLOCK_MODE, vbios_link_entry->nvLinkparam3),
|
|
regval);
|
|
}
|
|
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLIPT_LNK,
|
|
_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CLK_CTRL, regval);
|
|
|
|
// TXTRAIN SYSTEM register
|
|
regval = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT_LNK,
|
|
_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL);
|
|
|
|
fldval = DRF_VAL(_SWITCH_REGKEY, _TXTRAIN_CONTROL, _FOM_FORMAT,
|
|
device->regkeys.txtrain_control);
|
|
if (fldval != NV_SWITCH_REGKEY_TXTRAIN_CONTROL_FOM_FORMAT_NOP)
|
|
{
|
|
NVSWITCH_PRINT(device, SETUP, "%s: FOM_FORMAT = 0x%x requested by regkey\n",
|
|
__FUNCTION__, fldval);
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL,
|
|
_TXTRAIN_FOM_FORMAT, fldval, regval);
|
|
}
|
|
else if (vbios_link_entry != NULL)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CHANNEL_CTRL, _TXTRAIN_FOM_FORMAT,
|
|
DRF_VAL(_NVLINK_VBIOS,_PARAM5,_TXTRAIN_FOM_FORMAT, vbios_link_entry->nvLinkparam5),
|
|
regval);
|
|
}
|
|
|
|
fldval = DRF_VAL(_SWITCH_REGKEY, _TXTRAIN_CONTROL, _OPTIMIZATION_ALGORITHM,
|
|
device->regkeys.txtrain_control);
|
|
if (fldval != NV_SWITCH_REGKEY_TXTRAIN_CONTROL_OPTIMIZATION_ALGORITHM_NOP)
|
|
{
|
|
NVSWITCH_PRINT(device, SETUP, "%s: OPTIMIZATION_ALGORITHM = 0x%x requested by regkey\n",
|
|
__FUNCTION__, fldval);
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL,
|
|
_TXTRAIN_OPTIMIZATION_ALGORITHM, fldval, regval);
|
|
}
|
|
else if (vbios_link_entry != NULL)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CHANNEL_CTRL, _TXTRAIN_OPTIMIZATION_ALGORITHM,
|
|
vbios_link_entry->nvLinkparam4, regval);
|
|
}
|
|
|
|
fldval = DRF_VAL(_SWITCH_REGKEY, _TXTRAIN_CONTROL, _ADJUSTMENT_ALGORITHM,
|
|
device->regkeys.txtrain_control);
|
|
if (fldval != NV_SWITCH_REGKEY_TXTRAIN_CONTROL_ADJUSTMENT_ALGORITHM_NOP)
|
|
{
|
|
NVSWITCH_PRINT(device, SETUP, "%s: ADJUSTMENT_ALGORITHM = 0x%x requested by regkey\n",
|
|
__FUNCTION__, fldval);
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL,
|
|
_TXTRAIN_ADJUSTMENT_ALGORITHM, fldval, regval);
|
|
}
|
|
else if (vbios_link_entry != NULL)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CHANNEL_CTRL, _TXTRAIN_ADJUSTMENT_ALGORITHM,
|
|
DRF_VAL(_NVLINK_VBIOS,_PARAM5,_TXTRAIN_ADJUSTMENT_ALGORITHM, vbios_link_entry->nvLinkparam5),
|
|
regval);
|
|
}
|
|
|
|
fldval = DRF_VAL(_SWITCH_REGKEY, _TXTRAIN_CONTROL, _MINIMUM_TRAIN_TIME_MANTISSA,
|
|
device->regkeys.txtrain_control);
|
|
if (fldval != NV_SWITCH_REGKEY_TXTRAIN_CONTROL_MINIMUM_TRAIN_TIME_MANTISSA_NOP)
|
|
{
|
|
NVSWITCH_PRINT(device, SETUP, "%s: MINIMUM_TRAIN_TIME_MANTISSA = 0x%x requested by regkey\n",
|
|
__FUNCTION__, fldval);
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL,
|
|
_TXTRAIN_MINIMUM_TRAIN_TIME_MANTISSA, fldval, regval);
|
|
}
|
|
else if (vbios_link_entry != NULL)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CHANNEL_CTRL, _TXTRAIN_MINIMUM_TRAIN_TIME_MANTISSA,
|
|
DRF_VAL(_NVLINK_VBIOS,_PARAM6,_TXTRAIN_MINIMUM_TRAIN_TIME_MANTISSA, vbios_link_entry->nvLinkparam6),
|
|
regval);
|
|
}
|
|
|
|
fldval = DRF_VAL(_SWITCH_REGKEY, _TXTRAIN_CONTROL, _MINIMUM_TRAIN_TIME_EXPONENT,
|
|
device->regkeys.txtrain_control);
|
|
if (fldval != NV_SWITCH_REGKEY_TXTRAIN_CONTROL_MINIMUM_TRAIN_TIME_EXPONENT_NOP)
|
|
{
|
|
NVSWITCH_PRINT(device, SETUP, "%s: MINIMUM_TRAIN_TIME_EXPONENT = 0x%x requested by regkey\n",
|
|
__FUNCTION__, fldval);
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL,
|
|
_TXTRAIN_MINIMUM_TRAIN_TIME_EXPONENT, fldval, regval);
|
|
}
|
|
else if (vbios_link_entry != NULL)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CHANNEL_CTRL, _TXTRAIN_MINIMUM_TRAIN_TIME_EXPONENT,
|
|
DRF_VAL(_NVLINK_VBIOS,_PARAM6,_TXTRAIN_MINIMUM_TRAIN_TIME_EXPONENT, vbios_link_entry->nvLinkparam6),
|
|
regval);
|
|
}
|
|
|
|
// AC vs DC mode SYSTEM register
|
|
if (link->ac_coupled)
|
|
{
|
|
//
|
|
// In NVL3.0, ACMODE is handled by MINION in the INITPHASE1 command
|
|
// Here we just setup the register with the proper info
|
|
//
|
|
NVSWITCH_PRINT(device, SETUP, "%s: AC_DC_MODE = 0x%x\n",
|
|
__FUNCTION__, DRF_VAL(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CHANNEL_CTRL,
|
|
_AC_DC_MODE, regval));
|
|
regval = FLD_SET_DRF(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL,
|
|
_AC_DC_MODE, _AC, regval);
|
|
}
|
|
else if (vbios_link_entry != NULL)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CHANNEL_CTRL, _AC_DC_MODE,
|
|
DRF_VAL(_NVLINK_VBIOS, _PARAM0, _ACDC_MODE, vbios_link_entry->nvLinkparam0),
|
|
regval);
|
|
}
|
|
|
|
if (device->regkeys.block_code_mode != NV_SWITCH_REGKEY_BLOCK_CODE_MODE_DEFAULT)
|
|
{
|
|
NVSWITCH_PRINT(device, SETUP, "%s: BLOCK_CODE_MODE = 0x%x requested by regkey\n",
|
|
__FUNCTION__, device->regkeys.block_code_mode);
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL,
|
|
_BLOCK_CODE_MODE, device->regkeys.block_code_mode, regval);
|
|
}
|
|
else if (vbios_link_entry != NULL)
|
|
{
|
|
regval = FLD_SET_DRF_NUM(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_CHANNEL_CTRL, _BLOCK_CODE_MODE,
|
|
DRF_VAL(_NVLINK_VBIOS, _PARAM3, _CLOCK_MODE_BLOCK_CODE, vbios_link_entry->nvLinkparam3),
|
|
regval);
|
|
}
|
|
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLIPT_LNK,
|
|
_NVLIPT_LNK_CTRL_SYSTEM_LINK, _CHANNEL_CTRL, regval);
|
|
|
|
// Disable L2 (Bug 3176196)
|
|
regval = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber, NVLIPT_LNK, _NVLIPT_LNK, _CTRL_SYSTEM_LINK_AN1_CTRL);
|
|
regval = FLD_SET_DRF(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_AN1_CTRL, _PWRM_L2_ENABLE, _DISABLE, regval);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber, NVLIPT_LNK, _NVLIPT_LNK, _CTRL_SYSTEM_LINK_AN1_CTRL, regval);
|
|
|
|
// SW WAR: Bug 3364420
|
|
nvswitch_apply_recal_settings(device, link);
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
nvswitch_load_link_disable_settings_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
NvU32 val;
|
|
NVLINK_CONFIG_DATA_LINKENTRY *vbios_link_entry = NULL;
|
|
NVSWITCH_BIOS_NVLINK_CONFIG *bios_config;
|
|
|
|
bios_config = nvswitch_get_bios_nvlink_config(device);
|
|
if ((bios_config == NULL) || (bios_config->bit_address == 0))
|
|
{
|
|
NVSWITCH_PRINT(device, WARN,
|
|
"%s: VBIOS NvLink configuration table not found\n",
|
|
__FUNCTION__);
|
|
}
|
|
|
|
// SW CTRL - clear out LINK_DISABLE on driver load
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK, _NVLIPT_LNK, _CTRL_SW_LINK_MODE_CTRL);
|
|
val = FLD_SET_DRF(_NVLIPT_LNK, _CTRL_SW_LINK_MODE_CTRL, _LINK_DISABLE,
|
|
_ENABLED, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK, _NVLIPT_LNK, _CTRL_SW_LINK_MODE_CTRL, val);
|
|
|
|
//
|
|
// SYSTEM CTRL
|
|
// If the SYSTEM_CTRL setting had been overidden by another entity,
|
|
// it should also be locked, so this write would not take effect.
|
|
//
|
|
if (bios_config != NULL)
|
|
{
|
|
vbios_link_entry = &bios_config->link_vbios_entry[bios_config->link_base_entry_assigned][link->linkNumber];
|
|
}
|
|
|
|
val = NVSWITCH_LINK_RD32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK, _NVLIPT_LNK, _CTRL_SYSTEM_LINK_MODE_CTRL);
|
|
|
|
if ((vbios_link_entry != NULL) &&
|
|
(FLD_TEST_DRF(_NVLINK_VBIOS,_PARAM0, _LINK, _DISABLE, vbios_link_entry->nvLinkparam0)))
|
|
{
|
|
if (!nvswitch_is_link_in_reset(device, link))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: link #%d is not in reset, cannot set LINK_DISABLE\n",
|
|
__FUNCTION__, link->linkNumber);
|
|
return;
|
|
}
|
|
val = FLD_SET_DRF(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_MODE_CTRL, _LINK_DISABLE,
|
|
_DISABLED, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK, _NVLIPT_LNK, _CTRL_SYSTEM_LINK_MODE_CTRL, val);
|
|
|
|
// Set link to invalid and unregister from corelib
|
|
device->link[link->linkNumber].valid = NV_FALSE;
|
|
nvlink_lib_unregister_link(link);
|
|
nvswitch_destroy_link(link);
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
val = FLD_SET_DRF(_NVLIPT_LNK, _CTRL_SYSTEM_LINK_MODE_CTRL, _LINK_DISABLE,
|
|
_ENABLED, val);
|
|
NVSWITCH_LINK_WR32_LR10(device, link->linkNumber,
|
|
NVLIPT_LNK, _NVLIPT_LNK, _CTRL_SYSTEM_LINK_MODE_CTRL, val);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
nvswitch_reset_persistent_link_hw_state_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
NvU32 linkNumber
|
|
)
|
|
{
|
|
// Not Implemented for LR10
|
|
}
|
|
|
|
void
|
|
nvswitch_apply_recal_settings_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
// Not supported on LR10
|
|
return;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_launch_ALI_link_training_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link,
|
|
NvBool bSync
|
|
)
|
|
{
|
|
return NVL_ERR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_reset_and_train_link_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
return NVL_ERR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NvBool
|
|
nvswitch_does_link_need_termination_enabled_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link *link
|
|
)
|
|
{
|
|
#if defined(INCLUDE_NVLINK_LIB)
|
|
NvU32 i;
|
|
NvU32 physicalId;
|
|
lr10_device *chip_device;
|
|
|
|
physicalId = nvswitch_read_physical_id(device);
|
|
chip_device = NVSWITCH_GET_CHIP_DEVICE_LR10(device);
|
|
if (chip_device == NULL)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR,
|
|
"%s: Failed to get lr10 chip device!\n", __FUNCTION__);
|
|
return NV_FALSE;
|
|
}
|
|
|
|
//
|
|
// If disabledRemoteEndLinkMask has not been cached then
|
|
// using the switch's physicalId search nvswitchDisconnetedRemoteLinkMasks
|
|
// til a match is found then copy out the linkMask to the chip_device
|
|
// Only run this operation if there is a registed device with a reduced
|
|
// nvlink config
|
|
//
|
|
if (chip_device->bDisabledRemoteEndLinkMaskCached == NV_FALSE)
|
|
{
|
|
chip_device->disabledRemoteEndLinkMask = 0;
|
|
if (nvlink_lib_is_registerd_device_with_reduced_config())
|
|
{
|
|
for (i = 0; i < NUM_SWITCH_WITH_DISCONNETED_REMOTE_LINK; ++i)
|
|
{
|
|
if (nvswitchDisconnetedRemoteLinkMasks[i].switchPhysicalId == physicalId)
|
|
{
|
|
chip_device->disabledRemoteEndLinkMask =
|
|
nvswitchDisconnetedRemoteLinkMasks[i].linkMask;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
chip_device->bDisabledRemoteEndLinkMaskCached = NV_TRUE;
|
|
}
|
|
|
|
// return NV_TRUE if the link is inside of disabledRemoteEndLinkMask
|
|
return ((BIT64(link->linkNumber) & chip_device->disabledRemoteEndLinkMask) != 0);
|
|
#else
|
|
return NV_FALSE;
|
|
#endif //defined(INCLUDE_NVLINK_LIB)
|
|
}
|
|
|
|
NvlStatus
|
|
nvswitch_link_termination_setup_lr10
|
|
(
|
|
nvswitch_device *device,
|
|
nvlink_link* link
|
|
)
|
|
{
|
|
NvlStatus status;
|
|
NvU32 linkId = link->linkNumber;
|
|
|
|
// Sanity check
|
|
if ((link == NULL) ||
|
|
(linkId >= NVSWITCH_NVLINK_MAX_LINKS) ||
|
|
!NVSWITCH_IS_LINK_ENG_VALID_LR10(device, NVLDL, linkId))
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Link %d is invalid!\n", __FUNCTION__, linkId);
|
|
return NVL_BAD_ARGS;
|
|
}
|
|
|
|
// Sanity check nvlink version
|
|
if (link->version != NVLINK_DEVICE_VERSION_30)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Link %d: only nvlink version 3.0 can run the termination setup\n",
|
|
__FUNCTION__, linkId);
|
|
return NVL_BAD_ARGS;
|
|
}
|
|
|
|
// Send INITPHASE1 to the link
|
|
status = nvswitch_minion_send_command_lr10(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_INITPHASE1, 0);
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to send initphase1 to link %d", __FUNCTION__, linkId);
|
|
return NVL_ERR_INVALID_STATE;
|
|
}
|
|
|
|
// Send INITRXTXTERM to the link
|
|
nvswitch_minion_send_command_lr10(device, link->linkNumber,
|
|
NV_MINION_NVLINK_DL_CMD_COMMAND_INITRXTXTERM, 0);
|
|
|
|
if (status != NVL_SUCCESS)
|
|
{
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to send INITRXTXTERM to link %d", __FUNCTION__, linkId);
|
|
}
|
|
|
|
NVSWITCH_PRINT(device, INFO,
|
|
"%s: enabled termination for switchPhysicalId %d link# %d\n",
|
|
__FUNCTION__, nvswitch_read_physical_id(device), linkId);
|
|
|
|
return NVL_SUCCESS;
|
|
}
|