diff options
| author | Marek Behún <kabel@kernel.org> | 2021-05-31 22:02:45 +0200 |
|---|---|---|
| committer | Marek Behún <kabel@kernel.org> | 2021-11-10 19:09:46 +0100 |
| commit | c87c6f80c5fd6c1175c9c513933f95fdd0ad9959 (patch) | |
| tree | 83f3b96d9e1df5b61ba4299ac25ddec8de8f686f | |
| parent | 1202b721efac79bc264c27ad5879561647a28472 (diff) | |
net: mdiobus: add support to access PHY registers via debugfs [*not for mainline*]net-queue-work
This adds config option CONFIG_MDIO_BUS_DEBUGFS which, when enabled,
adds support to communicate with the devices connected to the MDIO
via debugfs.
For every MDIO bus this creates directory
/sys/kernel/debug/mdio_bus/MDIO_BUS_NAME
with files "addr", "reg" and "val".
User can write device address to the "addr" file and register number to
the "reg" file, and then can read the value of the register from the
"val" file, or can write new value by writing to the "val" file.
This is useful when debugging various PHYs or switches.
Signed-off-by: Marek Behún <kabel@kernel.org>
| -rw-r--r-- | drivers/net/mdio/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/net/phy/Makefile | 2 | ||||
| -rw-r--r-- | drivers/net/phy/mdio_bus.c | 32 | ||||
| -rw-r--r-- | drivers/net/phy/mdio_debugfs.c | 95 | ||||
| -rw-r--r-- | drivers/net/phy/mdio_debugfs.h | 36 | ||||
| -rw-r--r-- | include/linux/phy.h | 5 |
6 files changed, 173 insertions, 5 deletions
diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig index 6da1fcb25847e..205569faa0e2e 100644 --- a/drivers/net/mdio/Kconfig +++ b/drivers/net/mdio/Kconfig @@ -43,6 +43,14 @@ config ACPI_MDIO if MDIO_BUS +config MDIO_BUS_DEBUGFS + bool "MDIO bus debugfs support" + depends on DEBUG_FS + help + This adds support to communicate via the MDIO bus via files in + debugfs. Note that using this on a PHY device that is being handled by + a driver can break the state of the PHY. + config MDIO_DEVRES tristate diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 48733fb58dcb3..56c4a5f244273 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -5,6 +5,8 @@ libphy-y := phy.o phy-c45.o phy-core.o phy_device.o \ linkmode.o mdio-bus-y += mdio_bus.o mdio_device.o +obj-$(CONFIG_MDIO_BUS_DEBUGFS) += mdio_debugfs.o + ifdef CONFIG_MDIO_DEVICE obj-y += mdio-boardinfo.o endif diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 4638d73759438..1ed404bc32795 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -39,6 +39,7 @@ #include <trace/events/mdio.h> #include "mdio-boardinfo.h" +#include "mdio_debugfs.h" static int mdiobus_register_gpiod(struct mdio_device *mdiodev) { @@ -588,6 +589,12 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner) } } + err = mdiobus_register_debugfs(bus); + if (err) { + dev_err(&bus->dev, "mii_bus %s couldn't create debugfs entries\n", bus->id); + goto error; + } + mdiobus_setup_mdiodev_from_board_info(bus, mdiobus_create_device); bus->state = MDIOBUS_REGISTERED; @@ -622,6 +629,8 @@ void mdiobus_unregister(struct mii_bus *bus) return; bus->state = MDIOBUS_UNREGISTERED; + mdiobus_unregister_debugfs(bus); + for (i = 0; i < PHY_MAX_ADDR; i++) { mdiodev = bus->mdio_map[i]; if (!mdiodev) @@ -1051,11 +1060,23 @@ int __init mdio_bus_init(void) int ret; ret = class_register(&mdio_bus_class); - if (!ret) { - ret = bus_register(&mdio_bus_type); - if (ret) - class_unregister(&mdio_bus_class); - } + if (ret) + return ret; + + ret = bus_register(&mdio_bus_type); + if (ret) + goto err_class; + + ret = mdiobus_debugfs_init(); + if (ret) + goto err_bus; + + return 0; + +err_bus: + bus_unregister(&mdio_bus_type); +err_class: + class_unregister(&mdio_bus_class); return ret; } @@ -1064,6 +1085,7 @@ EXPORT_SYMBOL_GPL(mdio_bus_init); #if IS_ENABLED(CONFIG_PHYLIB) void mdio_bus_exit(void) { + mdiobus_debugfs_exit(); class_unregister(&mdio_bus_class); bus_unregister(&mdio_bus_type); } diff --git a/drivers/net/phy/mdio_debugfs.c b/drivers/net/phy/mdio_debugfs.c new file mode 100644 index 0000000000000..ad795a25b0483 --- /dev/null +++ b/drivers/net/phy/mdio_debugfs.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* MDIO Bus debugfs support + * + * Copyright (c) 2020 Marek Behun <marek.behun@nic.cz> + */ + +#include <linux/debugfs.h> +#include <linux/phy.h> + +static int val_get(void *data, u64 *ptr) +{ + struct mii_bus *bus = data; + int val; + + val = mdiobus_read(bus, bus->debug_addr, bus->debug_reg); + if (val < 0) + return val; + + *ptr = val; + + return 0; +} + +static int val_set(void *data, u64 val) +{ + struct mii_bus *bus = data; + int res; + + if (val > 0xffff) + return -EINVAL; + + res = mdiobus_write(bus, bus->debug_addr, bus->debug_reg, val); + if (res < 0) + return res; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(val_fops, val_get, val_set, "0x%04llx\n"); + +static struct dentry *mdiobus_dentry; + +int mdiobus_register_debugfs(struct mii_bus *bus) +{ + struct dentry *dir, *entry; + + dir = debugfs_create_dir(dev_name(&bus->dev), mdiobus_dentry); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + debugfs_create_u32("addr", 0600, dir, &bus->debug_addr); + debugfs_create_u32("reg", 0600, dir, &bus->debug_reg); + + entry = debugfs_create_file_unsafe("val", 0600, dir, bus, &val_fops); + if (IS_ERR(entry)) + goto fail; + + return 0; + +fail: + debugfs_remove_recursive(dir); + return PTR_ERR(entry); +} + +void mdiobus_unregister_debugfs(struct mii_bus *bus) +{ + struct dentry *dir; + + dir = debugfs_lookup(dev_name(&bus->dev), mdiobus_dentry); + if (!dir) + return; + + debugfs_remove_recursive(dir); +} + +int mdiobus_debugfs_init(void) +{ + struct dentry *dentry; + + dentry = debugfs_create_dir("mdio_bus", NULL); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + mdiobus_dentry = dentry; + + return 0; +} + +void mdiobus_debugfs_exit(void) +{ + if (mdiobus_dentry) { + debugfs_remove(mdiobus_dentry); + mdiobus_dentry = NULL; + } +} diff --git a/drivers/net/phy/mdio_debugfs.h b/drivers/net/phy/mdio_debugfs.h new file mode 100644 index 0000000000000..5faba96fc586a --- /dev/null +++ b/drivers/net/phy/mdio_debugfs.h @@ -0,0 +1,36 @@ +#ifndef MDIOBUS_DEBUGFS_H +#define MDIOBUS_DEBUGFS_H + +#include <linux/kernel.h> +#include <linux/phy.h> + +#if IS_ENABLED(CONFIG_MDIO_BUS_DEBUGFS) + +int mdiobus_register_debugfs(struct mii_bus *bus); +void mdiobus_unregister_debugfs(struct mii_bus *bus); +int mdiobus_debugfs_init(void); +void mdiobus_debugfs_exit(void); + +#else + +static inline int mdiobus_register_debugfs(struct mii_bus *bus) +{ + return 0; +} + +static inline void mdiobus_unregister_debugfs(struct mii_bus *bus) +{ +} + +static inline int mdiobus_debugfs_init(void) +{ + return 0; +} + +static inline void mdiobus_debugfs_exit(void) +{ +} + +#endif + +#endif diff --git a/include/linux/phy.h b/include/linux/phy.h index 987892fb81cc7..23107089b41f8 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -423,6 +423,11 @@ struct mii_bus { /** @shared: shared state across different PHYs */ struct phy_package_shared *shared[PHY_MAX_ADDR]; + +#if IS_ENABLED(CONFIG_MDIO_BUS_DEBUGFS) + /* address and regnum for debugfs */ + u32 debug_addr, debug_reg; +#endif }; #define to_mii_bus(d) container_of(d, struct mii_bus, dev) |
