All of lore.kernel.org
 help / color / mirror / Atom feed
From: Florian Fainelli <f.fainelli@gmail.com>
To: netdev@vger.kernel.org
Cc: cphealy@gmail.com, rmk+kernel@armlinux.org.uk, kuba@kernel.org,
	Florian Fainelli <f.fainelli@gmail.com>,
	Andrew Lunn <andrew@lunn.ch>,
	Heiner Kallweit <hkallweit1@gmail.com>,
	"David S. Miller" <davem@davemloft.net>,
	linux-kernel@vger.kernel.org (open list)
Subject: [PATCH net-next] net: phy: Maintain MDIO device and bus statistics
Date: Sun, 12 Jan 2020 20:53:19 -0800	[thread overview]
Message-ID: <20200113045325.13470-1-f.fainelli@gmail.com> (raw)

Maintain per MDIO device and MDIO bus statistics comprised of the number
of transfers/operations, reads and writes and errors. This is useful for
tracking the per-device and global MDIO bus bandwidth and doing
optimizations as necessary.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 Documentation/ABI/testing/sysfs-bus-mdio |  34 +++++++
 drivers/net/phy/mdio_bus.c               | 116 +++++++++++++++++++++++
 drivers/net/phy/mdio_device.c            |   1 +
 include/linux/mdio.h                     |  10 ++
 include/linux/phy.h                      |   2 +
 5 files changed, 163 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-mdio

diff --git a/Documentation/ABI/testing/sysfs-bus-mdio b/Documentation/ABI/testing/sysfs-bus-mdio
new file mode 100644
index 000000000000..a552d92890f1
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-mdio
@@ -0,0 +1,34 @@
+What:          /sys/bus/mdio_bus/devices/.../statistics/
+Date:          January 2020
+KernelVersion: 5.6
+Contact:       netdev@vger.kernel.org
+Description:
+		This folder contains statistics about MDIO bus transactions.
+
+What:          /sys/bus/mdio_bus/devices/.../statistics/transfers
+Date:          January 2020
+KernelVersion: 5.6
+Contact:       netdev@vger.kernel.org
+Description:
+		Total number of transfers for this MDIO bus.
+
+What:          /sys/bus/mdio_bus/devices/.../statistics/errors
+Date:          January 2020
+KernelVersion: 5.6
+Contact:       netdev@vger.kernel.org
+Description:
+		Total number of transfer errors for this MDIO bus.
+
+What:          /sys/bus/mdio_bus/devices/.../statistics/writes
+Date:          January 2020
+KernelVersion: 5.6
+Contact:       netdev@vger.kernel.org
+Description:
+		Total number of write transactions for this MDIO bus.
+
+What:          /sys/bus/mdio_bus/devices/.../statistics/reads
+Date:          January 2020
+KernelVersion: 5.6
+Contact:       netdev@vger.kernel.org
+Description:
+		Total number of read transactions for this MDIO bus.
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 229e480179ff..805bc2e3b139 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -168,6 +168,9 @@ struct mii_bus *mdiobus_alloc_size(size_t size)
 	for (i = 0; i < PHY_MAX_ADDR; i++)
 		bus->irq[i] = PHY_POLL;
 
+	/* Initialize 64-bit seqcounts */
+	u64_stats_init(&bus->stats.syncp);
+
 	return bus;
 }
 EXPORT_SYMBOL(mdiobus_alloc_size);
@@ -255,9 +258,77 @@ static void mdiobus_release(struct device *d)
 	kfree(bus);
 }
 
