From f661fdd1895608e675dfd43f0e85c5744f192910 Mon Sep 17 00:00:00 2001 From: Om Prakash Singh Date: Thu, 21 Apr 2022 15:17:24 +0530 Subject: [PATCH] core: add pcs register readback after write support As per T23X-MGBE_HSIv2-14 requirement for PCS register we need to perform readback for each write operation to verify write operation was successful Bug 3606649 Change-Id: I7cca6baa43feaa4207b6158f0abc796e656338dd Signed-off-by: Om Prakash Singh Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/2700845 Tested-by: mobile promotions Reviewed-by: mobile promotions --- osi/core/core_local.h | 2 +- osi/core/eqos_core.c | 5 ++- osi/core/mgbe_core.c | 37 ++++++++++++------- osi/core/osi_hal.c | 3 +- osi/core/xpcs.c | 83 +++++++++++++++++++++++++++++++------------ osi/core/xpcs.h | 40 +++++++++++++++++++-- 6 files changed, 129 insertions(+), 41 deletions(-) diff --git a/osi/core/core_local.h b/osi/core/core_local.h index 9534a9e..d616c53 100644 --- a/osi/core/core_local.h +++ b/osi/core/core_local.h @@ -280,7 +280,7 @@ struct core_ops { struct osi_core_ptp_tsc_data *data); #ifdef HSI_SUPPORT /** Interface function called to initialize HSI */ - void (*core_hsi_configure)(struct osi_core_priv_data *const osi_core, + int (*core_hsi_configure)(struct osi_core_priv_data *const osi_core, const nveu32_t enable); #endif }; diff --git a/osi/core/eqos_core.c b/osi/core/eqos_core.c index da8b05b..4ab9a96 100644 --- a/osi/core/eqos_core.c +++ b/osi/core/eqos_core.c @@ -1714,8 +1714,10 @@ static void eqos_configure_rxq_priority( * @param[in, out] osi_core: OSI core private data structure. * @param[in] enable: OSI_ENABLE for enabling HSI feature, else disable * + * @retval 0 on success + * @retval -1 on failure */ -static void eqos_hsi_configure(struct osi_core_priv_data *const osi_core, +static int eqos_hsi_configure(struct osi_core_priv_data *const osi_core, const nveu32_t enable) { nveu32_t value; @@ -1841,6 +1843,7 @@ static void eqos_hsi_configure(struct osi_core_priv_data *const osi_core, osi_writela(osi_core, value, (nveu8_t *)osi_core->base + EQOS_WRAP_COMMON_INTR_ENABLE); } + return 0; } #endif /** diff --git a/osi/core/mgbe_core.c b/osi/core/mgbe_core.c index 4388d19..18d03e2 100644 --- a/osi/core/mgbe_core.c +++ b/osi/core/mgbe_core.c @@ -2572,12 +2572,14 @@ static int mgbe_config_flow_control(struct osi_core_priv_data *const osi_core, * @param[in, out] osi_core: OSI core private data structure. * @param[in] enable: OSI_ENABLE for Enabling HSI feature, else disable * + * @retval 0 on success + * @retval -1 on failure */ -static void mgbe_hsi_configure(struct osi_core_priv_data *const osi_core, +static int mgbe_hsi_configure(struct osi_core_priv_data *const osi_core, const nveu32_t enable) { nveu32_t value = 0U; - void *xpcs_base = osi_core->xpcs_base; + int ret = 0; if (enable == OSI_ENABLE) { osi_core->hsi.enabled = OSI_ENABLE; @@ -2585,13 +2587,17 @@ static void mgbe_hsi_configure(struct osi_core_priv_data *const osi_core, /* T23X-MGBE_HSIv2-10 Enable PCS ECC */ value = (EN_ERR_IND | FEC_EN); - xpcs_write(xpcs_base, XPCS_BASE_PMA_MMD_SR_PMA_KR_FEC_CTRL, value); - + ret = xpcs_write_safety(osi_core, XPCS_BASE_PMA_MMD_SR_PMA_KR_FEC_CTRL, value); + if (ret != 0) { + return ret; + } /* T23X-MGBE_HSIv2-12:Initialization of Transaction Timeout in PCS */ /* T23X-MGBE_HSIv2-11:Initialization of Watchdog Timer */ value = (0xCCU << XPCS_SFTY_1US_MULT_SHIFT) & XPCS_SFTY_1US_MULT_MASK; - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_SFTY_TMR_CTRL, value); - + ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_SFTY_TMR_CTRL, value); + if (ret != 0) { + return ret; + } /* T23X-MGBE_HSIv2-1 Configure ECC */ value = osi_readla(osi_core, (nveu8_t *)osi_core->base + MGBE_MTL_ECC_CONTROL); @@ -2670,11 +2676,15 @@ static void mgbe_hsi_configure(struct osi_core_priv_data *const osi_core, osi_core->hsi.enabled = OSI_DISABLE; /* T23X-MGBE_HSIv2-10 Disable PCS ECC */ - xpcs_write(xpcs_base, XPCS_BASE_PMA_MMD_SR_PMA_KR_FEC_CTRL, 0); - + ret = xpcs_write_safety(osi_core, XPCS_BASE_PMA_MMD_SR_PMA_KR_FEC_CTRL, 0); + if (ret != 0) { + return ret; + } /* T23X-MGBE_HSIv2-11:Deinitialization of Watchdog Timer */ - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_SFTY_TMR_CTRL, 0); - + ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_SFTY_TMR_CTRL, 0); + if (ret != 0) { + return ret; + } /* T23X-MGBE_HSIv2-1 Disable ECC */ value = osi_readla(osi_core, (nveu8_t *)osi_core->base + MGBE_MTL_ECC_CONTROL); @@ -2732,6 +2742,7 @@ static void mgbe_hsi_configure(struct osi_core_priv_data *const osi_core, osi_writela(osi_core, value, (nveu8_t *)osi_core->xpcs_base + XPCS_WRAP_INTERRUPT_CONTROL); } + return ret; } #endif @@ -4250,11 +4261,11 @@ static void mgbe_handle_hsi_intr(struct osi_core_priv_data *osi_core) /* Clear status register for PCS error */ val = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_SFTY_UE_INTR0); if (val != 0U) { - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_SFTY_UE_INTR0, 0); + (void)xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_SFTY_UE_INTR0, 0); } val = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_SFTY_CE_INTR); if (val != 0U) { - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_SFTY_CE_INTR, 0); + (void)xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_SFTY_CE_INTR, 0); } } } @@ -5258,7 +5269,7 @@ static void mgbe_configure_eee(struct osi_core_priv_data *osi_core, unsigned int tic_counter = 0; void *addr = osi_core->base; - if (xpcs_eee(osi_core->xpcs_base, tx_lpi_enabled) != 0) { + if (xpcs_eee(osi_core, tx_lpi_enabled) != 0) { OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_INVALID, "xpcs_eee call failed\n", 0ULL); return; diff --git a/osi/core/osi_hal.c b/osi/core/osi_hal.c index a2c433c..0407070 100644 --- a/osi/core/osi_hal.c +++ b/osi/core/osi_hal.c @@ -2054,8 +2054,7 @@ nve32_t osi_hal_handle_ioctl(struct osi_core_priv_data *osi_core, break; #ifdef HSI_SUPPORT case OSI_CMD_HSI_CONFIGURE: - ops_p->core_hsi_configure(osi_core, data->arg1_u32); - ret = 0; + ret = ops_p->core_hsi_configure(osi_core, data->arg1_u32); break; #endif default: diff --git a/osi/core/xpcs.c b/osi/core/xpcs.c index 8576f84..6ba0d31 100644 --- a/osi/core/xpcs.c +++ b/osi/core/xpcs.c @@ -42,6 +42,7 @@ static inline int xpcs_poll_for_an_complete(struct osi_core_priv_data *osi_core, unsigned int retry = 1000; unsigned int count; int cond = 1; + int ret = 0; /* 14. Poll for AN complete */ cond = 1; @@ -70,7 +71,10 @@ static inline int xpcs_poll_for_an_complete(struct osi_core_priv_data *osi_core, } else { /* 15. clear interrupt */ status &= ~XPCS_VR_MII_AN_INTR_STS_CL37_ANCMPLT_INTR; - xpcs_write(xpcs_base, XPCS_VR_MII_AN_INTR_STS, status); + ret = xpcs_write_safety(osi_core, XPCS_VR_MII_AN_INTR_STS, status); + if (ret != 0) { + return ret; + } cond = 0; } } @@ -90,14 +94,18 @@ static inline int xpcs_poll_for_an_complete(struct osi_core_priv_data *osi_core, * * Algorithm: This routine program XPCS speed based on AN status. * - * @param[in] xpcs_base: XPCS base virtual address. + * @param[in] osi_core: OSI core data structure. * @param[in] status: Autonegotation Status. + * + * @retval 0 on success + * @retval -1 on failure */ -static inline void xpcs_set_speed(void *xpcs_base, +static inline int xpcs_set_speed(struct osi_core_priv_data *osi_core, unsigned int status) { unsigned int speed = status & XPCS_USXG_AN_STS_SPEED_MASK; unsigned int ctrl = 0; + void *xpcs_base = osi_core->xpcs_base; ctrl = xpcs_read(xpcs_base, XPCS_SR_MII_CTRL); @@ -120,7 +128,7 @@ static inline void xpcs_set_speed(void *xpcs_base, break; } - xpcs_write(xpcs_base, XPCS_SR_MII_CTRL, ctrl); + return xpcs_write_safety(osi_core, XPCS_SR_MII_CTRL, ctrl); } /** @@ -154,15 +162,19 @@ int xpcs_start(struct osi_core_priv_data *osi_core) (osi_core->phy_iface_mode == OSI_USXGMII_MODE_5G)) { ctrl = xpcs_read(xpcs_base, XPCS_SR_MII_CTRL); ctrl |= XPCS_SR_MII_CTRL_AN_ENABLE; - xpcs_write(xpcs_base, XPCS_SR_MII_CTRL, ctrl); - + ret = xpcs_write_safety(osi_core, XPCS_SR_MII_CTRL, ctrl); + if (ret != 0) { + return ret; + } ret = xpcs_poll_for_an_complete(osi_core, &an_status); if (ret < 0) { return ret; } - xpcs_set_speed(xpcs_base, an_status); - + ret = xpcs_set_speed(osi_core, an_status); + if (ret != 0) { + return ret; + } /* USXGMII Rate Adaptor Reset before data transfer */ ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1); ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_USRA_RST; @@ -446,6 +458,7 @@ int xpcs_init(struct osi_core_priv_data *osi_core) unsigned int count; unsigned int ctrl = 0; int cond = 1; + int ret = 0; if (osi_core->xpcs_base == OSI_NULL) { OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL, @@ -469,8 +482,10 @@ int xpcs_init(struct osi_core_priv_data *osi_core) /* 1. switch DWC_xpcs to BASE-R mode */ ctrl = xpcs_read(xpcs_base, XPCS_SR_XS_PCS_CTRL2); ctrl |= XPCS_SR_XS_PCS_CTRL2_PCS_TYPE_SEL_BASE_R; - xpcs_write(xpcs_base, XPCS_SR_XS_PCS_CTRL2, ctrl); - + ret = xpcs_write_safety(osi_core, XPCS_SR_XS_PCS_CTRL2, ctrl); + if (ret != 0) { + return ret; + } /* 2. enable USXGMII Mode inside DWC_xpcs */ /* 3. USXG_MODE = 10G - default it will be 10G mode */ @@ -484,8 +499,10 @@ int xpcs_init(struct osi_core_priv_data *osi_core) } } - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_KR_CTRL, ctrl); - + ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_KR_CTRL, ctrl); + if (ret != 0) { + return ret; + } /* 4. Program PHY to operate at 10Gbps/5Gbps/2Gbps * this step not required since PHY speed programming * already done as part of phy INIT @@ -493,6 +510,14 @@ int xpcs_init(struct osi_core_priv_data *osi_core) /* 5. Vendor specific software reset */ ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1); ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_USXG_EN; + ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl); + if (ret != 0) { + return ret; + } + + /* XPCS_VR_XS_PCS_DIG_CTRL1_VR_RST bit is self clearing + * value readback varification is not needed + */ ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_VR_RST; xpcs_write(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl); @@ -524,11 +549,16 @@ int xpcs_init(struct osi_core_priv_data *osi_core) (osi_core->phy_iface_mode == OSI_USXGMII_MODE_5G)) { ctrl = xpcs_read(xpcs_base, XPCS_SR_AN_CTRL); ctrl &= ~XPCS_SR_AN_CTRL_AN_EN; - xpcs_write(xpcs_base, XPCS_SR_AN_CTRL, ctrl); - + ret = xpcs_write_safety(osi_core, XPCS_SR_AN_CTRL, ctrl); + if (ret != 0) { + return ret; + } ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1); ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_CL37_BP; - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl); + ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl); + if (ret != 0) { + return ret; + } } /* TODO: 9. MII_AN_INTR_EN to 1, to enable auto-negotiation @@ -549,15 +579,17 @@ int xpcs_init(struct osi_core_priv_data *osi_core) * Algorithm: This routine update register related to EEE * for XPCS. * - * @param[in] xpcs_base: XPCS virtual base address + * @param[in] osi_core: OSI core data structure. * @param[in] en_dis: enable - 1 or disable - 0 * * @retval 0 on success * @retval -1 on failure. */ -int xpcs_eee(void *xpcs_base, unsigned int en_dis) +int xpcs_eee(struct osi_core_priv_data *osi_core, unsigned int en_dis) { + void *xpcs_base = osi_core->xpcs_base; unsigned int val = 0x0U; + int ret = 0; if (en_dis != OSI_ENABLE && en_dis != OSI_DISABLE) { return -1; @@ -570,7 +602,10 @@ int xpcs_eee(void *xpcs_base, unsigned int en_dis) val = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL0); val &= ~XPCS_VR_XS_PCS_EEE_MCTRL0_LTX_EN; val &= ~XPCS_VR_XS_PCS_EEE_MCTRL0_LRX_EN; - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL0, val); + ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_EEE_MCTRL0, val); + if (ret != 0) { + return ret; + } return 0; } @@ -588,12 +623,16 @@ int xpcs_eee(void *xpcs_base, unsigned int en_dis) /* 4. enable the EEE feature on the Tx path and Rx path */ val |= (XPCS_VR_XS_PCS_EEE_MCTRL0_LTX_EN | XPCS_VR_XS_PCS_EEE_MCTRL0_LRX_EN); - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL0, val); - + ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_EEE_MCTRL0, val); + if (ret != 0) { + return ret; + } /* Transparent Tx LPI Mode Enable */ val = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL1); val |= XPCS_VR_XS_PCS_EEE_MCTRL1_TRN_LPI; - xpcs_write(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL1, val); - + ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_EEE_MCTRL1, val); + if (ret != 0) { + return ret; + } return 0; } diff --git a/osi/core/xpcs.h b/osi/core/xpcs.h index c4d27ea..070e441 100644 --- a/osi/core/xpcs.h +++ b/osi/core/xpcs.h @@ -127,7 +127,7 @@ int xpcs_init(struct osi_core_priv_data *osi_core); int xpcs_start(struct osi_core_priv_data *osi_core); -int xpcs_eee(void *xpcs_base, unsigned int en_dis); +int xpcs_eee(struct osi_core_priv_data *osi_core, unsigned int en_dis); /** * @brief xpcs_read - read from xpcs. @@ -148,7 +148,7 @@ static inline unsigned int xpcs_read(void *xpcs_base, unsigned int reg_addr) } /** - * @brief xpcs_read - write to xpcs. + * @brief xpcs_write - write to xpcs. * * Algorithm: This routine writes data to XPCS register. * @@ -164,4 +164,40 @@ static inline void xpcs_write(void *xpcs_base, unsigned int reg_addr, osi_writel(val, (unsigned char *)xpcs_base + (((reg_addr) & XPCS_REG_VALUE_MASK))); } + +/** + * @brief xpcs_write_safety - write to xpcs. + * + * Algorithm: This routine writes data to XPCS register. + * And verifiy by reading back the value + * + * @param[in] osi_core: OSI core data structure + * @param[in] reg_addr: register address for writing + * @param[in] val: write value to register address + * + * @retval 0 on success + * @retval -1 on failure. + * + */ +static inline int xpcs_write_safety(struct osi_core_priv_data *osi_core, + unsigned int reg_addr, + unsigned int val) +{ + void *xpcs_base = osi_core->xpcs_base; + unsigned int read_val; + int retry = 10; + + while (--retry > 0) { + xpcs_write(xpcs_base, reg_addr, val); + read_val = xpcs_read(xpcs_base, reg_addr); + if (val == read_val) { + return 0; + } + osi_core->osd_ops.udelay(OSI_DELAY_1US); + } + + OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL, + "xpcs_write_safety failed", reg_addr); + return -1; +} #endif