Add an optional polling interface for PHY statistics to simplify driver
implementation. Drivers can request the PHYlib to handle the polling task by
explicitly setting the `PHY_POLL_STATS` flag in their driver configuration.
Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
---
drivers/net/phy/phy.c | 15 +++++++++++++++
include/linux/phy.h | 6 ++++++
2 files changed, 21 insertions(+)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 0d20b534122b..b10ee9223fc9 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1346,6 +1346,18 @@ static int phy_enable_interrupts(struct phy_device *phydev)
return phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
}
+/**
+ * phy_update_stats - update the PHY statistics
+ * @phydev: target phy_device struct
+ */
+static int phy_update_stats(struct phy_device *phydev)
+{
+ if (!phydev->drv->update_stats)
+ return 0;
+
+ return phydev->drv->update_stats(phydev);
+}
+
/**
* phy_request_interrupt - request and enable interrupt for a PHY device
* @phydev: target phy_device struct
@@ -1415,6 +1427,9 @@ static enum phy_state_work _phy_state_machine(struct phy_device *phydev)
case PHY_RUNNING:
err = phy_check_link_status(phydev);
func = &phy_check_link_status;
+
+ if (!err)
+ err = phy_update_stats(phydev);
break;
case PHY_CABLETEST:
err = phydev->drv->cable_test_get_status(phydev, &finished);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index a6c47b0675af..21cd44d177d2 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -90,6 +90,7 @@ extern const int phy_10gbit_features_array[1];
#define PHY_RST_AFTER_CLK_EN BIT(1)
#define PHY_POLL_CABLE_TEST BIT(2)
#define PHY_ALWAYS_CALL_SUSPEND BIT(3)
+#define PHY_POLL_STATS BIT(4)
#define MDIO_DEVICE_IS_PHY BIT(31)
/**
@@ -1101,6 +1102,8 @@ struct phy_driver {
struct ethtool_phy_stats *stats);
void (*get_link_stats)(struct phy_device *dev,
struct ethtool_link_ext_stats *link_stats);
+ int (*update_stats)(struct phy_device *dev);
+
/** @get_sset_count: Number of statistic counters */
int (*get_sset_count)(struct phy_device *dev);
/** @get_strings: Names of the statistic counters */
@@ -1591,6 +1594,9 @@ static inline bool phy_polling_mode(struct phy_device *phydev)
if (phydev->drv->flags & PHY_POLL_CABLE_TEST)
return true;
+ if (phydev->drv->update_stats && phydev->drv->flags & PHY_POLL_STATS)
+ return true;
+
return phydev->irq == PHY_POLL;
}