net: dsa: b53: Add support for reading PHY statistics

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>
This commit is contained in:
Florian Fainelli 2018-04-25 12:12:53 -07:00 committed by David S. Miller
parent cf96357303
commit c7d28c9df2
3 changed files with 70 additions and 10 deletions

View 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 b53_get_mib_size(dev);
return phy_ethtool_get_sset_count(phydev);
}
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);

View 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);

View 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,