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

net: dsa: Allow providing PHY statistics from CPU port

Implement the same type of ethtool diversion that we have for
ETH_SS_STATS and make it work with ETH_SS_PHY_STATS. This allows
providing PHY level statistics for CPU ports that are directly
connecting to a PHY device.
Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6207a78c
...@@ -361,6 +361,8 @@ struct dsa_switch_ops { ...@@ -361,6 +361,8 @@ struct dsa_switch_ops {
void (*get_ethtool_stats)(struct dsa_switch *ds, void (*get_ethtool_stats)(struct dsa_switch *ds,
int port, uint64_t *data); int port, uint64_t *data);
int (*get_sset_count)(struct dsa_switch *ds, int port, int sset); int (*get_sset_count)(struct dsa_switch *ds, int port, int sset);
void (*get_ethtool_phy_stats)(struct dsa_switch *ds,
int port, uint64_t *data);
/* /*
* ethtool Wake-on-LAN * ethtool Wake-on-LAN
...@@ -589,4 +591,9 @@ static inline int call_dsa_notifiers(unsigned long val, struct net_device *dev, ...@@ -589,4 +591,9 @@ static inline int call_dsa_notifiers(unsigned long val, struct net_device *dev,
#define BRCM_TAG_GET_PORT(v) ((v) >> 8) #define BRCM_TAG_GET_PORT(v) ((v) >> 8)
#define BRCM_TAG_GET_QUEUE(v) ((v) & 0xff) #define BRCM_TAG_GET_QUEUE(v) ((v) & 0xff)
int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data);
int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data);
int dsa_port_get_phy_sset_count(struct dsa_port *dp);
#endif #endif
...@@ -31,6 +31,32 @@ static void dsa_master_get_ethtool_stats(struct net_device *dev, ...@@ -31,6 +31,32 @@ static void dsa_master_get_ethtool_stats(struct net_device *dev,
ds->ops->get_ethtool_stats(ds, port, data + count); ds->ops->get_ethtool_stats(ds, port, data + count);
} }
static void dsa_master_get_ethtool_phy_stats(struct net_device *dev,
struct ethtool_stats *stats,
uint64_t *data)
{
struct dsa_port *cpu_dp = dev->dsa_ptr;
const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
struct dsa_switch *ds = cpu_dp->ds;
int port = cpu_dp->index;
int count = 0;
if (dev->phydev && !ops->get_ethtool_phy_stats) {
count = phy_ethtool_get_sset_count(dev->phydev);
if (count >= 0)
phy_ethtool_get_stats(dev->phydev, stats, data);
} else if (ops->get_sset_count && ops->get_ethtool_phy_stats) {
count = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
ops->get_ethtool_phy_stats(dev, stats, data);
}
if (count < 0)
count = 0;
if (ds->ops->get_ethtool_phy_stats)
ds->ops->get_ethtool_phy_stats(ds, port, data + count);
}
static int dsa_master_get_sset_count(struct net_device *dev, int sset) static int dsa_master_get_sset_count(struct net_device *dev, int sset)
{ {
struct dsa_port *cpu_dp = dev->dsa_ptr; struct dsa_port *cpu_dp = dev->dsa_ptr;
...@@ -38,11 +64,14 @@ static int dsa_master_get_sset_count(struct net_device *dev, int sset) ...@@ -38,11 +64,14 @@ static int dsa_master_get_sset_count(struct net_device *dev, int sset)
struct dsa_switch *ds = cpu_dp->ds; struct dsa_switch *ds = cpu_dp->ds;
int count = 0; int count = 0;
if (ops->get_sset_count) { if (sset == ETH_SS_PHY_STATS && dev->phydev &&
!ops->get_ethtool_phy_stats)
count = phy_ethtool_get_sset_count(dev->phydev);
else if (ops->get_sset_count)
count = ops->get_sset_count(dev, sset); count = ops->get_sset_count(dev, sset);
if (count < 0) if (count < 0)
count = 0; count = 0;
}
if (ds->ops->get_sset_count) if (ds->ops->get_sset_count)
count += ds->ops->get_sset_count(ds, cpu_dp->index, sset); count += ds->ops->get_sset_count(ds, cpu_dp->index, sset);
...@@ -67,7 +96,14 @@ static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset, ...@@ -67,7 +96,14 @@ static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset,
/* We do not want to be NULL-terminated, since this is a prefix */ /* We do not want to be NULL-terminated, since this is a prefix */
pfx[sizeof(pfx) - 1] = '_'; pfx[sizeof(pfx) - 1] = '_';
if (ops->get_sset_count && ops->get_strings) { if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
!ops->get_ethtool_phy_stats) {
mcount = phy_ethtool_get_sset_count(dev->phydev);
if (mcount < 0)
mcount = 0;
else
phy_ethtool_get_strings(dev->phydev, data);
} else if (ops->get_sset_count && ops->get_strings) {
mcount = ops->get_sset_count(dev, stringset); mcount = ops->get_sset_count(dev, stringset);
if (mcount < 0) if (mcount < 0)
mcount = 0; mcount = 0;
...@@ -107,6 +143,7 @@ static int dsa_master_ethtool_setup(struct net_device *dev) ...@@ -107,6 +143,7 @@ static int dsa_master_ethtool_setup(struct net_device *dev)
ops->get_sset_count = dsa_master_get_sset_count; ops->get_sset_count = dsa_master_get_sset_count;
ops->get_ethtool_stats = dsa_master_get_ethtool_stats; ops->get_ethtool_stats = dsa_master_get_ethtool_stats;
ops->get_strings = dsa_master_get_strings; ops->get_strings = dsa_master_get_strings;
ops->get_ethtool_phy_stats = dsa_master_get_ethtool_phy_stats;
dev->ethtool_ops = ops; dev->ethtool_ops = ops;
......
...@@ -383,3 +383,60 @@ void dsa_port_link_unregister_of(struct dsa_port *dp) ...@@ -383,3 +383,60 @@ void dsa_port_link_unregister_of(struct dsa_port *dp)
else else
dsa_port_setup_phy_of(dp, false); dsa_port_setup_phy_of(dp, false);
} }
int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data)
{
struct phy_device *phydev;
int ret = -EOPNOTSUPP;
if (of_phy_is_fixed_link(dp->dn))
return ret;
phydev = dsa_port_get_phy_device(dp);
if (IS_ERR_OR_NULL(phydev))
return ret;
ret = phy_ethtool_get_strings(phydev, data);
put_device(&phydev->mdio.dev);
return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings);
int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data)
{
struct phy_device *phydev;
int ret = -EOPNOTSUPP;
if (of_phy_is_fixed_link(dp->dn))
return ret;
phydev = dsa_port_get_phy_device(dp);
if (IS_ERR_OR_NULL(phydev))
return ret;
ret = phy_ethtool_get_stats(phydev, NULL, data);
put_device(&phydev->mdio.dev);
return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats);
int dsa_port_get_phy_sset_count(struct dsa_port *dp)
{
struct phy_device *phydev;
int ret = -EOPNOTSUPP;
if (of_phy_is_fixed_link(dp->dn))
return ret;
phydev = dsa_port_get_phy_device(dp);
if (IS_ERR_OR_NULL(phydev))
return ret;
ret = phy_ethtool_get_sset_count(phydev);
put_device(&phydev->mdio.dev);
return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);
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