+#define MDIO_BUS_STATS_ATTR(field, file)				\
+static ssize_t mdio_bus_##field##_show(struct device *dev,		\
+				       struct device_attribute *attr,	\
+				       char *buf)			\
+{									\
+	struct mii_bus *bus = to_mii_bus(dev);				\
+	return mdio_bus_stats_##field##_show(&bus->stats, buf);		\
+}									\
+static struct device_attribute dev_attr_mdio_bus_##field = {		\
+	.attr = { .name = file, .mode = 0444 },				\
+	.show = mdio_bus_##field##_show,				\
+};									\
+static ssize_t mdio_bus_device_##field##_show(struct device *dev,	\
+					      struct device_attribute *attr,\
+					      char *buf)		\
+{									\
+	struct mdio_device *mdiodev = to_mdio_device(dev);		\
+	return mdio_bus_stats_##field##_show(&mdiodev->stats, buf);	\
+}									\
+static struct device_attribute dev_attr_mdio_bus_device_##field = {	\
+	.attr = { .name = file, .mode = 0444 },				\
+	.show = mdio_bus_device_##field##_show,				\
+}
+
+#define MDIO_BUS_STATS_SHOW_NAME(name, file, field, format_string)	\
+static ssize_t mdio_bus_stats_##name##_show(struct mdio_bus_stats *s,	\
+					    char *buf)			\
+{									\
+	unsigned int start;						\
+	ssize_t len;							\
+	u64 tmp;							\
+	do {								\
+		start = u64_stats_fetch_begin(&s->syncp);		\
+		tmp = u64_stats_read(&s->field);			\
+	} while (u64_stats_fetch_retry(&s->syncp, start));		\
+	len = sprintf(buf, format_string ## "\n", tmp);			\
+	return len;							\
+}									\
+MDIO_BUS_STATS_ATTR(name, file)
+
+#define MDIO_BUS_STATS_SHOW(field, format_string)			\
+	MDIO_BUS_STATS_SHOW_NAME(field, __stringify(field),		\
+				      field, format_string)
+
+MDIO_BUS_STATS_SHOW(transfers, "%llu");
+MDIO_BUS_STATS_SHOW(errors, "%llu");
+MDIO_BUS_STATS_SHOW(writes, "%llu");
+MDIO_BUS_STATS_SHOW(reads, "%llu");
+
+static struct attribute *mdio_bus_statistics_attrs[] = {
+	&dev_attr_mdio_bus_transfers.attr,
+	&dev_attr_mdio_bus_errors.attr,
+	&dev_attr_mdio_bus_writes.attr,
+	&dev_attr_mdio_bus_reads.attr,
+	NULL,
+};
+
+static const struct attribute_group mdio_bus_statistics_group = {
+	.name	= "statistics",
+	.attrs	= mdio_bus_statistics_attrs,
+};
+
+static const struct attribute_group *mdio_bus_groups[] = {
+	&mdio_bus_statistics_group,
+	NULL,
+};
+
 static struct class mdio_bus_class = {
 	.name		= "mdio_bus",
 	.dev_release	= mdiobus_release,
+	.dev_groups	= mdio_bus_groups,
 };
 
 #if IS_ENABLED(CONFIG_OF_MDIO)
@@ -536,6 +607,24 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
 }
 EXPORT_SYMBOL(mdiobus_scan);
 
+static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
+{
+	u64_stats_update_begin(&stats->syncp);
+
+	u64_stats_inc(&stats->transfers);
+	if (ret < 0) {
+		u64_stats_inc(&stats->errors);
+		goto out;
+	}
+
+	if (op)
+		u64_stats_inc(&stats->reads);
+	else
+		u64_stats_inc(&stats->writes);
+out:
+	u64_stats_update_end(&stats->syncp);
+}
+
 /**
  * __mdiobus_read - Unlocked version of the mdiobus_read function
  * @bus: the mii_bus struct
@@ -548,6 +637,7 @@ EXPORT_SYMBOL(mdiobus_scan);
  */
 int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
 {
+	struct mdio_device *mdiodev = bus->mdio_map[addr];
 	int retval;
 
 	WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
@@ -555,6 +645,9 @@ int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
 	retval = bus->read(bus, addr, regnum);
 
 	trace_mdio_access(bus, 1, addr, regnum, retval, retval);
+	mdiobus_stats_acct(&bus->stats, true, retval);
+	if (mdiodev)
+		mdiobus_stats_acct(&mdiodev->stats, true, retval);
 
 	return retval;
 }
@@ -573,6 +666,7 @@ EXPORT_SYMBOL(__mdiobus_read);
  */
 int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
 {
+	struct mdio_device *mdiodev = bus->mdio_map[addr];
 	int err;
 
 	WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
@@ -580,6 +674,9 @@ int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
 	err = bus->write(bus, addr, regnum, val);
 
 	trace_mdio_access(bus, 0, addr, regnum, val, err);
+	mdiobus_stats_acct(&bus->stats, false, err);
+	if (mdiodev)
+		mdiobus_stats_acct(&mdiodev->stats, false, err);
 
 	return err;
 }
