net: dsa: b53: Add support for reading PHY statistics
authorFlorian Fainelli <f.fainelli@gmail.com>
Wed, 25 Apr 2018 19:12:53 +0000 (12:12 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 27 Apr 2018 15:53:03 +0000 (11:53 -0400)
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.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/b53/b53_common.c
drivers/net/dsa/b53/b53_priv.h
drivers/net/dsa/bcm_sf2.c

index 726b2d8c6fe9152af475ede44830b81e7a95c5da..9f561fe505cb06e8aebe89709c0704e97baf03c4 100644 (file)
@@ -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);
 
@@ -1484,7 +1523,7 @@ void b53_br_fast_age(struct dsa_switch *ds, int port)
 }
 EXPORT_SYMBOL(b53_br_fast_age);
 
-static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
+static bool b53_possible_cpu_port(struct dsa_switch *ds, int port)
 {
        /* Broadcom switches will accept enabling Broadcom tags on the
         * following ports: 5, 7 and 8, any other port is not supported
@@ -1496,10 +1535,19 @@ static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
                return true;
        }
 
-       dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n", port);
        return false;
 }
 
+static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
+{
+       bool ret = b53_possible_cpu_port(ds, port);
+
+       if (!ret)
+               dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n",
+                        port);
+       return ret;
+}
+
 enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port)
 {
        struct b53_device *dev = ds->priv;
@@ -1657,6 +1705,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 +2010,15 @@ 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 */
+       if (is539x(dev) || is531x5(dev)) {
+               for (i = 0; i < dev->num_ports; i++) {
+                       if (!(dev->ds->phys_mii_mask & BIT(i)) &&
+                           !b53_possible_cpu_port(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);
index b933d5cb5c2d7e2826e787d801e0a4df839438d4..cc284a514de90f4a55373a8a3468e02f18bfdeca 100644 (file)
@@ -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);
index 0378eded31f2cee00ea0d79c35b328b58317cd40..97236cfcbae4086d18caedbd2a4663ce82732fc7 100644 (file)
@@ -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,