From 07add97641b82d693a799ced08af89aa9b9927ed Mon Sep 17 00:00:00 2001 From: Heinrich Toews Date: Thu, 27 Nov 2025 16:17:51 +0100 Subject: [PATCH] net: dsa: microchip: ksz9477: add sysfs reg access support This commit adds sysfs support for ksz9477 register acccess in userspace. Although access is possible through the use of regmap it showed to be uncomfortable to work with whole register dumps and also or security reasons write access is prohibited by deault. Do a 16-bit read access: echo 16 0x040C > ksz_read A 32-bit wirte access: echo 32 0x0120 0x0115 > ksz_write Results will be logged in the kernel buffer. Signed-off-by: Heinrich Toews --- drivers/net/dsa/microchip/Kconfig | 7 ++ drivers/net/dsa/microchip/Makefile | 1 + drivers/net/dsa/microchip/ksz9477.c | 5 + drivers/net/dsa/microchip/ksz9477_sysfs.c | 139 ++++++++++++++++++++++ drivers/net/dsa/microchip/ksz9477_sysfs.h | 8 ++ 5 files changed, 160 insertions(+) create mode 100644 drivers/net/dsa/microchip/ksz9477_sysfs.c create mode 100644 drivers/net/dsa/microchip/ksz9477_sysfs.h diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index 394ca8678d2b..c0a951599cdf 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -39,3 +39,10 @@ config NET_DSA_MICROCHIP_KSZ8863_SMI help Select to enable support for registering switches configured through Microchip SMI. It supports the KSZ8863 and KSZ8873 switch. + +config NET_DSA_MICROCHIP_KSZ9477_SYSFS + tristate "SYSFS interface for userspace KSZ register access" + depends on NET_DSA_MICROCHIP_KSZ_COMMON + help + Select to enable support for accessing KSZ registers in userspace + through the sysfs interface. diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 1b0d4ec4c1c8..ab64e470221f 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -15,3 +15,4 @@ ksz_switch-objs += ksz_devlink.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C) += ksz9477_i2c.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_SPI) += ksz_spi.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI) += ksz8863_smi.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SYSFS) += ksz9477_sysfs.o diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 59134d117846..581913032510 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -18,6 +18,7 @@ #include "ksz9477_reg.h" #include "ksz_common.h" #include "ksz9477.h" +#include "ksz9477_sysfs.h" static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { @@ -1185,6 +1186,10 @@ int ksz9477_switch_init(struct ksz_device *dev) if (ret) return ret; +#ifdef CONFIG_NET_DSA_MICROCHIP_KSZ9477_SYSFS + ksz_sysfs_register(dev); +#endif + return 0; } diff --git a/drivers/net/dsa/microchip/ksz9477_sysfs.c b/drivers/net/dsa/microchip/ksz9477_sysfs.c new file mode 100644 index 000000000000..208a3d27314e --- /dev/null +++ b/drivers/net/dsa/microchip/ksz9477_sysfs.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KSZ9477 Sysfs Register Access + * + */ + +#include + +#include "ksz_common.h" +#include "ksz9477_reg.h" +#include "ksz9477_sysfs.h" + +#define to_kszdev(d) container_of(d, struct ksz_device, dev) + +struct ksz_device *g_kdev = NULL; + +static ssize_t ksz_read_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 reg, value; + int ret, bit; + char end; + + if (!g_kdev) + return -EINVAL; + + /* Parse remaining parameters, reject extra parameters */ + ret = sscanf(buf, "%d %x%c", &bit, ®, &end); + if (ret < 1) { + dev_err(dev, "%s: Can't parse REG address\n", __func__); + return -EINVAL; + } + if (ret > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", __func__); + return -EINVAL; + } + + switch(bit) { + case 8: + ret = ksz_read8(g_kdev, reg, (u8*)&value); + break; + case 16: + ret = ksz_read16(g_kdev, reg, (u16*)&value); + break; + case 32: + ret = ksz_read32(g_kdev, reg, &value); + break; + + } + + if (ret < 0) { + dev_err(dev, "%s: read failed.\n", __func__); + return ret; + } + + dev_info(dev, "%d-bit read: reg 0x%04x: 0x%08x.\n", bit, reg, value); + + return count; +} +static DEVICE_ATTR_WO(ksz_read); + +static ssize_t ksz_write_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 reg, value; + int ret, bit; + char end; + + if (!g_kdev) + return -EINVAL; + + /* Parse remaining parameters, reject extra parameters */ + ret = sscanf(buf, "%d %x %x%c", &bit, ®, &value, &end); + if (ret < 1) { + dev_err(dev, "%s: Can't parse register command\n", __func__); + return -EINVAL; + } + if (ret > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", __func__); + return -EINVAL; + } + + switch(bit) { + case 8: + ret = ksz_write8(g_kdev, reg, (u8)value); + break; + case 16: + ret = ksz_write16(g_kdev, reg, (u16)value); + break; + case 32: + ret = ksz_write32(g_kdev, reg, value); + break; + + } + + if (ret < 0) { + dev_err(dev, "%s: read failed.\n", __func__); + return ret; + } + + dev_info(dev, "%d-bit write: reg 0x%04x value 0x%08x.\n", + bit, reg, value); + + return count; +} +static DEVICE_ATTR_WO(ksz_write); + +int ksz_sysfs_register(struct ksz_device *kdev) +{ + struct device *dev = kdev->dev; + int ret; + + if (!kdev) + return -EINVAL; + + ret = device_create_file(dev, &dev_attr_ksz_read); + if (ret) + dev_err(dev, "Could not create <%s> attribute.\n", "ksz_read"); + + ret = device_create_file(dev, &dev_attr_ksz_write); + if (ret) + dev_err(dev, "Could not create <%s> attribute.\n", "ksz_write"); + + g_kdev = kdev; + + return ret; +} + +void ksz_sysfs_unregister(struct ksz_device *kdev) +{ + struct device *dev = kdev->dev; + + g_kdev = NULL; + + device_remove_file(dev, &dev_attr_ksz_read); + device_remove_file(dev, &dev_attr_ksz_write); +} diff --git a/drivers/net/dsa/microchip/ksz9477_sysfs.h b/drivers/net/dsa/microchip/ksz9477_sysfs.h new file mode 100644 index 000000000000..8e4f88ddca21 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz9477_sysfs.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef KSZ9477_SYSFS_H_ +#define KSZ9477_SYSFS_H_ + +int ksz_sysfs_register(struct ksz_device *kdev); +void ksz_sysfs_unregister(struct ksz_device *kdev); + +#endif /* KSZ9477_SYSFS_H_ */