From cf963573039a333eff7156629e61a06e59da61cf Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 25 Apr 2018 12:12:52 -0700 Subject: net: dsa: Allow providing PHY statistics from CPU port Implement the same type of ethtool diversion that we have for ETH_SS_STATS and make it work with ETH_SS_PHY_STATS. This allows providing PHY level statistics for CPU ports that are directly connecting to a PHY device. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/master.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'net/dsa/master.c') diff --git a/net/dsa/master.c b/net/dsa/master.c index 8d27687fd0ca..c90ee3227dea 100644 --- a/net/dsa/master.c +++ b/net/dsa/master.c @@ -31,6 +31,32 @@ static void dsa_master_get_ethtool_stats(struct net_device *dev, ds->ops->get_ethtool_stats(ds, port, data + count); } +static void dsa_master_get_ethtool_phy_stats(struct net_device *dev, + struct ethtool_stats *stats, + uint64_t *data) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; + struct dsa_switch *ds = cpu_dp->ds; + int port = cpu_dp->index; + int count = 0; + + if (dev->phydev && !ops->get_ethtool_phy_stats) { + count = phy_ethtool_get_sset_count(dev->phydev); + if (count >= 0) + phy_ethtool_get_stats(dev->phydev, stats, data); + } else if (ops->get_sset_count && ops->get_ethtool_phy_stats) { + count = ops->get_sset_count(dev, ETH_SS_PHY_STATS); + ops->get_ethtool_phy_stats(dev, stats, data); + } + + if (count < 0) + count = 0; + + if (ds->ops->get_ethtool_phy_stats) + ds->ops->get_ethtool_phy_stats(ds, port, data + count); +} + static int dsa_master_get_sset_count(struct net_device *dev, int sset) { struct dsa_port *cpu_dp = dev->dsa_ptr; @@ -38,11 +64,14 @@ static int dsa_master_get_sset_count(struct net_device *dev, int sset) struct dsa_switch *ds = cpu_dp->ds; int count = 0; - if (ops->get_sset_count) { + if (sset == ETH_SS_PHY_STATS && dev->phydev && + !ops->get_ethtool_phy_stats) + count = phy_ethtool_get_sset_count(dev->phydev); + else if (ops->get_sset_count) count = ops->get_sset_count(dev, sset); - if (count < 0) - count = 0; - } + + if (count < 0) + count = 0; if (ds->ops->get_sset_count) count += ds->ops->get_sset_count(ds, cpu_dp->index, sset); @@ -67,7 +96,14 @@ static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset, /* We do not want to be NULL-terminated, since this is a prefix */ pfx[sizeof(pfx) - 1] = '_'; - if (ops->get_sset_count && ops->get_strings) { + if (stringset == ETH_SS_PHY_STATS && dev->phydev && + !ops->get_ethtool_phy_stats) { + mcount = phy_ethtool_get_sset_count(dev->phydev); + if (mcount < 0) + mcount = 0; + else + phy_ethtool_get_strings(dev->phydev, data); + } else if (ops->get_sset_count && ops->get_strings) { mcount = ops->get_sset_count(dev, stringset); if (mcount < 0) mcount = 0; @@ -107,6 +143,7 @@ static int dsa_master_ethtool_setup(struct net_device *dev) ops->get_sset_count = dsa_master_get_sset_count; ops->get_ethtool_stats = dsa_master_get_ethtool_stats; ops->get_strings = dsa_master_get_strings; + ops->get_ethtool_phy_stats = dsa_master_get_ethtool_phy_stats; dev->ethtool_ops = ops; -- cgit v1.2.3-59-g8ed1b