Allow the b53 driver to return PHY statistics when the CPU port used is
different than 5, 7 or 8, because those are typically PHY-less on most
devices. This is useful for debugging link problems between the switch
and an external host when using a non standard CPU port number (e.g: 4).

Signed-off-by: Florian Fainelli <f.faine...@gmail.com>
---
 drivers/net/dsa/b53/b53_common.c | 63 +++++++++++++++++++++++++++++++++++-----
 drivers/net/dsa/b53/b53_priv.h   |  1 +
 drivers/net/dsa/bcm_sf2.c        |  1 +
 3 files changed, 57 insertions(+), 8 deletions(-)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 726b2d8c6fe9..a67c100be6eb 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -806,20 +806,39 @@ static unsigned int b53_get_mib_size(struct b53_device 
*dev)
                return B53_MIBS_SIZE;
 }
 
+static struct phy_device *b53_get_phy_device(struct dsa_switch *ds, int port)
+{
+       /* These ports typically do not have built-in PHYs */
+       switch (port) {
+       case B53_CPU_PORT_25:
+       case 7:
+       case B53_CPU_PORT:
+               return NULL;
+       }
+
+       return mdiobus_get_phy(ds->slave_mii_bus, port);
+}
+
 void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
                     uint8_t *data)
 {
        struct b53_device *dev = ds->priv;
        const struct b53_mib_desc *mibs = b53_get_mib(dev);
        unsigned int mib_size = b53_get_mib_size(dev);
+       struct phy_device *phydev;
        unsigned int i;
 
-       if (stringset != ETH_SS_STATS)
-               return;
+       if (stringset == ETH_SS_STATS) {
+               for (i = 0; i < mib_size; i++)
+                       strlcpy(data + i * ETH_GSTRING_LEN,
+                               mibs[i].name, ETH_GSTRING_LEN);
+       } else if (stringset == ETH_SS_PHY_STATS) {
+               phydev = b53_get_phy_device(ds, port);
+               if (!phydev)
+                       return;
 
-       for (i = 0; i < mib_size; i++)
-               strlcpy(data + i * ETH_GSTRING_LEN,
-                       mibs[i].name, ETH_GSTRING_LEN);
+               phy_ethtool_get_strings(phydev, data);
+       }
 }
 EXPORT_SYMBOL(b53_get_strings);
 
@@ -856,14 +875,34 @@ void b53_get_ethtool_stats(struct dsa_switch *ds, int 
port, uint64_t *data)
 }
 EXPORT_SYMBOL(b53_get_ethtool_stats);
 
+void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data)
+{
+       struct phy_device *phydev;
+
+       phydev = b53_get_phy_device(ds, port);
+       if (!phydev)
+               return;
+
+       phy_ethtool_get_stats(phydev, NULL, data);
+}
+EXPORT_SYMBOL(b53_get_ethtool_phy_stats);
+
 int b53_get_sset_count(struct dsa_switch *ds, int port, int sset)
 {
        struct b53_device *dev = ds->priv;
+       struct phy_device *phydev;
 
-       if (sset != ETH_SS_STATS)
-               return 0;
+       if (sset == ETH_SS_STATS) {
+               return b53_get_mib_size(dev);
+       } else if (sset == ETH_SS_PHY_STATS) {
+               phydev = b53_get_phy_device(ds, port);
+               if (!phydev)
+                       return 0;
+
+               return phy_ethtool_get_sset_count(phydev);
+       }
 
-       return b53_get_mib_size(dev);
+       return 0;
 }
 EXPORT_SYMBOL(b53_get_sset_count);
 
@@ -1657,6 +1696,7 @@ static const struct dsa_switch_ops b53_switch_ops = {
        .get_strings            = b53_get_strings,
        .get_ethtool_stats      = b53_get_ethtool_stats,
        .get_sset_count         = b53_get_sset_count,
+       .get_ethtool_phy_stats  = b53_get_ethtool_phy_stats,
        .phy_read               = b53_phy_read16,
        .phy_write              = b53_phy_write16,
        .adjust_link            = b53_adjust_link,
@@ -1961,6 +2001,13 @@ static int b53_switch_init(struct b53_device *dev)
        dev->num_ports = dev->cpu_port + 1;
        dev->enabled_ports |= BIT(dev->cpu_port);
 
+       /* Include non standard CPU port built-in PHYs to be probed */
+       for (i = 0; i < dev->num_ports; i++) {
+               if (!(dev->ds->phys_mii_mask & BIT(i)) &&
+                   !b53_can_enable_brcm_tags(dev->ds, i))
+                       dev->ds->phys_mii_mask |= BIT(i);
+       }
+
        dev->ports = devm_kzalloc(dev->dev,
                                  sizeof(struct b53_port) * dev->num_ports,
                                  GFP_KERNEL);
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index b933d5cb5c2d..cc284a514de9 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -290,6 +290,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 
stringset,
                     uint8_t *data);
 void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
 int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
+void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t 
*data);
 int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge);
 void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *bridge);
 void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state);
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 0378eded31f2..97236cfcbae4 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -859,6 +859,7 @@ static const struct dsa_switch_ops bcm_sf2_ops = {
        .get_strings            = b53_get_strings,
        .get_ethtool_stats      = b53_get_ethtool_stats,
        .get_sset_count         = b53_get_sset_count,
+       .get_ethtool_phy_stats  = b53_get_ethtool_phy_stats,
        .get_phy_flags          = bcm_sf2_sw_get_phy_flags,
        .adjust_link            = bcm_sf2_sw_adjust_link,
        .fixed_link_update      = bcm_sf2_sw_fixed_link_update,
-- 
2.7.4

Reply via email to