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 +