@@ -725,8 +822,27 @@ static int mdio_uevent(struct device *dev, struct kobj_uevent_env *env)
 	return 0;
 }
 
+static struct attribute *mdio_bus_device_statistics_attrs[] = {
+	&dev_attr_mdio_bus_device_transfers.attr,
+	&dev_attr_mdio_bus_device_errors.attr,
+	&dev_attr_mdio_bus_device_writes.attr,
+	&dev_attr_mdio_bus_device_reads.attr,
+	NULL,
+};
+
+static const struct attribute_group mdio_bus_device_statistics_group = {
+	.name	= "statistics",
+	.attrs	= mdio_bus_device_statistics_attrs,
+};
+
+static const struct attribute_group *mdio_bus_dev_groups[] = {
+	&mdio_bus_device_statistics_group,
+	NULL,
+};
+
 struct bus_type mdio_bus_type = {
 	.name		= "mdio_bus",
+	.dev_groups	= mdio_bus_dev_groups,
 	.match		= mdio_bus_match,
 	.uevent		= mdio_uevent,
 };
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
index c1d345c3cab3..e89ed990de7d 100644
--- a/drivers/net/phy/mdio_device.c
+++ b/drivers/net/phy/mdio_device.c
@@ -53,6 +53,7 @@ struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
 	if (!mdiodev)
 		return ERR_PTR(-ENOMEM);
 
+	u64_stats_init(&mdiodev->stats.syncp);
 	mdiodev->dev.release = mdio_device_release;
 	mdiodev->dev.parent = &bus->dev;
 	mdiodev->dev.bus = &mdio_bus_type;
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index a7604248777b..d6035d973a0d 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -8,6 +8,7 @@
 
 #include <uapi/linux/mdio.h>
 #include <linux/mod_devicetable.h>
+#include <linux/u64_stats_sync.h>
 
 struct gpio_desc;
 struct mii_bus;
@@ -23,11 +24,20 @@ enum mdio_mutex_lock_class {
 	MDIO_MUTEX_NESTED,
 };
 
+struct mdio_bus_stats {
+	struct u64_stats_sync syncp;
+	u64_stats_t transfers;
+	u64_stats_t errors;
+	u64_stats_t writes;
+	u64_stats_t reads;
+};
+
 struct mdio_device {
 	struct device dev;
 
 	struct mii_bus *bus;
 	char modalias[MDIO_NAME_SIZE];
+	struct mdio_bus_stats stats;
 
 	int (*bus_match)(struct device *dev, struct device_driver *drv);
 	void (*device_free)(struct mdio_device *mdiodev);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 5932bb8e9c35..8d3ac1ebfef2 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -22,6 +22,7 @@
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/mod_devicetable.h>
+#include <linux/u64_stats_sync.h>
 
 #include <linux/atomic.h>
 
@@ -224,6 +225,7 @@ struct mii_bus {
 	int (*read)(struct mii_bus *bus, int addr, int regnum);
 	int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);
 	int (*reset)(struct mii_bus *bus);
+	struct mdio_bus_stats stats;
 
 	/*
 	 * A lock to ensure that only one thing can read/write
-- 
2.19.1


             reply	other threads:[~2020-01-13  4:54 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-13  4:53 Florian Fainelli [this message]
2020-01-13  4:55 ` [PATCH net-next] net: phy: Maintain MDIO device and bus statistics Florian Fainelli
2020-01-13 13:21 ` Andrew Lunn
2020-01-13 18:00   ` Florian Fainelli
2020-01-13 18:29     ` Andrew Lunn
2020-01-14  4:44 ` kbuild test robot
2020-01-14  4:44   ` kbuild test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200113045325.13470-1-f.fainelli@gmail.com \
    --to=f.fainelli@gmail.com \
    --cc=andrew@lunn.ch \
    --cc=cphealy@gmail.com \
    --cc=davem@davemloft.net \
    --cc=hkallweit1@gmail.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=rmk+kernel@armlinux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.