From e6759c4acc8c9afe2e18b5b385a4ef4e5b4fb382 Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:04 +0200 Subject: [PATCH 01/10] net: dsa: microchip: remove useless common cls_flower_{add/del} operations All the KSZ switches share a common implementation of the cls_flower_{add/del} operations. These common implementations return ksz9477-specific implementations for the KSZ9477 family and -EOPNOTSUPP for the others. -EOPNOTSUPP is already returned by the DSA core when the operation isn't implemented. Remove the common implementations. Directly link the ksz9477_cls_flower_{add/del}() to the KSZ9477 callback. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-1-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8.c | 6 ---- drivers/net/dsa/microchip/ksz9477.c | 4 +-- drivers/net/dsa/microchip/ksz_common.c | 42 ------------------------ drivers/net/dsa/microchip/ksz_common.h | 4 --- drivers/net/dsa/microchip/lan937x_main.c | 2 -- 5 files changed, 2 insertions(+), 56 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index 4ec2d5d2a1bc..8046c8a94bc6 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -2551,8 +2551,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = { .port_hwtstamp_set = ksz_hwtstamp_set, .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, - .cls_flower_add = ksz_cls_flower_add, - .cls_flower_del = ksz_cls_flower_del, .port_setup_tc = ksz_setup_tc, .support_eee = ksz_support_eee, .set_mac_eee = ksz_set_mac_eee, @@ -2611,8 +2609,6 @@ const struct dsa_switch_ops ksz87xx_switch_ops = { .port_hwtstamp_set = ksz_hwtstamp_set, .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, - .cls_flower_add = ksz_cls_flower_add, - .cls_flower_del = ksz_cls_flower_del, .port_setup_tc = ksz_setup_tc, .support_eee = ksz_support_eee, .set_mac_eee = ksz_set_mac_eee, @@ -2671,8 +2667,6 @@ const struct dsa_switch_ops ksz88xx_switch_ops = { .port_hwtstamp_set = ksz_hwtstamp_set, .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, - .cls_flower_add = ksz_cls_flower_add, - .cls_flower_del = ksz_cls_flower_del, .port_setup_tc = ksz_setup_tc, .support_eee = ksz_support_eee, .set_mac_eee = ksz_set_mac_eee, diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index c1395322e54b..c18bad08a508 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1996,8 +1996,8 @@ const struct dsa_switch_ops ksz9477_switch_ops = { .port_hwtstamp_set = ksz_hwtstamp_set, .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, - .cls_flower_add = ksz_cls_flower_add, - .cls_flower_del = ksz_cls_flower_del, + .cls_flower_add = ksz9477_cls_flower_add, + .cls_flower_del = ksz9477_cls_flower_del, .port_setup_tc = ksz_setup_tc, .support_eee = ksz_support_eee, .set_mac_eee = ksz_set_mac_eee, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 57c8abfe0147..81d3ec88e436 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -3373,48 +3373,6 @@ static int ksz_switch_detect(struct ksz_device *dev) return 0; } -int ksz_cls_flower_add(struct dsa_switch *ds, int port, - struct flow_cls_offload *cls, bool ingress) -{ - struct ksz_device *dev = ds->priv; - - switch (dev->chip_id) { - case KSZ8563_CHIP_ID: - case KSZ8567_CHIP_ID: - case KSZ9477_CHIP_ID: - case KSZ9563_CHIP_ID: - case KSZ9567_CHIP_ID: - case KSZ9893_CHIP_ID: - case KSZ9896_CHIP_ID: - case KSZ9897_CHIP_ID: - case LAN9646_CHIP_ID: - return ksz9477_cls_flower_add(ds, port, cls, ingress); - } - - return -EOPNOTSUPP; -} - -int ksz_cls_flower_del(struct dsa_switch *ds, int port, - struct flow_cls_offload *cls, bool ingress) -{ - struct ksz_device *dev = ds->priv; - - switch (dev->chip_id) { - case KSZ8563_CHIP_ID: - case KSZ8567_CHIP_ID: - case KSZ9477_CHIP_ID: - case KSZ9563_CHIP_ID: - case KSZ9567_CHIP_ID: - case KSZ9893_CHIP_ID: - case KSZ9896_CHIP_ID: - case KSZ9897_CHIP_ID: - case LAN9646_CHIP_ID: - return ksz9477_cls_flower_del(ds, port, cls, ingress); - } - - return -EOPNOTSUPP; -} - /* Bandwidth is calculated by idle slope/transmission speed. Then the Bandwidth * is converted to Hex-decimal using the successive multiplication method. On * every step, integer part is taken and decimal part is carry forwarded. diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 45613b9aeb1e..1c22d10eff84 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -487,10 +487,6 @@ bool ksz_support_eee(struct dsa_switch *ds, int port); int ksz_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); -int ksz_cls_flower_add(struct dsa_switch *ds, int port, - struct flow_cls_offload *cls, bool ingress); -int ksz_cls_flower_del(struct dsa_switch *ds, int port, - struct flow_cls_offload *cls, bool ingress); int ksz_setup_tc(struct dsa_switch *ds, int port, enum tc_setup_type type, void *type_data); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 536153886f7b..731737fd58d1 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -890,8 +890,6 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_hwtstamp_set = ksz_hwtstamp_set, .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, - .cls_flower_add = ksz_cls_flower_add, - .cls_flower_del = ksz_cls_flower_del, .port_setup_tc = ksz_setup_tc, .support_eee = ksz_support_eee, .set_mac_eee = ksz_set_mac_eee, From b54a8087c43c8d704429e69c35e37f43c1c6270a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 8 Jun 2026 16:10:05 +0200 Subject: [PATCH 02/10] net: dsa: microchip: remove VLAN operations for ksz8463 KSZ8463 uses the common KSZ8 implementation for its VLAN operations. This implementation returns -ENOTSUPP for the KSZ8463 case, which is pointless. Remove the VLAN operations from the ksz8463_switch_ops so the core can directly return -ENOTSUPP. Signed-off-by: Vladimir Oltean Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-2-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index 8046c8a94bc6..9161326b34fd 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -1562,7 +1562,7 @@ static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag, { struct ksz_device *dev = ds->priv; - if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) + if (ksz_is_ksz88x3(dev)) return -ENOTSUPP; /* Discard packets with VID not enabled on the switch */ @@ -1599,7 +1599,7 @@ static int ksz8_port_vlan_add(struct dsa_switch *ds, int port, u16 data, new_pvid = 0; u8 fid, member, valid; - if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) + if (ksz_is_ksz88x3(dev)) return -ENOTSUPP; /* If a VLAN is added with untagged flag different from the @@ -1669,7 +1669,7 @@ static int ksz8_port_vlan_del(struct dsa_switch *ds, int port, u8 fid, member, valid; u16 data, pvid; - if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) + if (ksz_is_ksz88x3(dev)) return -ENOTSUPP; ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid); @@ -2528,9 +2528,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = { .port_pre_bridge_flags = ksz_port_pre_bridge_flags, .port_bridge_flags = ksz_port_bridge_flags, .port_fast_age = ksz8_flush_dyn_mac_table, - .port_vlan_filtering = ksz8_port_vlan_filtering, - .port_vlan_add = ksz8_port_vlan_add, - .port_vlan_del = ksz8_port_vlan_del, .port_fdb_dump = ksz8_fdb_dump, .port_fdb_add = ksz8_fdb_add, .port_fdb_del = ksz8_fdb_del, From 4d574a5cfa4859340638e60caad77d51bb6dbdaa Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:06 +0200 Subject: [PATCH 03/10] net: dsa: microchip: implement get_phy_flags only if needed The common ksz_get_phy_flags() is used by all the switches to implement the optional .get_phy_flags DSA operation. It always returns 0 except for KSZ88X3 switches where an errata has to be handled. Make ksz_get_phy_flags() ksz88xx-specific. Remove the get_phy_flags implementation for the switches that don't need it. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-3-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8.c | 22 +++++++++++++++++++--- drivers/net/dsa/microchip/ksz9477.c | 1 - drivers/net/dsa/microchip/ksz_common.c | 18 ------------------ drivers/net/dsa/microchip/ksz_common.h | 2 -- drivers/net/dsa/microchip/lan937x_main.c | 1 - 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index 9161326b34fd..ba708ad71c1e 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -2361,6 +2361,24 @@ static int ksz8463_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val return 0; } +static u32 ksz88xx_get_phy_flags(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + + switch (dev->chip_id) { + case KSZ88X3_CHIP_ID: + /* Silicon Errata Sheet (DS80000830A): + * Port 1 does not work with LinkMD Cable-Testing. + * Port 1 does not respond to received PAUSE control frames. + */ + if (!port) + return MICREL_KSZ8_P1_ERRATA; + break; + } + + return 0; +} + static int ksz8_switch_init(struct ksz_device *dev) { dev->cpu_port = fls(dev->info->cpu_ports) - 1; @@ -2508,7 +2526,6 @@ const struct ksz_dev_ops ksz88xx_dev_ops = { const struct dsa_switch_ops ksz8463_switch_ops = { .get_tag_protocol = ksz8463_get_tag_protocol, .connect_tag_protocol = ksz8463_connect_tag_protocol, - .get_phy_flags = ksz_get_phy_flags, .setup = ksz8_setup, .teardown = ksz_teardown, .phy_read = ksz8463_phy_read16, @@ -2563,7 +2580,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = { const struct dsa_switch_ops ksz87xx_switch_ops = { .get_tag_protocol = ksz87xx_get_tag_protocol, .connect_tag_protocol = ksz87xx_connect_tag_protocol, - .get_phy_flags = ksz_get_phy_flags, .setup = ksz8_setup, .teardown = ksz_teardown, .phy_read = ksz8_phy_read16, @@ -2621,7 +2637,7 @@ const struct dsa_switch_ops ksz87xx_switch_ops = { const struct dsa_switch_ops ksz88xx_switch_ops = { .get_tag_protocol = ksz88xx_get_tag_protocol, .connect_tag_protocol = ksz88xx_connect_tag_protocol, - .get_phy_flags = ksz_get_phy_flags, + .get_phy_flags = ksz88xx_get_phy_flags, .setup = ksz8_setup, .teardown = ksz_teardown, .phy_read = ksz8_phy_read16, diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index c18bad08a508..a39541d29ad5 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1952,7 +1952,6 @@ const struct ksz_dev_ops ksz9477_dev_ops = { const struct dsa_switch_ops ksz9477_switch_ops = { .get_tag_protocol = ksz9477_get_tag_protocol, .connect_tag_protocol = ksz9477_connect_tag_protocol, - .get_phy_flags = ksz_get_phy_flags, .setup = ksz9477_setup, .teardown = ksz_teardown, .phy_read = ksz9477_phy_read16, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 81d3ec88e436..5fb151fbf4f3 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2838,24 +2838,6 @@ void ksz_init_mib_timer(struct ksz_device *dev) } } -u32 ksz_get_phy_flags(struct dsa_switch *ds, int port) -{ - struct ksz_device *dev = ds->priv; - - switch (dev->chip_id) { - case KSZ88X3_CHIP_ID: - /* Silicon Errata Sheet (DS80000830A): - * Port 1 does not work with LinkMD Cable-Testing. - * Port 1 does not respond to received PAUSE control frames. - */ - if (!port) - return MICREL_KSZ8_P1_ERRATA; - break; - } - - return 0; -} - void ksz_phylink_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 1c22d10eff84..de47498db483 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -444,8 +444,6 @@ void ksz_switch_macaddr_put(struct dsa_switch *ds); void ksz_switch_shutdown(struct ksz_device *dev); int ksz_handle_wake_reason(struct ksz_device *dev, int port); -u32 ksz_get_phy_flags(struct dsa_switch *ds, int port); - int ksz_sset_count(struct dsa_switch *ds, int port, int sset); void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 731737fd58d1..57e289637193 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -846,7 +846,6 @@ const struct ksz_dev_ops lan937x_dev_ops = { const struct dsa_switch_ops lan937x_switch_ops = { .get_tag_protocol = lan937x_get_tag_protocol, .connect_tag_protocol = lan937x_connect_tag_protocol, - .get_phy_flags = ksz_get_phy_flags, .setup = lan937x_setup, .teardown = ksz_teardown, .phy_read = lan937x_phy_read16, From c90e80103ba5ee1ca704944352e5e5b7a064a292 Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:07 +0200 Subject: [PATCH 04/10] net: dsa: microchip: wrap the MAC configuration checks in a function The common .mac_config() implementation checks some conditions before doing any register access. As this common implementation is about to be split in the upcoming patch, these checks would lead to code duplication. Wrap all the checks in a need_config() function that returns true when the driver really need to access the switch registers to configure the MAC. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-4-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 42 +++++++++++++++++--------- drivers/net/dsa/microchip/ksz_common.h | 1 + 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 5fb151fbf4f3..f29287922843 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -3211,6 +3211,29 @@ phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit) return interface; } +bool ksz_phylink_need_config(struct phylink_config *config, + unsigned int mode) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ksz_device *dev = dp->ds->priv; + int port = dp->index; + + /* Internal PHYs */ + if (dev->info->internal_phy[port]) + return false; + + /* No need to configure XMII control register when using SGMII. */ + if (ksz_is_sgmii_port(dev, port)) + return false; + + if (phylink_autoneg_inband(mode)) { + dev_err(dev->dev, "In-band AN not supported!\n"); + return false; + } + + return true; +} + void ksz_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) @@ -3219,23 +3242,12 @@ void ksz_phylink_mac_config(struct phylink_config *config, struct ksz_device *dev = dp->ds->priv; int port = dp->index; - /* Internal PHYs */ - if (dev->info->internal_phy[port]) - return; + if (ksz_phylink_need_config(config, mode)) { + ksz_set_xmii(dev, port, state->interface); - /* No need to configure XMII control register when using SGMII. */ - if (ksz_is_sgmii_port(dev, port)) - return; - - if (phylink_autoneg_inband(mode)) { - dev_err(dev->dev, "In-band AN not supported!\n"); - return; + if (dev->dev_ops->setup_rgmii_delay) + dev->dev_ops->setup_rgmii_delay(dev, port); } - - ksz_set_xmii(dev, port, state->interface); - - if (dev->dev_ops->setup_rgmii_delay) - dev->dev_ops->setup_rgmii_delay(dev, port); } bool ksz_get_gbit(struct ksz_device *dev, int port) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index de47498db483..51d424233b29 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -472,6 +472,7 @@ void ksz_phylink_get_caps(struct dsa_switch *ds, int port, void ksz_phylink_mac_disable_tx_lpi(struct phylink_config *config); int ksz_phylink_mac_enable_tx_lpi(struct phylink_config *config, u32 timer, bool tx_clock_stop); +bool ksz_phylink_need_config(struct phylink_config *config, unsigned int mode); void ksz_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state); From b97d51f4501cf790802e1f2efafbfc153159f6e2 Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:08 +0200 Subject: [PATCH 05/10] net: dsa: microchip: remove setup_rgmii_delay() KSZ operation setup_rgmii_delay() operation is only used once during the common phylink MAC configuration. Only the lan937x switch implements this setup_rgmii_delay(). Remove the setup_rgmii_delay operation from ksz_dev_ops. Implement a lan937x-specific phylink MAC configuration that does this RGMII delay setup. Export ksz_set_xmii since it's needed by the lan937x implementation. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-5-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 9 ++------- drivers/net/dsa/microchip/ksz_common.h | 2 +- drivers/net/dsa/microchip/lan937x_main.c | 17 +++++++++++++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index f29287922843..33a20c2e0a8a 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -3127,8 +3127,7 @@ int ksz_set_mac_eee(struct dsa_switch *ds, int port, return 0; } -static void ksz_set_xmii(struct ksz_device *dev, int port, - phy_interface_t interface) +void ksz_set_xmii(struct ksz_device *dev, int port, phy_interface_t interface) { const u8 *bitval = dev->info->xmii_ctrl1; struct ksz_port *p = &dev->ports[port]; @@ -3242,12 +3241,8 @@ void ksz_phylink_mac_config(struct phylink_config *config, struct ksz_device *dev = dp->ds->priv; int port = dp->index; - if (ksz_phylink_need_config(config, mode)) { + if (ksz_phylink_need_config(config, mode)) ksz_set_xmii(dev, port, state->interface); - - if (dev->dev_ops->setup_rgmii_delay) - dev->dev_ops->setup_rgmii_delay(dev, port); - } } bool ksz_get_gbit(struct ksz_device *dev, int port) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 51d424233b29..4c3a551a5b60 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -414,7 +414,6 @@ struct ksz_dev_ops { u8 data); void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze); void (*port_init_cnt)(struct ksz_device *dev, int port); - void (*setup_rgmii_delay)(struct ksz_device *dev, int port); int (*tc_cbs_set_cinc)(struct ksz_device *dev, int port, u32 val); int (*init)(struct ksz_device *dev); }; @@ -472,6 +471,7 @@ void ksz_phylink_get_caps(struct dsa_switch *ds, int port, void ksz_phylink_mac_disable_tx_lpi(struct phylink_config *config); int ksz_phylink_mac_enable_tx_lpi(struct phylink_config *config, u32 timer, bool tx_clock_stop); +void ksz_set_xmii(struct ksz_device *dev, int port, phy_interface_t interface); bool ksz_phylink_need_config(struct phylink_config *config, unsigned int mode); void ksz_phylink_mac_config(struct phylink_config *config, unsigned int mode, diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 57e289637193..69df378a40bf 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -643,6 +643,20 @@ static void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port) } } +static void lan937x_phylink_mac_config(struct phylink_config *config, + unsigned int mode, + const struct phylink_link_state *state) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ksz_device *dev = dp->ds->priv; + int port = dp->index; + + if (ksz_phylink_need_config(config, mode)) { + ksz_set_xmii(dev, port, state->interface); + lan937x_setup_rgmii_delay(dev, port); + } +} + static int lan937x_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val) { return ksz_pwrite32(dev, port, REG_PORT_MTI_CREDIT_INCREMENT, val); @@ -821,7 +835,7 @@ static int lan937x_connect_tag_protocol(struct dsa_switch *ds, } const struct phylink_mac_ops lan937x_phylink_mac_ops = { - .mac_config = ksz_phylink_mac_config, + .mac_config = lan937x_phylink_mac_config, .mac_link_down = ksz_phylink_mac_link_down, .mac_link_up = ksz9477_phylink_mac_link_up, .mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi, @@ -838,7 +852,6 @@ const struct ksz_dev_ops lan937x_dev_ops = { .r_mib_stat64 = ksz_r_mib_stats64, .freeze_mib = ksz9477_freeze_mib, .port_init_cnt = ksz9477_port_init_cnt, - .setup_rgmii_delay = lan937x_setup_rgmii_delay, .tc_cbs_set_cinc = lan937x_tc_cbs_set_cinc, .init = lan937x_switch_init, }; From d654b3241436bb2226853915324ae841e878b74c Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:09 +0200 Subject: [PATCH 06/10] net: dsa: microchip: implement .support_eee() only if needed The .support_eee() operation is optional. Yet, it is implemented by the KSZ switches through a common functon that reports false for every chip except for KSZ8563, KSZ9563 and KSZ9893 from the KSZ9477 family. Remove the implementation from the switches that don't support EEE. Also remove .set_mac_eee() for them as .set_mac_eee() is gated by the `support_eee` presence in the core. Implement instead a ksz9477-specific support_eee for these three supported switches. Note that comment /* KSZ879x/KSZ877x/KSZ876x Errata DS80000687C Module 2 */ is completely removed because it concerns the KSZ87xx family that doesn't support at all EEE. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-6-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8.c | 6 --- drivers/net/dsa/microchip/ksz9477.c | 50 ++++++++++++++++++++- drivers/net/dsa/microchip/ksz_common.c | 57 ------------------------ drivers/net/dsa/microchip/ksz_common.h | 1 - drivers/net/dsa/microchip/lan937x_main.c | 2 - 5 files changed, 49 insertions(+), 67 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index ba708ad71c1e..c0420954cb10 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -2566,8 +2566,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = { .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, .port_setup_tc = ksz_setup_tc, - .support_eee = ksz_support_eee, - .set_mac_eee = ksz_set_mac_eee, .port_get_default_prio = ksz_port_get_default_prio, .port_set_default_prio = ksz_port_set_default_prio, .port_get_dscp_prio = ksz_port_get_dscp_prio, @@ -2623,8 +2621,6 @@ const struct dsa_switch_ops ksz87xx_switch_ops = { .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, .port_setup_tc = ksz_setup_tc, - .support_eee = ksz_support_eee, - .set_mac_eee = ksz_set_mac_eee, .port_get_default_prio = ksz_port_get_default_prio, .port_set_default_prio = ksz_port_set_default_prio, .port_get_dscp_prio = ksz_port_get_dscp_prio, @@ -2681,8 +2677,6 @@ const struct dsa_switch_ops ksz88xx_switch_ops = { .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, .port_setup_tc = ksz_setup_tc, - .support_eee = ksz_support_eee, - .set_mac_eee = ksz_set_mac_eee, .port_get_default_prio = ksz_port_get_default_prio, .port_set_default_prio = ksz_port_set_default_prio, .port_get_dscp_prio = ksz_port_get_dscp_prio, diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index a39541d29ad5..e0b3724a7558 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1909,6 +1909,54 @@ void ksz9477_phylink_mac_link_up(struct phylink_config *config, ksz9477_duplex_flowctrl(dev, port, duplex, tx_pause, rx_pause); } +/** + * ksz9477_support_eee - Determine Energy Efficient Ethernet (EEE) support for a + * port + * @ds: Pointer to the DSA switch structure + * @port: Port number to check + * + * This function also documents devices where EEE was initially advertised but + * later withdrawn due to reliability issues, as described in official errata + * documents. These devices are explicitly listed to record known limitations, + * even if there is no technical necessity for runtime checks. + * + * Returns: true if the internal PHY on the given port supports fully + * operational EEE, false otherwise. + */ +static bool ksz9477_support_eee(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->info->internal_phy[port]) + return false; + + switch (dev->chip_id) { + case KSZ8563_CHIP_ID: + case KSZ9563_CHIP_ID: + case KSZ9893_CHIP_ID: + return true; + default: + /* KSZ8567R Errata DS80000752C Module 4 */ + /* KSZ9477S Errata DS80000754A Module 4 */ + /* KSZ9567S Errata DS80000756A Module 4 */ + /* KSZ9896C Errata DS80000757A Module 3 */ + /* KSZ9897R Errata DS80000758C Module 4 */ + /* Energy Efficient Ethernet (EEE) feature select must be + * manually disabled + * The EEE feature is enabled by default, but it is not fully + * operational. It must be manually disabled through register + * controls. If not disabled, the PHY ports can auto-negotiate + * to enable EEE, and this feature can cause link drops when + * linked to another device supporting EEE. + * + * The same item appears in the errata for all switches above. + */ + break; + } + + return false; +} + static struct phylink_pcs * ksz9477_phylink_mac_select_pcs(struct phylink_config *config, phy_interface_t interface) @@ -1998,7 +2046,7 @@ const struct dsa_switch_ops ksz9477_switch_ops = { .cls_flower_add = ksz9477_cls_flower_add, .cls_flower_del = ksz9477_cls_flower_del, .port_setup_tc = ksz_setup_tc, - .support_eee = ksz_support_eee, + .support_eee = ksz9477_support_eee, .set_mac_eee = ksz_set_mac_eee, .port_get_default_prio = ksz_port_get_default_prio, .port_set_default_prio = ksz_port_set_default_prio, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 33a20c2e0a8a..bebf697ec60a 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -3052,63 +3052,6 @@ int ksz_max_mtu(struct dsa_switch *ds, int port) return -EOPNOTSUPP; } -/** - * ksz_support_eee - Determine Energy Efficient Ethernet (EEE) support for a - * port - * @ds: Pointer to the DSA switch structure - * @port: Port number to check - * - * This function also documents devices where EEE was initially advertised but - * later withdrawn due to reliability issues, as described in official errata - * documents. These devices are explicitly listed to record known limitations, - * even if there is no technical necessity for runtime checks. - * - * Returns: true if the internal PHY on the given port supports fully - * operational EEE, false otherwise. - */ -bool ksz_support_eee(struct dsa_switch *ds, int port) -{ - struct ksz_device *dev = ds->priv; - - if (!dev->info->internal_phy[port]) - return false; - - switch (dev->chip_id) { - case KSZ8563_CHIP_ID: - case KSZ9563_CHIP_ID: - case KSZ9893_CHIP_ID: - return true; - case KSZ8567_CHIP_ID: - /* KSZ8567R Errata DS80000752C Module 4 */ - case KSZ8765_CHIP_ID: - case KSZ8794_CHIP_ID: - case KSZ8795_CHIP_ID: - /* KSZ879x/KSZ877x/KSZ876x Errata DS80000687C Module 2 */ - case KSZ9477_CHIP_ID: - /* KSZ9477S Errata DS80000754A Module 4 */ - case KSZ9567_CHIP_ID: - /* KSZ9567S Errata DS80000756A Module 4 */ - case KSZ9896_CHIP_ID: - /* KSZ9896C Errata DS80000757A Module 3 */ - case KSZ9897_CHIP_ID: - case LAN9646_CHIP_ID: - /* KSZ9897R Errata DS80000758C Module 4 */ - /* Energy Efficient Ethernet (EEE) feature select must be - * manually disabled - * The EEE feature is enabled by default, but it is not fully - * operational. It must be manually disabled through register - * controls. If not disabled, the PHY ports can auto-negotiate - * to enable EEE, and this feature can cause link drops when - * linked to another device supporting EEE. - * - * The same item appears in the errata for all switches above. - */ - break; - } - - return false; -} - int ksz_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e) { diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 4c3a551a5b60..344d27a8dba1 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -482,7 +482,6 @@ void ksz_phylink_mac_link_down(struct phylink_config *config, int ksz_max_mtu(struct dsa_switch *ds, int port); -bool ksz_support_eee(struct dsa_switch *ds, int port); int ksz_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 69df378a40bf..e1aba93d1438 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -903,8 +903,6 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, .port_setup_tc = ksz_setup_tc, - .support_eee = ksz_support_eee, - .set_mac_eee = ksz_set_mac_eee, .port_get_default_prio = ksz_port_get_default_prio, .port_set_default_prio = ksz_port_set_default_prio, .port_get_dscp_prio = ksz_port_get_dscp_prio, From 75ad8c1bc79fe1735bdcbe469966a5ba1eddc1e2 Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:10 +0200 Subject: [PATCH 07/10] net: dsa: microchip: implement .{get/set}_wol only if needed All the KSZ switches use common {get/set}_wol operations while only the ksz9477 and the ksz87xx families really support it. These operations are optional so there is no point implementing them to return -EOPNOTSUPP. Remove the {get/set}_wol callbacks from the switch operations for the ksz88xx, the ksz8463 and the lan937x families. Remove the family check from the common {get/set}_wol implementation. Note that is_ksz9477() is only true for the KSZ9477 so this change will also add WoL support for the other switches using the ksz9477_switch_ops. I checked their datasheet, they implement the same PME_WOL registers, at the same addresses, so this should go fine. Modify the ksz_wol_pre_shutdown() initial check to ensure consistency in the WoL handling for these non-KSZ9477 switches using ksz9477_switch_ops. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-7-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8.c | 4 ---- drivers/net/dsa/microchip/ksz_common.c | 12 ++++-------- drivers/net/dsa/microchip/lan937x_main.c | 2 -- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index c0420954cb10..6ae0226c49a3 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -2556,8 +2556,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = { .get_pause_stats = ksz_get_pause_stats, .port_change_mtu = ksz8_change_mtu, .port_max_mtu = ksz_max_mtu, - .get_wol = ksz_get_wol, - .set_wol = ksz_set_wol, .suspend = ksz_suspend, .resume = ksz_resume, .get_ts_info = ksz_get_ts_info, @@ -2611,8 +2609,6 @@ const struct dsa_switch_ops ksz87xx_switch_ops = { .get_pause_stats = ksz_get_pause_stats, .port_change_mtu = ksz8_change_mtu, .port_max_mtu = ksz_max_mtu, - .get_wol = ksz_get_wol, - .set_wol = ksz_set_wol, .suspend = ksz_suspend, .resume = ksz_resume, .get_ts_info = ksz_get_ts_info, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index bebf697ec60a..809a0bc3c01e 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -3756,9 +3756,6 @@ void ksz_get_wol(struct dsa_switch *ds, int port, u8 pme_ctrl; int ret; - if (!is_ksz9477(dev) && !ksz_is_ksz87xx(dev)) - return; - if (!dev->wakeup_source) return; @@ -3809,9 +3806,6 @@ int ksz_set_wol(struct dsa_switch *ds, int port, if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC)) return -EINVAL; - if (!is_ksz9477(dev) && !ksz_is_ksz87xx(dev)) - return -EOPNOTSUPP; - if (!dev->wakeup_source) return -EOPNOTSUPP; @@ -3871,12 +3865,13 @@ static void ksz_wol_pre_shutdown(struct ksz_device *dev) { const struct ksz_dev_ops *ops = dev->dev_ops; const u16 *regs = dev->info->regs; + struct dsa_switch *ds = dev->ds; u8 pme_pin_en = PME_ENABLE; bool wol_enabled = false; struct dsa_port *dp; int ret; - if (!is_ksz9477(dev) && !ksz_is_ksz87xx(dev)) + if (!ds->ops->set_wol) return; if (!dev->wakeup_source) @@ -3924,7 +3919,8 @@ int ksz_port_set_mac_address(struct dsa_switch *ds, int port, */ wol.wolopts = 0; - ksz_get_wol(ds, dp->index, &wol); + if (ds->ops->get_wol) + ds->ops->get_wol(ds, dp->index, &wol); if (wol.wolopts & WAKE_MAGIC) { dev_err(ds->dev, "Cannot change MAC address on port %d with active Wake on Magic Packet\n", diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index e1aba93d1438..6b1306e81558 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -893,8 +893,6 @@ const struct dsa_switch_ops lan937x_switch_ops = { .get_pause_stats = ksz_get_pause_stats, .port_change_mtu = lan937x_change_mtu, .port_max_mtu = ksz_max_mtu, - .get_wol = ksz_get_wol, - .set_wol = ksz_set_wol, .suspend = ksz_suspend, .resume = ksz_resume, .get_ts_info = ksz_get_ts_info, From e33c16843686fef3f0da7dfff689c3a284060116 Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:11 +0200 Subject: [PATCH 08/10] net: dsa: microchip: implement port_hsr_join for KSZ9477 only All switches implement the optional .port_hsr_join operation while only the KSZ9477 truly supports it. Remove the common port_hsr_join implementation. Replace it with a specific implementation for the KSZ9477 case. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-8-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8.c | 6 --- drivers/net/dsa/microchip/ksz9477.c | 65 +++++++++++++++++++++-- drivers/net/dsa/microchip/ksz9477.h | 2 - drivers/net/dsa/microchip/ksz_common.c | 67 ------------------------ drivers/net/dsa/microchip/ksz_common.h | 4 -- drivers/net/dsa/microchip/lan937x_main.c | 2 - 6 files changed, 61 insertions(+), 85 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index 6ae0226c49a3..3a7e96403ed2 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -2537,8 +2537,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = { .get_sset_count = ksz_sset_count, .port_bridge_join = ksz_port_bridge_join, .port_bridge_leave = ksz_port_bridge_leave, - .port_hsr_join = ksz_hsr_join, - .port_hsr_leave = ksz_hsr_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, .port_teardown = ksz_port_teardown, @@ -2587,8 +2585,6 @@ const struct dsa_switch_ops ksz87xx_switch_ops = { .get_sset_count = ksz_sset_count, .port_bridge_join = ksz_port_bridge_join, .port_bridge_leave = ksz_port_bridge_leave, - .port_hsr_join = ksz_hsr_join, - .port_hsr_leave = ksz_hsr_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, .port_teardown = ksz_port_teardown, @@ -2641,8 +2637,6 @@ const struct dsa_switch_ops ksz88xx_switch_ops = { .get_sset_count = ksz_sset_count, .port_bridge_join = ksz_port_bridge_join, .port_bridge_leave = ksz_port_bridge_leave, - .port_hsr_join = ksz_hsr_join, - .port_hsr_leave = ksz_hsr_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, .port_teardown = ksz_port_teardown, diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index e0b3724a7558..48813b0f4280 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1707,12 +1708,52 @@ static int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val) */ #define KSZ9477_SUPPORTED_HSR_FEATURES (NETIF_F_HW_HSR_DUP | NETIF_F_HW_HSR_FWD) -void ksz9477_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr) +static int ksz9477_hsr_join(struct dsa_switch *ds, int port, + struct net_device *hsr, + struct netlink_ext_ack *extack) { struct ksz_device *dev = ds->priv; struct net_device *user; struct dsa_port *hsr_dp; u8 data, hsr_ports = 0; + enum hsr_version ver; + int ret; + + ret = hsr_get_version(hsr, &ver); + if (ret) + return ret; + + if (dev->chip_id != KSZ9477_CHIP_ID) { + NL_SET_ERR_MSG_MOD(extack, "Chip does not support HSR offload"); + return -EOPNOTSUPP; + } + + /* KSZ9477 can support HW offloading of only 1 HSR device */ + if (dev->hsr_dev && hsr != dev->hsr_dev) { + NL_SET_ERR_MSG_MOD(extack, + "Offload supported for a single HSR"); + return -EOPNOTSUPP; + } + + /* KSZ9477 only supports HSR v0 and v1 */ + if (!(ver == HSR_V0 || ver == HSR_V1)) { + NL_SET_ERR_MSG_MOD(extack, "Only HSR v0 and v1 supported"); + return -EOPNOTSUPP; + } + + /* KSZ9477 can only perform HSR offloading for up to two ports */ + if (hweight8(dev->hsr_ports) >= 2) { + NL_SET_ERR_MSG_MOD(extack, + "Cannot offload more than two ports - using software HSR"); + return -EOPNOTSUPP; + } + + /* Self MAC address filtering, to avoid frames traversing + * the HSR ring more than once. + */ + ret = ksz_switch_macaddr_get(ds, port, extack); + if (ret) + return ret; /* Program which port(s) shall support HSR */ ksz_rmw32(dev, REG_HSR_PORT_MAP__4, BIT(port), BIT(port)); @@ -1744,12 +1785,20 @@ void ksz9477_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr) /* Setup HW supported features for lan HSR ports */ user = dsa_to_port(ds, port)->user; user->features |= KSZ9477_SUPPORTED_HSR_FEATURES; + + dev->hsr_dev = hsr; + dev->hsr_ports |= BIT(port); + + return 0; } -void ksz9477_hsr_leave(struct dsa_switch *ds, int port, struct net_device *hsr) +static int ksz9477_hsr_leave(struct dsa_switch *ds, int port, + struct net_device *hsr) { struct ksz_device *dev = ds->priv; + WARN_ON(dev->chip_id != KSZ9477_CHIP_ID); + /* Clear port HSR support */ ksz_rmw32(dev, REG_HSR_PORT_MAP__4, BIT(port), 0); @@ -1758,6 +1807,14 @@ void ksz9477_hsr_leave(struct dsa_switch *ds, int port, struct net_device *hsr) /* Disable per port self-address filtering */ ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, PORT_SRC_ADDR_FILTER, false); + + dev->hsr_ports &= ~BIT(port); + if (!dev->hsr_ports) + dev->hsr_dev = NULL; + + ksz_switch_macaddr_put(ds); + + return 0; } static int ksz9477_switch_init(struct ksz_device *dev) @@ -2012,8 +2069,8 @@ const struct dsa_switch_ops ksz9477_switch_ops = { .get_sset_count = ksz_sset_count, .port_bridge_join = ksz_port_bridge_join, .port_bridge_leave = ksz_port_bridge_leave, - .port_hsr_join = ksz_hsr_join, - .port_hsr_leave = ksz_hsr_leave, + .port_hsr_join = ksz9477_hsr_join, + .port_hsr_leave = ksz9477_hsr_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, .port_teardown = ksz_port_teardown, diff --git a/drivers/net/dsa/microchip/ksz9477.h b/drivers/net/dsa/microchip/ksz9477.h index 599db0a6ba2e..92a1d889224d 100644 --- a/drivers/net/dsa/microchip/ksz9477.h +++ b/drivers/net/dsa/microchip/ksz9477.h @@ -45,8 +45,6 @@ int ksz9477_mdb_del(struct dsa_switch *ds, int port, const struct switchdev_obj_port_mdb *mdb, struct dsa_db db); int ksz9477_enable_stp_addr(struct ksz_device *dev); void ksz9477_port_queue_split(struct ksz_device *dev, int port); -void ksz9477_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr); -void ksz9477_hsr_leave(struct dsa_switch *ds, int port, struct net_device *hsr); int ksz9477_port_acl_init(struct ksz_device *dev, int port); void ksz9477_port_acl_free(struct ksz_device *dev, int port); diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 809a0bc3c01e..7dc8e4ffacdd 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -4055,72 +4054,6 @@ void ksz_switch_macaddr_put(struct dsa_switch *ds) kfree(switch_macaddr); } -int ksz_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr, - struct netlink_ext_ack *extack) -{ - struct ksz_device *dev = ds->priv; - enum hsr_version ver; - int ret; - - ret = hsr_get_version(hsr, &ver); - if (ret) - return ret; - - if (dev->chip_id != KSZ9477_CHIP_ID) { - NL_SET_ERR_MSG_MOD(extack, "Chip does not support HSR offload"); - return -EOPNOTSUPP; - } - - /* KSZ9477 can support HW offloading of only 1 HSR device */ - if (dev->hsr_dev && hsr != dev->hsr_dev) { - NL_SET_ERR_MSG_MOD(extack, "Offload supported for a single HSR"); - return -EOPNOTSUPP; - } - - /* KSZ9477 only supports HSR v0 and v1 */ - if (!(ver == HSR_V0 || ver == HSR_V1)) { - NL_SET_ERR_MSG_MOD(extack, "Only HSR v0 and v1 supported"); - return -EOPNOTSUPP; - } - - /* KSZ9477 can only perform HSR offloading for up to two ports */ - if (hweight8(dev->hsr_ports) >= 2) { - NL_SET_ERR_MSG_MOD(extack, - "Cannot offload more than two ports - using software HSR"); - return -EOPNOTSUPP; - } - - /* Self MAC address filtering, to avoid frames traversing - * the HSR ring more than once. - */ - ret = ksz_switch_macaddr_get(ds, port, extack); - if (ret) - return ret; - - ksz9477_hsr_join(ds, port, hsr); - dev->hsr_dev = hsr; - dev->hsr_ports |= BIT(port); - - return 0; -} - -int ksz_hsr_leave(struct dsa_switch *ds, int port, - struct net_device *hsr) -{ - struct ksz_device *dev = ds->priv; - - WARN_ON(dev->chip_id != KSZ9477_CHIP_ID); - - ksz9477_hsr_leave(ds, port, hsr); - dev->hsr_ports &= ~BIT(port); - if (!dev->hsr_ports) - dev->hsr_dev = NULL; - - ksz_switch_macaddr_put(ds); - - return 0; -} - int ksz_suspend(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 344d27a8dba1..bdc93f2855c7 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -494,10 +494,6 @@ int ksz_set_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol); int ksz_port_set_mac_address(struct dsa_switch *ds, int port, const unsigned char *addr); -int ksz_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr, - struct netlink_ext_ack *extack); -int ksz_hsr_leave(struct dsa_switch *ds, int port, - struct net_device *hsr); int ksz_suspend(struct dsa_switch *ds); int ksz_resume(struct dsa_switch *ds); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 6b1306e81558..d45798de4ce9 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -871,8 +871,6 @@ const struct dsa_switch_ops lan937x_switch_ops = { .get_sset_count = ksz_sset_count, .port_bridge_join = ksz_port_bridge_join, .port_bridge_leave = ksz_port_bridge_leave, - .port_hsr_join = ksz_hsr_join, - .port_hsr_leave = ksz_hsr_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, .port_teardown = ksz_port_teardown, From 03d10c776802ba627191a3ab622f59af5def08b5 Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:12 +0200 Subject: [PATCH 09/10] net: dsa: microchip: implement lan937x-specific MDIO registration All the switches use a common mdio_register() function that uses two ksz_dev_ops callbacks (.mdio_bus_preinit() and .create_phy_addr_map()) to handle the lan937x specific case. These two callbacks are used only at this place in the code. Implement a new lan937x-specific MDIO registration functions that uses these two lan937x-specific functions. The lan937x bindings don't have any 'interrupts' property so this lan937x_mdio_register() doesn't call ksz_irq_phy_setup(). Expose the common ksz_*_mdio_{read/write} functions so they can be used in lan937x.c Remove the callbacks from ksz_dev_ops. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-9-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 30 ++----- drivers/net/dsa/microchip/ksz_common.h | 42 ++-------- drivers/net/dsa/microchip/lan937x_main.c | 100 ++++++++++++++++++++++- 3 files changed, 111 insertions(+), 61 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 7dc8e4ffacdd..d08659ffa442 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2256,7 +2256,7 @@ static void ksz_update_port_member(struct ksz_device *dev, int port) dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port); } -static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) +int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) { struct ksz_device *dev = bus->priv; struct dsa_switch *ds = dev->ds; @@ -2264,8 +2264,7 @@ static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) return ds->ops->phy_read(ds, addr, regnum); } -static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, - u16 val) +int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) { struct ksz_device *dev = bus->priv; struct dsa_switch *ds = dev->ds; @@ -2286,7 +2285,7 @@ static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, * * Return: Value of the PHY register, or a negative error code on failure. */ -static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum) +int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum) { struct ksz_device *dev = bus->priv; @@ -2306,8 +2305,7 @@ static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum) * * Return: 0 on success, or a negative error code on failure. */ -static int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, - u16 val) +int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) { struct ksz_device *dev = bus->priv; @@ -2415,8 +2413,8 @@ static void ksz_irq_phy_free(struct ksz_device *dev) * * Return: 0 on success, or a negative error code on failure. */ -static int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus, - struct device_node *mdio_np) +int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus, + struct device_node *mdio_np) { struct device_node *phy_node, *phy_parent_node; bool phys_are_valid = true; @@ -2519,20 +2517,8 @@ int ksz_mdio_register(struct ksz_device *dev) goto put_mdio_node; } - if (dev->dev_ops->mdio_bus_preinit) { - ret = dev->dev_ops->mdio_bus_preinit(dev, !!parent_bus); - if (ret) - goto put_mdio_node; - } - - if (dev->dev_ops->create_phy_addr_map) { - ret = dev->dev_ops->create_phy_addr_map(dev, !!parent_bus); - if (ret) - goto put_mdio_node; - } else { - for (i = 0; i < dev->info->port_cnt; i++) - dev->phy_addr_map[i] = i; - } + for (i = 0; i < dev->info->port_cnt; i++) + dev->phy_addr_map[i] = i; bus->priv = dev; if (parent_bus) { diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index bdc93f2855c7..0c10cd5775bc 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -366,42 +366,6 @@ struct ksz_dev_ops { u32 (*get_port_addr)(int port, int offset); void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member); - /** - * @mdio_bus_preinit: Function pointer to pre-initialize the MDIO bus - * for accessing PHYs. - * @dev: Pointer to device structure. - * @side_mdio: Boolean indicating if the PHYs are accessed over a side - * MDIO bus. - * - * This function pointer is used to configure the MDIO bus for PHY - * access before initiating regular PHY operations. It enables either - * SPI/I2C or side MDIO access modes by unlocking necessary registers - * and setting up access permissions for the selected mode. - * - * Return: - * - 0 on success. - * - Negative error code on failure. - */ - int (*mdio_bus_preinit)(struct ksz_device *dev, bool side_mdio); - - /** - * @create_phy_addr_map: Function pointer to create a port-to-PHY - * address map. - * @dev: Pointer to device structure. - * @side_mdio: Boolean indicating if the PHYs are accessed over a side - * MDIO bus. - * - * This function pointer is responsible for mapping switch ports to PHY - * addresses according to the configured access mode (SPI or side MDIO) - * and the device’s strap configuration. The mapping setup may vary - * depending on the chip variant and configuration. Ensures the correct - * address mapping for PHY communication. - * - * Return: - * - 0 on success. - * - Negative error code on failure (e.g., invalid configuration). - */ - int (*create_phy_addr_map)(struct ksz_device *dev, bool side_mdio); void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr, u64 *cnt); void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr, @@ -498,6 +462,12 @@ int ksz_port_set_mac_address(struct dsa_switch *ds, int port, int ksz_suspend(struct dsa_switch *ds); int ksz_resume(struct dsa_switch *ds); +int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus, + struct device_node *mdio_np); +int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum); +int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val); +int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum); +int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val); int ksz_mdio_register(struct ksz_device *dev); int ksz_pirq_setup(struct ksz_device *dev, u8 p); int ksz_girq_setup(struct ksz_device *dev); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index d45798de4ce9..48cd367455c3 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -669,6 +670,101 @@ static int lan937x_switch_init(struct ksz_device *dev) return 0; } +/** + * lan937x_mdio_register - Register and configure the MDIO bus for the LAN937x. + * @dev: Pointer to the KSZ device structure. + * + * This function sets up and registers an MDIO bus for a LAN937x switch, + * allowing access to its internal PHYs. If the device supports side MDIO, + * the function will configure the external MDIO controller specified by the + * "mdio-parent-bus" device tree property to directly manage internal PHYs. + * Otherwise, SPI or I2C access is set up for PHY access. + * + * Return: 0 on success, or a negative error code on failure. + */ +static int lan937x_mdio_register(struct ksz_device *dev) +{ + struct device_node *parent_bus_node; + struct mii_bus *parent_bus = NULL; + struct dsa_switch *ds = dev->ds; + struct device_node *mdio_np; + struct mii_bus *bus; + int ret; + + mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio"); + if (!mdio_np) + return 0; + + parent_bus_node = of_parse_phandle(mdio_np, "mdio-parent-bus", 0); + if (parent_bus_node && !dev->info->phy_side_mdio_supported) { + dev_err(dev->dev, "Side MDIO bus is not supported for this HW, ignoring 'mdio-parent-bus' property.\n"); + ret = -EINVAL; + + goto put_mdio_node; + } else if (parent_bus_node) { + parent_bus = of_mdio_find_bus(parent_bus_node); + if (!parent_bus) { + ret = -EPROBE_DEFER; + + goto put_mdio_node; + } + + dev->parent_mdio_bus = parent_bus; + } + + bus = devm_mdiobus_alloc(ds->dev); + if (!bus) { + ret = -ENOMEM; + goto put_mdio_node; + } + + ret = lan937x_mdio_bus_preinit(dev, !!parent_bus); + if (ret) + goto put_mdio_node; + + ret = lan937x_create_phy_addr_map(dev, !!parent_bus); + if (ret) + goto put_mdio_node; + + bus->priv = dev; + if (parent_bus) { + bus->read = ksz_parent_mdio_read; + bus->write = ksz_parent_mdio_write; + bus->name = "KSZ side MDIO"; + snprintf(bus->id, MII_BUS_ID_SIZE, "ksz-side-mdio-%d", + ds->index); + } else { + bus->read = ksz_sw_mdio_read; + bus->write = ksz_sw_mdio_write; + bus->name = "ksz user smi"; + if (ds->dst->index != 0) + snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d-%d", + ds->dst->index, ds->index); + else + snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); + } + + ret = ksz_parse_dt_phy_config(dev, bus, mdio_np); + if (ret) + goto put_mdio_node; + + ds->phys_mii_mask = bus->phy_mask; + bus->parent = ds->dev; + + ds->user_mii_bus = bus; + + ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); + if (ret) + dev_err(ds->dev, "unable to register MDIO bus %s\n", + bus->id); + +put_mdio_node: + of_node_put(mdio_np); + of_node_put(parent_bus_node); + + return ret; +} + static int lan937x_setup(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -782,7 +878,7 @@ static int lan937x_setup(struct dsa_switch *ds) goto port_release; } - ret = ksz_mdio_register(dev); + ret = lan937x_mdio_register(dev); if (ret < 0) { dev_err(dev->dev, "failed to register the mdio"); goto out_ptp_clock_unregister; @@ -845,8 +941,6 @@ const struct phylink_mac_ops lan937x_phylink_mac_ops = { const struct ksz_dev_ops lan937x_dev_ops = { .get_port_addr = ksz9477_get_port_addr, .cfg_port_member = ksz9477_cfg_port_member, - .mdio_bus_preinit = lan937x_mdio_bus_preinit, - .create_phy_addr_map = lan937x_create_phy_addr_map, .r_mib_cnt = ksz9477_r_mib_cnt, .r_mib_pkt = ksz9477_r_mib_pkt, .r_mib_stat64 = ksz_r_mib_stats64, From af472a40b276f986ff41d9e40b4c5e4de0ea5ba3 Mon Sep 17 00:00:00 2001 From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 8 Jun 2026 16:10:13 +0200 Subject: [PATCH 10/10] net: dsa: microchip: implement port_teardown only if needed The port_teardown() operation is optional. Yet, it is implemented by all the KSZ switches through a common function that doesn't do anything for the switches that aren't part of the ksz9477 family Remove the implementation from the switches that don't need it. Implement instead a ksz9477-specific port_teardown. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-10-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8.c | 3 --- drivers/net/dsa/microchip/ksz9477.c | 10 +++++++++- drivers/net/dsa/microchip/ksz_common.c | 19 ------------------- drivers/net/dsa/microchip/ksz_common.h | 1 - drivers/net/dsa/microchip/lan937x_main.c | 1 - 5 files changed, 9 insertions(+), 25 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index 3a7e96403ed2..138f2ab0774e 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -2539,7 +2539,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = { .port_bridge_leave = ksz_port_bridge_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, - .port_teardown = ksz_port_teardown, .port_pre_bridge_flags = ksz_port_pre_bridge_flags, .port_bridge_flags = ksz_port_bridge_flags, .port_fast_age = ksz8_flush_dyn_mac_table, @@ -2587,7 +2586,6 @@ const struct dsa_switch_ops ksz87xx_switch_ops = { .port_bridge_leave = ksz_port_bridge_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, - .port_teardown = ksz_port_teardown, .port_pre_bridge_flags = ksz_port_pre_bridge_flags, .port_bridge_flags = ksz_port_bridge_flags, .port_fast_age = ksz8_flush_dyn_mac_table, @@ -2639,7 +2637,6 @@ const struct dsa_switch_ops ksz88xx_switch_ops = { .port_bridge_leave = ksz_port_bridge_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, - .port_teardown = ksz_port_teardown, .port_pre_bridge_flags = ksz_port_pre_bridge_flags, .port_bridge_flags = ksz_port_bridge_flags, .port_fast_age = ksz8_flush_dyn_mac_table, diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 48813b0f4280..f3f0c98dfb5a 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1941,6 +1941,14 @@ static void ksz9477_duplex_flowctrl(struct ksz_device *dev, int port, int duplex ksz_prmw8(dev, port, regs[P_XMII_CTRL_0], mask, val); } +static void ksz9477_port_teardown(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + + if (dsa_is_user_port(ds, port)) + ksz9477_port_acl_free(dev, port); +} + void ksz9477_phylink_mac_link_up(struct phylink_config *config, struct phy_device *phydev, unsigned int mode, @@ -2073,7 +2081,7 @@ const struct dsa_switch_ops ksz9477_switch_ops = { .port_hsr_leave = ksz9477_hsr_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, - .port_teardown = ksz_port_teardown, + .port_teardown = ksz9477_port_teardown, .port_pre_bridge_flags = ksz_port_pre_bridge_flags, .port_bridge_flags = ksz_port_bridge_flags, .port_fast_age = ksz9477_flush_dyn_mac_table, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index d08659ffa442..d1726778bb48 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2953,25 +2953,6 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) ksz_update_port_member(dev, port); } -void ksz_port_teardown(struct dsa_switch *ds, int port) -{ - struct ksz_device *dev = ds->priv; - - switch (dev->chip_id) { - case KSZ8563_CHIP_ID: - case KSZ8567_CHIP_ID: - case KSZ9477_CHIP_ID: - case KSZ9563_CHIP_ID: - case KSZ9567_CHIP_ID: - case KSZ9893_CHIP_ID: - case KSZ9896_CHIP_ID: - case KSZ9897_CHIP_ID: - case LAN9646_CHIP_ID: - if (dsa_is_user_port(ds, port)) - ksz9477_port_acl_free(dev, port); - } -} - int ksz_port_pre_bridge_flags(struct dsa_switch *ds, int port, struct switchdev_brport_flags flags, struct netlink_ext_ack *extack) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 0c10cd5775bc..b4a5673ba365 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -391,7 +391,6 @@ int ksz_switch_suspend(struct device *dev); int ksz_switch_resume(struct device *dev); void ksz_teardown(struct dsa_switch *ds); -void ksz_port_teardown(struct dsa_switch *ds, int port); void ksz_init_mib_timer(struct ksz_device *dev); bool ksz_is_port_mac_global_usable(struct dsa_switch *ds, int port); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 48cd367455c3..8eb5337b0c10 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -967,7 +967,6 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_bridge_leave = ksz_port_bridge_leave, .port_set_mac_address = ksz_port_set_mac_address, .port_stp_state_set = ksz_port_stp_state_set, - .port_teardown = ksz_port_teardown, .port_pre_bridge_flags = ksz_port_pre_bridge_flags, .port_bridge_flags = ksz_port_bridge_flags, .port_fast_age = ksz9477_flush_dyn_mac_table,