diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2018-04-25 15:12:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-27 11:53:03 -0400 |
commit | cf963573039a333eff7156629e61a06e59da61cf (patch) | |
tree | 78375bd5f5d00dab15a09c64c962b59ed93601ab | |
parent | 6207a78c098a183df1620c1e2cbf620a4cc7c3e3 (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.h | 7 | ||||
-rw-r--r-- | net/dsa/master.c | 47 | ||||
-rw-r--r-- | net/dsa/port.c | 57 |
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 | |||
595 | int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data); | ||
596 | int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data); | ||
597 | int 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 | ||
34 | static 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 | |||
34 | static int dsa_master_get_sset_count(struct net_device *dev, int sset) | 60 | static 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 | |||
387 | int 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 | } | ||
404 | EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings); | ||
405 | |||
406 | int 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 | } | ||
423 | EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats); | ||
424 | |||
425 | int 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 | } | ||
442 | EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count); | ||