[v2,06/10] net/ngbe: add spinlock protection on YT PHY

Message ID 20230202092132.3271910-7-jiawenwu@trustnetic.com (mailing list archive)
State Accepted, archived
Delegated to: Ferruh Yigit
Headers
Series Wangxun fixes and new supports |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Jiawen Wu Feb. 2, 2023, 9:21 a.m. UTC
  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: stable@dpdk.org

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
 drivers/net/ngbe/base/ngbe_phy_yt.c | 36 +++++++++++++++++++++++++++++
 drivers/net/ngbe/base/ngbe_type.h   |  1 +
 2 files changed, 37 insertions(+)
  

Patch

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;