For yt8521s/yt8531s PHY, if other registers are accessing between reads/writes of ext field registers, the value of ext filed registers will get weird for unknown reasons. So it's protected when all of ext field registers accessing.
Fixes: 44e97550ca68 ("net/ngbe: identify and reset PHY") Cc: sta...@dpdk.org Signed-off-by: Jiawen Wu <jiawe...@trustnetic.com> --- drivers/net/ngbe/base/ngbe_phy_yt.c | 36 +++++++++++++++++++++++++++++ drivers/net/ngbe/base/ngbe_type.h | 1 + 2 files changed, 37 insertions(+) diff --git a/drivers/net/ngbe/base/ngbe_phy_yt.c b/drivers/net/ngbe/base/ngbe_phy_yt.c index c88946f7c3..726d6c8ef5 100644 --- a/drivers/net/ngbe/base/ngbe_phy_yt.c +++ b/drivers/net/ngbe/base/ngbe_phy_yt.c @@ -100,11 +100,15 @@ s32 ngbe_write_phy_reg_sds_ext_yt(struct ngbe_hw *hw, s32 ngbe_init_phy_yt(struct ngbe_hw *hw) { + rte_spinlock_init(&hw->phy_lock); + + rte_spinlock_lock(&hw->phy_lock); /* close sds area register */ ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0); /* enable interrupts */ ngbe_write_phy_reg_mdi(hw, YT_INTR, 0, YT_INTR_ENA_MASK | YT_SDS_INTR_ENA_MASK); + rte_spinlock_unlock(&hw->phy_lock); hw->phy.set_phy_power(hw, false); @@ -123,7 +127,9 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, hw->phy.autoneg_advertised = 0; /* check chip_mode first */ + rte_spinlock_lock(&hw->phy_lock); ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &value); + rte_spinlock_unlock(&hw->phy_lock); if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(0)) { /* UTP to rgmii */ if (!hw->mac.autoneg) { @@ -146,11 +152,14 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, } /* duplex full */ value |= YT_BCR_DUPLEX | YT_BCR_RESET; + rte_spinlock_lock(&hw->phy_lock); ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value); + rte_spinlock_unlock(&hw->phy_lock); goto skip_an; } + rte_spinlock_lock(&hw->phy_lock); /*disable 100/10base-T Self-negotiation ability*/ ngbe_read_phy_reg_mdi(hw, YT_ANA, 0, &value); value &= ~(YT_ANA_100BASET_FULL | YT_ANA_100BASET_HALF | @@ -189,6 +198,7 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value); value |= YT_BCR_RESET | YT_BCR_ANE | YT_BCR_RESTART_AN; ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value); + rte_spinlock_unlock(&hw->phy_lock); skip_an: hw->phy.set_phy_power(hw, true); } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(1)) { @@ -199,6 +209,7 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, value = YT_RGMII_CONF1_RXDELAY | YT_RGMII_CONF1_TXDELAY_FE | YT_RGMII_CONF1_TXDELAY; + rte_spinlock_lock(&hw->phy_lock); ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value); value = YT_CHIP_MODE_SEL(1) | YT_CHIP_SW_LDO_EN | @@ -225,17 +236,21 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, value = YT_BCR_RESET | YT_BCR_DUPLEX | YT_BCR_SPEED_SELECT1; hw->phy.write_reg(hw, YT_BCR, 0, value); + rte_spinlock_unlock(&hw->phy_lock); hw->phy.set_phy_power(hw, true); } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(2)) { hw->phy.set_phy_power(hw, true); + rte_spinlock_lock(&hw->phy_lock); hw->phy.read_reg(hw, YT_SPST, 0, &value); + rte_spinlock_unlock(&hw->phy_lock); if (value & YT_SPST_LINK) { /* fiber up */ hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL; } else { /* utp up */ + rte_spinlock_lock(&hw->phy_lock); /*disable 100/10base-T Self-negotiation ability*/ ngbe_read_phy_reg_mdi(hw, YT_ANA, 0, &value); value &= ~(YT_ANA_100BASET_FULL | YT_ANA_100BASET_HALF | @@ -279,10 +294,12 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value); value |= YT_BCR_RESET; ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value); + rte_spinlock_unlock(&hw->phy_lock); } } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(4)) { hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL; + rte_spinlock_lock(&hw->phy_lock); ngbe_read_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, &value); value |= YT_RGMII_CONF1_MODE; ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value); @@ -297,6 +314,7 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &value); value &= ~YT_SMI_PHY_SW_RST; ngbe_write_phy_reg_ext_yt(hw, YT_CHIP, 0, value); + rte_spinlock_unlock(&hw->phy_lock); hw->phy.set_phy_power(hw, true); } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(5)) { @@ -320,7 +338,9 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, } /* duplex full */ value |= YT_BCR_DUPLEX | YT_BCR_RESET; + rte_spinlock_lock(&hw->phy_lock); hw->phy.write_reg(hw, YT_BCR, 0, value); + rte_spinlock_unlock(&hw->phy_lock); goto skip_an_sr; } @@ -339,19 +359,23 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, /* duplex full */ value |= YT_BCR_DUPLEX | YT_BCR_RESET; + rte_spinlock_lock(&hw->phy_lock); hw->phy.write_reg(hw, YT_BCR, 0, value); /* software reset to make the above configuration take effect */ hw->phy.read_reg(hw, YT_BCR, 0, &value); value |= YT_BCR_RESET | YT_BCR_ANE | YT_BCR_RESTART_AN; hw->phy.write_reg(hw, 0x0, 0, value); + rte_spinlock_unlock(&hw->phy_lock); skip_an_sr: hw->phy.set_phy_power(hw, true); } + rte_spinlock_lock(&hw->phy_lock); ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0); ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &value); + rte_spinlock_unlock(&hw->phy_lock); return 0; } @@ -366,6 +390,7 @@ s32 ngbe_reset_phy_yt(struct ngbe_hw *hw) hw->phy.type != ngbe_phy_yt8521s_sfi) return NGBE_ERR_PHY_TYPE; + rte_spinlock_lock(&hw->phy_lock); /* check chip_mode first */ ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &ctrl); if (ctrl & YT_CHIP_MODE_MASK) { @@ -395,6 +420,7 @@ s32 ngbe_reset_phy_yt(struct ngbe_hw *hw) msleep(1); } } + rte_spinlock_unlock(&hw->phy_lock); if (i == YT_PHY_RST_WAIT_PERIOD) { DEBUGOUT("PHY reset polling failed to complete."); @@ -409,7 +435,9 @@ s32 ngbe_get_phy_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit) u16 value; s32 status = 0; + rte_spinlock_lock(&hw->phy_lock); status = hw->phy.read_reg(hw, YT_ANA, 0, &value); + rte_spinlock_unlock(&hw->phy_lock); value &= YT_FANA_PAUSE_MASK; *pause_bit = (u8)(value >> 7); @@ -421,7 +449,9 @@ s32 ngbe_get_phy_lp_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit) u16 value; s32 status = 0; + rte_spinlock_lock(&hw->phy_lock); status = hw->phy.read_reg(hw, YT_LPAR, 0, &value); + rte_spinlock_unlock(&hw->phy_lock); value &= YT_FLPAR_PAUSE_MASK; *pause_bit = (u8)(value >> 7); @@ -433,10 +463,12 @@ s32 ngbe_set_phy_pause_adv_yt(struct ngbe_hw *hw, u16 pause_bit) u16 value; s32 status = 0; + rte_spinlock_lock(&hw->phy_lock); status = hw->phy.read_reg(hw, YT_ANA, 0, &value); value &= ~YT_FANA_PAUSE_MASK; value |= pause_bit; status = hw->phy.write_reg(hw, YT_ANA, 0, value); + rte_spinlock_unlock(&hw->phy_lock); return status; } @@ -453,6 +485,7 @@ s32 ngbe_check_phy_link_yt(struct ngbe_hw *hw, /* Initialize speed and link to default case */ *link_up = false; *speed = NGBE_LINK_SPEED_UNKNOWN; + rte_spinlock_lock(&hw->phy_lock); ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0); ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &insr); @@ -472,6 +505,7 @@ s32 ngbe_check_phy_link_yt(struct ngbe_hw *hw, *link_up = true; } + rte_spinlock_unlock(&hw->phy_lock); if (*link_up) { if (phy_speed == YT_SPST_SPEED_1000M) *speed = NGBE_LINK_SPEED_1GB_FULL; @@ -488,6 +522,7 @@ s32 ngbe_set_phy_power_yt(struct ngbe_hw *hw, bool on) { u16 value = 0; + rte_spinlock_lock(&hw->phy_lock); /* power down/up in fiber mode */ hw->phy.read_reg(hw, YT_BCR, 0, &value); if (on) @@ -504,6 +539,7 @@ s32 ngbe_set_phy_power_yt(struct ngbe_hw *hw, bool on) else value |= YT_BCR_PWDN; ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value); + rte_spinlock_unlock(&hw->phy_lock); return 0; } diff --git a/drivers/net/ngbe/base/ngbe_type.h b/drivers/net/ngbe/base/ngbe_type.h index aa5c41146c..05804eeab7 100644 --- a/drivers/net/ngbe/base/ngbe_type.h +++ b/drivers/net/ngbe/base/ngbe_type.h @@ -433,6 +433,7 @@ struct ngbe_hw { bool gpio_ctl; u32 led_conf; bool init_phy; + rte_spinlock_t phy_lock; struct { u64 rx_qp_packets; u64 tx_qp_packets; -- 2.27.0