[PATCH net 2/6 RESEND] net: dsa: b53: manage SerDes power through the PCS callbacks
flat view
WARM2d
From: Florian Fainelli <florian.fainelli@broadcom.com>
Date: 2026-10-22 22:57:19
Also in:
lkml
Subsystem:
broadcom b53/sf2 ethernet switch driver, networking drivers, networking [dsa], the rest · Maintainers:
Florian Fainelli, Jonas Gorski, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn, Vladimir Oltean, Linus Torvalds
Powering down the SerDes from mac_link_down() prevents the PCS from
observing link recovery. This also ties PCS power management to in-band
802.3z mode, leaving SGMII and other negotiation modes inconsistent.
Implement pcs_enable() and pcs_disable() so that phylink controls the
lane lifetime independently of individual link transitions. Remove the
MAC-to-SerDes power callback and perform read-modify-write operations
under the register mutex.
Fixes: 0e01491de646 ("net: dsa: b53: Add SerDes support")
Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
---
drivers/net/dsa/b53/b53_common.c | 8 ----
drivers/net/dsa/b53/b53_priv.h | 3 --
drivers/net/dsa/b53/b53_serdes.c | 70 +++++++++++++++++++++++---------
drivers/net/dsa/b53/b53_serdes.h | 2 -
drivers/net/dsa/b53/b53_srab.c | 1 -
5 files changed, 51 insertions(+), 33 deletions(-)
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 3f8f956aab82..09de3520e71a 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c@@ -1630,10 +1630,6 @@ static void b53_phylink_mac_link_down(struct phylink_config *config, b53_force_link(dev, port, false); return; } - - if (phy_interface_mode_is_8023z(interface) && - dev->ops->serdes_link_set) - dev->ops->serdes_link_set(dev, port, mode, interface, false); } static void b53_phylink_mac_link_up(struct phylink_config *config,
@@ -1672,10 +1668,6 @@ static void b53_phylink_mac_link_up(struct phylink_config *config, b53_force_link(dev, port, true); return; } - - if (phy_interface_mode_is_8023z(interface) && - dev->ops->serdes_link_set) - dev->ops->serdes_link_set(dev, port, mode, interface, true); } int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index 29cca7945df7..cebbebe4ae0f 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h@@ -54,9 +54,6 @@ struct b53_io_ops { int port, phy_interface_t interface); u8 (*serdes_map_lane)(struct b53_device *dev, int port); - void (*serdes_link_set)(struct b53_device *dev, int port, - unsigned int mode, phy_interface_t interface, - bool link_up); }; struct b53_arl_entry;
diff --git a/drivers/net/dsa/b53/b53_serdes.c b/drivers/net/dsa/b53/b53_serdes.c
index c90894877626..87771e3788f7 100644
--- a/drivers/net/dsa/b53/b53_serdes.c
+++ b/drivers/net/dsa/b53/b53_serdes.c@@ -107,6 +107,39 @@ static int b53_serdes_read(struct b53_device *dev, u8 lane, return ret; } +/* Return one if the register changed, zero if unchanged, or an error. */ +static int b53_serdes_modify(struct b53_device *dev, u8 lane, u8 offset, + u16 block, u16 mask, u16 set) +{ + int ret, old; + u16 new; + + mutex_lock(&dev->reg_mutex); + ret = b53_serdes_set_lane(dev, lane); + if (ret) + goto out; + + old = b53_serdes_read_blk(dev, offset, block); + if (old < 0) { + ret = old; + goto out; + } + + new = (old & ~mask) | set; + if (new == old) + goto out; + + ret = b53_serdes_write_blk(dev, offset, block, new); + if (!ret) + ret = 1; +out: + if (ret < 0) + dev->serdes_lane = B53_INVALID_LANE; + mutex_unlock(&dev->reg_mutex); + + return ret; +} + static void b53_serdes_error(struct b53_device *dev, u8 lane, int ret) { if (ret < 0)
@@ -202,32 +235,31 @@ static void b53_serdes_get_state(struct phylink_pcs *pcs, unsigned int neg_mode, state->pause |= MLO_PAUSE_TX; } -void b53_serdes_link_set(struct b53_device *dev, int port, unsigned int mode, - phy_interface_t interface, bool link_up) +static int b53_serdes_enable(struct phylink_pcs *pcs) { - u8 lane = b53_serdes_map_lane(dev, port); - int reg; + struct b53_pcs *priv = pcs_to_b53_pcs(pcs); + int ret; - if (lane == B53_INVALID_LANE) - return; + ret = b53_serdes_modify(priv->dev, priv->lane, + B53_SERDES_MII_REG(MII_BMCR), SERDES_MII_BLK, + BMCR_PDOWN, 0); + return ret < 0 ? ret : 0; +} - reg = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMCR), - SERDES_MII_BLK); - if (reg < 0) - goto out; +static void b53_serdes_disable(struct phylink_pcs *pcs) +{ + struct b53_pcs *priv = pcs_to_b53_pcs(pcs); + int ret; - if (link_up) - reg &= ~BMCR_PDOWN; - else - reg |= BMCR_PDOWN; - reg = b53_serdes_write(dev, lane, B53_SERDES_MII_REG(MII_BMCR), - SERDES_MII_BLK, reg); -out: - b53_serdes_error(dev, lane, reg); + ret = b53_serdes_modify(priv->dev, priv->lane, + B53_SERDES_MII_REG(MII_BMCR), SERDES_MII_BLK, + BMCR_PDOWN, BMCR_PDOWN); + b53_serdes_error(priv->dev, priv->lane, ret); } -EXPORT_SYMBOL(b53_serdes_link_set); static const struct phylink_pcs_ops b53_pcs_ops = { + .pcs_enable = b53_serdes_enable, + .pcs_disable = b53_serdes_disable, .pcs_get_state = b53_serdes_get_state, .pcs_config = b53_serdes_config, .pcs_an_restart = b53_serdes_an_restart,
diff --git a/drivers/net/dsa/b53/b53_serdes.h b/drivers/net/dsa/b53/b53_serdes.h
index 3d367c4df4d9..6c851838457e 100644
--- a/drivers/net/dsa/b53/b53_serdes.h
+++ b/drivers/net/dsa/b53/b53_serdes.h@@ -107,8 +107,6 @@ static inline u8 b53_serdes_map_lane(struct b53_device *dev, int port) return dev->ops->serdes_map_lane(dev, port); } -void b53_serdes_link_set(struct b53_device *dev, int port, unsigned int mode, - phy_interface_t interface, bool link_up); struct phylink_pcs *b53_serdes_phylink_mac_select_pcs(struct b53_device *dev, int port, phy_interface_t interface);
diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c
index 83a03fca142a..9988a83fa7b7 100644
--- a/drivers/net/dsa/b53/b53_srab.c
+++ b/drivers/net/dsa/b53/b53_srab.c@@ -493,7 +493,6 @@ static const struct b53_io_ops b53_srab_ops = { #if IS_ENABLED(CONFIG_B53_SERDES) .phylink_mac_select_pcs = b53_serdes_phylink_mac_select_pcs, .serdes_map_lane = b53_srab_serdes_map_lane, - .serdes_link_set = b53_serdes_link_set, #endif };
--
2.53.0