History

net: phy: Maintain MDIO device and bus statistics

We maintain global statistics for an entire MDIO bus, as well as broken down, per MDIO bus address statistics. Given that it is possible for MDIO devices such as switches to access MDIO bus addresses for which there is not a mdio_device instance created (therefore not a a corresponding device directory in sysfs either), we also maintain per-address statistics under the statistics folder. The layout looks like this: /sys/class/mdio_bus/../statistics/ transfers errrors writes reads transfers_<addr> errors_<addr> writes_<addr> reads_<addr> When a mdio_device instance is registered, a statistics/ folder is created with the tranfers, errors, writes and reads attributes which point to the appropriate MDIO bus statistics structure. Statistics are 64-bit unsigned quantities and maintained through the u64_stats_sync.h helper functions.

Florian Fainelli committed 6 years ago

Commit 080bb351 parent 41cdc743 files · +323 −2Browse files

Unified · Split

3 files
  1. Documentation/ABI/testing/sysfs-bus-mdio +63 −0
  2. drivers/net/phy/mdio_bus.c +249 −2
  3. include/linux/phy.h +11 −0
Documentation/ABI/testing/sysfs-bus-mdio+63−0
@@ -0,0 +1,63 @@
1+What: /sys/bus/mdio_bus/devices/.../statistics/
2+Date: January 2020
3+KernelVersion: 5.6
4+Contact: netdev@vger.kernel.org
5+Description:
6+ This folder contains statistics about global and per
7+ MDIO bus address statistics.
8+
9+What: /sys/bus/mdio_bus/devices/.../statistics/transfers
10+Date: January 2020
11+KernelVersion: 5.6
12+Contact: netdev@vger.kernel.org
13+Description:
14+ Total number of transfers for this MDIO bus.
15+
16+What: /sys/bus/mdio_bus/devices/.../statistics/errors
17+Date: January 2020
18+KernelVersion: 5.6
19+Contact: netdev@vger.kernel.org
20+Description:
21+ Total number of transfer errors for this MDIO bus.
22+
23+What: /sys/bus/mdio_bus/devices/.../statistics/writes
24+Date: January 2020
25+KernelVersion: 5.6
26+Contact: netdev@vger.kernel.org
27+Description:
28+ Total number of write transactions for this MDIO bus.
29+
30+What: /sys/bus/mdio_bus/devices/.../statistics/reads
31+Date: January 2020
32+KernelVersion: 5.6
33+Contact: netdev@vger.kernel.org
34+Description:
35+ Total number of read transactions for this MDIO bus.
36+
37+What: /sys/bus/mdio_bus/devices/.../statistics/transfers_<addr>
38+Date: January 2020
39+KernelVersion: 5.6
40+Contact: netdev@vger.kernel.org
41+Description:
42+ Total number of transfers for this MDIO bus address.
43+
44+What: /sys/bus/mdio_bus/devices/.../statistics/errors_<addr>
45+Date: January 2020
46+KernelVersion: 5.6
47+Contact: netdev@vger.kernel.org
48+Description:
49+ Total number of transfer errors for this MDIO bus address.
50+
51+What: /sys/bus/mdio_bus/devices/.../statistics/writes_<addr>
52+Date: January 2020
53+KernelVersion: 5.6
54+Contact: netdev@vger.kernel.org
55+Description:
56+ Total number of write transactions for this MDIO bus address.
57+
58+What: /sys/bus/mdio_bus/devices/.../statistics/reads_<addr>
59+Date: January 2020
60+KernelVersion: 5.6
61+Contact: netdev@vger.kernel.org
62+Description:
63+ Total number of read transactions for this MDIO bus address.
drivers/net/phy/mdio_bus.c+249−2
@@ -158,9 +158,11 @@ struct mii_bus *mdiobus_alloc_size(size_t size) · 157 unmodified lines
158158 if (size)
159159 bus->priv = (void *)bus + aligned_size;
160160
161− /* Initialise the interrupts to polling */
162− for (i = 0; i < PHY_MAX_ADDR; i++)
161+ /* Initialise the interrupts to polling and 64-bit seqcounts */
162+ for (i = 0; i < PHY_MAX_ADDR; i++) {
163163 bus->irq[i] = PHY_POLL;
164+ u64_stats_init(&bus->stats[i].syncp);
165+ }
164166
165167 return bus;
166168 }
@@ -249,9 +251,215 @@ static void mdiobus_release(struct device *d) · 82 unmodified lines
249251 kfree(bus);
250252 }
251253
254+struct mdio_bus_stat_attr {
255+ int addr;
256+ unsigned int field_offset;
257+};
258+
259+static u64 mdio_bus_get_stat(struct mdio_bus_stats *s, unsigned int offset)
260+{
261+ const char *p = (const char *)s + offset;
262+ unsigned int start;
263+ u64 val = 0;
264+
265+ do {
266+ start = u64_stats_fetch_begin(&s->syncp);
267+ val = u64_stats_read((const u64_stats_t *)p);
268+ } while (u64_stats_fetch_retry(&s->syncp, start));
269+
270+ return val;
271+}
272+
273+static u64 mdio_bus_get_global_stat(struct mii_bus *bus, unsigned int offset)
274+{
275+ unsigned int i;
276+ u64 val = 0;
277+
278+ for (i = 0; i < PHY_MAX_ADDR; i++)
279+ val += mdio_bus_get_stat(&bus->stats[i], offset);
280+
281+ return val;
282+}
283+
284+static ssize_t mdio_bus_stat_field_show(struct device *dev,
285+ struct device_attribute *attr,
286+ char *buf)
287+{
288+ struct mii_bus *bus = to_mii_bus(dev);
289+ struct mdio_bus_stat_attr *sattr;
290+ struct dev_ext_attribute *eattr;
291+ u64 val;
292+
293+ eattr = container_of(attr, struct dev_ext_attribute, attr);
294+ sattr = eattr->var;
295+
296+ if (sattr->addr < 0)
297+ val = mdio_bus_get_global_stat(bus, sattr->field_offset);
298+ else
299+ val = mdio_bus_get_stat(&bus->stats[sattr->addr],
300+ sattr->field_offset);
301+
302+ return sprintf(buf, "%llu\n", val);
303+}
304+
305+static ssize_t mdio_bus_device_stat_field_show(struct device *dev,
306+ struct device_attribute *attr,
307+ char *buf)
308+{
309+ struct mdio_device *mdiodev = to_mdio_device(dev);
310+ struct mii_bus *bus = mdiodev->bus;
311+ struct mdio_bus_stat_attr *sattr;
312+ struct dev_ext_attribute *eattr;
313+ int addr = mdiodev->addr;
314+ u64 val;
315+
316+ eattr = container_of(attr, struct dev_ext_attribute, attr);
317+ sattr = eattr->var;
318+
319+ val = mdio_bus_get_stat(&bus->stats[addr], sattr->field_offset);
320+
321+ return sprintf(buf, "%llu\n", val);
322+}
323+
324+#define MDIO_BUS_STATS_ATTR_DECL(field, file) \
325+static struct dev_ext_attribute dev_attr_mdio_bus_##field = { \
326+ .attr = { .attr = { .name = file, .mode = 0444 }, \
327+ .show = mdio_bus_stat_field_show, \
328+ }, \
329+ .var = &((struct mdio_bus_stat_attr) { \
330+ -1, offsetof(struct mdio_bus_stats, field) \
331+ }), \
332+}; \
333+static struct dev_ext_attribute dev_attr_mdio_bus_device_##field = { \
334+ .attr = { .attr = { .name = file, .mode = 0444 }, \
335+ .show = mdio_bus_device_stat_field_show, \
336+ }, \
337+ .var = &((struct mdio_bus_stat_attr) { \
338+ -1, offsetof(struct mdio_bus_stats, field) \
339+ }), \
340+};
341+
342+#define MDIO_BUS_STATS_ATTR(field) \
343+ MDIO_BUS_STATS_ATTR_DECL(field, __stringify(field))
344+
345+MDIO_BUS_STATS_ATTR(transfers);
346+MDIO_BUS_STATS_ATTR(errors);
347+MDIO_BUS_STATS_ATTR(writes);
348+MDIO_BUS_STATS_ATTR(reads);
349+
350+#define MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, file) \
351+static struct dev_ext_attribute dev_attr_mdio_bus_addr_##field##_##addr = { \
352+ .attr = { .attr = { .name = file, .mode = 0444 }, \
353+ .show = mdio_bus_stat_field_show, \
354+ }, \
355+ .var = &((struct mdio_bus_stat_attr) { \
356+ addr, offsetof(struct mdio_bus_stats, field) \
357+ }), \
358+}
359+
360+#define MDIO_BUS_STATS_ADDR_ATTR(field, addr) \
361+ MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, \
362+ __stringify(field) "_" __stringify(addr))
363+
364+#define MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(addr) \
365+ MDIO_BUS_STATS_ADDR_ATTR(transfers, addr); \
366+ MDIO_BUS_STATS_ADDR_ATTR(errors, addr); \
367+ MDIO_BUS_STATS_ADDR_ATTR(writes, addr); \
368+ MDIO_BUS_STATS_ADDR_ATTR(reads, addr) \
369+
370+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(0);
371+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(1);
372+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(2);
373+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(3);
374+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(4);
375+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(5);
376+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(6);
377+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(7);
378+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(8);
379+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(9);
380+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(10);
381+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(11);
382+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(12);
383+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(13);
384+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(14);
385+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(15);
386+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(16);
387+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(17);
388+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(18);
389+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(19);
390+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(20);
391+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(21);
392+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(22);
393+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(23);
394+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(24);
395+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(25);
396+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(26);
397+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(27);
398+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(28);
399+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(29);
400+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(30);
401+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(31);
402+
403+#define MDIO_BUS_STATS_ADDR_ATTR_GROUP(addr) \
404+ &dev_attr_mdio_bus_addr_transfers_##addr.attr.attr, \
405+ &dev_attr_mdio_bus_addr_errors_##addr.attr.attr, \
406+ &dev_attr_mdio_bus_addr_writes_##addr.attr.attr, \
407+ &dev_attr_mdio_bus_addr_reads_##addr.attr.attr \
408+
409+static struct attribute *mdio_bus_statistics_attrs[] = {
410+ &dev_attr_mdio_bus_transfers.attr.attr,
411+ &dev_attr_mdio_bus_errors.attr.attr,
412+ &dev_attr_mdio_bus_writes.attr.attr,
413+ &dev_attr_mdio_bus_reads.attr.attr,
414+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(0),
415+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(1),
416+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(2),
417+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(3),
418+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(4),
419+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(5),
420+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(6),
421+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(7),
422+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(8),
423+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(9),
424+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(10),
425+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(11),
426+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(12),
427+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(13),
428+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(14),
429+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(15),
430+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(16),
431+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(17),
432+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(18),
433+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(19),
434+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(20),
435+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(21),
436+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(22),
437+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(23),
438+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(24),
439+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(25),
440+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(26),
441+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(27),
442+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(28),
443+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(29),
444+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(30),
445+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(31),
446+ NULL,
447+};
448+
449+static const struct attribute_group mdio_bus_statistics_group = {
450+ .name = "statistics",
451+ .attrs = mdio_bus_statistics_attrs,
452+};
453+
454+static const struct attribute_group *mdio_bus_groups[] = {
455+ &mdio_bus_statistics_group,
456+ NULL,
457+};
458+
252459 static struct class mdio_bus_class = {
253460 .name = "mdio_bus",
254461 .dev_release = mdiobus_release,
462+ .dev_groups = mdio_bus_groups,
255463 };
256464
257465 #if IS_ENABLED(CONFIG_OF_MDIO)
@@ -530,6 +738,24 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) · 272 unmodified lines
530738 }
531739 EXPORT_SYMBOL(mdiobus_scan);
532740
741+static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
742+{
743+ u64_stats_update_begin(&stats->syncp);
744+
745+ u64_stats_inc(&stats->transfers);
746+ if (ret < 0) {
747+ u64_stats_inc(&stats->errors);
748+ goto out;
749+ }
750+
751+ if (op)
752+ u64_stats_inc(&stats->reads);
753+ else
754+ u64_stats_inc(&stats->writes);
755+out:
756+ u64_stats_update_end(&stats->syncp);
757+}
758+
533759 /**
534760 * __mdiobus_read - Unlocked version of the mdiobus_read function
535761 * @bus: the mii_bus struct
@@ -549,6 +775,7 @@ int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) · 13 unmodified lines
549775 retval = bus->read(bus, addr, regnum);
550776
551777 trace_mdio_access(bus, 1, addr, regnum, retval, retval);
778+ mdiobus_stats_acct(&bus->stats[addr], true, retval);
552779
553780 return retval;
554781 }
@@ -574,6 +801,7 @@ int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) · 19 unmodified lines
574801 err = bus->write(bus, addr, regnum, val);
575802
576803 trace_mdio_access(bus, 0, addr, regnum, val, err);
804+ mdiobus_stats_acct(&bus->stats[addr], false, err);
577805
578806 return err;
579807 }
@@ -719,8 +947,27 @@ static int mdio_uevent(struct device *dev, struct kobj_uevent_env *env) · 139 unmodified lines
719947 return 0;
720948 }
721949
950+static struct attribute *mdio_bus_device_statistics_attrs[] = {
951+ &dev_attr_mdio_bus_device_transfers.attr.attr,
952+ &dev_attr_mdio_bus_device_errors.attr.attr,
953+ &dev_attr_mdio_bus_device_writes.attr.attr,
954+ &dev_attr_mdio_bus_device_reads.attr.attr,
955+ NULL,
956+};
957+
958+static const struct attribute_group mdio_bus_device_statistics_group = {
959+ .name = "statistics",
960+ .attrs = mdio_bus_device_statistics_attrs,
961+};
962+
963+static const struct attribute_group *mdio_bus_dev_groups[] = {
964+ &mdio_bus_device_statistics_group,
965+ NULL,
966+};
967+
722968 struct bus_type mdio_bus_type = {
723969 .name = "mdio_bus",
970+ .dev_groups = mdio_bus_dev_groups,
724971 .match = mdio_bus_match,
725972 .uevent = mdio_uevent,
726973 };
include/linux/phy.h+11−0
@@ -22,6 +22,7 @@ · 21 unmodified lines
2222 #include <linux/timer.h>
2323 #include <linux/workqueue.h>
2424 #include <linux/mod_devicetable.h>
25+#include <linux/u64_stats_sync.h>
2526
2627 #include <linux/atomic.h>
2728
@@ -212,6 +213,15 @@ struct sfp_bus; · 184 unmodified lines
212213 struct sfp_upstream_ops;
213214 struct sk_buff;
214215
216+struct mdio_bus_stats {
217+ u64_stats_t transfers;
218+ u64_stats_t errors;
219+ u64_stats_t writes;
220+ u64_stats_t reads;
221+ /* Must be last, add new statistics above */
222+ struct u64_stats_sync syncp;
223+};
224+
215225 /*
216226 * The Bus class for PHYs. Devices which provide access to
217227 * PHYs should register using this structure
@@ -224,6 +234,7 @@ struct mii_bus { · 6 unmodified lines
224234 int (*read)(struct mii_bus *bus, int addr, int regnum);
225235 int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);
226236 int (*reset)(struct mii_bus *bus);
237+ struct mdio_bus_stats stats[PHY_MAX_ADDR];
227238
228239 /*
229240 * A lock to ensure that only one thing can read/write