summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2018-04-25 15:12:52 -0400
committerDavid S. Miller <davem@davemloft.net>2018-04-27 11:53:03 -0400
commitcf963573039a333eff7156629e61a06e59da61cf (patch)
tree78375bd5f5d00dab15a09c64c962b59ed93601ab
parent6207a78c098a183df1620c1e2cbf620a4cc7c3e3 (diff)
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: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/dsa.h7
-rw-r--r--net/dsa/master.c47
-rw-r--r--net/dsa/port.c57
3 files changed, 106 insertions, 5 deletions
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 0bc0aad1b02e..462e9741b210 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -361,6 +361,8 @@ struct dsa_switch_ops {
361 void (*get_ethtool_stats)(struct dsa_switch *ds, 361 void (*get_ethtool_stats)(struct dsa_switch *ds,
362 int port, uint64_t *data); 362 int port, uint64_t *data);
363 int (*get_sset_count)(struct dsa_switch *ds, int port, int sset); 363 int (*get_sset_count)(struct dsa_switch *ds, int port, int sset);
364 void (*get_ethtool_phy_stats)(struct dsa_switch *ds,
365 int port, uint64_t *data);
364 366
365 /* 367 /*
366 * ethtool Wake-on-LAN 368 * ethtool Wake-on-LAN
@@ -589,4 +591,9 @@ static inline int call_dsa_notifiers(unsigned long val, struct net_device *dev,
589#define BRCM_TAG_GET_PORT(v) ((v) >> 8) 591#define BRCM_TAG_GET_PORT(v) ((v) >> 8)
590#define BRCM_TAG_GET_QUEUE(v) ((v) & 0xff) 592#define BRCM_TAG_GET_QUEUE(v) ((v) & 0xff)
591 593
594
595int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data);
596int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data);
597int dsa_port_get_phy_sset_count(struct dsa_port *dp);
598
592#endif 599#endif
diff --git a/net/dsa/master.c b/net/dsa/master.c
index 8d27687fd0ca..c90ee3227dea 100644
--- a/net/dsa/master.c
+++ b/net/dsa/master.c
@@ -31,6 +31,32 @@ static void dsa_master_get_ethtool_stats(struct net_device *dev,
31 ds->ops->get_ethtool_stats(ds, port, data + count); 31 ds->ops->get_ethtool_stats(ds, port, data + count);
32} 32}
33 33
34static void dsa_master_get_ethtool_phy_stats(struct net_device *dev,
35 struct ethtool_stats *stats,
36 uint64_t *data)
37{
38 struct dsa_port *cpu_dp = dev->dsa_ptr;
39 const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
40 struct dsa_switch *ds = cpu_dp->ds;
41 int port = cpu_dp->index;
42 int count = 0;
43
44 if (dev->phydev && !ops->get_ethtool_phy_stats) {
45 count = phy_ethtool_get_sset_count(dev->phydev);
46 if (count >= 0)
47 phy_ethtool_get_stats(dev->phydev, stats, data);
48 } else if (ops->get_sset_count && ops->get_ethtool_phy_stats) {
49 count = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
50 ops->get_ethtool_phy_stats(dev, stats, data);
51 }
52
53 if (count < 0)
54 count = 0;
55
56 if (ds->ops->get_ethtool_phy_stats)
57 ds->ops->get_ethtool_phy_stats(ds, port, data + count);
58}
59
34static int dsa_master_get_sset_count(struct net_device *dev, int sset) 60static int dsa_master_get_sset_count(struct net_device *dev, int sset)
35{ 61{
36 struct dsa_port *cpu_dp = dev->dsa_ptr; 62 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 struct dsa_switch *ds = cpu_dp->ds; 64 struct dsa_switch *ds = cpu_dp->ds;
39 int count = 0; 65 int count = 0;
40 66
41 if (ops->get_sset_count) { 67 if (sset == ETH_SS_PHY_STATS && dev->phydev &&
68 !ops->get_ethtool_phy_stats)
69 count = phy_ethtool_get_sset_count(dev->phydev);
70 else if (ops->get_sset_count)
42 count = ops->get_sset_count(dev, sset); 71 count = ops->get_sset_count(dev, sset);
43 if (count < 0) 72
44 count = 0; 73 if (count < 0)
45 } 74 count = 0;
46 75
47 if (ds->ops->get_sset_count) 76 if (ds->ops->get_sset_count)
48 count += ds->ops->get_sset_count(ds, cpu_dp->index, sset); 77 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 /* We do not want to be NULL-terminated, since this is a prefix */ 96 /* We do not want to be NULL-terminated, since this is a prefix */
68 pfx[sizeof(pfx) - 1] = '_'; 97 pfx[sizeof(pfx) - 1] = '_';
69 98
70 if (ops->get_sset_count && ops->get_strings) { 99 if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
100 !ops->get_ethtool_phy_stats) {
101 mcount = phy_ethtool_get_sset_count(dev->phydev);
102 if (mcount < 0)
103 mcount = 0;
104 else
105 phy_ethtool_get_strings(dev->phydev, data);
106 } else if (ops->get_sset_count && ops->get_strings) {
71 mcount = ops->get_sset_count(dev, stringset); 107 mcount = ops->get_sset_count(dev, stringset);
72 if (mcount < 0) 108 if (mcount < 0)
73 mcount = 0; 109 mcount = 0;
@@ -107,6 +143,7 @@ static int dsa_master_ethtool_setup(struct net_device *dev)
107 ops->get_sset_count = dsa_master_get_sset_count; 143 ops->get_sset_count = dsa_master_get_sset_count;
108 ops->get_ethtool_stats = dsa_master_get_ethtool_stats; 144 ops->get_ethtool_stats = dsa_master_get_ethtool_stats;
109 ops->get_strings = dsa_master_get_strings; 145 ops->get_strings = dsa_master_get_strings;
146 ops->get_ethtool_phy_stats = dsa_master_get_ethtool_phy_stats;
110 147
111 dev->ethtool_ops = ops; 148 dev->ethtool_ops = ops;
112 149
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 5e2a88720a9a..2413beb995be 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -383,3 +383,60 @@ void dsa_port_link_unregister_of(struct dsa_port *dp)
383 else 383 else
384 dsa_port_setup_phy_of(dp, false); 384 dsa_port_setup_phy_of(dp, false);
385} 385}
386
387int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data)
388{
389 struct phy_device *phydev;
390 int ret = -EOPNOTSUPP;
391
392 if (of_phy_is_fixed_link(dp->dn))
393 return ret;
394
395 phydev = dsa_port_get_phy_device(dp);
396 if (IS_ERR_OR_NULL(phydev))
397 return ret;
398
399 ret = phy_ethtool_get_strings(phydev, data);
400 put_device(&phydev->mdio.dev);
401
402 return ret;
403}
404EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings);
405
406int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data)
407{
408 struct phy_device *phydev;
409 int ret = -EOPNOTSUPP;
410
411 if (of_phy_is_fixed_link(dp->dn))
412 return ret;
413
414 phydev = dsa_port_get_phy_device(dp);
415 if (IS_ERR_OR_NULL(phydev))
416 return ret;
417
418 ret = phy_ethtool_get_stats(phydev, NULL, data);
419 put_device(&phydev->mdio.dev);
420
421 return ret;
422}
423EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats);
424
425int dsa_port_get_phy_sset_count(struct dsa_port *dp)
426{
427 struct phy_device *phydev;
428 int ret = -EOPNOTSUPP;
429
430 if (of_phy_is_fixed_link(dp->dn))
431 return ret;
432
433 phydev = dsa_port_get_phy_device(dp);
434 if (IS_ERR_OR_NULL(phydev))
435 return ret;
436
437 ret = phy_ethtool_get_sset_count(phydev);
438 put_device(&phydev->mdio.dev);
439
440 return ret;
441}
442EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);