From: Oleksij Rempel Date: Tue, 10 Jun 2025 09:13:53 +0000 (+0200) Subject: net: phy: micrel: Add RX error counter support for KSZ9477 switch-integrated PHYs X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=597ebdf37222ba7deb2ed24aa4de777d7edf22f7;p=thirdparty%2Flinux.git net: phy: micrel: Add RX error counter support for KSZ9477 switch-integrated PHYs Add support for tracking receive error statistics from PHYs integrated into the KSZ9477 family of Ethernet switches. The integrated PHYs expose a receive error (RXER) counter in register 0x15. This counter increments when the PHY detects one or more symbol errors on a received frame. The register is cleared upon reading. Changes include: - `kszphy_update_stats()` to accumulate the RX error count. - `kszphy_get_phy_stats()` to expose this count via ethtool PHY stats. - Addition of a private `rx_err_pkt_cnt` field in the driver. - Registration of `.update_stats` and `.get_phy_stats` callbacks in the KSZ9477 PHY driver structure. The functionality of this counter was confirmed by physically disturbing the signal lines - specifically by wiggling exposed twisted pair wires and intentionally shorting between pairs. These actions triggered RXER increments, validating the counter's behavior. This RXER counter is confirmed for KSZ9477 and likely applicable to other related PHYs like those in KSZ9313. Signed-off-by: Oleksij Rempel Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250610091354.4060454-3-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index a51010e644444..68d86383e6c7a 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -431,6 +431,10 @@ struct kszphy_ptp_priv { spinlock_t seconds_lock; }; +struct kszphy_phy_stats { + u64 rx_err_pkt_cnt; +}; + struct kszphy_priv { struct kszphy_ptp_priv ptp_priv; const struct kszphy_type *type; @@ -441,6 +445,7 @@ struct kszphy_priv { bool rmii_ref_clk_sel_val; bool clk_enable; u64 stats[ARRAY_SIZE(kszphy_hw_stats)]; + struct kszphy_phy_stats phy_stats; }; static const struct kszphy_type lan8814_type = { @@ -2130,6 +2135,35 @@ static void kszphy_get_stats(struct phy_device *phydev, data[i] = kszphy_get_stat(phydev, i); } +/* KSZ9477 PHY RXER Counter. Probably supported by other PHYs like KSZ9313, + * etc. The counter is incremented when the PHY receives a frame with one or + * more symbol errors. The counter is cleared when the register is read. + */ +#define MII_KSZ9477_PHY_RXER_COUNTER 0x15 + +static int kszphy_update_stats(struct phy_device *phydev) +{ + struct kszphy_priv *priv = phydev->priv; + int ret; + + ret = phy_read(phydev, MII_KSZ9477_PHY_RXER_COUNTER); + if (ret < 0) + return ret; + + priv->phy_stats.rx_err_pkt_cnt += ret; + + return 0; +} + +static void kszphy_get_phy_stats(struct phy_device *phydev, + struct ethtool_eth_phy_stats *eth_stats, + struct ethtool_phy_stats *stats) +{ + struct kszphy_priv *priv = phydev->priv; + + stats->rx_errors = priv->phy_stats.rx_err_pkt_cnt; +} + static void kszphy_enable_clk(struct phy_device *phydev) { struct kszphy_priv *priv = phydev->priv; @@ -5745,6 +5779,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id = PHY_ID_KSZ9477, .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Microchip KSZ9477", + .probe = kszphy_probe, /* PHY_GBIT_FEATURES */ .config_init = ksz9477_config_init, .config_intr = kszphy_config_intr, @@ -5753,6 +5788,8 @@ static struct phy_driver ksphy_driver[] = { .handle_interrupt = kszphy_handle_interrupt, .suspend = genphy_suspend, .resume = ksz9477_resume, + .get_phy_stats = kszphy_get_phy_stats, + .update_stats = kszphy_update_stats, } }; module_phy_driver(ksphy_driver);