diff options
author | David S. Miller <davem@davemloft.net> | 2018-04-27 11:53:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-27 11:53:04 -0400 |
commit | 21fca6e01beb9cae33c7d45a69e032d91c81f07d (patch) | |
tree | ee5924b4a53b16f813c239101935af3f480b7781 /drivers | |
parent | 834944073301e85001c3ed9913027ca47c6f889b (diff) | |
parent | 96cbddcd52e76d9052948e408b17bedc8aa1c11a (diff) | |
download | linux-21fca6e01beb9cae33c7d45a69e032d91c81f07d.tar.bz2 |
Merge branch 'net-Extend-availability-of-PHY-statistics'
Florian Fainelli says:
====================
net: Extend availability of PHY statistics
This patch series adds support for retrieving PHY statistics with DSA switches
when the CPU port uses a PHY to PHY connection (as opposed to MAC to MAC).
To get there a number of things are done:
- first we move the code dealing with PHY statistics outside of net/core/ethtool.c
and create helper functions since the same code will be reused
- then we allow network device drivers to provide an ethtool_get_phy_stats callback
when the standard PHY library helpers are not suitable
- we update the DSA functions dealing with ethtool operations to get passed a
stringset instead of assuming ETH_SS_STATS like they currently do
- then we provide a set of standard helpers within DSA as a framework and add
the plumbing to allow retrieving the PHY statistics of the CPU port(s)
- finally plug support for retrieving such PHY statistics with the b53 driver
Changes in v3:
- retrict the b53 change to 539x and 531x5 series of switches
- added a change to dsa_loop.c to help test the feature
Changes in v2:
- got actual testing when the DSA master network device has a PHY that
already provides statistics (thanks Nikita!)
- fixed the kbuild error reported when CONFIG_PHYLIB=n
- removed the checking of ops which is redundant and not needed
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/dsa/b53/b53_common.c | 81 | ||||
-rw-r--r-- | drivers/net/dsa/b53/b53_priv.h | 6 | ||||
-rw-r--r-- | drivers/net/dsa/bcm_sf2.c | 1 | ||||
-rw-r--r-- | drivers/net/dsa/dsa_loop.c | 12 | ||||
-rw-r--r-- | drivers/net/dsa/lan9303-core.c | 11 | ||||
-rw-r--r-- | drivers/net/dsa/microchip/ksz_common.c | 11 | ||||
-rw-r--r-- | drivers/net/dsa/mt7530.c | 11 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 10 | ||||
-rw-r--r-- | drivers/net/dsa/qca8k.c | 10 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 48 |
10 files changed, 179 insertions, 22 deletions
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 78616787f2a3..9f561fe505cb 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -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, @@ -1954,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); diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 1187ebd79287..cc284a514de9 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -286,9 +286,11 @@ static inline int b53_switch_get_reset_gpio(struct b53_device *dev) /* Exported functions towards other drivers */ void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port); int b53_configure_vlan(struct dsa_switch *ds); -void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data); +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 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, diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index f77be9f85cb3..58f14af04639 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -86,16 +86,23 @@ static int dsa_loop_setup(struct dsa_switch *ds) return 0; } -static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port) +static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset) { + if (sset != ETH_SS_STATS && sset != ETH_SS_PHY_STATS) + return 0; + return __DSA_LOOP_CNT_MAX; } -static void dsa_loop_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +static void dsa_loop_get_strings(struct dsa_switch *ds, int port, + u32 stringset, uint8_t *data) { struct dsa_loop_priv *ps = ds->priv; unsigned int i; + if (stringset != ETH_SS_STATS && stringset != ETH_SS_PHY_STATS) + return; + for (i = 0; i < __DSA_LOOP_CNT_MAX; i++) memcpy(data + i * ETH_GSTRING_LEN, ps->ports[port].mib[i].name, ETH_GSTRING_LEN); @@ -256,6 +263,7 @@ static const struct dsa_switch_ops dsa_loop_driver = { .get_strings = dsa_loop_get_strings, .get_ethtool_stats = dsa_loop_get_ethtool_stats, .get_sset_count = dsa_loop_get_sset_count, + .get_ethtool_phy_stats = dsa_loop_get_ethtool_stats, .phy_read = dsa_loop_phy_read, .phy_write = dsa_loop_phy_write, .port_bridge_join = dsa_loop_port_bridge_join, diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index fefa454f3e56..b4f6e1a67dd9 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -977,10 +977,14 @@ static const struct lan9303_mib_desc lan9303_mib[] = { { .offset = LAN9303_MAC_TX_LATECOL_0, .name = "TxLateCol", }, }; -static void lan9303_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +static void lan9303_get_strings(struct dsa_switch *ds, int port, + u32 stringset, uint8_t *data) { unsigned int u; + if (stringset != ETH_SS_STATS) + return; + for (u = 0; u < ARRAY_SIZE(lan9303_mib); u++) { strncpy(data + u * ETH_GSTRING_LEN, lan9303_mib[u].name, ETH_GSTRING_LEN); @@ -1007,8 +1011,11 @@ static void lan9303_get_ethtool_stats(struct dsa_switch *ds, int port, } } -static int lan9303_get_sset_count(struct dsa_switch *ds, int port) +static int lan9303_get_sset_count(struct dsa_switch *ds, int port, int sset) { + if (sset != ETH_SS_STATS) + return 0; + return ARRAY_SIZE(lan9303_mib); } diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index bcb3e6c734f2..7210c49b7922 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -439,15 +439,22 @@ static void ksz_disable_port(struct dsa_switch *ds, int port, ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, true); } -static int ksz_sset_count(struct dsa_switch *ds, int port) +static int ksz_sset_count(struct dsa_switch *ds, int port, int sset) { + if (sset != ETH_SS_STATS) + return 0; + return TOTAL_SWITCH_COUNTER_NUM; } -static void ksz_get_strings(struct dsa_switch *ds, int port, uint8_t *buf) +static void ksz_get_strings(struct dsa_switch *ds, int port, + u32 stringset, uint8_t *buf) { int i; + if (stringset != ETH_SS_STATS) + return; + for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) { memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string, ETH_GSTRING_LEN); diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 80a4dbc3a499..62e486652e62 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -573,10 +573,14 @@ static int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, } static void -mt7530_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset, + uint8_t *data) { int i; + if (stringset != ETH_SS_STATS) + return; + for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name, ETH_GSTRING_LEN); @@ -604,8 +608,11 @@ mt7530_get_ethtool_stats(struct dsa_switch *ds, int port, } static int -mt7530_get_sset_count(struct dsa_switch *ds, int port) +mt7530_get_sset_count(struct dsa_switch *ds, int port, int sset) { + if (sset != ETH_SS_STATS) + return 0; + return ARRAY_SIZE(mt7530_mib); } diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 3d2091099f7f..8f92ccc0dd54 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -742,11 +742,14 @@ static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) } static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, - uint8_t *data) + u32 stringset, uint8_t *data) { struct mv88e6xxx_chip *chip = ds->priv; int count = 0; + if (stringset != ETH_SS_STATS) + return; + mutex_lock(&chip->reg_lock); if (chip->info->ops->stats_get_strings) @@ -789,12 +792,15 @@ static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) STATS_TYPE_BANK1); } -static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port) +static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) { struct mv88e6xxx_chip *chip = ds->priv; int serdes_count = 0; int count = 0; + if (sset != ETH_SS_STATS) + return 0; + mutex_lock(&chip->reg_lock); if (chip->info->ops->stats_get_sset_count) count = chip->info->ops->stats_get_sset_count(chip); diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 600d5ad1fbde..757b6d90ea36 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -600,10 +600,13 @@ qca8k_phy_write(struct dsa_switch *ds, int phy, int regnum, u16 val) } static void -qca8k_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) { int i; + if (stringset != ETH_SS_STATS) + return; + for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, ETH_GSTRING_LEN); @@ -631,8 +634,11 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, } static int -qca8k_get_sset_count(struct dsa_switch *ds, int port) +qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) { + if (sset != ETH_SS_STATS) + return 0; + return ARRAY_SIZE(ar8327_mib); } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 05c1e8ef15e6..a98ed12c0009 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1277,3 +1277,51 @@ int phy_ethtool_nway_reset(struct net_device *ndev) return phy_restart_aneg(phydev); } EXPORT_SYMBOL(phy_ethtool_nway_reset); + +int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data) +{ + if (!phydev->drv) + return -EIO; + + mutex_lock(&phydev->lock); + phydev->drv->get_strings(phydev, data); + mutex_unlock(&phydev->lock); + + return 0; +} +EXPORT_SYMBOL(phy_ethtool_get_strings); + +int phy_ethtool_get_sset_count(struct phy_device *phydev) +{ + int ret; + + if (!phydev->drv) + return -EIO; + + if (phydev->drv->get_sset_count && + phydev->drv->get_strings && + phydev->drv->get_stats) { + mutex_lock(&phydev->lock); + ret = phydev->drv->get_sset_count(phydev); + mutex_unlock(&phydev->lock); + + return ret; + } + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(phy_ethtool_get_sset_count); + +int phy_ethtool_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + if (!phydev->drv) + return -EIO; + + mutex_lock(&phydev->lock); + phydev->drv->get_stats(phydev, stats, data); + mutex_unlock(&phydev->lock); + + return 0; +} +EXPORT_SYMBOL(phy_ethtool_get_stats); |