* [PATCH net-next] net: phy: broadcom: Save PHY counters during suspend
@ 2026-04-28 21:24 Justin Chen
2026-04-28 21:58 ` Florian Fainelli
2026-04-29 23:22 ` Jakub Kicinski
0 siblings, 2 replies; 3+ messages in thread
From: Justin Chen @ 2026-04-28 21:24 UTC (permalink / raw)
To: netdev
Cc: pabeni, kuba, edumazet, davem, linux, hkallweit1, andrew,
bcm-kernel-feedback-list, Justin Chen
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.
Signed-off-by: Justin Chen <justin.chen@broadcom.com>
---
drivers/net/phy/bcm-phy-lib.c | 9 +++++++++
drivers/net/phy/bcm-phy-lib.h | 1 +
drivers/net/phy/bcm7xxx.c | 19 +++++++++++++++++++
drivers/net/phy/broadcom.c | 5 +++++
4 files changed, 34 insertions(+)
diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
index 5198d66dbbc0..b64beade8dd9 100644
--- a/drivers/net/phy/bcm-phy-lib.c
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -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 */
diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h
index bceddbc860eb..bba94ce96195 100644
--- a/drivers/net/phy/bcm-phy-lib.h
+++ b/drivers/net/phy/bcm-phy-lib.h
@@ -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);
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index 00e8fa14aa77..6cfcf039494e 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -733,6 +733,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
*/
static int bcm7xxx_suspend(struct phy_device *phydev)
{
+ struct bcm7xxx_phy_priv *priv = phydev->priv;
int ret;
static const struct bcm7xxx_regs {
int reg;
@@ -747,6 +748,10 @@ static int bcm7xxx_suspend(struct phy_device *phydev)
};
unsigned int i;
+ mutex_lock(&phydev->lock);
+ bcm_phy_update_stats_shadow(phydev, priv->stats);
+ mutex_unlock(&phydev->lock);
+
for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
ret = phy_write(phydev,
bcm7xxx_suspend_cfg[i].reg,
@@ -807,6 +812,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 +865,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 +883,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 +920,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[] = {
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index bf0c6a04481e..d1a4edb34ad2 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -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 */
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH net-next] net: phy: broadcom: Save PHY counters during suspend
2026-04-28 21:24 [PATCH net-next] net: phy: broadcom: Save PHY counters during suspend Justin Chen
@ 2026-04-28 21:58 ` Florian Fainelli
2026-04-29 23:22 ` Jakub Kicinski
1 sibling, 0 replies; 3+ messages in thread
From: Florian Fainelli @ 2026-04-28 21:58 UTC (permalink / raw)
To: Justin Chen, netdev
Cc: pabeni, kuba, edumazet, davem, linux, hkallweit1, andrew,
bcm-kernel-feedback-list
On 4/28/26 14:24, Justin Chen wrote:
> 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.
>
> Signed-off-by: Justin Chen <justin.chen@broadcom.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net-next] net: phy: broadcom: Save PHY counters during suspend
2026-04-28 21:24 [PATCH net-next] net: phy: broadcom: Save PHY counters during suspend Justin Chen
2026-04-28 21:58 ` Florian Fainelli
@ 2026-04-29 23:22 ` Jakub Kicinski
1 sibling, 0 replies; 3+ messages in thread
From: Jakub Kicinski @ 2026-04-29 23:22 UTC (permalink / raw)
To: justin.chen
Cc: Jakub Kicinski, netdev, pabeni, edumazet, davem, linux,
hkallweit1, andrew, bcm-kernel-feedback-list
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
net: phy: broadcom: Save PHY counters during suspend
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.
> diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
> --- a/drivers/net/phy/bcm7xxx.c
> +++ b/drivers/net/phy/bcm7xxx.c
> @@ -733,6 +733,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
> */
> static int bcm7xxx_suspend(struct phy_device *phydev)
> {
> + struct bcm7xxx_phy_priv *priv = phydev->priv;
> int ret;
[ ... ]
> unsigned int i;
>
> + mutex_lock(&phydev->lock);
> + bcm_phy_update_stats_shadow(phydev, priv->stats);
Does this cause a NULL pointer dereference for 40nm PHYs?
The bcm7xxx_suspend() function is used as the suspend callback for PHY
models defined by the BCM7XXX_40NM_EPHY() macro (like BCM7346, BCM7362,
and BCM7425).
Unlike the 28nm and 16nm PHY macros which assign a probe callback to
allocate phydev->priv, the BCM7XXX_40NM_EPHY() macro does not appear to
define a probe callback. This would leave phydev->priv as NULL and cause a
crash when trying to access priv->stats here.
> + mutex_unlock(&phydev->lock);
>
> for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
> ret = phy_write(phydev,
--
pw-bot: cr
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-04-29 23:22 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-28 21:24 [PATCH net-next] net: phy: broadcom: Save PHY counters during suspend Justin Chen
2026-04-28 21:58 ` Florian Fainelli
2026-04-29 23:22 ` Jakub Kicinski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox