]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: phy: broadcom: Save PHY counters during suspend
authorJustin Chen <justin.chen@broadcom.com>
Tue, 5 May 2026 17:39:26 +0000 (10:39 -0700)
committerJakub Kicinski <kuba@kernel.org>
Thu, 7 May 2026 15:36:47 +0000 (08:36 -0700)
The PHY counters can be lost if the PHY is reset during suspend. We
need to save the values into the shadow counters or the accounting
will be incorrect over multiple suspend and resume cycles.

Fixes: 820ee17b8d3b ("net: phy: broadcom: Add support code for reading PHY counters")
Signed-off-by: Justin Chen <justin.chen@broadcom.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Link: https://patch.msgid.link/20260505173926.2870069-1-justin.chen@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/bcm-phy-lib.c
drivers/net/phy/bcm-phy-lib.h
drivers/net/phy/bcm7xxx.c
drivers/net/phy/broadcom.c

index 5198d66dbbc0483d1dee6d11cccb191f33de9c52..b64beade8dd933d326e993379eb44693835f69ab 100644 (file)
@@ -563,6 +563,15 @@ void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
 }
 EXPORT_SYMBOL_GPL(bcm_phy_get_stats);
 
+void bcm_phy_update_stats_shadow(struct phy_device *phydev, u64 *shadow)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
+               bcm_phy_get_stat(phydev, shadow, i);
+}
+EXPORT_SYMBOL_GPL(bcm_phy_update_stats_shadow);
+
 void bcm_phy_r_rc_cal_reset(struct phy_device *phydev)
 {
        /* Reset R_CAL/RC_CAL Engine */
index bceddbc860eb285b17a9e8c78f9564dbf993de19..bba94ce961954350be01cfe6cc1b409c9a7a7761 100644 (file)
@@ -85,6 +85,7 @@ int bcm_phy_get_sset_count(struct phy_device *phydev);
 void bcm_phy_get_strings(struct phy_device *phydev, u8 *data);
 void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
                       struct ethtool_stats *stats, u64 *data);
+void bcm_phy_update_stats_shadow(struct phy_device *phydev, u64 *shadow);
 void bcm_phy_r_rc_cal_reset(struct phy_device *phydev);
 int bcm_phy_28nm_a0b0_afe_config_init(struct phy_device *phydev);
 int bcm_phy_enable_jumbo(struct phy_device *phydev);
index 00e8fa14aa773a932f3dab0155a5c4fcb46dbe70..71a163f62c0eb6f3912bd9fb3b8078869d5a8683 100644 (file)
@@ -807,6 +807,17 @@ static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev,
        bcm_phy_get_stats(phydev, priv->stats, stats, data);
 }
 
+static int bcm7xxx_28nm_suspend(struct phy_device *phydev)
+{
+       struct bcm7xxx_phy_priv *priv = phydev->priv;
+
+       mutex_lock(&phydev->lock);
+       bcm_phy_update_stats_shadow(phydev, priv->stats);
+       mutex_unlock(&phydev->lock);
+
+       return genphy_suspend(phydev);
+}
+
 static int bcm7xxx_28nm_probe(struct phy_device *phydev)
 {
        struct bcm7xxx_phy_priv *priv;
@@ -849,6 +860,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
        .flags          = PHY_IS_INTERNAL,                              \
        .config_init    = bcm7xxx_28nm_config_init,                     \
        .resume         = bcm7xxx_28nm_resume,                          \
+       .suspend        = bcm7xxx_28nm_suspend,                         \
        .get_tunable    = bcm7xxx_28nm_get_tunable,                     \
        .set_tunable    = bcm7xxx_28nm_set_tunable,                     \
        .get_sset_count = bcm_phy_get_sset_count,                       \
@@ -866,6 +878,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
        .flags          = PHY_IS_INTERNAL,                              \
        .config_init    = bcm7xxx_28nm_ephy_config_init,                \
        .resume         = bcm7xxx_28nm_ephy_resume,                     \
+       .suspend        = bcm7xxx_28nm_suspend,                         \
        .get_sset_count = bcm_phy_get_sset_count,                       \
        .get_strings    = bcm_phy_get_strings,                          \
        .get_stats      = bcm7xxx_28nm_get_phy_stats,                   \
@@ -902,6 +915,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
        .config_aneg    = genphy_config_aneg,                           \
        .read_status    = genphy_read_status,                           \
        .resume         = bcm7xxx_16nm_ephy_resume,                     \
+       .suspend        = bcm7xxx_28nm_suspend,                         \
 }
 
 static struct phy_driver bcm7xxx_driver[] = {
index bf0c6a04481ee23110e249118bbe086ffe8e7a8f..d1a4edb34ad2efc3b7eb55fea612acef3627d3a8 100644 (file)
@@ -592,8 +592,13 @@ static int bcm54xx_set_wakeup_irq(struct phy_device *phydev, bool state)
 
 static int bcm54xx_suspend(struct phy_device *phydev)
 {
+       struct bcm54xx_phy_priv *priv = phydev->priv;
        int ret = 0;
 
+       mutex_lock(&phydev->lock);
+       bcm_phy_update_stats_shadow(phydev, priv->stats);
+       mutex_unlock(&phydev->lock);
+
        bcm54xx_ptp_stop(phydev);
 
        /* Acknowledge any Wake-on-LAN interrupt prior to suspend */