Commit c7d28c9d authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller

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: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cf963573
...@@ -806,20 +806,39 @@ static unsigned int b53_get_mib_size(struct b53_device *dev) ...@@ -806,20 +806,39 @@ static unsigned int b53_get_mib_size(struct b53_device *dev)
return B53_MIBS_SIZE; 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, void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
uint8_t *data) uint8_t *data)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
const struct b53_mib_desc *mibs = b53_get_mib(dev); const struct b53_mib_desc *mibs = b53_get_mib(dev);
unsigned int mib_size = b53_get_mib_size(dev); unsigned int mib_size = b53_get_mib_size(dev);
struct phy_device *phydev;
unsigned int i; unsigned int i;
if (stringset != ETH_SS_STATS) if (stringset == ETH_SS_STATS) {
return;
for (i = 0; i < mib_size; i++) for (i = 0; i < mib_size; i++)
strlcpy(data + i * ETH_GSTRING_LEN, strlcpy(data + i * ETH_GSTRING_LEN,
mibs[i].name, 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); EXPORT_SYMBOL(b53_get_strings);
...@@ -856,14 +875,34 @@ void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) ...@@ -856,14 +875,34 @@ void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
} }
EXPORT_SYMBOL(b53_get_ethtool_stats); 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) int b53_get_sset_count(struct dsa_switch *ds, int port, int sset)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
struct phy_device *phydev;
if (sset != ETH_SS_STATS) 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 0;
return b53_get_mib_size(dev); return phy_ethtool_get_sset_count(phydev);
}
return 0;
} }
EXPORT_SYMBOL(b53_get_sset_count); EXPORT_SYMBOL(b53_get_sset_count);
...@@ -1484,7 +1523,7 @@ void b53_br_fast_age(struct dsa_switch *ds, int port) ...@@ -1484,7 +1523,7 @@ void b53_br_fast_age(struct dsa_switch *ds, int port)
} }
EXPORT_SYMBOL(b53_br_fast_age); 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 /* Broadcom switches will accept enabling Broadcom tags on the
* following ports: 5, 7 and 8, any other port is not supported * 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) ...@@ -1496,10 +1535,19 @@ static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
return true; return true;
} }
dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n", port);
return false; 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) enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
...@@ -1657,6 +1705,7 @@ static const struct dsa_switch_ops b53_switch_ops = { ...@@ -1657,6 +1705,7 @@ static const struct dsa_switch_ops b53_switch_ops = {
.get_strings = b53_get_strings, .get_strings = b53_get_strings,
.get_ethtool_stats = b53_get_ethtool_stats, .get_ethtool_stats = b53_get_ethtool_stats,
.get_sset_count = b53_get_sset_count, .get_sset_count = b53_get_sset_count,
.get_ethtool_phy_stats = b53_get_ethtool_phy_stats,
.phy_read = b53_phy_read16, .phy_read = b53_phy_read16,
.phy_write = b53_phy_write16, .phy_write = b53_phy_write16,
.adjust_link = b53_adjust_link, .adjust_link = b53_adjust_link,
...@@ -1961,6 +2010,15 @@ static int b53_switch_init(struct b53_device *dev) ...@@ -1961,6 +2010,15 @@ static int b53_switch_init(struct b53_device *dev)
dev->num_ports = dev->cpu_port + 1; dev->num_ports = dev->cpu_port + 1;
dev->enabled_ports |= BIT(dev->cpu_port); 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, dev->ports = devm_kzalloc(dev->dev,
sizeof(struct b53_port) * dev->num_ports, sizeof(struct b53_port) * dev->num_ports,
GFP_KERNEL); GFP_KERNEL);
......
...@@ -290,6 +290,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset, ...@@ -290,6 +290,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
uint8_t *data); uint8_t *data);
void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_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); 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); 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_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); void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state);
......
...@@ -859,6 +859,7 @@ static const struct dsa_switch_ops bcm_sf2_ops = { ...@@ -859,6 +859,7 @@ static const struct dsa_switch_ops bcm_sf2_ops = {
.get_strings = b53_get_strings, .get_strings = b53_get_strings,
.get_ethtool_stats = b53_get_ethtool_stats, .get_ethtool_stats = b53_get_ethtool_stats,
.get_sset_count = b53_get_sset_count, .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, .get_phy_flags = bcm_sf2_sw_get_phy_flags,
.adjust_link = bcm_sf2_sw_adjust_link, .adjust_link = bcm_sf2_sw_adjust_link,
.fixed_link_update = bcm_sf2_sw_fixed_link_update, .fixed_link_update = bcm_sf2_sw_fixed_link_update,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment