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 @@
1What: /sys/bus/mdio_bus/devices/.../statistics/
2Date: January 2020
3KernelVersion: 5.6
4Contact: netdev@vger.kernel.org
5Description:
6 This folder contains statistics about global and per
7 MDIO bus address statistics.
8
9What: /sys/bus/mdio_bus/devices/.../statistics/transfers
10Date: January 2020
11KernelVersion: 5.6
12Contact: netdev@vger.kernel.org
13Description:
14 Total number of transfers for this MDIO bus.
15
16What: /sys/bus/mdio_bus/devices/.../statistics/errors
17Date: January 2020
18KernelVersion: 5.6
19Contact: netdev@vger.kernel.org
20Description:
21 Total number of transfer errors for this MDIO bus.
22
23What: /sys/bus/mdio_bus/devices/.../statistics/writes
24Date: January 2020
25KernelVersion: 5.6
26Contact: netdev@vger.kernel.org
27Description:
28 Total number of write transactions for this MDIO bus.
29
30What: /sys/bus/mdio_bus/devices/.../statistics/reads
31Date: January 2020
32KernelVersion: 5.6
33Contact: netdev@vger.kernel.org
34Description:
35 Total number of read transactions for this MDIO bus.
36
37What: /sys/bus/mdio_bus/devices/.../statistics/transfers_<addr>
38Date: January 2020
39KernelVersion: 5.6
40Contact: netdev@vger.kernel.org
41Description:
42 Total number of transfers for this MDIO bus address.
43
44What: /sys/bus/mdio_bus/devices/.../statistics/errors_<addr>
45Date: January 2020
46KernelVersion: 5.6
47Contact: netdev@vger.kernel.org
48Description:
49 Total number of transfer errors for this MDIO bus address.
50
51What: /sys/bus/mdio_bus/devices/.../statistics/writes_<addr>
52Date: January 2020
53KernelVersion: 5.6
54Contact: netdev@vger.kernel.org
55Description:
56 Total number of write transactions for this MDIO bus address.
57
58What: /sys/bus/mdio_bus/devices/.../statistics/reads_<addr>
59Date: January 2020
60KernelVersion: 5.6
61Contact: netdev@vger.kernel.org
62Description:
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
158 if (size)158 if (size)
159 bus->priv = (void *)bus + aligned_size;159 bus->priv = (void *)bus + aligned_size;
160 160
161 /* Initialise the interrupts to polling */161 /* Initialise the interrupts to polling and 64-bit seqcounts */
162 for (i = 0; i < PHY_MAX_ADDR; i++)162 for (i = 0; i < PHY_MAX_ADDR; i++) {
163 bus->irq[i] = PHY_POLL;163 bus->irq[i] = PHY_POLL;
164 u64_stats_init(&bus->stats[i].syncp);
165 }
164 166
165 return bus;167 return bus;
166}168}
@@ -249,9 +251,215 @@ static void mdiobus_release(struct device *d) · 82 unmodified lines
249 kfree(bus);251 kfree(bus);
250}252}
251 253
254struct mdio_bus_stat_attr {
255 int addr;
256 unsigned int field_offset;
257};
258
259static 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
273static 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
284static 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
305static 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) \
325static 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}; \
333static 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
345MDIO_BUS_STATS_ATTR(transfers);
346MDIO_BUS_STATS_ATTR(errors);
347MDIO_BUS_STATS_ATTR(writes);
348MDIO_BUS_STATS_ATTR(reads);
349
350#define MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, file) \
351static 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
370MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(0);
371MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(1);
372MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(2);
373MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(3);
374MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(4);
375MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(5);
376MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(6);
377MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(7);
378MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(8);
379MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(9);
380MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(10);
381MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(11);
382MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(12);
383MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(13);
384MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(14);
385MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(15);
386MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(16);
387MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(17);
388MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(18);
389MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(19);
390MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(20);
391MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(21);
392MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(22);
393MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(23);
394MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(24);
395MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(25);
396MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(26);
397MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(27);
398MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(28);
399MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(29);
400MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(30);
401MDIO_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
409static 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
449static const struct attribute_group mdio_bus_statistics_group = {
450 .name = "statistics",
451 .attrs = mdio_bus_statistics_attrs,
452};
453
454static const struct attribute_group *mdio_bus_groups[] = {
455 &mdio_bus_statistics_group,
456 NULL,
457};
458
252static struct class mdio_bus_class = {459static struct class mdio_bus_class = {
253 .name = "mdio_bus",460 .name = "mdio_bus",
254 .dev_release = mdiobus_release,461 .dev_release = mdiobus_release,
462 .dev_groups = mdio_bus_groups,
255};463};
256 464
257#if IS_ENABLED(CONFIG_OF_MDIO)465#if IS_ENABLED(CONFIG_OF_MDIO)
@@ -530,6 +738,24 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) · 272 unmodified lines
530}738}
531EXPORT_SYMBOL(mdiobus_scan);739EXPORT_SYMBOL(mdiobus_scan);
532 740
741static 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);
755out:
756 u64_stats_update_end(&stats->syncp);
757}
758
533/**759/**
534 * __mdiobus_read - Unlocked version of the mdiobus_read function760 * __mdiobus_read - Unlocked version of the mdiobus_read function
535 * @bus: the mii_bus struct761 * @bus: the mii_bus struct
@@ -549,6 +775,7 @@ int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) · 13 unmodified lines
549 retval = bus->read(bus, addr, regnum);775 retval = bus->read(bus, addr, regnum);
550 776
551 trace_mdio_access(bus, 1, addr, regnum, retval, retval);777 trace_mdio_access(bus, 1, addr, regnum, retval, retval);
778 mdiobus_stats_acct(&bus->stats[addr], true, retval);
552 779
553 return retval;780 return retval;
554}781}
@@ -574,6 +801,7 @@ int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) · 19 unmodified lines
574 err = bus->write(bus, addr, regnum, val);801 err = bus->write(bus, addr, regnum, val);
575 802
576 trace_mdio_access(bus, 0, addr, regnum, val, err);803 trace_mdio_access(bus, 0, addr, regnum, val, err);
804 mdiobus_stats_acct(&bus->stats[addr], false, err);
577 805
578 return err;806 return err;
579}807}
@@ -719,8 +947,27 @@ static int mdio_uevent(struct device *dev, struct kobj_uevent_env *env) · 139 unmodified lines
719 return 0;947 return 0;
720}948}
721 949
950static 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
958static const struct attribute_group mdio_bus_device_statistics_group = {
959 .name = "statistics",
960 .attrs = mdio_bus_device_statistics_attrs,
961};
962
963static const struct attribute_group *mdio_bus_dev_groups[] = {
964 &mdio_bus_device_statistics_group,
965 NULL,
966};
967
722struct bus_type mdio_bus_type = {968struct bus_type mdio_bus_type = {
723 .name = "mdio_bus",969 .name = "mdio_bus",
970 .dev_groups = mdio_bus_dev_groups,
724 .match = mdio_bus_match,971 .match = mdio_bus_match,
725 .uevent = mdio_uevent,972 .uevent = mdio_uevent,
726};973};
include/linux/phy.h+11−0
@@ -22,6 +22,7 @@ · 21 unmodified lines
22#include <linux/timer.h>22#include <linux/timer.h>
23#include <linux/workqueue.h>23#include <linux/workqueue.h>
24#include <linux/mod_devicetable.h>24#include <linux/mod_devicetable.h>
25#include <linux/u64_stats_sync.h>
25 26
26#include <linux/atomic.h>27#include <linux/atomic.h>
27 28
@@ -212,6 +213,15 @@ struct sfp_bus; · 184 unmodified lines
212struct sfp_upstream_ops;213struct sfp_upstream_ops;
213struct sk_buff;214struct sk_buff;
214 215
216struct 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
215/*225/*
216 * The Bus class for PHYs. Devices which provide access to226 * The Bus class for PHYs. Devices which provide access to
217 * PHYs should register using this structure227 * PHYs should register using this structure
@@ -224,6 +234,7 @@ struct mii_bus { · 6 unmodified lines
224 int (*read)(struct mii_bus *bus, int addr, int regnum);234 int (*read)(struct mii_bus *bus, int addr, int regnum);
225 int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);235 int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);
226 int (*reset)(struct mii_bus *bus);236 int (*reset)(struct mii_bus *bus);
237 struct mdio_bus_stats stats[PHY_MAX_ADDR];
227 238
228 /*239 /*
229 * A lock to ensure that only one thing can read/write240 * A lock to ensure that only one thing can read/write