From 2d6b9d3c39655252cd6a222b5d1531612069a557 Mon Sep 17 00:00:00 2001 From: Jan Sondhauss Date: Thu, 11 Sep 2025 12:06:47 +0200 Subject: [PATCH 1/2] net: dsa: ksz9477: add devlink parameter interface The devlink interface exposes the switches broadcast and multicast protection feature to the userspace. The handling is similiar to that of the ksz8863 but with different registers and values. Signed-off-by: Jan Sondhauss --- drivers/net/dsa/microchip/ksz_common.c | 23 +++-- drivers/net/dsa/microchip/ksz_devlink.c | 115 ++++++++++++++++++++---- drivers/net/dsa/microchip/ksz_devlink.h | 9 +- 3 files changed, 116 insertions(+), 31 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index fdd8d3baaa58..e67b080d1d41 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -218,9 +218,9 @@ static const struct ksz_dev_ops ksz8_dev_ops = { .change_mtu = ksz8_change_mtu, .devlink_param_setup = ksz8_setup_devlink_params, .devlink_param_teardown = ksz8_teardown_devlink_params, - .devlink_param_get = ksz8_devlink_param_get, - .devlink_param_set = ksz8_devlink_param_set, - .devlink_info_get= ksz8_devlink_info_get, + .devlink_param_get = ksz_devlink_param_get, + .devlink_param_set = ksz_devlink_param_set, + .devlink_info_get= ksz_devlink_info_get, .get_regs = ksz8_get_regs, .get_regs_len = ksz8_get_regs_len, }; @@ -262,6 +262,11 @@ static const struct ksz_dev_ops ksz9477_dev_ops = { .config_cpu_port = ksz9477_config_cpu_port, .tc_cbs_set_cinc = ksz9477_tc_cbs_set_cinc, .enable_stp_addr = ksz9477_enable_stp_addr, + .devlink_info_get = ksz_devlink_info_get, + .devlink_param_get = ksz_devlink_param_get, + .devlink_param_set = ksz_devlink_param_set, + .devlink_param_setup = ksz9477_setup_devlink_params, + .devlink_param_teardown = ksz9477_teardown_devlink_params, .reset = ksz9477_reset_switch, .init = ksz9477_switch_init, .exit = ksz9477_switch_exit, @@ -3442,7 +3447,7 @@ static int ksz_devlink_param_setup(struct dsa_switch *ds) return 0; } -static int ksz_devlink_info_get(struct dsa_switch *ds, struct devlink_info_req *req, struct netlink_ext_ack *extack) { +static int ksz_get_devlink_info(struct dsa_switch *ds, struct devlink_info_req *req, struct netlink_ext_ack *extack) { struct ksz_device* dev = ds->priv; @@ -3452,7 +3457,7 @@ static int ksz_devlink_info_get(struct dsa_switch *ds, struct devlink_info_req * return -EOPNOTSUPP; } -static int ksz_devlink_param_get(struct dsa_switch *ds, u32 id, +static int ksz_get_devlink_param(struct dsa_switch *ds, u32 id, struct devlink_param_gset_ctx *ctx) { struct ksz_device *dev = ds->priv; @@ -3463,7 +3468,7 @@ static int ksz_devlink_param_get(struct dsa_switch *ds, u32 id, return -EOPNOTSUPP; } -static int ksz_devlink_param_set(struct dsa_switch *ds, u32 id, +static int ksz_set_devlink_param(struct dsa_switch *ds, u32 id, struct devlink_param_gset_ctx *ctx) { struct ksz_device *dev = ds->priv; @@ -3538,9 +3543,9 @@ static const struct dsa_switch_ops ksz_switch_ops = { .port_setup_tc = ksz_setup_tc, .get_mac_eee = ksz_get_mac_eee, .set_mac_eee = ksz_set_mac_eee, - .devlink_param_get = ksz_devlink_param_get, - .devlink_param_set = ksz_devlink_param_set, - .devlink_info_get = ksz_devlink_info_get, + .devlink_param_get = ksz_get_devlink_param, + .devlink_param_set = ksz_set_devlink_param, + .devlink_info_get = ksz_get_devlink_info, .get_regs = ksz_get_regs, .get_regs_len = ksz_get_regs_len, }; diff --git a/drivers/net/dsa/microchip/ksz_devlink.c b/drivers/net/dsa/microchip/ksz_devlink.c index cc2d5f164855..649b0b1e8a7c 100644 --- a/drivers/net/dsa/microchip/ksz_devlink.c +++ b/drivers/net/dsa/microchip/ksz_devlink.c @@ -7,13 +7,20 @@ #include #include -#include "ksz8795_reg.h" #include "ksz_common.h" + +#define KSZ8_P_BCAST_STORM_CTRL 0 +#define KSZ8_PORT_BROADCAST_STORM BIT(7) + +#define KSZ9_P_BCAST_STORM_CTRL 0x400 +#define KSZ9_PORT_BROADCAST_STORM BIT(1) + + static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, bool set) { - regmap_update_bits(ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset), + regmap_update_bits(ksz_regmap_8(dev), dev->dev_ops->get_port_addr(port, offset), bits, set ? bits : 0); } @@ -23,9 +30,11 @@ enum ksz_devlink_param_id { KSZ_DEVLINK_PARAM_ID_MCAST_STORM_RATE_DISABLE, KSZ_DEVLINK_PARAM_ID_PORT_BASE, KSZ_DEVLINK_PARAM_ID_PORT_MAX = KSZ_DEVLINK_PARAM_ID_PORT_BASE + 3, + KSZ9_DEVLINK_PARAM_ID_PORT_BASE, + KSZ9_DEVLINK_PARAM_ID_PORT_MAX = KSZ9_DEVLINK_PARAM_ID_PORT_BASE + 8, }; -static const struct devlink_param ksz_devlink_params[] = { +static const struct devlink_param ksz8_devlink_params[] = { DSA_DEVLINK_PARAM_DRIVER(KSZ_DEVLINK_PARAM_ID_BROADCAST_STORM_RATE, "bcast storm rate", DEVLINK_PARAM_TYPE_U16, BIT(DEVLINK_PARAM_CMODE_RUNTIME)), @@ -48,19 +57,73 @@ static const struct devlink_param ksz_devlink_params[] = { }; +static const struct devlink_param ksz9_devlink_params[] = { + DSA_DEVLINK_PARAM_DRIVER(KSZ_DEVLINK_PARAM_ID_BROADCAST_STORM_RATE, + "bcast storm rate", DEVLINK_PARAM_TYPE_U16, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ_DEVLINK_PARAM_ID_MCAST_STORM_RATE_DISABLE, + "mcast storm rate disable", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ9_DEVLINK_PARAM_ID_PORT_BASE, + "bcast storm protection enable port 0", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ9_DEVLINK_PARAM_ID_PORT_BASE + 1, + "bcast storm protection enable port 1", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ9_DEVLINK_PARAM_ID_PORT_BASE + 2, + "bcast storm protection enable port 2", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ9_DEVLINK_PARAM_ID_PORT_BASE + 3, + "bcast storm protection enable port 3", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ9_DEVLINK_PARAM_ID_PORT_BASE + 4, + "bcast storm protection enable port 4", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ9_DEVLINK_PARAM_ID_PORT_BASE + 5, + "bcast storm protection enable port 5", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ9_DEVLINK_PARAM_ID_PORT_BASE + 6, + "bcast storm protection enable port 6", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(KSZ9_DEVLINK_PARAM_ID_PORT_BASE + 7, + "bcast storm protection enable port 7", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), +}; + int ksz8_setup_devlink_params(struct dsa_switch *ds) { - return dsa_devlink_params_register(ds, ksz_devlink_params, - ARRAY_SIZE(ksz_devlink_params)); + return dsa_devlink_params_register(ds, ksz8_devlink_params, + ARRAY_SIZE(ksz8_devlink_params)); } void ksz8_teardown_devlink_params(struct dsa_switch *ds) { - dsa_devlink_params_unregister(ds, ksz_devlink_params, - ARRAY_SIZE(ksz_devlink_params)); + dsa_devlink_params_unregister(ds, ksz8_devlink_params, + ARRAY_SIZE(ksz8_devlink_params)); } -int ksz8_devlink_param_get(struct ksz_device *dev, u32 id, +int ksz9477_setup_devlink_params(struct dsa_switch *ds) +{ + return dsa_devlink_params_register(ds, ksz9_devlink_params, + ARRAY_SIZE(ksz9_devlink_params)); +} + +void ksz9477_teardown_devlink_params(struct dsa_switch *ds) +{ + dsa_devlink_params_unregister(ds, ksz9_devlink_params, + ARRAY_SIZE(ksz9_devlink_params)); +} + +int ksz_devlink_param_get(struct ksz_device *dev, u32 id, struct devlink_param_gset_ctx *ctx) { const u16 *regs = dev->info->regs; @@ -84,9 +147,19 @@ int ksz8_devlink_param_get(struct ksz_device *dev, u32 id, int port = id - KSZ_DEVLINK_PARAM_ID_PORT_BASE; u8 val; - ksz_pread8(dev, port, P_BCAST_STORM_CTRL, &val); - ctx->val.vbool = (val & PORT_BROADCAST_STORM) == - PORT_BROADCAST_STORM; + ksz_pread8(dev, port, KSZ8_P_BCAST_STORM_CTRL, &val); + ctx->val.vbool = (val & KSZ8_PORT_BROADCAST_STORM) == + KSZ8_PORT_BROADCAST_STORM; + } break; + + case KSZ9_DEVLINK_PARAM_ID_PORT_BASE ... KSZ9_DEVLINK_PARAM_ID_PORT_MAX: { + int port = id - KSZ9_DEVLINK_PARAM_ID_PORT_BASE; + u8 val; + + ksz_pread8(dev, port, 0x400, &val); + + ctx->val.vbool = (val & KSZ9_PORT_BROADCAST_STORM) == + KSZ9_PORT_BROADCAST_STORM; } break; default: @@ -96,7 +169,7 @@ int ksz8_devlink_param_get(struct ksz_device *dev, u32 id, return 0; } -int ksz8_devlink_param_set(struct ksz_device *dev, u32 id, +int ksz_devlink_param_set(struct ksz_device *dev, u32 id, struct devlink_param_gset_ctx *ctx) { const u16 *regs; @@ -128,8 +201,15 @@ int ksz8_devlink_param_set(struct ksz_device *dev, u32 id, case KSZ_DEVLINK_PARAM_ID_PORT_BASE ... KSZ_DEVLINK_PARAM_ID_PORT_MAX: { int port = id - KSZ_DEVLINK_PARAM_ID_PORT_BASE; - ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, - PORT_BROADCAST_STORM, ctx->val.vbool); + ksz_port_cfg(dev, port, KSZ8_P_BCAST_STORM_CTRL, + KSZ8_PORT_BROADCAST_STORM, ctx->val.vbool); + } break; + + case KSZ9_DEVLINK_PARAM_ID_PORT_BASE ... KSZ9_DEVLINK_PARAM_ID_PORT_MAX: { + int port = id - KSZ9_DEVLINK_PARAM_ID_PORT_BASE; + + ksz_port_cfg(dev, port, KSZ9_P_BCAST_STORM_CTRL, + KSZ9_PORT_BROADCAST_STORM, ctx->val.vbool); } break; default: @@ -139,12 +219,9 @@ int ksz8_devlink_param_set(struct ksz_device *dev, u32 id, return 0; } -int ksz8_devlink_info_get(struct ksz_device *dev, struct devlink_info_req *req, +int ksz_devlink_info_get(struct ksz_device *dev, struct devlink_info_req *req, struct netlink_ext_ack *extack) { - return devlink_info_version_fixed_put( - req, DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, - dev->info->dev_name); + req, DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, dev->info->dev_name); } - diff --git a/drivers/net/dsa/microchip/ksz_devlink.h b/drivers/net/dsa/microchip/ksz_devlink.h index 5377f37469df..6fb03d19330c 100644 --- a/drivers/net/dsa/microchip/ksz_devlink.h +++ b/drivers/net/dsa/microchip/ksz_devlink.h @@ -13,12 +13,15 @@ int ksz8_setup_devlink_params(struct dsa_switch *ds); void ksz8_teardown_devlink_params(struct dsa_switch *ds); -int ksz8_devlink_param_get(struct ksz_device *dev, u32 id, +int ksz9477_setup_devlink_params(struct dsa_switch *ds); +void ksz9477_teardown_devlink_params(struct dsa_switch *ds); + +int ksz_devlink_param_get(struct ksz_device *dev, u32 id, struct devlink_param_gset_ctx *ctx); -int ksz8_devlink_param_set(struct ksz_device *dev, u32 id, +int ksz_devlink_param_set(struct ksz_device *dev, u32 id, struct devlink_param_gset_ctx *ctx); -int ksz8_devlink_info_get(struct ksz_device *dev, struct devlink_info_req *req, +int ksz_devlink_info_get(struct ksz_device *dev, struct devlink_info_req *req, struct netlink_ext_ack *extack); #endif From f613e4249f5e1ced7cc047b4e96df09e7a322fd7 Mon Sep 17 00:00:00 2001 From: Jan Sondhauss Date: Mon, 15 Sep 2025 09:04:49 +0200 Subject: [PATCH 2/2] net: dsa: ksz9477: add ethtool regdump functionality This allows for the switches registers to be dumped via the ethtool interface. Compared to the ksz8 implemention only the registers are exposed. Dumping of the fdb and stat mac table can be added once the need arises. The reg-dump uses the reg_map of the driver to select which registers to dump. Signed-off-by: Jan Sondhauss --- drivers/net/dsa/microchip/Makefile | 1 + drivers/net/dsa/microchip/ksz8_ethtool.c | 152 +++++++++----------- drivers/net/dsa/microchip/ksz8_ethtool.h | 2 + drivers/net/dsa/microchip/ksz9477_ethtool.c | 86 +++++++++++ drivers/net/dsa/microchip/ksz9477_ethtool.h | 14 ++ drivers/net/dsa/microchip/ksz_common.c | 3 + drivers/net/dsa/microchip/ksz_ethtool.h | 60 ++++++++ 7 files changed, 232 insertions(+), 86 deletions(-) create mode 100644 drivers/net/dsa/microchip/ksz9477_ethtool.c create mode 100644 drivers/net/dsa/microchip/ksz9477_ethtool.h create mode 100644 drivers/net/dsa/microchip/ksz_ethtool.h diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 2f129b30e851..1b0d4ec4c1c8 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -10,6 +10,7 @@ ksz_switch-objs += ksz_ptp.o endif ksz_switch-objs += ksz8_ethtool.o +ksz_switch-objs += ksz9477_ethtool.o 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 diff --git a/drivers/net/dsa/microchip/ksz8_ethtool.c b/drivers/net/dsa/microchip/ksz8_ethtool.c index ee1caa4754a5..9ef4095f284f 100644 --- a/drivers/net/dsa/microchip/ksz8_ethtool.c +++ b/drivers/net/dsa/microchip/ksz8_ethtool.c @@ -2,64 +2,17 @@ #include "ksz8_ethtool.h" #include "ksz8.h" - -enum { - KSZ8_REGDUMP_ID_GLOBAL = 0x1100, - KSZ8_REGDUMP_ID_PORT = 0x1200, - KSZ8_REGDUMP_ID_STAT_MAC_TBL = 0x2000, - KSZ8_REGDUMP_ID_FDB = 0x2100, -}; - -struct ksz_regdump_hdr { - u32 module_id; - u32 len; -}; - -struct ksz_regdump_record { - struct ksz_regdump_hdr hdr; - u32 start_off; - u32 end_off; -}; - -// creates a regdump record entry -// note we use u32 to transport register values, despite their size in -// the device -#define KSZ_REGDUMP_ENTRY(id, start, end) { \ - .hdr.module_id = (id), \ - .hdr.len = (((end) - (start)) * sizeof(u32)) * 2 \ - + sizeof(struct ksz_regdump_hdr), \ - .start_off = (start), \ - .end_off = (end), \ -} - -#define SIZE_IS_MULTIPLE_OF(T, T2) (sizeof(T) == (DIV_ROUND_UP(sizeof(T), sizeof(T2))* sizeof(T2))) - -// sizeof(ksz8_dyn_mac_entry) == 12 -struct ksz8_dyn_mac_entry { - /*entry 1*/ - u32 : 24; - u8 timestamp; - /* entry 2 & 3 */ - u8 fid; - u8 src_port; - u8 mac[ETH_ALEN]; -}; - -#define KSZ8_REGDUMP_MAC_ENTRY(id, entry_size, max_entries) { \ - .hdr.module_id = (id), \ - .hdr.len = 2 * sizeof(u32) + (entry_size) * (max_entries) \ - + sizeof(struct ksz_regdump_hdr), \ - .start_off = 0, \ - .end_off = 0, \ -} +#include "ksz_ethtool.h" static const struct ksz_regdump_record ksz8_regdump_records[] = { - KSZ_REGDUMP_ENTRY(KSZ8_REGDUMP_ID_GLOBAL, 0x00, 0x10), - KSZ_REGDUMP_ENTRY(KSZ8_REGDUMP_ID_PORT, 0x10, 0x20), - KSZ_REGDUMP_ENTRY(KSZ8_REGDUMP_ID_PORT + 1, 0x20, 0x30), - KSZ_REGDUMP_ENTRY(KSZ8_REGDUMP_ID_PORT + 2, 0x30, 0x40), - KSZ8_REGDUMP_MAC_ENTRY(KSZ8_REGDUMP_ID_STAT_MAC_TBL, sizeof(struct alu_struct), 8), - KSZ8_REGDUMP_MAC_ENTRY(KSZ8_REGDUMP_ID_FDB, sizeof(struct ksz8_dyn_mac_entry), 1024), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_GLOBAL, 0x00, 0x10), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT, 0x10, 0x20), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 1, 0x20, 0x30), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 2, 0x30, 0x40), + KSZ8_REGDUMP_MAC_ENTRY(KSZ_REGDUMP_ID_STAT_MAC_TBL, + sizeof(struct alu_struct), 8), + KSZ8_REGDUMP_MAC_ENTRY(KSZ_REGDUMP_ID_FDB, + sizeof(struct ksz8_dyn_mac_entry), 1024), }; int ksz8_get_regs_len(struct ksz_device *dev, int port) @@ -72,20 +25,22 @@ int ksz8_get_regs_len(struct ksz_device *dev, int port) return length; } -static void ksz8_get_regs_dump_static_mac_table(struct ksz_device *dev, u32 *reg, u32 *pos) +static void ksz8_get_regs_dump_static_mac_table(struct ksz_device *dev, + u32 *reg, u32 *pos) { BUILD_BUG_ON(!SIZE_IS_MULTIPLE_OF(struct alu_struct, u32)); int index, ret; u32 cnt = *pos; - reg[cnt++] = KSZ8_REGDUMP_ID_STAT_MAC_TBL; + struct ksz_regdump_hdr *hdr = (struct ksz_regdump_hdr *)®[cnt]; - const u32 pos_length = cnt++; - reg[pos_length] = sizeof(struct ksz_regdump_hdr); + hdr->module_id = KSZ_REGDUMP_ID_STAT_MAC_TBL; + hdr->len = sizeof(struct ksz_regdump_hdr); + cnt += 2; for (index = 0; index < dev->info->num_statics; index++) { bool valid; - struct alu_struct* alu = (struct alu_struct*)®[cnt]; + struct alu_struct *alu = (struct alu_struct *)®[cnt]; ret = ksz8_r_sta_mac_table(dev, index, alu, &valid); if (ret) @@ -94,7 +49,7 @@ static void ksz8_get_regs_dump_static_mac_table(struct ksz_device *dev, u32 *reg if (!valid) continue; - reg[pos_length] += sizeof(struct alu_struct); + hdr->len += sizeof(struct alu_struct); cnt += sizeof(struct alu_struct) / sizeof(u32); } *pos = cnt; @@ -107,55 +62,80 @@ static void ksz8_get_regs_dump_fdb(struct ksz_device *dev, u32 *reg, u32 *pos) u16 entries = 0; u32 cnt = *pos; - reg[cnt++] = KSZ8_REGDUMP_ID_FDB; + struct ksz_regdump_hdr *hdr = (struct ksz_regdump_hdr *)®[cnt]; - const u32 pos_length = cnt++; - reg[pos_length] = sizeof(struct ksz_regdump_hdr); + hdr->module_id = KSZ_REGDUMP_ID_FDB; + hdr->len = sizeof(struct ksz_regdump_hdr); + cnt += 2; do { - struct ksz8_dyn_mac_entry *entry = (struct ksz8_dyn_mac_entry*) ®[cnt]; - int ret = ksz8_r_dyn_mac_table(dev, i, entry->mac, &entry->fid, &entry->src_port, - &entry->timestamp, &entries); + struct ksz8_dyn_mac_entry *entry = + (struct ksz8_dyn_mac_entry *)®[cnt]; + int ret = ksz8_r_dyn_mac_table(dev, i, entry->mac, &entry->fid, + &entry->src_port, + &entry->timestamp, &entries); if (!ret) { - reg[pos_length] += sizeof(struct ksz8_dyn_mac_entry); - cnt += DIV_ROUND_UP(sizeof(struct ksz8_dyn_mac_entry), sizeof(u32)); + hdr->len += sizeof(struct ksz8_dyn_mac_entry); + cnt += DIV_ROUND_UP(sizeof(struct ksz8_dyn_mac_entry), + sizeof(u32)); } i++; } while (i < entries); *pos = cnt; } -void ksz8_get_regs(struct ksz_device *dev, int port, - struct ethtool_regs *regs, void *p) +static void ksz_dump_regmap_range(struct ksz_device *dev, u32 *regs, u32 *pos, + u32 start, u32 end) { - int i, j; + int i, length = *pos; + + const struct regmap_range *yes_ranges = dev->info->rd_table->yes_ranges; + for (i = 0; i < dev->info->rd_table->n_yes_ranges; i++) { + const struct regmap_range range = yes_ranges[i]; + u32 reg; + if (range.range_max < start || range.range_min >= end) + continue; + + for (reg = range.range_min; reg <= range.range_max; reg++) { + u8 val; + ksz_read8(dev, reg, &val); + + regs[length++] = reg; + regs[length++] = val; + } + } + + *pos = length; +} + +void ksz8_get_regs(struct ksz_device *dev, int port, struct ethtool_regs *regs, + void *p) +{ + int i; u32 pos = 0; u32 *reg = p; for (i = 0; i < ARRAY_SIZE(ksz8_regdump_records); i++) { struct ksz_regdump_record rec = ksz8_regdump_records[i]; + struct ksz_regdump_hdr *hdr = + (struct ksz_regdump_hdr *)®[pos]; - if (rec.hdr.module_id == KSZ8_REGDUMP_ID_STAT_MAC_TBL) { + if (rec.hdr.module_id == KSZ_REGDUMP_ID_STAT_MAC_TBL) { ksz8_get_regs_dump_static_mac_table(dev, reg, &pos); continue; } - if (rec.hdr.module_id == KSZ8_REGDUMP_ID_FDB) { + if (rec.hdr.module_id == KSZ_REGDUMP_ID_FDB) { ksz8_get_regs_dump_fdb(dev, reg, &pos); continue; } - reg[pos++] = rec.hdr.module_id; - reg[pos++] = rec.hdr.len; - - for (j = rec.start_off; - j < rec.end_off; j++) { - u8 val; - - reg[pos++] = j; - ksz_read8(dev, j, &val); - reg[pos++] = val; - } + pos += 2; + hdr->module_id = rec.hdr.module_id; + hdr->len = pos; + ksz_dump_regmap_range(dev, reg, &pos, rec.start_off, + rec.end_off); + hdr->len = (pos - hdr->len + 2) * sizeof(u32); } } diff --git a/drivers/net/dsa/microchip/ksz8_ethtool.h b/drivers/net/dsa/microchip/ksz8_ethtool.h index 84e28e4d55c2..4296524ccf12 100644 --- a/drivers/net/dsa/microchip/ksz8_ethtool.h +++ b/drivers/net/dsa/microchip/ksz8_ethtool.h @@ -4,8 +4,10 @@ #define __KSZ8XXX_ETHTOOL_H #include +#include "ksz_ethtool.h" #include "ksz_common.h" + int ksz8_get_regs_len(struct ksz_device *dev, int port); void ksz8_get_regs(struct ksz_device *dev, int port, struct ethtool_regs *regs, void *p); diff --git a/drivers/net/dsa/microchip/ksz9477_ethtool.c b/drivers/net/dsa/microchip/ksz9477_ethtool.c new file mode 100644 index 000000000000..2ecf3e7d2fef --- /dev/null +++ b/drivers/net/dsa/microchip/ksz9477_ethtool.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "ksz9477_ethtool.h" +#include "ksz_ethtool.h" + +static const struct ksz_regdump_record ksz8_regdump_records[] = { + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_GLOBAL, 0x00, 0x700), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 0, 0x1000, 0x1fff), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 1, 0x2000, 0x2fff), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 2, 0x3000, 0x3fff), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 3, 0x4000, 0x4fff), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 4, 0x5000, 0x5fff), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 5, 0x6000, 0x6fff), + KSZ_REGDUMP_ENTRY(KSZ_REGDUMP_ID_PORT + 6, 0x7000, 0x7fff), +}; + +int ksz9477_get_regs_len(struct ksz_device *dev, int port) +{ + int i, length = 0; + + const struct regmap_range *yes_ranges = dev->info->rd_table->yes_ranges; + + for (i = 0; i < dev->info->rd_table->n_yes_ranges; i++) { + const struct regmap_range range = yes_ranges[i]; + length += (range.range_max - range.range_min + 1) * + sizeof(u32) * 2; + } + // ports + global + stat + fdb + length += (7 + 1 + 1 + 1) * sizeof(struct ksz_regdump_hdr); + + return length; +} + +static void ksz_dump_regmap_range(struct ksz_device *dev, u32 *regs, u32 *pos, + u32 start, u32 end) +{ + int i, length = *pos; + + const struct regmap_range *yes_ranges = dev->info->rd_table->yes_ranges; + + for (i = 0; i < dev->info->rd_table->n_yes_ranges; i++) { + const struct regmap_range range = yes_ranges[i]; + u32 reg; + if (range.range_max < start || range.range_min >= end) + continue; + + for (reg = range.range_min; reg <= range.range_max; reg++) { + u8 val; + ksz_read8(dev, reg, &val); + + regs[length++] = reg; + regs[length++] = val; + } + } + + *pos = length; +} + +void ksz9477_get_regs(struct ksz_device *dev, int port, + struct ethtool_regs *regs, void *p) +{ + int i; + u32 pos = 0; + u32 *reg = p; + + for (i = 0; i < ARRAY_SIZE(ksz8_regdump_records); i++) { + struct ksz_regdump_record rec = ksz8_regdump_records[i]; + struct ksz_regdump_hdr *hdr = + (struct ksz_regdump_hdr *)®[pos]; + hdr->module_id = rec.hdr.module_id; + pos += 2; + + if (rec.hdr.module_id == KSZ_REGDUMP_ID_STAT_MAC_TBL) { + continue; + } + + if (rec.hdr.module_id == KSZ_REGDUMP_ID_FDB) { + continue; + } + + hdr->len = pos; + ksz_dump_regmap_range(dev, reg, &pos, rec.start_off, + rec.end_off); + hdr->len = (pos - hdr->len + 2) * sizeof(u32); + } +} diff --git a/drivers/net/dsa/microchip/ksz9477_ethtool.h b/drivers/net/dsa/microchip/ksz9477_ethtool.h new file mode 100644 index 000000000000..88106c37343c --- /dev/null +++ b/drivers/net/dsa/microchip/ksz9477_ethtool.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef __KSZ9477_ETHTOOL_H +#define __KSZ9477_ETHTOOL_H + +#include +#include "ksz_ethtool.h" +#include "ksz_common.h" + +int ksz9477_get_regs_len(struct ksz_device *dev, int port); +void ksz9477_get_regs(struct ksz_device *dev, int port, + struct ethtool_regs *regs, void *p); + +#endif diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index e67b080d1d41..ba7e8fc00504 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -33,6 +33,7 @@ #include "lan937x.h" #include "ksz_devlink.h" #include "ksz8_ethtool.h" +#include "ksz9477_ethtool.h" #define MIB_COUNTER_NUM 0x20 @@ -270,6 +271,8 @@ static const struct ksz_dev_ops ksz9477_dev_ops = { .reset = ksz9477_reset_switch, .init = ksz9477_switch_init, .exit = ksz9477_switch_exit, + .get_regs = ksz9477_get_regs, + .get_regs_len = ksz9477_get_regs_len, }; static const struct ksz_dev_ops lan937x_dev_ops = { diff --git a/drivers/net/dsa/microchip/ksz_ethtool.h b/drivers/net/dsa/microchip/ksz_ethtool.h new file mode 100644 index 000000000000..92f26c6794c1 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_ethtool.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef __KSZ_ETHTOOL_H +#define __KSZ_ETHTOOL_H + +#include +#include + +// sizeof(ksz8_dyn_mac_entry) == 12 +struct ksz8_dyn_mac_entry { + /*entry 1*/ + u32 : 24; + u8 timestamp; + /* entry 2 & 3 */ + u8 fid; + u8 src_port; + u8 mac[ETH_ALEN]; +}; + +struct ksz_regdump_hdr { + u32 module_id; + u32 len; +}; + +struct ksz_regdump_record { + struct ksz_regdump_hdr hdr; + u32 start_off; + u32 end_off; +}; + +enum { + KSZ_REGDUMP_ID_GLOBAL = 0x1100, + KSZ_REGDUMP_ID_PORT = 0x1200, + KSZ_REGDUMP_ID_STAT_MAC_TBL = 0x2000, + KSZ_REGDUMP_ID_FDB = 0x2100, +}; + +// creates a regdump record entry +// note we use u32 to transport register values, despite their size in +// the device +#define KSZ_REGDUMP_ENTRY(id, start, end) { \ + .hdr.module_id = (id), \ + .hdr.len = (((end) - (start)) * sizeof(u32)) * 2 \ + + sizeof(struct ksz_regdump_hdr), \ + .start_off = (start), \ + .end_off = (end), \ +} + +#define SIZE_IS_MULTIPLE_OF(T, T2) (sizeof(T) == (DIV_ROUND_UP(sizeof(T), sizeof(T2))* sizeof(T2))) + +#define KSZ8_REGDUMP_MAC_ENTRY(id, entry_size, max_entries) { \ + .hdr.module_id = (id), \ + .hdr.len = 2 * sizeof(u32) + (entry_size) * (max_entries) \ + + sizeof(struct ksz_regdump_hdr), \ + .start_off = 0, \ + .end_off = 0, \ +} + +#endif +