Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-block.git] / drivers / net / dsa / b53 / b53_common.c
index 3da5fca77cbdd70e3e4991f230ac6ec74de4f5a9..db9a80e1ee14585afd7392f8524795bf51f4a0c3 100644 (file)
@@ -806,16 +806,39 @@ static unsigned int b53_get_mib_size(struct b53_device *dev)
                return B53_MIBS_SIZE;
 }
 
-void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
+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;
 
-       for (i = 0; i < mib_size; i++)
-               strlcpy(data + i * ETH_GSTRING_LEN,
-                       mibs[i].name, ETH_GSTRING_LEN);
+       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;
+
+               phy_ethtool_get_strings(phydev, data);
+       }
 }
 EXPORT_SYMBOL(b53_get_strings);
 
@@ -852,11 +875,34 @@ void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
 }
 EXPORT_SYMBOL(b53_get_ethtool_stats);
 
-int b53_get_sset_count(struct dsa_switch *ds, int port)
+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 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);
 
@@ -1477,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
@@ -1489,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;
@@ -1650,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,
@@ -1966,6 +2022,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);