From 8a43cf10fb08c169d9f64868c977ff8fa0685244 Mon Sep 17 00:00:00 2001 From: Revanth Kumar Uppala Date: Fri, 16 May 2025 08:52:50 +0000 Subject: [PATCH] osi: Add RX_EQ training via SW override method Add RX_EQ training after mgbe link up to overcome insertion loss Bug 5277708 Bug 5017313 Change-Id: I19270c68cc570b3320c1db24298439cfbf412170 Signed-off-by: Revanth Kumar Uppala (cherry picked from commit ac35e507b220de89de9d856e2ba0cdae59656b1f) Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/3383664 Reviewed-by: Srinivas Ramachandran Reviewed-by: Narayana Reddy P Reviewed-by: Bhadram Varka Reviewed-by: svcacv --- include/osi_core.h | 12 ++++ osi/core/core_local.h | 3 + osi/core/xpcs.c | 137 ++++++++++++++++++++++++++++++++++++++++++ osi/core/xpcs.h | 36 +++++++++++ 4 files changed, 188 insertions(+) diff --git a/include/osi_core.h b/include/osi_core.h index d88a55a..d65917f 100644 --- a/include/osi_core.h +++ b/include/osi_core.h @@ -776,6 +776,16 @@ typedef my_lint_64 nvel64_t; /** @} */ #endif +/** + * @addtogroup RX EQ related information + * + * @brief RX EQ Software override + * @{ + */ +/** @brief RX EQ Software override is enabled */ +#define OSI_RX_EQ_SW_OVRD 1U +/** @} */ + struct osi_core_priv_data; /** @@ -1892,6 +1902,8 @@ struct osi_core_priv_data { nveu32_t skip_usxgmii_an; /** MAC common interrupt received */ nveu32_t mac_common_intr_rcvd; + /** Flag to enable pcs RX EQ SW override logic */ + nveu32_t pcs_rx_eq_sw_ovrd_en; }; /** diff --git a/osi/core/core_local.h b/osi/core/core_local.h index 10bf209..28d37de 100644 --- a/osi/core/core_local.h +++ b/osi/core/core_local.h @@ -613,15 +613,18 @@ static inline nveu64_t osi_update_stats_counter(nveu64_t last_value, */ #define RETRY_COUNT 1000U #define RETRY_DELAY 1U +#define OSI_DELAY_2US 2U #define OSI_DELAY_4US 4U #define OSI_DELAY_10US 10U #ifndef OSI_STRIPPED_LIB #define OSI_DELAY_100US 100U #endif #define OSI_DELAY_200US 200U +#define OSI_DELAY_500US 500U #define OSI_DELAY_1000US 1000U #define OSI_DELAY_10000US 10000U #define OSI_DELAY_30000US 30000U +#define OSI_DELAY_1000000US 1000000U /** @} */ diff --git a/osi/core/xpcs.c b/osi/core/xpcs.c index 77a795a..2aba507 100644 --- a/osi/core/xpcs.c +++ b/osi/core/xpcs.c @@ -575,6 +575,136 @@ fail: return ret; } +/** + * @brief xpcs_rx_eq_sw_override - Execute RX EQ training + * + * Algorithm: This routine executes RX EQ training through + * sw override method. + * + * @param[in] osi_core: OSI core data structure. + * + * @retval 0 on success + * @retval -1 on failure. + */ +nve32_t xpcs_rx_eq_sw_override(struct osi_core_priv_data *osi_core) +{ + nveu32_t val = 0; + nve32_t ret = 0; + nveu32_t count; + nve32_t cond; + nveu32_t rx_eq_retry = RETRY_COUNT; + + osi_writela(osi_core, XPCS_WRAP_UPHY_RX_CTRL_12_0_SLEEP_DLY, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_12_0); + + val = osi_readla(osi_core, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_12_0); + if (val != XPCS_WRAP_UPHY_RX_CTRL_12_0_SLEEP_DLY) { + ret = -1; + goto fail; + } + + val = osi_readla(osi_core, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + + val |= XPCS_WRAP_UPHY_RX_CTRL_0_0_PRE_RX_EQ_MASK_1; + + val &= ~(XPCS_WRAP_UPHY_RX_CTRL_0_0_PRE_RX_EQ_MASK_2); + + osi_writela(osi_core, val, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + + val = osi_readla(osi_core, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + /* Enable RX_SW_OVRD */ + val |= XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_SW_OVRD; + osi_writela(osi_core, val, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + + /* wait 1 second */ + osi_core->osd_ops.usleep(OSI_DELAY_1000000US); + + val = osi_readla(osi_core, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + /* RX_EQ_RESET */ + val |= XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_EQ_RESET; + osi_writela(osi_core, val, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + + cond = COND_NOT_MET; + count = 0; + while (cond == COND_NOT_MET) { + val = osi_readla(osi_core, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + + if ((val & XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_EQ_RESET) != 0) { + if (count > rx_eq_retry) { + ret = -1; + OSI_CORE_INFO(osi_core->osd, OSI_LOG_ARG_HW_FAIL, + "RX_EQ_RESET failed\n", 0ULL); + goto fail; // RX_EQ_RESET failed + } + count++; + osi_core->osd_ops.udelay(OSI_DELAY_2US); + } else { + cond = COND_MET; + } + } + + /* wait 1 second */ + osi_core->osd_ops.usleep(OSI_DELAY_1000000US); + + /* RX_EQ_TRAIN_EN */ + val |= XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_EQ_TRAIN_EN; + osi_writela(osi_core, val, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + + /* Poll until bit 11 clears or timeout */ + + cond = COND_NOT_MET; + count = 0; + while (cond == COND_NOT_MET) { + val = osi_readla(osi_core, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + + if ((val & XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_EQ_TRAIN_EN) != 0) { + if (count > rx_eq_retry) { + ret = -1; + OSI_CORE_INFO(osi_core->osd, OSI_LOG_ARG_HW_FAIL, + "RX_EQ_TRAIN_EN failed\n", 0ULL); + goto fail; // RX_EQ_TRAIN_EN failed + } + count++; + osi_core->osd_ops.usleep(OSI_DELAY_500US); + } else { + cond = COND_MET; + } + } + + /* Disable RX_SW_OVRD */ + val &= ~XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_SW_OVRD; + osi_writela(osi_core, val, + (nveu8_t *)osi_core->xpcs_base + + T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0); + + /* wait 2 micro seconds */ + osi_core->osd_ops.udelay(OSI_DELAY_2US); + +fail: + return ret; +} + /** * @brief xpcs_lane_bring_up - Bring up UPHY Tx/Rx lanes * @@ -769,6 +899,13 @@ step10: OSI_CORE_INFO(osi_core->osd, OSI_LOG_ARG_HW_FAIL, "PCS block lock SUCCESS\n", 0ULL); } + + if (osi_core->pcs_rx_eq_sw_ovrd_en == OSI_RX_EQ_SW_OVRD) { + if (xpcs_rx_eq_sw_override(osi_core)) { + ret = -1; + } + } + fail: return ret; } diff --git a/osi/core/xpcs.h b/osi/core/xpcs.h index 282a7c1..907de0c 100644 --- a/osi/core/xpcs.h +++ b/osi/core/xpcs.h @@ -71,6 +71,8 @@ #define T26X_XPCS_WRAP_UPHY_RX_CTRL_2 0x8040 #define T26X_XPCS_WRAP_UPHY_RX_CTRL_3 0x8044 #define T26X_XPCS_WRAP_UPHY_TIMEOUT_CONTROL_0_0 0x8070 +#define T26X_XPCS_WRAP_UPHY_RX_CTRL_0_0 0x8034 +#define T26X_XPCS_WRAP_UPHY_RX_CTRL_12_0 0x8058 /** @} */ @@ -195,6 +197,13 @@ #define XPCS_SR_PMA_KR_FEC_CTRL_FEC_EN OSI_BIT(0) #define XPCS_SR_PMA_KR_FEC_CTRL_EN_ERR_IND OSI_BIT(1) +#define XPCS_WRAP_UPHY_RX_CTRL_0_0_PRE_RX_EQ_MASK_1 OSI_BIT(0) | OSI_BIT(10) +#define XPCS_WRAP_UPHY_RX_CTRL_0_0_PRE_RX_EQ_MASK_2 OSI_BIT(4) | OSI_BIT(5) | OSI_BIT(6) | OSI_BIT(7) +#define XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_EQ_TRAIN_EN OSI_BIT(11) +#define XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_EQ_RESET OSI_BIT(12) +#define XPCS_WRAP_UPHY_RX_CTRL_0_0_RX_SW_OVRD OSI_BIT(31) +#define XPCS_WRAP_UPHY_RX_CTRL_12_0_SLEEP_DLY 0x200U + #ifdef HSI_SUPPORT #define XPCS_WRAP_INTERRUPT_CONTROL 0x8048 #define T26X_XPCS_WRAP_INTERRUPT_CONTROL 0x8084 @@ -327,4 +336,31 @@ static inline nve32_t xpcs_write_safety(struct osi_core_priv_data *osi_core, #endif /* !OSI_STRIPPED_LIB */ return ret; } + +/** + * @brief + * Description: Execute RX EQ training through SW Override method. + * + * @param[in] osi_core: A pointer to the osi_core_priv_data structure + * * Range: A non-null pointer to NVETHERNETRM_PIF$osi_core_priv_data structure. + * * Refer NVETHERNETRM_PIF$osi_core_priv_data + * + * @usage + * - Allowed context for the API call + * - Interrupt handler: No + * - Signal handler: No + * - Thread safe: No + * - Async/Sync: Sync + * - Required Privileges: None + * - API Group: + * - Initialization: Yes + * - Run time: No + * - De-initialization: No + * + * @return + * 0 on success + * -1 on failure + * + */ +nve32_t xpcs_rx_eq_sw_override(struct osi_core_priv_data *osi_core); #endif /* INCLUDED_XPCS_H_ */