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 <ruppala@nvidia.com>
(cherry picked from commit ac35e507b220de89de9d856e2ba0cdae59656b1f)
Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/3383664
Reviewed-by: Srinivas Ramachandran <srinivasra@nvidia.com>
Reviewed-by: Narayana Reddy P <narayanr@nvidia.com>
Reviewed-by: Bhadram Varka <vbhadram@nvidia.com>
Reviewed-by: svcacv <svcacv@nvidia.com>
This commit is contained in:
Revanth Kumar Uppala
2025-05-16 08:52:50 +00:00
committed by Amulya Yarlagadda
parent 53c6e3ffc4
commit 8a43cf10fb
4 changed files with 188 additions and 0 deletions

View File

@@ -776,6 +776,16 @@ typedef my_lint_64 nvel64_t;
/** @} */ /** @} */
#endif #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; struct osi_core_priv_data;
/** /**
@@ -1892,6 +1902,8 @@ struct osi_core_priv_data {
nveu32_t skip_usxgmii_an; nveu32_t skip_usxgmii_an;
/** MAC common interrupt received */ /** MAC common interrupt received */
nveu32_t mac_common_intr_rcvd; nveu32_t mac_common_intr_rcvd;
/** Flag to enable pcs RX EQ SW override logic */
nveu32_t pcs_rx_eq_sw_ovrd_en;
}; };
/** /**

View File

@@ -613,15 +613,18 @@ static inline nveu64_t osi_update_stats_counter(nveu64_t last_value,
*/ */
#define RETRY_COUNT 1000U #define RETRY_COUNT 1000U
#define RETRY_DELAY 1U #define RETRY_DELAY 1U
#define OSI_DELAY_2US 2U
#define OSI_DELAY_4US 4U #define OSI_DELAY_4US 4U
#define OSI_DELAY_10US 10U #define OSI_DELAY_10US 10U
#ifndef OSI_STRIPPED_LIB #ifndef OSI_STRIPPED_LIB
#define OSI_DELAY_100US 100U #define OSI_DELAY_100US 100U
#endif #endif
#define OSI_DELAY_200US 200U #define OSI_DELAY_200US 200U
#define OSI_DELAY_500US 500U
#define OSI_DELAY_1000US 1000U #define OSI_DELAY_1000US 1000U
#define OSI_DELAY_10000US 10000U #define OSI_DELAY_10000US 10000U
#define OSI_DELAY_30000US 30000U #define OSI_DELAY_30000US 30000U
#define OSI_DELAY_1000000US 1000000U
/** @} */ /** @} */

View File

@@ -575,6 +575,136 @@ fail:
return ret; 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 * @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, OSI_CORE_INFO(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"PCS block lock SUCCESS\n", 0ULL); "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: fail:
return ret; return ret;
} }

View File

@@ -71,6 +71,8 @@
#define T26X_XPCS_WRAP_UPHY_RX_CTRL_2 0x8040 #define T26X_XPCS_WRAP_UPHY_RX_CTRL_2 0x8040
#define T26X_XPCS_WRAP_UPHY_RX_CTRL_3 0x8044 #define T26X_XPCS_WRAP_UPHY_RX_CTRL_3 0x8044
#define T26X_XPCS_WRAP_UPHY_TIMEOUT_CONTROL_0_0 0x8070 #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_FEC_EN OSI_BIT(0)
#define XPCS_SR_PMA_KR_FEC_CTRL_EN_ERR_IND OSI_BIT(1) #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 #ifdef HSI_SUPPORT
#define XPCS_WRAP_INTERRUPT_CONTROL 0x8048 #define XPCS_WRAP_INTERRUPT_CONTROL 0x8048
#define T26X_XPCS_WRAP_INTERRUPT_CONTROL 0x8084 #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 */ #endif /* !OSI_STRIPPED_LIB */
return ret; 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_ */ #endif /* INCLUDED_XPCS_H_ */