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 <ht@twx-software.de>
This commit is contained in:
Heinrich Toews
2025-11-27 16:17:51 +01:00
parent 008d7df4af
commit 07add97641
5 changed files with 160 additions and 0 deletions
+7
View File
@@ -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.
+1
View File
@@ -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
+5
View File
@@ -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;
}
+139
View File
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* KSZ9477 Sysfs Register Access
*
*/
#include <linux/device.h>
#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, &reg, &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, &reg, &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);
}
@@ -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_ */