diff --git a/target/linux/generic/pending-6.12/760-00-net-dsa-mxl862xx-cancel-pending-work-on-probe-error.patch b/target/linux/generic/pending-6.12/760-00-net-dsa-mxl862xx-cancel-pending-work-on-probe-error.patch new file mode 100644 index 0000000000..d215cbbb8d --- /dev/null +++ b/target/linux/generic/pending-6.12/760-00-net-dsa-mxl862xx-cancel-pending-work-on-probe-error.patch @@ -0,0 +1,37 @@ +From 3fd163f5bb88de426ca9847549f94b4296170ef0 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 30 Mar 2026 23:40:53 +0100 +Subject: [PATCH] net: dsa: mxl862xx: cancel pending work on probe error + +Call mxl862xx_host_shutdown() in case dsa_register_switch() returns +an error, so any still pending crc_err_work get canceled. + +Fixes: a319d0c8c8ced ("net: dsa: mxl862xx: add CRC for MDIO communication)" +Signed-off-by: Daniel Golle +--- + drivers/net/dsa/mxl862xx/mxl862xx.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/net/dsa/mxl862xx/mxl862xx.c ++++ b/drivers/net/dsa/mxl862xx/mxl862xx.c +@@ -407,6 +407,7 @@ static int mxl862xx_probe(struct mdio_de + struct device *dev = &mdiodev->dev; + struct mxl862xx_priv *priv; + struct dsa_switch *ds; ++ int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -428,7 +429,11 @@ static int mxl862xx_probe(struct mdio_de + + dev_set_drvdata(dev, ds); + +- return dsa_register_switch(ds); ++ err = dsa_register_switch(ds); ++ if (err) ++ mxl862xx_host_shutdown(priv); ++ ++ return err; + } + + static void mxl862xx_remove(struct mdio_device *mdiodev) diff --git a/target/linux/generic/pending-6.12/760-01-net-dsa-move-dsa_bridge_ports-helper-to-dsa.h.patch b/target/linux/generic/pending-6.12/760-01-net-dsa-move-dsa_bridge_ports-helper-to-dsa.h.patch index 843ca14b64..c203174a8a 100644 --- a/target/linux/generic/pending-6.12/760-01-net-dsa-move-dsa_bridge_ports-helper-to-dsa.h.patch +++ b/target/linux/generic/pending-6.12/760-01-net-dsa-move-dsa_bridge_ports-helper-to-dsa.h.patch @@ -1,7 +1,7 @@ -From de6dd19a3edd1dc6400fecf77610e438441a02ac Mon Sep 17 00:00:00 2001 +From cd698f1ae94c16499e2714b31dd6048e6f9f068d Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 17:54:11 +0000 -Subject: [PATCH 10/35] net: dsa: move dsa_bridge_ports() helper to dsa.h +Subject: [PATCH 01/26] net: dsa: move dsa_bridge_ports() helper to dsa.h The yt921x driver contains a helper to create a bitmap of ports which are members of a bridge. diff --git a/target/linux/generic/pending-6.12/760-02-net-dsa-add-bridge-member-iteration-macro.patch b/target/linux/generic/pending-6.12/760-02-net-dsa-add-bridge-member-iteration-macro.patch index af90028b98..67dc948461 100644 --- a/target/linux/generic/pending-6.12/760-02-net-dsa-add-bridge-member-iteration-macro.patch +++ b/target/linux/generic/pending-6.12/760-02-net-dsa-add-bridge-member-iteration-macro.patch @@ -1,7 +1,7 @@ -From 880cde7abf58cb1316382ae7f59aac93c313e8fe Mon Sep 17 00:00:00 2001 +From c161533e1605a7282563c139323a3913890fdb72 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 17:54:41 +0000 -Subject: [PATCH 11/35] net: dsa: add bridge member iteration macro +Subject: [PATCH 02/26] net: dsa: add bridge member iteration macro Drivers that offload bridges need to iterate over the ports that are members of a given bridge, for example to rebuild per-port forwarding diff --git a/target/linux/generic/pending-6.12/760-03-dsa-tag_mxl862xx-set-dsa_default_offload_fwd_mark.patch b/target/linux/generic/pending-6.12/760-03-dsa-tag_mxl862xx-set-dsa_default_offload_fwd_mark.patch index 7c824994aa..e47f4e44c8 100644 --- a/target/linux/generic/pending-6.12/760-03-dsa-tag_mxl862xx-set-dsa_default_offload_fwd_mark.patch +++ b/target/linux/generic/pending-6.12/760-03-dsa-tag_mxl862xx-set-dsa_default_offload_fwd_mark.patch @@ -1,7 +1,7 @@ -From 149bb02d5bf031a1eb85f91377f54913de3a08ff Mon Sep 17 00:00:00 2001 +From 753efe27a9afee52c4ad42098a9b9278366d63cc Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 17:54:52 +0000 -Subject: [PATCH 12/35] dsa: tag_mxl862xx: set dsa_default_offload_fwd_mark() +Subject: [PATCH 03/26] dsa: tag_mxl862xx: set dsa_default_offload_fwd_mark() The MxL862xx offloads bridge forwarding in hardware, so set dsa_default_offload_fwd_mark() to avoid duplicate forwarding of diff --git a/target/linux/generic/pending-6.12/760-04-net-dsa-mxl862xx-implement-bridge-offloading.patch b/target/linux/generic/pending-6.12/760-04-net-dsa-mxl862xx-implement-bridge-offloading.patch index 9d1c1c958b..a545e70677 100644 --- a/target/linux/generic/pending-6.12/760-04-net-dsa-mxl862xx-implement-bridge-offloading.patch +++ b/target/linux/generic/pending-6.12/760-04-net-dsa-mxl862xx-implement-bridge-offloading.patch @@ -1,7 +1,7 @@ -From 5acdee6df2fbd4a9b02045694227f25cb1d4e5e0 Mon Sep 17 00:00:00 2001 +From ce0664ff8f75c3ab01101c3f0f8569924d948775 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 17:55:08 +0000 -Subject: [PATCH 13/35] net: dsa: mxl862xx: implement bridge offloading +Subject: [PATCH 04/26] net: dsa: mxl862xx: implement bridge offloading Implement joining and leaving bridges as well as add, delete and dump operations on isolated FDBs, port MDB membership management, and @@ -39,9 +39,9 @@ Signed-off-by: Daniel Golle --- drivers/net/dsa/mxl862xx/mxl862xx-api.h | 225 ++++++- drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 20 +- - drivers/net/dsa/mxl862xx/mxl862xx.c | 752 ++++++++++++++++++++++-- + drivers/net/dsa/mxl862xx/mxl862xx.c | 743 ++++++++++++++++++++++-- drivers/net/dsa/mxl862xx/mxl862xx.h | 133 +++++ - 4 files changed, 1087 insertions(+), 43 deletions(-) + 4 files changed, 1076 insertions(+), 45 deletions(-) --- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h @@ -384,7 +384,7 @@ Signed-off-by: Daniel Golle static enum dsa_tag_protocol mxl862xx_get_tag_protocol(struct dsa_switch *ds, int port, enum dsa_tag_protocol m) -@@ -168,6 +182,225 @@ static int mxl862xx_setup_mdio(struct ds +@@ -168,6 +182,213 @@ static int mxl862xx_setup_mdio(struct ds return ret; } @@ -535,18 +535,6 @@ Signed-off-by: Daniel Golle + return ret; +} + -+/** -+ * mxl862xx_allocate_bridge - Allocate a firmware bridge instance -+ * @priv: driver private data -+ * @bridge_id: output -- firmware bridge ID assigned by the firmware -+ * -+ * Newly allocated bridges default to flooding all traffic classes -+ * (unknown unicast, multicast, broadcast). Callers that need -+ * different forwarding behavior must call mxl862xx_bridge_config_fwd() -+ * after allocation. -+ * -+ * Return: 0 on success, negative errno on failure. -+ */ +static int mxl862xx_allocate_bridge(struct mxl862xx_priv *priv, u16 *bridge_id) +{ + struct mxl862xx_bridge_alloc br_alloc = {}; @@ -610,7 +598,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_setup(struct dsa_switch *ds) { struct mxl862xx_priv *priv = ds->priv; -@@ -181,6 +414,10 @@ static int mxl862xx_setup(struct dsa_swi +@@ -181,6 +402,10 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; @@ -621,7 +609,7 @@ Signed-off-by: Daniel Golle return mxl862xx_setup_mdio(ds); } -@@ -260,66 +497,87 @@ static int mxl862xx_configure_sp_tag_pro +@@ -260,66 +485,87 @@ static int mxl862xx_configure_sp_tag_pro static int mxl862xx_setup_cpu_bridge(struct dsa_switch *ds, int port) { @@ -744,7 +732,7 @@ Signed-off-by: Daniel Golle struct dsa_port *dp = dsa_to_port(ds, port); bool is_cpu_port = dsa_port_is_cpu(dp); int ret; -@@ -352,7 +610,31 @@ static int mxl862xx_port_setup(struct ds +@@ -352,7 +598,31 @@ static int mxl862xx_port_setup(struct ds return mxl862xx_setup_cpu_bridge(ds, port); /* setup single-port bridge for user ports */ @@ -777,7 +765,7 @@ Signed-off-by: Daniel Golle } static void mxl862xx_phylink_get_caps(struct dsa_switch *ds, int port, -@@ -365,14 +647,385 @@ static void mxl862xx_phylink_get_caps(st +@@ -365,14 +635,383 @@ static void mxl862xx_phylink_get_caps(st config->supported_interfaces); } @@ -942,7 +930,7 @@ Signed-off-by: Daniel Golle + mxl862xx_fw_portmap_clear_bit(qparam.port_map, port); + + if (mxl862xx_fw_portmap_is_empty(qparam.port_map)) { -+ /* No ports left — remove the entry entirely */ ++ /* No ports left -- remove the entry entirely */ + rparam.fid = cpu_to_le16(fid); + rparam.tci = cpu_to_le16(FIELD_PREP(MXL862XX_TCI_VLAN_ID, mdb->vid)); + ether_addr_copy(rparam.mac, mdb->addr); @@ -1033,7 +1021,7 @@ Signed-off-by: Daniel Golle +/* Deferred work handler for host flood configuration. + * + * port_set_host_flood is called from atomic context (under -+ * netif_addr_lock), so firmware calls must be deferred. The worker ++ * netif_addr_lock), so firmware calls must be deferred. The worker + * acquires rtnl_lock() to serialize with DSA callbacks that access the + * same driver state. + */ @@ -1058,9 +1046,9 @@ Signed-off-by: Daniel Golle + mc = p->host_flood_mc; + + /* The hardware controls unknown-unicast/multicast forwarding per FID -+ * (bridge), not per source port. For bridged ports all members share ++ * (bridge), not per source port. For bridged ports all members share + * one FID, so we cannot selectively suppress flooding to the CPU for -+ * one source port while allowing it for another. Silently ignore the ++ * one source port while allowing it for another. Silently ignore the + * request -- the excess flooding towards the CPU is harmless. + */ + if (!dsa_port_bridge_dev_get(dsa_to_port(ds, port))) @@ -1098,7 +1086,6 @@ Signed-off-by: Daniel Golle + struct mxl862xx_priv *priv = ds->priv; + unsigned long old_block = priv->ports[port].flood_block; + unsigned long block = old_block; -+ bool need_update = false; + int ret; + + if (flags.mask & BR_FLOOD) { @@ -1128,8 +1115,7 @@ Signed-off-by: Daniel Golle + if (flags.mask & BR_LEARNING) + priv->ports[port].learning = !!(flags.val & BR_LEARNING); + -+ need_update = (block != old_block) || (flags.mask & BR_LEARNING); -+ if (need_update) { ++ if ((block != old_block) || (flags.mask & BR_LEARNING)) { + priv->ports[port].flood_block = block; + ret = mxl862xx_set_bridge_port(ds, port); + if (ret) @@ -1163,15 +1149,16 @@ Signed-off-by: Daniel Golle }; static void mxl862xx_phylink_mac_config(struct phylink_config *config, -@@ -407,6 +1060,7 @@ static int mxl862xx_probe(struct mdio_de +@@ -407,7 +1046,7 @@ static int mxl862xx_probe(struct mdio_de struct device *dev = &mdiodev->dev; struct mxl862xx_priv *priv; struct dsa_switch *ds; -+ int i; +- int err; ++ int err, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) -@@ -424,8 +1078,17 @@ static int mxl862xx_probe(struct mdio_de +@@ -425,14 +1064,25 @@ static int mxl862xx_probe(struct mdio_de ds->ops = &mxl862xx_switch_ops; ds->phylink_mac_ops = &mxl862xx_phylink_mac_ops; ds->num_ports = MXL862XX_MAX_PORTS; @@ -1188,8 +1175,18 @@ Signed-off-by: Daniel Golle + dev_set_drvdata(dev, ds); - return dsa_register_switch(ds); -@@ -435,6 +1098,7 @@ static void mxl862xx_remove(struct mdio_ + err = dsa_register_switch(ds); +- if (err) ++ if (err) { + mxl862xx_host_shutdown(priv); +- ++ for (i = 0; i < MXL862XX_MAX_PORTS; i++) ++ cancel_work_sync(&priv->ports[i].host_flood_work); ++ } + return err; + } + +@@ -440,6 +1090,7 @@ static void mxl862xx_remove(struct mdio_ { struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); struct mxl862xx_priv *priv; @@ -1197,14 +1194,14 @@ Signed-off-by: Daniel Golle if (!ds) return; -@@ -444,12 +1108,21 @@ static void mxl862xx_remove(struct mdio_ +@@ -449,12 +1100,21 @@ static void mxl862xx_remove(struct mdio_ dsa_unregister_switch(ds); mxl862xx_host_shutdown(priv); + -+ /* Cancel any pending host flood work. dsa_unregister_switch() ++ /* Cancel any pending host flood work. dsa_unregister_switch() + * has already called port_teardown (which sets setup_done=false), -+ * but a worker could still be blocked on rtnl_lock(). Since we ++ * but a worker could still be blocked on rtnl_lock(). Since we + * are now outside RTNL, cancel_work_sync() will not deadlock. + */ + for (i = 0; i < MXL862XX_MAX_PORTS; i++) @@ -1219,7 +1216,7 @@ Signed-off-by: Daniel Golle if (!ds) return; -@@ -460,6 +1133,9 @@ static void mxl862xx_shutdown(struct mdi +@@ -465,6 +1125,9 @@ static void mxl862xx_shutdown(struct mdi mxl862xx_host_shutdown(priv); diff --git a/target/linux/generic/pending-6.12/760-05-net-dsa-mxl862xx-implement-VLAN-functionality.patch b/target/linux/generic/pending-6.12/760-05-net-dsa-mxl862xx-implement-VLAN-functionality.patch index 109808792c..c9e1769d98 100644 --- a/target/linux/generic/pending-6.12/760-05-net-dsa-mxl862xx-implement-VLAN-functionality.patch +++ b/target/linux/generic/pending-6.12/760-05-net-dsa-mxl862xx-implement-VLAN-functionality.patch @@ -1,7 +1,7 @@ -From 7286ac4f850339aac37dd52633f4a70816b621a8 Mon Sep 17 00:00:00 2001 +From 0d88d02cc9dccad01ff88f54e1beee867107b942 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 10 Mar 2026 02:36:00 +0000 -Subject: [PATCH 14/35] net: dsa: mxl862xx: implement VLAN functionality +Subject: [PATCH 05/26] net: dsa: mxl862xx: implement VLAN functionality Add VLAN support using both the Extended VLAN (EVLAN) engine and the VLAN Filter (VF) engine in a hybrid architecture that allows a higher @@ -35,11 +35,11 @@ VLAN Filter blocks across ports with identical VID sets. Signed-off-by: Daniel Golle --- - drivers/net/dsa/mxl862xx/mxl862xx-api.h | 329 ++++++++ + drivers/net/dsa/mxl862xx/mxl862xx-api.h | 329 +++++++++ drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 12 + - drivers/net/dsa/mxl862xx/mxl862xx.c | 960 +++++++++++++++++++++++- - drivers/net/dsa/mxl862xx/mxl862xx.h | 110 ++- - 4 files changed, 1386 insertions(+), 25 deletions(-) + drivers/net/dsa/mxl862xx/mxl862xx.c | 915 +++++++++++++++++++++++- + drivers/net/dsa/mxl862xx/mxl862xx.h | 104 ++- + 4 files changed, 1344 insertions(+), 16 deletions(-) --- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h @@ -577,7 +577,7 @@ Signed-off-by: Daniel Golle mxl862xx_fw_portmap_from_bitmap(br_port_cfg.bridge_port_map, p->portmap); for (i = 0; i < ARRAY_SIZE(mxl862xx_flood_meters); i++) { -@@ -329,13 +472,131 @@ static int mxl862xx_sync_bridge_members( +@@ -329,6 +472,91 @@ static int mxl862xx_sync_bridge_members( return ret; } @@ -609,11 +609,6 @@ Signed-off-by: Daniel Golle + return 0; +} + -+/** -+ * mxl862xx_vf_init - Initialize per-port VF block software state -+ * @vf: VLAN Filter block to initialize -+ * @size: block size (entries per port) -+ */ +static void mxl862xx_vf_init(struct mxl862xx_vf_block *vf, u16 size) +{ + vf->allocated = false; @@ -623,15 +618,6 @@ Signed-off-by: Daniel Golle + INIT_LIST_HEAD(&vf->vids); +} + -+/** -+ * mxl862xx_vf_block_alloc - Allocate a VLAN Filter block from firmware -+ * @priv: driver private data -+ * @size: number of entries to allocate -+ * @block_id: output -- block ID assigned by firmware -+ * -+ * Allocates a contiguous VLAN Filter block and configures it to discard -+ * unmatched tagged frames (VID membership enforcement). -+ */ +static int mxl862xx_vf_block_alloc(struct mxl862xx_priv *priv, + u16 size, u16 *block_id) +{ @@ -650,15 +636,6 @@ Signed-off-by: Daniel Golle + return 0; +} + -+/** -+ * mxl862xx_vf_entry_discard - Write a DISCARD entry to plug an unused slot -+ * @priv: driver private data -+ * @block_id: HW VLAN Filter block ID -+ * @index: entry index within the block -+ * -+ * Unwritten VLAN Filter entries default to VID=0 / ALLOW which would -+ * leak VID 0 traffic. This writes a DISCARD entry to plug the slot. -+ */ +static int mxl862xx_vf_entry_discard(struct mxl862xx_priv *priv, + u16 block_id, u16 index) +{ @@ -673,16 +650,6 @@ Signed-off-by: Daniel Golle + return MXL862XX_API_WRITE(priv, MXL862XX_VLANFILTER_SET, cfg); +} + -+/** -+ * mxl862xx_vf_alloc - Allocate the port's VF HW block -+ * @priv: driver private data -+ * @vf: VLAN Filter block (must have been initialized via mxl862xx_vf_init) -+ * -+ * Allocates the block and writes a DISCARD sentinel at index 0 so that -+ * when active_count is 0, the single-entry scan window blocks VID-0 -+ * (which would otherwise match the zeroed-out default and be allowed). -+ * Called once per port from port_setup. -+ */ +static int mxl862xx_vf_alloc(struct mxl862xx_priv *priv, + struct mxl862xx_vf_block *vf) +{ @@ -699,18 +666,10 @@ Signed-off-by: Daniel Golle + return mxl862xx_vf_entry_discard(priv, vf->block_id, 0); +} + - /** - * mxl862xx_allocate_bridge - Allocate a firmware bridge instance - * @priv: driver private data - * @bridge_id: output -- firmware bridge ID assigned by the firmware - * - * Newly allocated bridges default to flooding all traffic classes -- * (unknown unicast, multicast, broadcast). Callers that need -+ * (unknown unicast, multicast, broadcast). Callers that need - * different forwarding behavior must call mxl862xx_bridge_config_fwd() - * after allocation. - * -@@ -404,6 +665,9 @@ static int mxl862xx_add_single_port_brid + static int mxl862xx_allocate_bridge(struct mxl862xx_priv *priv, u16 *bridge_id) + { + struct mxl862xx_bridge_alloc br_alloc = {}; +@@ -392,6 +620,9 @@ static int mxl862xx_add_single_port_brid static int mxl862xx_setup(struct dsa_switch *ds) { struct mxl862xx_priv *priv = ds->priv; @@ -720,7 +679,7 @@ Signed-off-by: Daniel Golle int ret; ret = mxl862xx_reset(priv); -@@ -414,6 +678,50 @@ static int mxl862xx_setup(struct dsa_swi +@@ -402,6 +633,50 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; @@ -771,7 +730,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_setup_drop_meter(ds); if (ret) return ret; -@@ -495,27 +803,616 @@ static int mxl862xx_configure_sp_tag_pro +@@ -483,27 +758,616 @@ static int mxl862xx_configure_sp_tag_pro return MXL862XX_API_WRITE(ds->priv, MXL862XX_SS_SPTAG_SET, tag); } @@ -1392,7 +1351,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port, const struct dsa_bridge bridge, bool *tx_fwd_offload, -@@ -565,6 +1462,22 @@ static void mxl862xx_port_bridge_leave(s +@@ -553,6 +1417,22 @@ static void mxl862xx_port_bridge_leave(s bitmap_zero(p->portmap, MXL862XX_MAX_BRIDGE_PORTS); __set_bit(dp->cpu_dp->index, p->portmap); p->flood_block = 0; @@ -1415,7 +1374,7 @@ Signed-off-by: Daniel Golle err = mxl862xx_set_bridge_port(ds, port); if (err) dev_err(ds->dev, -@@ -614,6 +1527,28 @@ static int mxl862xx_port_setup(struct ds +@@ -602,6 +1482,28 @@ static int mxl862xx_port_setup(struct ds if (ret) return ret; @@ -1444,37 +1403,7 @@ Signed-off-by: Daniel Golle priv->ports[port].setup_done = true; return 0; -@@ -808,7 +1743,7 @@ static int mxl862xx_port_mdb_del(struct - mxl862xx_fw_portmap_clear_bit(qparam.port_map, port); - - if (mxl862xx_fw_portmap_is_empty(qparam.port_map)) { -- /* No ports left — remove the entry entirely */ -+ /* No ports left -- remove the entry entirely */ - rparam.fid = cpu_to_le16(fid); - rparam.tci = cpu_to_le16(FIELD_PREP(MXL862XX_TCI_VLAN_ID, mdb->vid)); - ether_addr_copy(rparam.mac, mdb->addr); -@@ -899,7 +1834,7 @@ static void mxl862xx_port_stp_state_set( - /* Deferred work handler for host flood configuration. - * - * port_set_host_flood is called from atomic context (under -- * netif_addr_lock), so firmware calls must be deferred. The worker -+ * netif_addr_lock), so firmware calls must be deferred. The worker - * acquires rtnl_lock() to serialize with DSA callbacks that access the - * same driver state. - */ -@@ -924,9 +1859,9 @@ static void mxl862xx_host_flood_work_fn( - mc = p->host_flood_mc; - - /* The hardware controls unknown-unicast/multicast forwarding per FID -- * (bridge), not per source port. For bridged ports all members share -+ * (bridge), not per source port. For bridged ports all members share - * one FID, so we cannot selectively suppress flooding to the CPU for -- * one source port while allowing it for another. Silently ignore the -+ * one source port while allowing it for another. Silently ignore the - * request -- the excess flooding towards the CPU is harmless. - */ - if (!dsa_port_bridge_dev_get(dsa_to_port(ds, port))) -@@ -1026,6 +1961,9 @@ static const struct dsa_switch_ops mxl86 +@@ -1012,6 +1914,9 @@ static const struct dsa_switch_ops mxl86 .port_fdb_dump = mxl862xx_port_fdb_dump, .port_mdb_add = mxl862xx_port_mdb_add, .port_mdb_del = mxl862xx_port_mdb_del, @@ -1484,15 +1413,6 @@ Signed-off-by: Daniel Golle }; static void mxl862xx_phylink_mac_config(struct phylink_config *config, -@@ -1111,7 +2049,7 @@ static void mxl862xx_remove(struct mdio_ - - /* Cancel any pending host flood work. dsa_unregister_switch() - * has already called port_teardown (which sets setup_done=false), -- * but a worker could still be blocked on rtnl_lock(). Since we -+ * but a worker could still be blocked on rtnl_lock(). Since we - * are now outside RTNL, cancel_work_sync() will not deadlock. - */ - for (i = 0; i < MXL862XX_MAX_PORTS; i++) --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h @@ -13,6 +13,8 @@ struct mxl862xx_priv; @@ -1504,7 +1424,7 @@ Signed-off-by: Daniel Golle /* Number of __le16 words in a firmware portmap (128-bit bitmap). */ #define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16) -@@ -86,12 +88,72 @@ static inline bool mxl862xx_fw_portmap_i +@@ -86,6 +88,66 @@ static inline bool mxl862xx_fw_portmap_i } /** @@ -1571,15 +1491,6 @@ Signed-off-by: Daniel Golle * struct mxl862xx_port - per-port state tracked by the driver * @priv: back-pointer to switch private data; needed by * deferred work handlers to access ds and priv -- * @fid: firmware FID for the permanent single-port bridge; -- * kept alive for the lifetime of the port so traffic is -- * never forwarded while the port is unbridged -+ * @fid: firmware FID for the permanent single-port bridge; kept -+ * alive for the lifetime of the port so traffic is never -+ * forwarded while the port is unbridged - * @portmap: bitmap of switch port indices that share the current - * bridge with this port - * @flood_block: bitmask of firmware meter indices that are currently @@ -101,6 +163,11 @@ static inline bool mxl862xx_fw_portmap_i * @setup_done: set at end of port_setup, cleared at start of * port_teardown; guards deferred work against diff --git a/target/linux/generic/pending-6.12/760-06-net-dsa-mxl862xx-add-ethtool-statistics-support.patch b/target/linux/generic/pending-6.12/760-06-net-dsa-mxl862xx-add-ethtool-statistics-support.patch index a1517ccde0..9788fb4021 100644 --- a/target/linux/generic/pending-6.12/760-06-net-dsa-mxl862xx-add-ethtool-statistics-support.patch +++ b/target/linux/generic/pending-6.12/760-06-net-dsa-mxl862xx-add-ethtool-statistics-support.patch @@ -1,7 +1,7 @@ -From 03b583e774835f771dd7c3c265be5903f008e8e5 Mon Sep 17 00:00:00 2001 +From 0067d79d10becfc5779fb50d5c0ac152cc5dc303 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 22 Mar 2026 00:57:33 +0000 -Subject: [PATCH 15/35] net: dsa: mxl862xx: add ethtool statistics support +Subject: [PATCH 06/26] net: dsa: mxl862xx: add ethtool statistics support The MxL862xx firmware exposes per-port RMON counters through the RMON_PORT_GET command, covering standard IEEE 802.3 MAC statistics @@ -257,7 +257,7 @@ Signed-off-by: Daniel Golle #define MXL862XX_SDMA_PCTRLP(p) (0xbc0 + ((p) * 0x6)) #define MXL862XX_SDMA_PCTRL_EN BIT(0) -@@ -1940,6 +1998,110 @@ static int mxl862xx_port_bridge_flags(st +@@ -1893,6 +1951,110 @@ static int mxl862xx_port_bridge_flags(st return 0; } @@ -368,7 +368,7 @@ Signed-off-by: Daniel Golle static const struct dsa_switch_ops mxl862xx_switch_ops = { .get_tag_protocol = mxl862xx_get_tag_protocol, .setup = mxl862xx_setup, -@@ -1964,6 +2126,12 @@ static const struct dsa_switch_ops mxl86 +@@ -1917,6 +2079,12 @@ static const struct dsa_switch_ops mxl86 .port_vlan_filtering = mxl862xx_port_vlan_filtering, .port_vlan_add = mxl862xx_port_vlan_add, .port_vlan_del = mxl862xx_port_vlan_del, diff --git a/target/linux/generic/pending-6.12/760-07-net-dsa-mxl862xx-implement-.get_stats64.patch b/target/linux/generic/pending-6.12/760-07-net-dsa-mxl862xx-implement-.get_stats64.patch index 9d4d93bc2d..55b81a7023 100644 --- a/target/linux/generic/pending-6.12/760-07-net-dsa-mxl862xx-implement-.get_stats64.patch +++ b/target/linux/generic/pending-6.12/760-07-net-dsa-mxl862xx-implement-.get_stats64.patch @@ -1,7 +1,7 @@ -From 8b66d20f7e5226f4854a39cfb9f25a0591a5bb83 Mon Sep 17 00:00:00 2001 +From bab5a69e3872a693069e430a1fa0d2825ea83b4f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 04:14:38 +0000 -Subject: [PATCH 16/35] net: dsa: mxl862xx: implement .get_stats64 +Subject: [PATCH 07/26] net: dsa: mxl862xx: implement .get_stats64 Poll free-running firmware RMON counters every 2 seconds and accumulate deltas into 64-bit per-port statistics. 32-bit packet counters wrap @@ -11,10 +11,49 @@ that counters are always up to date when queried. Signed-off-by: Daniel Golle --- - drivers/net/dsa/mxl862xx/mxl862xx.c | 167 ++++++++++++++++++++++++++++ - drivers/net/dsa/mxl862xx/mxl862xx.h | 51 +++++++++ - 2 files changed, 218 insertions(+) + drivers/net/dsa/mxl862xx/mxl862xx-host.c | 8 +- + drivers/net/dsa/mxl862xx/mxl862xx.c | 174 +++++++++++++++++++++++ + drivers/net/dsa/mxl862xx/mxl862xx.h | 63 +++++++- + 3 files changed, 238 insertions(+), 7 deletions(-) +--- a/drivers/net/dsa/mxl862xx/mxl862xx-host.c ++++ b/drivers/net/dsa/mxl862xx/mxl862xx-host.c +@@ -48,7 +48,7 @@ static void mxl862xx_crc_err_work_fn(str + dev_close(dp->conduit); + rtnl_unlock(); + +- clear_bit(0, &priv->crc_err); ++ clear_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags); + } + + /* Firmware CRC error codes (outside normal Zephyr errno range). */ +@@ -247,7 +247,7 @@ static int mxl862xx_issue_cmd(struct mxl + + ret = mxl862xx_crc6_verify(ctrl_enc, len_enc, &fw_result); + if (ret) { +- if (!test_and_set_bit(0, &priv->crc_err)) ++ if (!test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags)) + schedule_work(&priv->crc_err_work); + return -EIO; + } +@@ -314,7 +314,7 @@ static int mxl862xx_send_cmd(struct mxl8 + if (ret < 0) { + if ((ret == MXL862XX_FW_CRC6_ERR || + ret == MXL862XX_FW_CRC16_ERR) && +- !test_and_set_bit(0, &priv->crc_err)) ++ !test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags)) + schedule_work(&priv->crc_err_work); + if (!quiet) + dev_err(&priv->mdiodev->dev, +@@ -458,7 +458,7 @@ int mxl862xx_api_wrap(struct mxl862xx_pr + } + + if (crc16(0xffff, (const u8 *)data, size) != crc) { +- if (!test_and_set_bit(0, &priv->crc_err)) ++ if (!test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags)) + schedule_work(&priv->crc_err_work); + ret = -EIO; + goto out; --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c @@ -30,6 +30,12 @@ @@ -30,7 +69,7 @@ Signed-off-by: Daniel Golle struct mxl862xx_mib_desc { unsigned int size; unsigned int offset; -@@ -784,6 +790,9 @@ static int mxl862xx_setup(struct dsa_swi +@@ -739,6 +745,9 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; @@ -40,7 +79,7 @@ Signed-off-by: Daniel Golle return mxl862xx_setup_mdio(ds); } -@@ -2102,6 +2111,156 @@ static void mxl862xx_get_pause_stats(str +@@ -2055,6 +2064,158 @@ static void mxl862xx_get_pause_stats(str pause_stats->rx_pause_frames = le32_to_cpu(cnt.rx_good_pause_pkts); } @@ -160,8 +199,9 @@ Signed-off-by: Daniel Golle + dsa_switch_for_each_available_port(dp, ds) + mxl862xx_stats_poll(ds, dp->index); + -+ schedule_delayed_work(&priv->stats_work, -+ MXL862XX_STATS_POLL_INTERVAL); ++ if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags)) ++ schedule_delayed_work(&priv->stats_work, ++ MXL862XX_STATS_POLL_INTERVAL); +} + +static void mxl862xx_get_stats64(struct dsa_switch *ds, int port, @@ -189,15 +229,16 @@ Signed-off-by: Daniel Golle + spin_unlock_bh(&priv->ports[port].stats_lock); + + /* Trigger a fresh poll so the next read sees up-to-date counters. -+ * No-op if the work is already pending or running. ++ * No-op if the work is already pending, running, or teardown started. + */ -+ schedule_delayed_work(&priv->stats_work, 0); ++ if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags)) ++ schedule_delayed_work(&priv->stats_work, 0); +} + static const struct dsa_switch_ops mxl862xx_switch_ops = { .get_tag_protocol = mxl862xx_get_tag_protocol, .setup = mxl862xx_setup, -@@ -2132,6 +2291,7 @@ static const struct dsa_switch_ops mxl86 +@@ -2085,6 +2246,7 @@ static const struct dsa_switch_ops mxl86 .get_eth_mac_stats = mxl862xx_get_eth_mac_stats, .get_eth_ctrl_stats = mxl862xx_get_eth_ctrl_stats, .get_pause_stats = mxl862xx_get_pause_stats, @@ -205,7 +246,7 @@ Signed-off-by: Daniel Golle }; static void mxl862xx_phylink_mac_config(struct phylink_config *config, -@@ -2193,8 +2353,11 @@ static int mxl862xx_probe(struct mdio_de +@@ -2146,16 +2308,22 @@ static int mxl862xx_probe(struct mdio_de priv->ports[i].priv = priv; INIT_WORK(&priv->ports[i].host_flood_work, mxl862xx_host_flood_work_fn); @@ -216,20 +257,33 @@ Signed-off-by: Daniel Golle + dev_set_drvdata(dev, ds); - return dsa_register_switch(ds); -@@ -2213,6 +2376,8 @@ static void mxl862xx_remove(struct mdio_ + err = dsa_register_switch(ds); + if (err) { ++ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); ++ cancel_delayed_work_sync(&priv->stats_work); + mxl862xx_host_shutdown(priv); + for (i = 0; i < MXL862XX_MAX_PORTS; i++) + cancel_work_sync(&priv->ports[i].host_flood_work); + } ++ + return err; + } - dsa_unregister_switch(ds); +@@ -2170,6 +2338,9 @@ static void mxl862xx_remove(struct mdio_ + priv = ds->priv; + ++ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); + cancel_delayed_work_sync(&priv->stats_work); + - mxl862xx_host_shutdown(priv); + dsa_unregister_switch(ds); - /* Cancel any pending host flood work. dsa_unregister_switch() -@@ -2237,6 +2402,8 @@ static void mxl862xx_shutdown(struct mdi + mxl862xx_host_shutdown(priv); +@@ -2196,6 +2367,9 @@ static void mxl862xx_shutdown(struct mdi dsa_switch_shutdown(ds); ++ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); + cancel_delayed_work_sync(&priv->stats_work); + mxl862xx_host_shutdown(priv); @@ -296,7 +350,7 @@ Signed-off-by: Daniel Golle */ struct mxl862xx_port { struct mxl862xx_priv *priv; -@@ -195,6 +240,9 @@ struct mxl862xx_port { +@@ -195,16 +240,25 @@ struct mxl862xx_port { bool host_flood_uc; bool host_flood_mc; struct work_struct host_flood_work; @@ -305,8 +359,26 @@ Signed-off-by: Daniel Golle + spinlock_t stats_lock; }; ++/* Bit indices for struct mxl862xx_priv::flags */ ++#define MXL862XX_FLAG_CRC_ERR 0 ++#define MXL862XX_FLAG_WORK_STOPPED 1 ++ /** -@@ -216,6 +264,8 @@ struct mxl862xx_port { + * struct mxl862xx_priv - driver private data for an MxL862xx switch + * @ds: pointer to the DSA switch instance + * @mdiodev: MDIO device used to communicate with the switch firmware + * @crc_err_work: deferred work for shutting down all ports on MDIO CRC + * errors +- * @crc_err: set atomically before CRC-triggered shutdown, cleared +- * after ++ * @flags: atomic status flags; %MXL862XX_FLAG_CRC_ERR is set ++ * before CRC-triggered shutdown and cleared after; ++ * %MXL862XX_FLAG_WORK_STOPPED is set before cancelling ++ * stats_work to prevent rescheduling during teardown + * @drop_meter: index of the single shared zero-rate firmware meter + * used to unconditionally drop traffic (used to block + * flooding) +@@ -216,18 +270,21 @@ struct mxl862xx_port { * @evlan_ingress_size: per-port ingress Extended VLAN block size * @evlan_egress_size: per-port egress Extended VLAN block size * @vf_block_size: per-port VLAN Filter block size @@ -315,7 +387,13 @@ Signed-off-by: Daniel Golle */ struct mxl862xx_priv { struct dsa_switch *ds; -@@ -228,6 +278,7 @@ struct mxl862xx_priv { + struct mdio_device *mdiodev; + struct work_struct crc_err_work; +- unsigned long crc_err; ++ unsigned long flags; + u16 drop_meter; + struct mxl862xx_port ports[MXL862XX_MAX_PORTS]; + u16 bridges[MXL862XX_MAX_BRIDGES + 1]; u16 evlan_ingress_size; u16 evlan_egress_size; u16 vf_block_size; diff --git a/target/linux/generic/pending-6.12/760-08-net-dsa-mxl862xx-store-firmware-version-for-feature-.patch b/target/linux/generic/pending-6.12/760-08-net-dsa-mxl862xx-store-firmware-version-for-feature-.patch index d62b466029..03aeb8c9b7 100644 --- a/target/linux/generic/pending-6.12/760-08-net-dsa-mxl862xx-store-firmware-version-for-feature-.patch +++ b/target/linux/generic/pending-6.12/760-08-net-dsa-mxl862xx-store-firmware-version-for-feature-.patch @@ -1,7 +1,7 @@ -From fecfbea928cd762b19ff17aa16fb1ab143d73db1 Mon Sep 17 00:00:00 2001 +From da12469e73282da814163125153f381823e33f20 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 17:56:35 +0000 -Subject: [PATCH 17/35] net: dsa: mxl862xx: store firmware version for feature +Subject: [PATCH 08/26] net: dsa: mxl862xx: store firmware version for feature gating Query the firmware version at init (already done in wait_ready), @@ -40,10 +40,11 @@ Signed-off-by: Daniel Golle #include #include #include -@@ -246,6 +247,38 @@ struct mxl862xx_port { +@@ -245,6 +246,38 @@ struct mxl862xx_port { + spinlock_t stats_lock; }; - /** ++/** + * union mxl862xx_fw_version - firmware version for comparison and display + * @major: firmware major version + * @minor: firmware minor version @@ -75,11 +76,10 @@ Signed-off-by: Daniel Golle +#define MXL862XX_FW_VER_MIN(priv, maj, min, rev) \ + ((priv)->fw_version.raw >= MXL862XX_FW_VER(maj, min, rev)) + -+/** - * struct mxl862xx_priv - driver private data for an MxL862xx switch - * @ds: pointer to the DSA switch instance - * @mdiodev: MDIO device used to communicate with the switch firmware -@@ -256,6 +289,8 @@ struct mxl862xx_port { + /* Bit indices for struct mxl862xx_priv::flags */ + #define MXL862XX_FLAG_CRC_ERR 0 + #define MXL862XX_FLAG_WORK_STOPPED 1 +@@ -262,6 +295,8 @@ struct mxl862xx_port { * @drop_meter: index of the single shared zero-rate firmware meter * used to unconditionally drop traffic (used to block * flooding) @@ -88,9 +88,9 @@ Signed-off-by: Daniel Golle * @ports: per-port state, indexed by switch port number * @bridges: maps DSA bridge number to firmware bridge ID; * zero means no firmware bridge allocated for that -@@ -273,6 +308,7 @@ struct mxl862xx_priv { +@@ -279,6 +314,7 @@ struct mxl862xx_priv { struct work_struct crc_err_work; - unsigned long crc_err; + unsigned long flags; u16 drop_meter; + union mxl862xx_fw_version fw_version; struct mxl862xx_port ports[MXL862XX_MAX_PORTS]; diff --git a/target/linux/generic/pending-6.12/760-09-net-dsa-mxl862xx-move-phylink-stubs-to-mxl862xx-phyl.patch b/target/linux/generic/pending-6.12/760-09-net-dsa-mxl862xx-move-phylink-stubs-to-mxl862xx-phyl.patch index 833ec0642e..2ce4d1fb0e 100644 --- a/target/linux/generic/pending-6.12/760-09-net-dsa-mxl862xx-move-phylink-stubs-to-mxl862xx-phyl.patch +++ b/target/linux/generic/pending-6.12/760-09-net-dsa-mxl862xx-move-phylink-stubs-to-mxl862xx-phyl.patch @@ -1,7 +1,7 @@ -From 3cb224514226928df80e43ca2280c7dca654bdfe Mon Sep 17 00:00:00 2001 +From f7606470d398e4091e1bc405bf2125dc5fc99919 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 21:39:30 +0000 -Subject: [PATCH 18/35] net: dsa: mxl862xx: move phylink stubs to +Subject: [PATCH 09/26] net: dsa: mxl862xx: move phylink stubs to mxl862xx-phylink.c Move the phylink MAC operations and get_caps callback from mxl862xx.c @@ -110,7 +110,7 @@ Signed-off-by: Daniel Golle #define MXL862XX_API_WRITE(dev, cmd, data) \ mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), false, false) -@@ -1642,16 +1643,6 @@ static void mxl862xx_port_teardown(struc +@@ -1597,16 +1598,6 @@ static void mxl862xx_port_teardown(struc priv->ports[port].setup_done = false; } @@ -127,7 +127,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_get_fid(struct dsa_switch *ds, struct dsa_db db) { struct mxl862xx_priv *priv = ds->priv; -@@ -2297,33 +2288,6 @@ static const struct dsa_switch_ops mxl86 +@@ -2252,33 +2243,6 @@ static const struct dsa_switch_ops mxl86 .get_stats64 = mxl862xx_get_stats64, }; diff --git a/target/linux/generic/pending-6.12/760-10-net-dsa-mxl862xx-move-API-macros-to-mxl862xx-host.h.patch b/target/linux/generic/pending-6.12/760-10-net-dsa-mxl862xx-move-API-macros-to-mxl862xx-host.h.patch index 01013eec3e..7ac42cb3a6 100644 --- a/target/linux/generic/pending-6.12/760-10-net-dsa-mxl862xx-move-API-macros-to-mxl862xx-host.h.patch +++ b/target/linux/generic/pending-6.12/760-10-net-dsa-mxl862xx-move-API-macros-to-mxl862xx-host.h.patch @@ -1,7 +1,7 @@ -From de41d438c4e90876449715a307dd03fa37338742 Mon Sep 17 00:00:00 2001 +From e583eeeb907f0abeef2082162293a5d63b9fd6fa Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 26 Mar 2026 01:50:00 +0000 -Subject: [PATCH 19/35] net: dsa: mxl862xx: move API macros to mxl862xx-host.h +Subject: [PATCH 10/26] net: dsa: mxl862xx: move API macros to mxl862xx-host.h Move the MXL862XX_API_WRITE, MXL862XX_API_READ and MXL862XX_API_READ_QUIET convenience macros from mxl862xx.c to diff --git a/target/linux/generic/pending-6.12/760-11-net-dsa-mxl862xx-add-support-for-SerDes-ports.patch b/target/linux/generic/pending-6.12/760-11-net-dsa-mxl862xx-add-support-for-SerDes-ports.patch index 790f50c87d..6fe50aeb90 100644 --- a/target/linux/generic/pending-6.12/760-11-net-dsa-mxl862xx-add-support-for-SerDes-ports.patch +++ b/target/linux/generic/pending-6.12/760-11-net-dsa-mxl862xx-add-support-for-SerDes-ports.patch @@ -1,7 +1,7 @@ -From 88f46eb32d1aed296af2005c3ed8f23a6eea64c3 Mon Sep 17 00:00:00 2001 +From e25f0886853607e4a6d1157ae84e43e8224cf3b7 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 22 Mar 2026 00:57:44 +0000 -Subject: [PATCH 20/35] net: dsa: mxl862xx: add support for SerDes ports +Subject: [PATCH 11/26] net: dsa: mxl862xx: add support for SerDes ports The MxL862xx has two XPCS/SerDes interfaces (XPCS0 for ports 9-12, XPCS1 for ports 13-16). Each can operate in various single-lane @@ -990,7 +990,7 @@ Signed-off-by: Daniel Golle #endif /* __MXL862XX_PHYLINK_H */ --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -729,7 +729,7 @@ static int mxl862xx_setup(struct dsa_swi +@@ -684,7 +684,7 @@ static int mxl862xx_setup(struct dsa_swi int n_user_ports = 0, max_vlans; int ingress_finals, vid_rules; struct dsa_port *dp; @@ -999,7 +999,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_reset(priv); if (ret) -@@ -739,6 +739,9 @@ static int mxl862xx_setup(struct dsa_swi +@@ -694,6 +694,9 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; @@ -1034,7 +1034,7 @@ Signed-off-by: Daniel Golle * union mxl862xx_fw_version - firmware version for comparison and display * @major: firmware major version * @minor: firmware minor version -@@ -291,6 +307,8 @@ union mxl862xx_fw_version { +@@ -297,6 +313,8 @@ union mxl862xx_fw_version { * flooding) * @fw_version: cached firmware version, populated at probe and * compared with MXL862XX_FW_VER_MIN() @@ -1043,8 +1043,8 @@ Signed-off-by: Daniel Golle * @ports: per-port state, indexed by switch port number * @bridges: maps DSA bridge number to firmware bridge ID; * zero means no firmware bridge allocated for that -@@ -309,6 +327,7 @@ struct mxl862xx_priv { - unsigned long crc_err; +@@ -315,6 +333,7 @@ struct mxl862xx_priv { + unsigned long flags; u16 drop_meter; union mxl862xx_fw_version fw_version; + struct mxl862xx_pcs serdes_ports[8]; diff --git a/target/linux/generic/pending-6.12/760-12-net-dsa-mxl862xx-add-SerDes-ethtool-statistics.patch b/target/linux/generic/pending-6.12/760-12-net-dsa-mxl862xx-add-SerDes-ethtool-statistics.patch index 5f1e1bb3e5..749a1ee2a6 100644 --- a/target/linux/generic/pending-6.12/760-12-net-dsa-mxl862xx-add-SerDes-ethtool-statistics.patch +++ b/target/linux/generic/pending-6.12/760-12-net-dsa-mxl862xx-add-SerDes-ethtool-statistics.patch @@ -1,7 +1,7 @@ -From d40565e2e00fc2c8f04b9c571fcbea2f146db844 Mon Sep 17 00:00:00 2001 +From 24d752291784e30d7329bed15744bbbc6a3e2485 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:14:33 +0000 -Subject: [PATCH 21/35] net: dsa: mxl862xx: add SerDes ethtool statistics +Subject: [PATCH 12/26] net: dsa: mxl862xx: add SerDes ethtool statistics Expose SerDes equalization and signal detect parameters as ethtool statistics on ports 9-16 (XPCS-backed ports). Uses the XPCS EQ_GET @@ -239,7 +239,7 @@ Signed-off-by: Daniel Golle #endif /* __MXL862XX_PHYLINK_H */ --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -2007,6 +2007,8 @@ static void mxl862xx_get_strings(struct +@@ -1960,6 +1960,8 @@ static void mxl862xx_get_strings(struct for (i = 0; i < ARRAY_SIZE(mxl862xx_mib); i++) ethtool_puts(&data, mxl862xx_mib[i].name); @@ -248,7 +248,7 @@ Signed-off-by: Daniel Golle } static int mxl862xx_get_sset_count(struct dsa_switch *ds, int port, int sset) -@@ -2014,7 +2016,7 @@ static int mxl862xx_get_sset_count(struc +@@ -1967,7 +1969,7 @@ static int mxl862xx_get_sset_count(struc if (sset != ETH_SS_STATS) return 0; @@ -257,7 +257,7 @@ Signed-off-by: Daniel Golle } static int mxl862xx_read_rmon(struct dsa_switch *ds, int port, -@@ -2050,6 +2052,8 @@ static void mxl862xx_get_ethtool_stats(s +@@ -2003,6 +2005,8 @@ static void mxl862xx_get_ethtool_stats(s else *data++ = le64_to_cpu(*(__le64 *)field); } diff --git a/target/linux/generic/pending-6.12/760-13-net-dsa-mxl862xx-add-SerDes-self-test-via-PRBS-and-B.patch b/target/linux/generic/pending-6.12/760-13-net-dsa-mxl862xx-add-SerDes-self-test-via-PRBS-and-B.patch index 1da11ae9c0..baba8311c6 100644 --- a/target/linux/generic/pending-6.12/760-13-net-dsa-mxl862xx-add-SerDes-self-test-via-PRBS-and-B.patch +++ b/target/linux/generic/pending-6.12/760-13-net-dsa-mxl862xx-add-SerDes-self-test-via-PRBS-and-B.patch @@ -1,7 +1,7 @@ -From 54dd5fabc543f8538202367a863eb0e9161bacab Mon Sep 17 00:00:00 2001 +From ee227a5e4c74f599cc1b34578b32214d5873ad2f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:15:32 +0000 -Subject: [PATCH 22/35] net: dsa: mxl862xx: add SerDes self-test via PRBS and +Subject: [PATCH 13/26] net: dsa: mxl862xx: add SerDes self-test via PRBS and BERT Implement the dsa_switch_ops.self_test callback for SerDes ports @@ -198,7 +198,7 @@ Signed-off-by: Daniel Golle #endif /* __MXL862XX_PHYLINK_H */ --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -2286,6 +2286,7 @@ static const struct dsa_switch_ops mxl86 +@@ -2241,6 +2241,7 @@ static const struct dsa_switch_ops mxl86 .get_eth_ctrl_stats = mxl862xx_get_eth_ctrl_stats, .get_pause_stats = mxl862xx_get_pause_stats, .get_stats64 = mxl862xx_get_stats64, diff --git a/target/linux/generic/pending-6.12/760-14-net-dsa-mxl862xx-trap-link-local-frames-to-the-CPU-p.patch b/target/linux/generic/pending-6.12/760-14-net-dsa-mxl862xx-trap-link-local-frames-to-the-CPU-p.patch index 385e44f480..56d3612310 100644 --- a/target/linux/generic/pending-6.12/760-14-net-dsa-mxl862xx-trap-link-local-frames-to-the-CPU-p.patch +++ b/target/linux/generic/pending-6.12/760-14-net-dsa-mxl862xx-trap-link-local-frames-to-the-CPU-p.patch @@ -1,7 +1,7 @@ -From dd62e68cd0bd29934c3efbce687d5e103cc4b331 Mon Sep 17 00:00:00 2001 +From 43eb3eed250ea4e7e83371fcbf2bfb8d626eade6 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:51:13 +0000 -Subject: [PATCH 23/35] net: dsa: mxl862xx: trap link-local frames to the CPU +Subject: [PATCH 14/26] net: dsa: mxl862xx: trap link-local frames to the CPU port Install per-CTP PCE rules on each user port that trap IEEE 802.1D @@ -817,7 +817,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port) { struct mxl862xx_bridge_port_config br_port_cfg = {}; -@@ -1594,6 +1658,11 @@ static int mxl862xx_port_setup(struct ds +@@ -1549,6 +1613,11 @@ static int mxl862xx_port_setup(struct ds if (ret) return ret; diff --git a/target/linux/generic/pending-6.12/760-15-net-dsa-mxl862xx-warn-about-old-firmware-default-PCE.patch b/target/linux/generic/pending-6.12/760-15-net-dsa-mxl862xx-warn-about-old-firmware-default-PCE.patch index 38dc45c594..d590f54f47 100644 --- a/target/linux/generic/pending-6.12/760-15-net-dsa-mxl862xx-warn-about-old-firmware-default-PCE.patch +++ b/target/linux/generic/pending-6.12/760-15-net-dsa-mxl862xx-warn-about-old-firmware-default-PCE.patch @@ -1,7 +1,7 @@ -From 3bba25f7ba35e3bca8230bd37ffb612944dbf301 Mon Sep 17 00:00:00 2001 +From e18f5b235d8df21209c73f4f0bbc00cc3a1973ba Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:51:21 +0000 -Subject: [PATCH 24/35] net: dsa: mxl862xx: warn about old firmware default PCE +Subject: [PATCH 15/26] net: dsa: mxl862xx: warn about old firmware default PCE rules Firmware versions older than 1.0.80 install global PCE rules at @@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -854,6 +854,10 @@ static int mxl862xx_setup(struct dsa_swi +@@ -809,6 +809,10 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; diff --git a/target/linux/generic/pending-6.12/760-16-net-dsa-add-802.1Q-VLAN-based-tag-driver-for-MxL862x.patch b/target/linux/generic/pending-6.12/760-16-net-dsa-add-802.1Q-VLAN-based-tag-driver-for-MxL862x.patch index 8663883077..9b7a719db0 100644 --- a/target/linux/generic/pending-6.12/760-16-net-dsa-add-802.1Q-VLAN-based-tag-driver-for-MxL862x.patch +++ b/target/linux/generic/pending-6.12/760-16-net-dsa-add-802.1Q-VLAN-based-tag-driver-for-MxL862x.patch @@ -1,7 +1,7 @@ -From 1687c5632dfd80461b12425b943e30555faa3dd4 Mon Sep 17 00:00:00 2001 +From 04929904d3a7d824593587e52e3ed21d6f0f109a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 22 Mar 2026 00:58:04 +0000 -Subject: [PATCH 25/35] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx +Subject: [PATCH 16/26] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx The MxL862xx native 8-byte special tag (SpTag) requires firmware support on the switch CPU and is not compatible with all SoC Ethernet @@ -23,12 +23,12 @@ Signed-off-by: Daniel Golle drivers/net/dsa/mxl862xx/mxl862xx-api.h | 221 +++ drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 + drivers/net/dsa/mxl862xx/mxl862xx.c | 1626 ++++++++++++++++++++--- - drivers/net/dsa/mxl862xx/mxl862xx.h | 21 +- + drivers/net/dsa/mxl862xx/mxl862xx.h | 13 + include/net/dsa.h | 2 + net/dsa/Kconfig | 7 + net/dsa/Makefile | 1 + net/dsa/tag_mxl862xx_8021q.c | 59 + - 9 files changed, 1738 insertions(+), 202 deletions(-) + 9 files changed, 1736 insertions(+), 196 deletions(-) create mode 100644 net/dsa/tag_mxl862xx_8021q.c --- a/drivers/net/dsa/mxl862xx/Kconfig @@ -511,7 +511,7 @@ Signed-off-by: Daniel Golle err = mxl862xx_set_bridge_port(ds, port); if (err) -@@ -762,7 +909,6 @@ static void mxl862xx_free_bridge(struct +@@ -717,7 +864,6 @@ static void mxl862xx_free_bridge(struct static int mxl862xx_add_single_port_bridge(struct dsa_switch *ds, int port) { @@ -519,7 +519,7 @@ Signed-off-by: Daniel Golle struct mxl862xx_priv *priv = ds->priv; int ret; -@@ -774,15 +920,27 @@ static int mxl862xx_add_single_port_brid +@@ -729,15 +875,27 @@ static int mxl862xx_add_single_port_brid priv->ports[port].learning = false; bitmap_zero(priv->ports[port].portmap, MXL862XX_MAX_BRIDGE_PORTS); @@ -533,7 +533,6 @@ Signed-off-by: Daniel Golle - /* Standalone ports should not flood unknown unicast or multicast - * towards the CPU by default; only broadcast is needed initially. -- */ + /* In tag_8021q mode the TX path goes through the bridge engine + * (CTP ingress EVLAN reassigns to a virtual bridge port which + * then forwards via the bridge). With learning disabled on @@ -543,7 +542,7 @@ Signed-off-by: Daniel Golle + * In native SpTag mode, TX bypasses the bridge engine entirely + * (the special tag selects the egress port directly), so flood + * control only affects CPU-bound traffic and can be restrictive. -+ */ + */ + if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q) + return mxl862xx_bridge_config_fwd(ds, priv->ports[port].fid, + true, true, true); @@ -551,7 +550,7 @@ Signed-off-by: Daniel Golle return mxl862xx_bridge_config_fwd(ds, priv->ports[port].fid, false, false, true); } -@@ -790,10 +948,12 @@ static int mxl862xx_add_single_port_brid +@@ -745,10 +903,12 @@ static int mxl862xx_add_single_port_brid static int mxl862xx_setup(struct dsa_switch *ds) { struct mxl862xx_priv *priv = ds->priv; @@ -566,7 +565,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_reset(priv); if (ret) -@@ -806,7 +966,7 @@ static int mxl862xx_setup(struct dsa_swi +@@ -761,7 +921,7 @@ static int mxl862xx_setup(struct dsa_swi for (i = 0; i < 8; i++) mxl862xx_setup_pcs(priv, &priv->serdes_ports[i], i + 9); @@ -575,7 +574,7 @@ Signed-off-by: Daniel Golle * With VLAN Filter handling VID membership checks: * Ingress: only final catchall rules (PVID insertion, 802.1Q * accept, non-8021Q TPID handling, discard). -@@ -814,40 +974,67 @@ static int mxl862xx_setup(struct dsa_swi +@@ -769,40 +929,67 @@ static int mxl862xx_setup(struct dsa_swi * ingress EVLAN rules are needed. (7 entries.) * Egress: 2 rules per VID that needs tag stripping (untagged VIDs). * No egress final catchalls -- VLAN Filter does the discard. @@ -657,7 +656,7 @@ Signed-off-by: Daniel Golle } ret = mxl862xx_setup_drop_meter(ds); -@@ -858,6 +1045,68 @@ static int mxl862xx_setup(struct dsa_swi +@@ -813,6 +1000,68 @@ static int mxl862xx_setup(struct dsa_swi dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules " "that interfere with DSA operation, please update\n"); @@ -726,7 +725,7 @@ Signed-off-by: Daniel Golle schedule_delayed_work(&priv->stats_work, MXL862XX_STATS_POLL_INTERVAL); -@@ -939,6 +1188,52 @@ static int mxl862xx_configure_sp_tag_pro +@@ -894,6 +1143,52 @@ static int mxl862xx_configure_sp_tag_pro } /** @@ -779,7 +778,7 @@ Signed-off-by: Daniel Golle * mxl862xx_evlan_write_rule - Write a single Extended VLAN rule to hardware * @priv: driver private data * @block_id: HW Extended VLAN block ID -@@ -947,6 +1242,7 @@ static int mxl862xx_configure_sp_tag_pro +@@ -902,6 +1197,7 @@ static int mxl862xx_configure_sp_tag_pro * @vid: VLAN ID for VID-specific rules (ignored when !desc->match_vid) * @untagged: strip tag on egress for EVLAN_STRIP_IF_UNTAGGED action * @pvid: port VLAN ID for PVID insertion rules (0 = no PVID) @@ -787,7 +786,7 @@ Signed-off-by: Daniel Golle * * Translates a compact rule descriptor into a full firmware * mxl862xx_extendedvlan_config struct and writes it via the API. -@@ -954,7 +1250,8 @@ static int mxl862xx_configure_sp_tag_pro +@@ -909,7 +1205,8 @@ static int mxl862xx_configure_sp_tag_pro static int mxl862xx_evlan_write_rule(struct mxl862xx_priv *priv, u16 block_id, u16 entry_index, const struct mxl862xx_evlan_rule_desc *desc, @@ -797,7 +796,7 @@ Signed-off-by: Daniel Golle { struct mxl862xx_extendedvlan_config cfg = {}; struct mxl862xx_extendedvlan_filter_vlan *fv; -@@ -1044,6 +1341,31 @@ static int mxl862xx_evlan_write_rule(str +@@ -999,6 +1296,31 @@ static int mxl862xx_evlan_write_rule(str cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM); } break; @@ -829,7 +828,7 @@ Signed-off-by: Daniel Golle } return MXL862XX_API_WRITE(priv, MXL862XX_EXTENDEDVLAN_SET, cfg); -@@ -1104,7 +1426,7 @@ static int mxl862xx_evlan_write_final_ru +@@ -1059,7 +1381,7 @@ static int mxl862xx_evlan_write_final_ru for (i = 0; i < n_rules; i++) { ret = mxl862xx_evlan_write_rule(priv, blk->block_id, start_idx + i, &rules[i], @@ -838,7 +837,7 @@ Signed-off-by: Daniel Golle if (ret) return ret; } -@@ -1273,6 +1595,27 @@ static int mxl862xx_vf_del_vid(struct mx +@@ -1228,6 +1550,27 @@ static int mxl862xx_vf_del_vid(struct mx } /** @@ -866,7 +865,7 @@ Signed-off-by: Daniel Golle * mxl862xx_evlan_program_ingress - Write the fixed ingress catchall rules * @priv: driver private data * @port: port number -@@ -1323,8 +1666,8 @@ static int mxl862xx_evlan_program_egress +@@ -1278,8 +1621,8 @@ static int mxl862xx_evlan_program_egress const struct mxl862xx_evlan_rule_desc *vid_rules; struct mxl862xx_vf_vid *vfv; u16 old_active = blk->n_active; @@ -876,7 +875,7 @@ Signed-off-by: Daniel Golle if (p->vlan_filtering) { vid_rules = vid_accept_standard; -@@ -1341,13 +1684,23 @@ static int mxl862xx_evlan_program_egress +@@ -1296,13 +1639,23 @@ static int mxl862xx_evlan_program_egress if (p->vlan_filtering && !vfv->untagged) continue; @@ -901,7 +900,7 @@ Signed-off-by: Daniel Golle if (ret) return ret; -@@ -1356,7 +1709,29 @@ static int mxl862xx_evlan_program_egress +@@ -1311,7 +1664,29 @@ static int mxl862xx_evlan_program_egress idx++, &vid_rules[1], vfv->vid, vfv->untagged, @@ -932,7 +931,7 @@ Signed-off-by: Daniel Golle if (ret) return ret; } -@@ -1368,8 +1743,7 @@ static int mxl862xx_evlan_program_egress +@@ -1323,8 +1698,7 @@ static int mxl862xx_evlan_program_egress */ for (i = idx; i < old_active; i++) { ret = mxl862xx_evlan_deactivate_entry(priv, @@ -942,7 +941,7 @@ Signed-off-by: Daniel Golle if (ret) return ret; } -@@ -1393,13 +1767,16 @@ static int mxl862xx_port_vlan_filtering( +@@ -1348,13 +1722,16 @@ static int mxl862xx_port_vlan_filtering( /* Reprogram Extended VLAN rules if filtering mode changed */ if (changed) { @@ -964,7 +963,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_evlan_program_ingress(priv, port); if (ret) -@@ -1536,18 +1913,19 @@ static int mxl862xx_setup_cpu_bridge(str +@@ -1491,18 +1868,19 @@ static int mxl862xx_setup_cpu_bridge(str /* include all assigned user ports in the CPU portmap */ bitmap_zero(p->portmap, MXL862XX_MAX_BRIDGE_PORTS); @@ -990,7 +989,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port, const struct dsa_bridge bridge, bool *tx_fwd_offload, -@@ -1580,7 +1958,6 @@ static int mxl862xx_port_bridge_join(str +@@ -1535,7 +1913,6 @@ static int mxl862xx_port_bridge_join(str static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port, const struct dsa_bridge bridge) { @@ -998,7 +997,7 @@ Signed-off-by: Daniel Golle struct mxl862xx_priv *priv = ds->priv; struct mxl862xx_port *p = &priv->ports[port]; int err; -@@ -1595,34 +1972,587 @@ static void mxl862xx_port_bridge_leave(s +@@ -1550,34 +1927,587 @@ static void mxl862xx_port_bridge_leave(s * single-port bridge */ bitmap_zero(p->portmap, MXL862XX_MAX_BRIDGE_PORTS); @@ -1010,14 +1009,14 @@ Signed-off-by: Daniel Golle - /* Detach EVLAN and VF blocks from the bridge port BEFORE freeing - * them. The firmware tracks a usage count per block and rejects - * FREE while the count is non-zero. +- * +- * For EVLAN: setting in_use=false makes set_bridge_port send +- * enable=false, which decrements the firmware refcount. + /* Reset VLAN state for standalone mode. Ingress EVLAN is not + * needed outside a VLAN-aware bridge. Egress EVLAN is + * reprogrammed below -- in tag_8021q mode it gets the + * management VID strip catchalls, in SpTag mode it is cleared. * -- * For EVLAN: setting in_use=false makes set_bridge_port send -- * enable=false, which decrements the firmware refcount. -- * - * For VF: set_bridge_port sees dp->bridge == NULL (DSA already - * cleared it) and sends vlan_filter_enable=0, which decrements - * the firmware VF refcount. @@ -1597,7 +1596,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_port_setup(struct dsa_switch *ds, int port) { struct mxl862xx_priv *priv = ds->priv; -@@ -1642,55 +2572,30 @@ static int mxl862xx_port_setup(struct ds +@@ -1597,55 +2527,30 @@ static int mxl862xx_port_setup(struct ds dsa_port_is_dsa(dp)) return 0; @@ -1660,7 +1659,7 @@ Signed-off-by: Daniel Golle return 0; } -@@ -1712,7 +2617,7 @@ static void mxl862xx_port_teardown(struc +@@ -1667,7 +2572,7 @@ static void mxl862xx_port_teardown(struc priv->ports[port].setup_done = false; } @@ -1669,7 +1668,7 @@ Signed-off-by: Daniel Golle { struct mxl862xx_priv *priv = ds->priv; -@@ -1730,23 +2635,244 @@ static int mxl862xx_get_fid(struct dsa_s +@@ -1685,23 +2590,244 @@ static int mxl862xx_get_fid(struct dsa_s } } @@ -1702,7 +1701,8 @@ Signed-off-by: Daniel Golle + if (dsa_is_cpu_port(ds, port) && priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && + db.type == DSA_DB_PORT) { + bp_cpu = priv->ports[db.dp->index].bridge_port_cpu; -+ + +- param.port_id = cpu_to_le32(port); + if (bp_cpu) + return bp_cpu; + } @@ -1719,8 +1719,7 @@ Signed-off-by: Daniel Golle +{ + struct mxl862xx_mac_table_add param = {}; + struct mxl862xx_priv *priv = ds->priv; - -- param.port_id = cpu_to_le32(port); ++ + param.port_id = cpu_to_le32(port_id); param.static_entry = true; param.fid = cpu_to_le16(fid); @@ -1922,7 +1921,7 @@ Signed-off-by: Daniel Golle if (ret) dev_err(ds->dev, "failed to add FDB entry on port %d\n", port); -@@ -1756,18 +2882,25 @@ static int mxl862xx_port_fdb_add(struct +@@ -1711,18 +2837,25 @@ static int mxl862xx_port_fdb_add(struct static int mxl862xx_port_fdb_del(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid, const struct dsa_db db) { @@ -1955,7 +1954,7 @@ Signed-off-by: Daniel Golle if (ret) dev_err(ds->dev, "failed to remove FDB entry on port %d\n", port); -@@ -1806,88 +2939,147 @@ static int mxl862xx_port_fdb_dump(struct +@@ -1761,88 +2894,147 @@ static int mxl862xx_port_fdb_dump(struct return 0; } @@ -2097,7 +2096,7 @@ Signed-off-by: Daniel Golle - int fid = mxl862xx_get_fid(ds, db), ret; struct mxl862xx_priv *priv = ds->priv; + int fid, ret; -+ + + /* tag_8021q host MDB for bridged ports: clear all VBP bits */ + if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && dsa_is_cpu_port(ds, port) && + db.type == DSA_DB_BRIDGE) { @@ -2107,7 +2106,7 @@ Signed-off-by: Daniel Golle + return mxl862xx_mac_del_host_bridge(ds, mdb->addr, + mdb->vid, &db.bridge); + } - ++ + fid = mxl862xx_get_fid(ds, db); if (fid < 0) return fid; @@ -2154,7 +2153,7 @@ Signed-off-by: Daniel Golle return ret; } -@@ -1975,7 +3167,9 @@ static void mxl862xx_host_flood_work_fn( +@@ -1930,7 +3122,9 @@ static void mxl862xx_host_flood_work_fn( struct mxl862xx_priv *priv = p->priv; struct dsa_switch *ds = priv->ds; int port = p - priv->ports; @@ -2164,7 +2163,7 @@ Signed-off-by: Daniel Golle rtnl_lock(); -@@ -1988,14 +3182,31 @@ static void mxl862xx_host_flood_work_fn( +@@ -1943,14 +3137,35 @@ static void mxl862xx_host_flood_work_fn( uc = p->host_flood_uc; mc = p->host_flood_mc; @@ -2195,8 +2194,12 @@ Signed-off-by: Daniel Golle + port, ERR_PTR(ret)); + } + } else { -+ /* SpTag mode: per-FID forwarding, only works for -+ * standalone ports (each has its own FID). ++ /* The hardware controls unknown-unicast/multicast forwarding ++ * per FID (bridge), not per source port. For bridged ports all ++ * members share one FID, so we cannot selectively suppress ++ * flooding to the CPU for one source port while allowing it ++ * for another. Silently ignore the request -- the excess ++ * flooding towards the CPU is harmless. + */ + if (!dsa_port_bridge_dev_get(dsa_to_port(ds, port))) + mxl862xx_bridge_config_fwd(ds, p->fid, uc, mc, true); @@ -2204,7 +2207,7 @@ Signed-off-by: Daniel Golle rtnl_unlock(); } -@@ -2330,7 +3541,9 @@ static void mxl862xx_get_stats64(struct +@@ -2285,7 +3500,9 @@ static void mxl862xx_get_stats64(struct static const struct dsa_switch_ops mxl862xx_switch_ops = { .get_tag_protocol = mxl862xx_get_tag_protocol, @@ -2214,7 +2217,7 @@ Signed-off-by: Daniel Golle .port_setup = mxl862xx_port_setup, .port_teardown = mxl862xx_port_teardown, .phylink_get_caps = mxl862xx_phylink_get_caps, -@@ -2352,6 +3565,8 @@ static const struct dsa_switch_ops mxl86 +@@ -2307,6 +3524,8 @@ static const struct dsa_switch_ops mxl86 .port_vlan_filtering = mxl862xx_port_vlan_filtering, .port_vlan_add = mxl862xx_port_vlan_add, .port_vlan_del = mxl862xx_port_vlan_del, @@ -2223,7 +2226,7 @@ Signed-off-by: Daniel Golle .get_strings = mxl862xx_get_strings, .get_sset_count = mxl862xx_get_sset_count, .get_ethtool_stats = mxl862xx_get_ethtool_stats, -@@ -2399,6 +3614,8 @@ static int mxl862xx_probe(struct mdio_de +@@ -2354,6 +3573,8 @@ static int mxl862xx_probe(struct mdio_de INIT_DELAYED_WORK(&priv->stats_work, mxl862xx_stats_work_fn); @@ -2231,10 +2234,10 @@ Signed-off-by: Daniel Golle + dev_set_drvdata(dev, ds); - return dsa_register_switch(ds); -@@ -2415,16 +3632,29 @@ static void mxl862xx_remove(struct mdio_ - - priv = ds->priv; + err = dsa_register_switch(ds); +@@ -2382,6 +3603,19 @@ static void mxl862xx_remove(struct mdio_ + set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); + cancel_delayed_work_sync(&priv->stats_work); + /* Tear down tag_8021q under RTNL before dsa_unregister_switch(). + * dsa_tag_8021q_unregister() calls vlan_vid_del() which needs @@ -2251,39 +2254,9 @@ Signed-off-by: Daniel Golle + dsa_unregister_switch(ds); - cancel_delayed_work_sync(&priv->stats_work); - mxl862xx_host_shutdown(priv); - -- /* Cancel any pending host flood work. dsa_unregister_switch() -+ /* Cancel any pending host flood work. dsa_unregister_switch() - * has already called port_teardown (which sets setup_done=false), - * but a worker could still be blocked on rtnl_lock(). Since we -- * are now outside RTNL, cancel_work_sync() will not deadlock. -+ * are now outside RTNL, cancel_work_sync() won't deadlock. - */ - for (i = 0; i < MXL862XX_MAX_PORTS; i++) - cancel_work_sync(&priv->ports[i].host_flood_work); --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h -@@ -8,8 +8,6 @@ - #include - #include - --struct mxl862xx_priv; -- - #define MXL862XX_MAX_PORTS 17 - #define MXL862XX_DEFAULT_BRIDGE 0 - #define MXL862XX_MAX_BRIDGES 48 -@@ -20,6 +18,8 @@ struct mxl862xx_priv; - /* Number of __le16 words in a firmware portmap (128-bit bitmap). */ - #define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16) - -+struct mxl862xx_priv; -+ - /** - * mxl862xx_fw_portmap_from_bitmap - convert a kernel bitmap to a firmware - * portmap (__le16[8]) @@ -210,6 +210,9 @@ struct mxl862xx_port_stats { * @vf: per-port VLAN Filter block state * @ingress_evlan: ingress extended VLAN block state @@ -2317,39 +2290,31 @@ Signed-off-by: Daniel Golle /* Hardware stats accumulation */ struct mxl862xx_port_stats stats; spinlock_t stats_lock; -@@ -302,6 +311,7 @@ union mxl862xx_fw_version { - * errors - * @crc_err: set atomically before CRC-triggered shutdown, cleared - * after +@@ -308,6 +317,7 @@ union mxl862xx_fw_version { + * before CRC-triggered shutdown and cleared after; + * %MXL862XX_FLAG_WORK_STOPPED is set before cancelling + * stats_work to prevent rescheduling during teardown + * @tag_proto: active DSA tag protocol (native or 8021q) * @drop_meter: index of the single shared zero-rate firmware meter * used to unconditionally drop traffic (used to block * flooding) -@@ -310,12 +320,13 @@ union mxl862xx_fw_version { - * @serdes_ports: SerDes interfaces incl. sub-interfaces in case of - * 10G_QXGMII - * @ports: per-port state, indexed by switch port number -+ * @evlan_ingress_size: per-port ingress Extended VLAN block size -+ * @evlan_egress_size: per-port egress Extended VLAN block size -+ * @cpu_evlan_ingress_size: CPU port ingress EVLAN block size (tag_8021q) - * @bridges: maps DSA bridge number to firmware bridge ID; - * zero means no firmware bridge allocated for that - * DSA bridge number. Indexed by dsa_bridge.num +@@ -322,6 +332,7 @@ union mxl862xx_fw_version { * (0 .. ds->max_num_bridges). -- * @evlan_ingress_size: per-port ingress Extended VLAN block size -- * @evlan_egress_size: per-port egress Extended VLAN block size + * @evlan_ingress_size: per-port ingress Extended VLAN block size + * @evlan_egress_size: per-port egress Extended VLAN block size ++ * @cpu_evlan_ingress_size: CPU port ingress EVLAN block size (tag_8021q) * @vf_block_size: per-port VLAN Filter block size * @stats_work: periodic work item that polls RMON hardware counters * and accumulates them into 64-bit per-port stats -@@ -325,6 +336,7 @@ struct mxl862xx_priv { +@@ -331,6 +342,7 @@ struct mxl862xx_priv { struct mdio_device *mdiodev; struct work_struct crc_err_work; - unsigned long crc_err; + unsigned long flags; + enum dsa_tag_protocol tag_proto; u16 drop_meter; union mxl862xx_fw_version fw_version; struct mxl862xx_pcs serdes_ports[8]; -@@ -332,6 +344,7 @@ struct mxl862xx_priv { +@@ -338,6 +350,7 @@ struct mxl862xx_priv { u16 bridges[MXL862XX_MAX_BRIDGES + 1]; u16 evlan_ingress_size; u16 evlan_egress_size; @@ -2359,16 +2324,15 @@ Signed-off-by: Daniel Golle }; --- a/include/net/dsa.h +++ b/include/net/dsa.h -@@ -56,6 +56,8 @@ struct tc_action; +@@ -56,6 +56,7 @@ struct tc_action; #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28 #define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29 #define DSA_TAG_PROTO_MXL862_VALUE 30 +#define DSA_TAG_PROTO_MXL862_8021Q_VALUE 31 -+ enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, -@@ -89,6 +91,7 @@ enum dsa_tag_protocol { +@@ -89,6 +90,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE, DSA_TAG_PROTO_VSC73XX_8021Q = DSA_TAG_PROTO_VSC73XX_8021Q_VALUE, DSA_TAG_PROTO_MXL862 = DSA_TAG_PROTO_MXL862_VALUE, diff --git a/target/linux/generic/pending-6.12/760-17-net-dsa-mxl862xx-add-link-aggregation-support.patch b/target/linux/generic/pending-6.12/760-17-net-dsa-mxl862xx-add-link-aggregation-support.patch index d373f6511f..0e4074254b 100644 --- a/target/linux/generic/pending-6.12/760-17-net-dsa-mxl862xx-add-link-aggregation-support.patch +++ b/target/linux/generic/pending-6.12/760-17-net-dsa-mxl862xx-add-link-aggregation-support.patch @@ -1,7 +1,7 @@ -From 31359e8b7673e656d0591a9eb5014b45911383ae Mon Sep 17 00:00:00 2001 +From 4e1d854199c166f617b93b7542e863e6a8ad2ccb Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 03:44:41 +0000 -Subject: [PATCH 26/35] net: dsa: mxl862xx: add link aggregation support +Subject: [PATCH 17/26] net: dsa: mxl862xx: add link aggregation support Implement LAG offloading via the firmware's trunking engine. A dedicated firmware bridge port is allocated per LAG and remains @@ -234,7 +234,7 @@ Signed-off-by: Daniel Golle return ret; } -@@ -1926,6 +2018,408 @@ static int mxl862xx_setup_cpu_bridge(str +@@ -1881,6 +1973,408 @@ static int mxl862xx_setup_cpu_bridge(str return mxl862xx_set_bridge_port(ds, port); } @@ -643,7 +643,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port, const struct dsa_bridge bridge, bool *tx_fwd_offload, -@@ -1952,7 +2446,18 @@ static int mxl862xx_port_bridge_join(str +@@ -1907,7 +2401,18 @@ static int mxl862xx_port_bridge_join(str return 0; } @@ -663,7 +663,7 @@ Signed-off-by: Daniel Golle } static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port, -@@ -2011,6 +2516,17 @@ static void mxl862xx_port_bridge_leave(s +@@ -1966,6 +2471,17 @@ static void mxl862xx_port_bridge_leave(s "failed to update CPU VBP for port %d: %pe\n", port, ERR_PTR(err)); @@ -681,7 +681,7 @@ Signed-off-by: Daniel Golle if (!dsa_bridge_ports(ds, bridge.dev)) mxl862xx_free_bridge(ds, &bridge); } -@@ -2636,18 +3152,17 @@ static int mxl862xx_get_fid(struct dsa_s +@@ -2591,18 +3107,17 @@ static int mxl862xx_get_fid(struct dsa_s } /** @@ -707,7 +707,7 @@ Signed-off-by: Daniel Golle */ static int mxl862xx_fdb_bridge_port(struct dsa_switch *ds, int port, const struct dsa_db db) -@@ -2663,7 +3178,7 @@ static int mxl862xx_fdb_bridge_port(stru +@@ -2618,7 +3133,7 @@ static int mxl862xx_fdb_bridge_port(stru return bp_cpu; } @@ -716,7 +716,7 @@ Signed-off-by: Daniel Golle } /** -@@ -2907,11 +3422,43 @@ static int mxl862xx_port_fdb_del(struct +@@ -2862,11 +3377,43 @@ static int mxl862xx_port_fdb_del(struct return ret; } @@ -760,7 +760,7 @@ Signed-off-by: Daniel Golle u32 entry_port_id; int ret; -@@ -2925,7 +3472,7 @@ static int mxl862xx_port_fdb_dump(struct +@@ -2880,7 +3427,7 @@ static int mxl862xx_port_fdb_dump(struct entry_port_id = le32_to_cpu(param.port_id); @@ -769,7 +769,7 @@ Signed-off-by: Daniel Golle ret = cb(param.mac, FIELD_GET(MXL862XX_TCI_VLAN_ID, le16_to_cpu(param.tci)), param.static_entry, data); -@@ -3562,6 +4109,11 @@ static const struct dsa_switch_ops mxl86 +@@ -3521,6 +4068,11 @@ static const struct dsa_switch_ops mxl86 .port_fdb_dump = mxl862xx_port_fdb_dump, .port_mdb_add = mxl862xx_port_mdb_add, .port_mdb_del = mxl862xx_port_mdb_del, @@ -781,7 +781,7 @@ Signed-off-by: Daniel Golle .port_vlan_filtering = mxl862xx_port_vlan_filtering, .port_vlan_add = mxl862xx_port_vlan_add, .port_vlan_del = mxl862xx_port_vlan_del, -@@ -3602,6 +4154,7 @@ static int mxl862xx_probe(struct mdio_de +@@ -3561,6 +4113,7 @@ static int mxl862xx_probe(struct mdio_de ds->num_ports = MXL862XX_MAX_PORTS; ds->fdb_isolation = true; ds->max_num_bridges = MXL862XX_MAX_BRIDGES; @@ -791,7 +791,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h -@@ -14,6 +14,19 @@ +@@ -16,6 +16,19 @@ struct mxl862xx_priv; #define MXL862XX_MAX_BRIDGE_PORTS 128 #define MXL862XX_TOTAL_EVLAN_ENTRIES 1024 #define MXL862XX_TOTAL_VF_ENTRIES 1024 @@ -835,9 +835,9 @@ Signed-off-by: Daniel Golle /* Hardware stats accumulation */ struct mxl862xx_port_stats stats; spinlock_t stats_lock; -@@ -328,6 +351,15 @@ union mxl862xx_fw_version { - * DSA bridge number. Indexed by dsa_bridge.num - * (0 .. ds->max_num_bridges). +@@ -334,6 +357,15 @@ union mxl862xx_fw_version { + * @evlan_egress_size: per-port egress Extended VLAN block size + * @cpu_evlan_ingress_size: CPU port ingress EVLAN block size (tag_8021q) * @vf_block_size: per-port VLAN Filter block size + * @lag_bridge_ports: maps DSA LAG ID to firmware bridge port ID; + * zero means no bridge port allocated for that LAG. @@ -851,7 +851,7 @@ Signed-off-by: Daniel Golle * @stats_work: periodic work item that polls RMON hardware counters * and accumulates them into 64-bit per-port stats */ -@@ -346,6 +378,8 @@ struct mxl862xx_priv { +@@ -352,6 +384,8 @@ struct mxl862xx_priv { u16 evlan_egress_size; u16 cpu_evlan_ingress_size; u16 vf_block_size; diff --git a/target/linux/generic/pending-6.12/760-18-net-dsa-mxl862xx-add-support-for-mirror-port.patch b/target/linux/generic/pending-6.12/760-18-net-dsa-mxl862xx-add-support-for-mirror-port.patch index faf69c0c0e..cdcbaee869 100644 --- a/target/linux/generic/pending-6.12/760-18-net-dsa-mxl862xx-add-support-for-mirror-port.patch +++ b/target/linux/generic/pending-6.12/760-18-net-dsa-mxl862xx-add-support-for-mirror-port.patch @@ -1,7 +1,7 @@ -From fbfa1b0649c578e0d43e3a61617b53a9a722efad Mon Sep 17 00:00:00 2001 +From 5528f38c3d709417625eb7f36628be31727a8221 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 12:05:29 +0000 -Subject: [PATCH 27/35] net: dsa: mxl862xx: add support for mirror port +Subject: [PATCH 18/26] net: dsa: mxl862xx: add support for mirror port The MxL862xx hardware supports a single monitor port which can be configured to mirror any other port's ingress and/or egress traffic. @@ -50,7 +50,7 @@ Signed-off-by: Daniel Golle #define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2) --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -1129,6 +1129,8 @@ static int mxl862xx_setup(struct dsa_swi +@@ -1084,6 +1084,8 @@ static int mxl862xx_setup(struct dsa_swi (n_user_ports + n_cpu_ports); } @@ -59,7 +59,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_setup_drop_meter(ds); if (ret) return ret; -@@ -2018,6 +2020,120 @@ static int mxl862xx_setup_cpu_bridge(str +@@ -1973,6 +1975,120 @@ static int mxl862xx_setup_cpu_bridge(str return mxl862xx_set_bridge_port(ds, port); } @@ -180,7 +180,7 @@ Signed-off-by: Daniel Golle /** * mxl862xx_lag_master_port - Find the LAG master (lowest-numbered member) * @ds: DSA switch -@@ -4109,6 +4225,8 @@ static const struct dsa_switch_ops mxl86 +@@ -4068,6 +4184,8 @@ static const struct dsa_switch_ops mxl86 .port_fdb_dump = mxl862xx_port_fdb_dump, .port_mdb_add = mxl862xx_port_mdb_add, .port_mdb_del = mxl862xx_port_mdb_del, @@ -210,7 +210,7 @@ Signed-off-by: Daniel Golle /* LAG state */ struct dsa_lag *lag; bool lag_tx_enabled; -@@ -360,6 +365,8 @@ union mxl862xx_fw_version { +@@ -366,6 +371,8 @@ union mxl862xx_fw_version { * @trunk_hash: current global hash field bitmask (6 bits, * MXL862XX_TRUNK_HASH_*); union of all active LAGs' * hash requirements @@ -219,7 +219,7 @@ Signed-off-by: Daniel Golle * @stats_work: periodic work item that polls RMON hardware counters * and accumulates them into 64-bit per-port stats */ -@@ -380,6 +387,7 @@ struct mxl862xx_priv { +@@ -386,6 +393,7 @@ struct mxl862xx_priv { u16 vf_block_size; u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1]; u8 trunk_hash; diff --git a/target/linux/generic/pending-6.12/760-19-net-dsa-wire-flash_update-devlink-callback-to-driver.patch b/target/linux/generic/pending-6.12/760-19-net-dsa-wire-flash_update-devlink-callback-to-driver.patch index bd0e9ef628..2adad2d11c 100644 --- a/target/linux/generic/pending-6.12/760-19-net-dsa-wire-flash_update-devlink-callback-to-driver.patch +++ b/target/linux/generic/pending-6.12/760-19-net-dsa-wire-flash_update-devlink-callback-to-driver.patch @@ -1,7 +1,7 @@ -From 67f82834819b71417b58dc1293c20f71b990264f Mon Sep 17 00:00:00 2001 +From 4059d35a5bbf1901b2e0eb7126369cd713cacfce Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 16:30:08 +0000 -Subject: [PATCH 28/35] net: dsa: wire flash_update devlink callback to drivers +Subject: [PATCH 19/26] net: dsa: wire flash_update devlink callback to drivers Add a devlink_flash_update callback to dsa_switch_ops so that DSA drivers can support devlink dev flash without open-coding the devlink @@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle --- a/include/net/dsa.h +++ b/include/net/dsa.h -@@ -1186,6 +1186,9 @@ struct dsa_switch_ops { +@@ -1185,6 +1185,9 @@ struct dsa_switch_ops { int (*devlink_info_get)(struct dsa_switch *ds, struct devlink_info_req *req, struct netlink_ext_ack *extack); diff --git a/target/linux/generic/pending-6.12/760-20-net-dsa-mxl862xx-add-SMDIO-clause-22-register-access.patch b/target/linux/generic/pending-6.12/760-20-net-dsa-mxl862xx-add-SMDIO-clause-22-register-access.patch index 17668b9734..2986143175 100644 --- a/target/linux/generic/pending-6.12/760-20-net-dsa-mxl862xx-add-SMDIO-clause-22-register-access.patch +++ b/target/linux/generic/pending-6.12/760-20-net-dsa-mxl862xx-add-SMDIO-clause-22-register-access.patch @@ -1,7 +1,7 @@ -From 1a87b829ef3280d646dc480f7b261d9e32896899 Mon Sep 17 00:00:00 2001 +From 0145151dc68aa318d8addb6fe7f12c0967f951da Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 16:30:17 +0000 -Subject: [PATCH 29/35] net: dsa: mxl862xx: add SMDIO clause-22 register access +Subject: [PATCH 20/26] net: dsa: mxl862xx: add SMDIO clause-22 register access Add mxl862xx_smdio_read() and mxl862xx_smdio_write() for clause-22 SMDIO register access. MCUboot rescue mode only exposes clause-22 diff --git a/target/linux/generic/pending-6.12/760-21-net-dsa-mxl862xx-add-devlink-flash_update-and-info_g.patch b/target/linux/generic/pending-6.12/760-21-net-dsa-mxl862xx-add-devlink-flash_update-and-info_g.patch index 28b91f8021..d731ec1b08 100644 --- a/target/linux/generic/pending-6.12/760-21-net-dsa-mxl862xx-add-devlink-flash_update-and-info_g.patch +++ b/target/linux/generic/pending-6.12/760-21-net-dsa-mxl862xx-add-devlink-flash_update-and-info_g.patch @@ -1,7 +1,7 @@ -From b7e8f8fd4493b255f0f01fe790a73ad61b5e8ce8 Mon Sep 17 00:00:00 2001 +From bdbca48510e3e96ed9210f20fa4244dd6df5d44a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 16:30:31 +0000 -Subject: [PATCH 30/35] net: dsa: mxl862xx: add devlink flash_update and +Subject: [PATCH 21/26] net: dsa: mxl862xx: add devlink flash_update and info_get Implement runtime firmware upgrade via "devlink dev flash" and version @@ -546,7 +546,7 @@ Signed-off-by: Daniel Golle #include "mxl862xx-host.h" #include "mxl862xx-phylink.h" -@@ -4245,6 +4246,9 @@ static const struct dsa_switch_ops mxl86 +@@ -4204,6 +4205,9 @@ static const struct dsa_switch_ops mxl86 .get_pause_stats = mxl862xx_get_pause_stats, .get_stats64 = mxl862xx_get_stats64, .self_test = mxl862xx_serdes_self_test, @@ -558,7 +558,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_probe(struct mdio_device *mdiodev) --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h -@@ -388,6 +388,8 @@ struct mxl862xx_priv { +@@ -394,6 +394,8 @@ struct mxl862xx_priv { u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1]; u8 trunk_hash; int mirror_dest; diff --git a/target/linux/generic/pending-6.12/760-22-net-dsa-mxl862xx-implement-port-MTU-configuration.patch b/target/linux/generic/pending-6.12/760-22-net-dsa-mxl862xx-implement-port-MTU-configuration.patch index 1869a9f17c..1a22bba1f1 100644 --- a/target/linux/generic/pending-6.12/760-22-net-dsa-mxl862xx-implement-port-MTU-configuration.patch +++ b/target/linux/generic/pending-6.12/760-22-net-dsa-mxl862xx-implement-port-MTU-configuration.patch @@ -1,7 +1,7 @@ -From 2cb9aeb3a8d7ebac20331e0a533dcfbd73fa4237 Mon Sep 17 00:00:00 2001 +From 8deb5be9638f7eb3009ed3eb619eedadee1df523 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 23:42:18 +0000 -Subject: [PATCH 31/35] net: dsa: mxl862xx: implement port MTU configuration +Subject: [PATCH 22/26] net: dsa: mxl862xx: implement port MTU configuration The firmware exposes a global max_packet_len register via MXL862XX_COMMON_CFGSET. Since this is switch-wide rather than @@ -25,7 +25,7 @@ Signed-off-by: Daniel Golle #include #include #include -@@ -3768,6 +3769,53 @@ static int mxl862xx_set_ageing_time(stru +@@ -3723,6 +3724,53 @@ static int mxl862xx_set_ageing_time(stru return ret; } @@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle static void mxl862xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { -@@ -4215,6 +4263,8 @@ static const struct dsa_switch_ops mxl86 +@@ -4174,6 +4222,8 @@ static const struct dsa_switch_ops mxl86 .port_disable = mxl862xx_port_disable, .port_fast_age = mxl862xx_port_fast_age, .set_ageing_time = mxl862xx_set_ageing_time, diff --git a/target/linux/generic/pending-6.12/760-23-net-dsa-mxl862xx-support-BR_HAIRPIN_MODE-bridge-flag.patch b/target/linux/generic/pending-6.12/760-23-net-dsa-mxl862xx-support-BR_HAIRPIN_MODE-bridge-flag.patch index bf4d2f0ca7..dfbf953754 100644 --- a/target/linux/generic/pending-6.12/760-23-net-dsa-mxl862xx-support-BR_HAIRPIN_MODE-bridge-flag.patch +++ b/target/linux/generic/pending-6.12/760-23-net-dsa-mxl862xx-support-BR_HAIRPIN_MODE-bridge-flag.patch @@ -1,7 +1,7 @@ -From d55ca68eb0d20a66c32d531b0a454871b486c1b1 Mon Sep 17 00:00:00 2001 +From 13a4c918cd9ded7207f38033511ab13f7aff9bd2 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 01:47:19 +0000 -Subject: [PATCH 32/35] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag +Subject: [PATCH 23/26] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag Implement hairpin mode by including the port's own bridge port ID in its forwarding portmap. When hairpin is enabled, bridged frames whose @@ -18,9 +18,9 @@ bridge member rebuild since only the calling port is affected. Signed-off-by: Daniel Golle --- - drivers/net/dsa/mxl862xx/mxl862xx.c | 30 ++++++++++++++++++++++++++++- + drivers/net/dsa/mxl862xx/mxl862xx.c | 29 +++++++++++++++++++++++++++-- drivers/net/dsa/mxl862xx/mxl862xx.h | 6 ++++++ - 2 files changed, 35 insertions(+), 1 deletion(-) + 2 files changed, 33 insertions(+), 2 deletions(-) --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c @@ -40,7 +40,7 @@ Signed-off-by: Daniel Golle err = mxl862xx_set_bridge_port(ds, port); if (err) ret = err; -@@ -3939,7 +3948,7 @@ static int mxl862xx_port_pre_bridge_flag +@@ -3898,7 +3907,7 @@ static int mxl862xx_port_pre_bridge_flag struct netlink_ext_ack *extack) { if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | @@ -49,20 +49,19 @@ Signed-off-by: Daniel Golle return -EINVAL; return 0; -@@ -3954,6 +3963,7 @@ static int mxl862xx_port_bridge_flags(st +@@ -3912,6 +3921,7 @@ static int mxl862xx_port_bridge_flags(st + unsigned long old_block = priv->ports[port].flood_block; unsigned long block = old_block; - bool need_update = false; int ret; + u16 bp; if (flags.mask & BR_FLOOD) { if (flags.val & BR_FLOOD) -@@ -3988,6 +3998,24 @@ static int mxl862xx_port_bridge_flags(st - ret = mxl862xx_set_bridge_port(ds, port); - if (ret) - return ret; -+ } -+ +@@ -3940,7 +3950,22 @@ static int mxl862xx_port_bridge_flags(st + if (flags.mask & BR_LEARNING) + priv->ports[port].learning = !!(flags.val & BR_LEARNING); + +- if ((block != old_block) || (flags.mask & BR_LEARNING)) { + if (flags.mask & BR_HAIRPIN_MODE) { + bp = mxl862xx_lag_bridge_port(priv, port); + priv->ports[port].hairpin = !!(flags.val & BR_HAIRPIN_MODE); @@ -75,13 +74,13 @@ Signed-off-by: Daniel Golle + __set_bit(bp, priv->ports[port].portmap); + else + __clear_bit(bp, priv->ports[port].portmap); ++ } + -+ ret = mxl862xx_set_bridge_port(ds, port); -+ if (ret) -+ return ret; - } - - return 0; ++ if ((block != old_block) || ++ (flags.mask & (BR_LEARNING | BR_HAIRPIN_MODE))) { + priv->ports[port].flood_block = block; + ret = mxl862xx_set_bridge_port(ds, port); + if (ret) --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h @@ -241,6 +241,10 @@ struct mxl862xx_port_stats { diff --git a/target/linux/generic/pending-6.12/760-24-net-dsa-mxl862xx-support-BR_ISOLATED-bridge-flag.patch b/target/linux/generic/pending-6.12/760-24-net-dsa-mxl862xx-support-BR_ISOLATED-bridge-flag.patch index a524d157e5..c67d95d5c5 100644 --- a/target/linux/generic/pending-6.12/760-24-net-dsa-mxl862xx-support-BR_ISOLATED-bridge-flag.patch +++ b/target/linux/generic/pending-6.12/760-24-net-dsa-mxl862xx-support-BR_ISOLATED-bridge-flag.patch @@ -1,7 +1,7 @@ -From 74b6654ba74eb142340de4c51b97c0221cfcae37 Mon Sep 17 00:00:00 2001 +From d49d1f8bee29269def7593f980d0e08bfb5c3ef8 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 01:51:33 +0000 -Subject: [PATCH 33/35] net: dsa: mxl862xx: support BR_ISOLATED bridge flag +Subject: [PATCH 24/26] net: dsa: mxl862xx: support BR_ISOLATED bridge flag Implement port isolation by excluding isolated ports from each other's forwarding portmaps in sync_bridge_members. Non-isolated ports can @@ -34,7 +34,7 @@ Signed-off-by: Daniel Golle if (member != port) { bp = mxl862xx_lag_bridge_port(priv, member); -@@ -3948,7 +3956,7 @@ static int mxl862xx_port_pre_bridge_flag +@@ -3907,7 +3915,7 @@ static int mxl862xx_port_pre_bridge_flag struct netlink_ext_ack *extack) { if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | @@ -43,15 +43,15 @@ Signed-off-by: Daniel Golle return -EINVAL; return 0; -@@ -3962,6 +3970,7 @@ static int mxl862xx_port_bridge_flags(st +@@ -3920,6 +3928,7 @@ static int mxl862xx_port_bridge_flags(st + struct mxl862xx_priv *priv = ds->priv; unsigned long old_block = priv->ports[port].flood_block; unsigned long block = old_block; - bool need_update = false; + struct dsa_port *dp; int ret; u16 bp; -@@ -4018,6 +4027,21 @@ static int mxl862xx_port_bridge_flags(st +@@ -3972,6 +3981,21 @@ static int mxl862xx_port_bridge_flags(st return ret; } diff --git a/target/linux/generic/pending-6.12/760-25-DO-NOT-SUBMIT-net-dsa-mxl862xx-re-introduce-PCE-work.patch b/target/linux/generic/pending-6.12/760-25-DO-NOT-SUBMIT-net-dsa-mxl862xx-re-introduce-PCE-work.patch index 98cfb44d48..6e5d25069d 100644 --- a/target/linux/generic/pending-6.12/760-25-DO-NOT-SUBMIT-net-dsa-mxl862xx-re-introduce-PCE-work.patch +++ b/target/linux/generic/pending-6.12/760-25-DO-NOT-SUBMIT-net-dsa-mxl862xx-re-introduce-PCE-work.patch @@ -1,7 +1,7 @@ -From 0902a6790750714445c75a66d60f1bc4897126ce Mon Sep 17 00:00:00 2001 +From c2fb7f0df63ac994850f766e7f2eb50c6c5ef2cf Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:17:49 +0000 -Subject: [PATCH 34/35] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE +Subject: [PATCH 25/26] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE workaround for old firmware Re-introduce the mxl862xx_disable_fw_global_rules() function that @@ -64,7 +64,7 @@ Signed-off-by: Daniel Golle /* Per-CTP offset used for the link-local trap rule. Each port's CTP * flow-table block is pre-allocated by the firmware during init (44 -@@ -1154,9 +1191,11 @@ static int mxl862xx_setup(struct dsa_swi +@@ -1109,9 +1146,11 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; diff --git a/target/linux/generic/pending-6.12/760-26-DO-NOT-SUBMIT-net-dsa-mxl862xx-legacy-SFP-API-fallba.patch b/target/linux/generic/pending-6.12/760-26-DO-NOT-SUBMIT-net-dsa-mxl862xx-legacy-SFP-API-fallba.patch index 41cd927ac4..cba47630f4 100644 --- a/target/linux/generic/pending-6.12/760-26-DO-NOT-SUBMIT-net-dsa-mxl862xx-legacy-SFP-API-fallba.patch +++ b/target/linux/generic/pending-6.12/760-26-DO-NOT-SUBMIT-net-dsa-mxl862xx-legacy-SFP-API-fallba.patch @@ -1,7 +1,7 @@ -From 0ac876d5b952218ab79ea0a0815cf6fd1290b1d0 Mon Sep 17 00:00:00 2001 +From f0548f842b9ff31f19452a2fc72a16f937d86008 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:19:56 +0000 -Subject: [PATCH 35/35] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API +Subject: [PATCH 26/26] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API fallback for old firmware Re-introduce the SYS_MISC_SFP_SET-based PCS implementation as a diff --git a/target/linux/generic/pending-6.18/760-00-net-dsa-mxl862xx-cancel-pending-work-on-probe-error.patch b/target/linux/generic/pending-6.18/760-00-net-dsa-mxl862xx-cancel-pending-work-on-probe-error.patch new file mode 100644 index 0000000000..d215cbbb8d --- /dev/null +++ b/target/linux/generic/pending-6.18/760-00-net-dsa-mxl862xx-cancel-pending-work-on-probe-error.patch @@ -0,0 +1,37 @@ +From 3fd163f5bb88de426ca9847549f94b4296170ef0 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 30 Mar 2026 23:40:53 +0100 +Subject: [PATCH] net: dsa: mxl862xx: cancel pending work on probe error + +Call mxl862xx_host_shutdown() in case dsa_register_switch() returns +an error, so any still pending crc_err_work get canceled. + +Fixes: a319d0c8c8ced ("net: dsa: mxl862xx: add CRC for MDIO communication)" +Signed-off-by: Daniel Golle +--- + drivers/net/dsa/mxl862xx/mxl862xx.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/net/dsa/mxl862xx/mxl862xx.c ++++ b/drivers/net/dsa/mxl862xx/mxl862xx.c +@@ -407,6 +407,7 @@ static int mxl862xx_probe(struct mdio_de + struct device *dev = &mdiodev->dev; + struct mxl862xx_priv *priv; + struct dsa_switch *ds; ++ int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -428,7 +429,11 @@ static int mxl862xx_probe(struct mdio_de + + dev_set_drvdata(dev, ds); + +- return dsa_register_switch(ds); ++ err = dsa_register_switch(ds); ++ if (err) ++ mxl862xx_host_shutdown(priv); ++ ++ return err; + } + + static void mxl862xx_remove(struct mdio_device *mdiodev) diff --git a/target/linux/generic/pending-6.18/760-01-net-dsa-move-dsa_bridge_ports-helper-to-dsa.h.patch b/target/linux/generic/pending-6.18/760-01-net-dsa-move-dsa_bridge_ports-helper-to-dsa.h.patch index 843ca14b64..51d3644d58 100644 --- a/target/linux/generic/pending-6.18/760-01-net-dsa-move-dsa_bridge_ports-helper-to-dsa.h.patch +++ b/target/linux/generic/pending-6.18/760-01-net-dsa-move-dsa_bridge_ports-helper-to-dsa.h.patch @@ -1,7 +1,7 @@ -From de6dd19a3edd1dc6400fecf77610e438441a02ac Mon Sep 17 00:00:00 2001 +From cd698f1ae94c16499e2714b31dd6048e6f9f068d Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 17:54:11 +0000 -Subject: [PATCH 10/35] net: dsa: move dsa_bridge_ports() helper to dsa.h +Subject: [PATCH 01/26] net: dsa: move dsa_bridge_ports() helper to dsa.h The yt921x driver contains a helper to create a bitmap of ports which are members of a bridge. @@ -12,7 +12,7 @@ can make use of it as well. Signed-off-by: Daniel Golle --- include/net/dsa.h | 13 +++++++++++++ - 1 file changed, 13 insertions(+) + 2 files changed, 13 insertions(+), 13 deletions(-) --- a/include/net/dsa.h +++ b/include/net/dsa.h diff --git a/target/linux/generic/pending-6.18/760-02-net-dsa-add-bridge-member-iteration-macro.patch b/target/linux/generic/pending-6.18/760-02-net-dsa-add-bridge-member-iteration-macro.patch index af90028b98..67dc948461 100644 --- a/target/linux/generic/pending-6.18/760-02-net-dsa-add-bridge-member-iteration-macro.patch +++ b/target/linux/generic/pending-6.18/760-02-net-dsa-add-bridge-member-iteration-macro.patch @@ -1,7 +1,7 @@ -From 880cde7abf58cb1316382ae7f59aac93c313e8fe Mon Sep 17 00:00:00 2001 +From c161533e1605a7282563c139323a3913890fdb72 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 17:54:41 +0000 -Subject: [PATCH 11/35] net: dsa: add bridge member iteration macro +Subject: [PATCH 02/26] net: dsa: add bridge member iteration macro Drivers that offload bridges need to iterate over the ports that are members of a given bridge, for example to rebuild per-port forwarding diff --git a/target/linux/generic/pending-6.18/760-03-dsa-tag_mxl862xx-set-dsa_default_offload_fwd_mark.patch b/target/linux/generic/pending-6.18/760-03-dsa-tag_mxl862xx-set-dsa_default_offload_fwd_mark.patch index 7c824994aa..e47f4e44c8 100644 --- a/target/linux/generic/pending-6.18/760-03-dsa-tag_mxl862xx-set-dsa_default_offload_fwd_mark.patch +++ b/target/linux/generic/pending-6.18/760-03-dsa-tag_mxl862xx-set-dsa_default_offload_fwd_mark.patch @@ -1,7 +1,7 @@ -From 149bb02d5bf031a1eb85f91377f54913de3a08ff Mon Sep 17 00:00:00 2001 +From 753efe27a9afee52c4ad42098a9b9278366d63cc Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 17:54:52 +0000 -Subject: [PATCH 12/35] dsa: tag_mxl862xx: set dsa_default_offload_fwd_mark() +Subject: [PATCH 03/26] dsa: tag_mxl862xx: set dsa_default_offload_fwd_mark() The MxL862xx offloads bridge forwarding in hardware, so set dsa_default_offload_fwd_mark() to avoid duplicate forwarding of diff --git a/target/linux/generic/pending-6.18/760-04-net-dsa-mxl862xx-implement-bridge-offloading.patch b/target/linux/generic/pending-6.18/760-04-net-dsa-mxl862xx-implement-bridge-offloading.patch index 9d1c1c958b..a545e70677 100644 --- a/target/linux/generic/pending-6.18/760-04-net-dsa-mxl862xx-implement-bridge-offloading.patch +++ b/target/linux/generic/pending-6.18/760-04-net-dsa-mxl862xx-implement-bridge-offloading.patch @@ -1,7 +1,7 @@ -From 5acdee6df2fbd4a9b02045694227f25cb1d4e5e0 Mon Sep 17 00:00:00 2001 +From ce0664ff8f75c3ab01101c3f0f8569924d948775 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 17:55:08 +0000 -Subject: [PATCH 13/35] net: dsa: mxl862xx: implement bridge offloading +Subject: [PATCH 04/26] net: dsa: mxl862xx: implement bridge offloading Implement joining and leaving bridges as well as add, delete and dump operations on isolated FDBs, port MDB membership management, and @@ -39,9 +39,9 @@ Signed-off-by: Daniel Golle --- drivers/net/dsa/mxl862xx/mxl862xx-api.h | 225 ++++++- drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 20 +- - drivers/net/dsa/mxl862xx/mxl862xx.c | 752 ++++++++++++++++++++++-- + drivers/net/dsa/mxl862xx/mxl862xx.c | 743 ++++++++++++++++++++++-- drivers/net/dsa/mxl862xx/mxl862xx.h | 133 +++++ - 4 files changed, 1087 insertions(+), 43 deletions(-) + 4 files changed, 1076 insertions(+), 45 deletions(-) --- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h @@ -384,7 +384,7 @@ Signed-off-by: Daniel Golle static enum dsa_tag_protocol mxl862xx_get_tag_protocol(struct dsa_switch *ds, int port, enum dsa_tag_protocol m) -@@ -168,6 +182,225 @@ static int mxl862xx_setup_mdio(struct ds +@@ -168,6 +182,213 @@ static int mxl862xx_setup_mdio(struct ds return ret; } @@ -535,18 +535,6 @@ Signed-off-by: Daniel Golle + return ret; +} + -+/** -+ * mxl862xx_allocate_bridge - Allocate a firmware bridge instance -+ * @priv: driver private data -+ * @bridge_id: output -- firmware bridge ID assigned by the firmware -+ * -+ * Newly allocated bridges default to flooding all traffic classes -+ * (unknown unicast, multicast, broadcast). Callers that need -+ * different forwarding behavior must call mxl862xx_bridge_config_fwd() -+ * after allocation. -+ * -+ * Return: 0 on success, negative errno on failure. -+ */ +static int mxl862xx_allocate_bridge(struct mxl862xx_priv *priv, u16 *bridge_id) +{ + struct mxl862xx_bridge_alloc br_alloc = {}; @@ -610,7 +598,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_setup(struct dsa_switch *ds) { struct mxl862xx_priv *priv = ds->priv; -@@ -181,6 +414,10 @@ static int mxl862xx_setup(struct dsa_swi +@@ -181,6 +402,10 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; @@ -621,7 +609,7 @@ Signed-off-by: Daniel Golle return mxl862xx_setup_mdio(ds); } -@@ -260,66 +497,87 @@ static int mxl862xx_configure_sp_tag_pro +@@ -260,66 +485,87 @@ static int mxl862xx_configure_sp_tag_pro static int mxl862xx_setup_cpu_bridge(struct dsa_switch *ds, int port) { @@ -744,7 +732,7 @@ Signed-off-by: Daniel Golle struct dsa_port *dp = dsa_to_port(ds, port); bool is_cpu_port = dsa_port_is_cpu(dp); int ret; -@@ -352,7 +610,31 @@ static int mxl862xx_port_setup(struct ds +@@ -352,7 +598,31 @@ static int mxl862xx_port_setup(struct ds return mxl862xx_setup_cpu_bridge(ds, port); /* setup single-port bridge for user ports */ @@ -777,7 +765,7 @@ Signed-off-by: Daniel Golle } static void mxl862xx_phylink_get_caps(struct dsa_switch *ds, int port, -@@ -365,14 +647,385 @@ static void mxl862xx_phylink_get_caps(st +@@ -365,14 +635,383 @@ static void mxl862xx_phylink_get_caps(st config->supported_interfaces); } @@ -942,7 +930,7 @@ Signed-off-by: Daniel Golle + mxl862xx_fw_portmap_clear_bit(qparam.port_map, port); + + if (mxl862xx_fw_portmap_is_empty(qparam.port_map)) { -+ /* No ports left — remove the entry entirely */ ++ /* No ports left -- remove the entry entirely */ + rparam.fid = cpu_to_le16(fid); + rparam.tci = cpu_to_le16(FIELD_PREP(MXL862XX_TCI_VLAN_ID, mdb->vid)); + ether_addr_copy(rparam.mac, mdb->addr); @@ -1033,7 +1021,7 @@ Signed-off-by: Daniel Golle +/* Deferred work handler for host flood configuration. + * + * port_set_host_flood is called from atomic context (under -+ * netif_addr_lock), so firmware calls must be deferred. The worker ++ * netif_addr_lock), so firmware calls must be deferred. The worker + * acquires rtnl_lock() to serialize with DSA callbacks that access the + * same driver state. + */ @@ -1058,9 +1046,9 @@ Signed-off-by: Daniel Golle + mc = p->host_flood_mc; + + /* The hardware controls unknown-unicast/multicast forwarding per FID -+ * (bridge), not per source port. For bridged ports all members share ++ * (bridge), not per source port. For bridged ports all members share + * one FID, so we cannot selectively suppress flooding to the CPU for -+ * one source port while allowing it for another. Silently ignore the ++ * one source port while allowing it for another. Silently ignore the + * request -- the excess flooding towards the CPU is harmless. + */ + if (!dsa_port_bridge_dev_get(dsa_to_port(ds, port))) @@ -1098,7 +1086,6 @@ Signed-off-by: Daniel Golle + struct mxl862xx_priv *priv = ds->priv; + unsigned long old_block = priv->ports[port].flood_block; + unsigned long block = old_block; -+ bool need_update = false; + int ret; + + if (flags.mask & BR_FLOOD) { @@ -1128,8 +1115,7 @@ Signed-off-by: Daniel Golle + if (flags.mask & BR_LEARNING) + priv->ports[port].learning = !!(flags.val & BR_LEARNING); + -+ need_update = (block != old_block) || (flags.mask & BR_LEARNING); -+ if (need_update) { ++ if ((block != old_block) || (flags.mask & BR_LEARNING)) { + priv->ports[port].flood_block = block; + ret = mxl862xx_set_bridge_port(ds, port); + if (ret) @@ -1163,15 +1149,16 @@ Signed-off-by: Daniel Golle }; static void mxl862xx_phylink_mac_config(struct phylink_config *config, -@@ -407,6 +1060,7 @@ static int mxl862xx_probe(struct mdio_de +@@ -407,7 +1046,7 @@ static int mxl862xx_probe(struct mdio_de struct device *dev = &mdiodev->dev; struct mxl862xx_priv *priv; struct dsa_switch *ds; -+ int i; +- int err; ++ int err, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) -@@ -424,8 +1078,17 @@ static int mxl862xx_probe(struct mdio_de +@@ -425,14 +1064,25 @@ static int mxl862xx_probe(struct mdio_de ds->ops = &mxl862xx_switch_ops; ds->phylink_mac_ops = &mxl862xx_phylink_mac_ops; ds->num_ports = MXL862XX_MAX_PORTS; @@ -1188,8 +1175,18 @@ Signed-off-by: Daniel Golle + dev_set_drvdata(dev, ds); - return dsa_register_switch(ds); -@@ -435,6 +1098,7 @@ static void mxl862xx_remove(struct mdio_ + err = dsa_register_switch(ds); +- if (err) ++ if (err) { + mxl862xx_host_shutdown(priv); +- ++ for (i = 0; i < MXL862XX_MAX_PORTS; i++) ++ cancel_work_sync(&priv->ports[i].host_flood_work); ++ } + return err; + } + +@@ -440,6 +1090,7 @@ static void mxl862xx_remove(struct mdio_ { struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); struct mxl862xx_priv *priv; @@ -1197,14 +1194,14 @@ Signed-off-by: Daniel Golle if (!ds) return; -@@ -444,12 +1108,21 @@ static void mxl862xx_remove(struct mdio_ +@@ -449,12 +1100,21 @@ static void mxl862xx_remove(struct mdio_ dsa_unregister_switch(ds); mxl862xx_host_shutdown(priv); + -+ /* Cancel any pending host flood work. dsa_unregister_switch() ++ /* Cancel any pending host flood work. dsa_unregister_switch() + * has already called port_teardown (which sets setup_done=false), -+ * but a worker could still be blocked on rtnl_lock(). Since we ++ * but a worker could still be blocked on rtnl_lock(). Since we + * are now outside RTNL, cancel_work_sync() will not deadlock. + */ + for (i = 0; i < MXL862XX_MAX_PORTS; i++) @@ -1219,7 +1216,7 @@ Signed-off-by: Daniel Golle if (!ds) return; -@@ -460,6 +1133,9 @@ static void mxl862xx_shutdown(struct mdi +@@ -465,6 +1125,9 @@ static void mxl862xx_shutdown(struct mdi mxl862xx_host_shutdown(priv); diff --git a/target/linux/generic/pending-6.18/760-05-net-dsa-mxl862xx-implement-VLAN-functionality.patch b/target/linux/generic/pending-6.18/760-05-net-dsa-mxl862xx-implement-VLAN-functionality.patch index 109808792c..c9e1769d98 100644 --- a/target/linux/generic/pending-6.18/760-05-net-dsa-mxl862xx-implement-VLAN-functionality.patch +++ b/target/linux/generic/pending-6.18/760-05-net-dsa-mxl862xx-implement-VLAN-functionality.patch @@ -1,7 +1,7 @@ -From 7286ac4f850339aac37dd52633f4a70816b621a8 Mon Sep 17 00:00:00 2001 +From 0d88d02cc9dccad01ff88f54e1beee867107b942 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 10 Mar 2026 02:36:00 +0000 -Subject: [PATCH 14/35] net: dsa: mxl862xx: implement VLAN functionality +Subject: [PATCH 05/26] net: dsa: mxl862xx: implement VLAN functionality Add VLAN support using both the Extended VLAN (EVLAN) engine and the VLAN Filter (VF) engine in a hybrid architecture that allows a higher @@ -35,11 +35,11 @@ VLAN Filter blocks across ports with identical VID sets. Signed-off-by: Daniel Golle --- - drivers/net/dsa/mxl862xx/mxl862xx-api.h | 329 ++++++++ + drivers/net/dsa/mxl862xx/mxl862xx-api.h | 329 +++++++++ drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 12 + - drivers/net/dsa/mxl862xx/mxl862xx.c | 960 +++++++++++++++++++++++- - drivers/net/dsa/mxl862xx/mxl862xx.h | 110 ++- - 4 files changed, 1386 insertions(+), 25 deletions(-) + drivers/net/dsa/mxl862xx/mxl862xx.c | 915 +++++++++++++++++++++++- + drivers/net/dsa/mxl862xx/mxl862xx.h | 104 ++- + 4 files changed, 1344 insertions(+), 16 deletions(-) --- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h @@ -577,7 +577,7 @@ Signed-off-by: Daniel Golle mxl862xx_fw_portmap_from_bitmap(br_port_cfg.bridge_port_map, p->portmap); for (i = 0; i < ARRAY_SIZE(mxl862xx_flood_meters); i++) { -@@ -329,13 +472,131 @@ static int mxl862xx_sync_bridge_members( +@@ -329,6 +472,91 @@ static int mxl862xx_sync_bridge_members( return ret; } @@ -609,11 +609,6 @@ Signed-off-by: Daniel Golle + return 0; +} + -+/** -+ * mxl862xx_vf_init - Initialize per-port VF block software state -+ * @vf: VLAN Filter block to initialize -+ * @size: block size (entries per port) -+ */ +static void mxl862xx_vf_init(struct mxl862xx_vf_block *vf, u16 size) +{ + vf->allocated = false; @@ -623,15 +618,6 @@ Signed-off-by: Daniel Golle + INIT_LIST_HEAD(&vf->vids); +} + -+/** -+ * mxl862xx_vf_block_alloc - Allocate a VLAN Filter block from firmware -+ * @priv: driver private data -+ * @size: number of entries to allocate -+ * @block_id: output -- block ID assigned by firmware -+ * -+ * Allocates a contiguous VLAN Filter block and configures it to discard -+ * unmatched tagged frames (VID membership enforcement). -+ */ +static int mxl862xx_vf_block_alloc(struct mxl862xx_priv *priv, + u16 size, u16 *block_id) +{ @@ -650,15 +636,6 @@ Signed-off-by: Daniel Golle + return 0; +} + -+/** -+ * mxl862xx_vf_entry_discard - Write a DISCARD entry to plug an unused slot -+ * @priv: driver private data -+ * @block_id: HW VLAN Filter block ID -+ * @index: entry index within the block -+ * -+ * Unwritten VLAN Filter entries default to VID=0 / ALLOW which would -+ * leak VID 0 traffic. This writes a DISCARD entry to plug the slot. -+ */ +static int mxl862xx_vf_entry_discard(struct mxl862xx_priv *priv, + u16 block_id, u16 index) +{ @@ -673,16 +650,6 @@ Signed-off-by: Daniel Golle + return MXL862XX_API_WRITE(priv, MXL862XX_VLANFILTER_SET, cfg); +} + -+/** -+ * mxl862xx_vf_alloc - Allocate the port's VF HW block -+ * @priv: driver private data -+ * @vf: VLAN Filter block (must have been initialized via mxl862xx_vf_init) -+ * -+ * Allocates the block and writes a DISCARD sentinel at index 0 so that -+ * when active_count is 0, the single-entry scan window blocks VID-0 -+ * (which would otherwise match the zeroed-out default and be allowed). -+ * Called once per port from port_setup. -+ */ +static int mxl862xx_vf_alloc(struct mxl862xx_priv *priv, + struct mxl862xx_vf_block *vf) +{ @@ -699,18 +666,10 @@ Signed-off-by: Daniel Golle + return mxl862xx_vf_entry_discard(priv, vf->block_id, 0); +} + - /** - * mxl862xx_allocate_bridge - Allocate a firmware bridge instance - * @priv: driver private data - * @bridge_id: output -- firmware bridge ID assigned by the firmware - * - * Newly allocated bridges default to flooding all traffic classes -- * (unknown unicast, multicast, broadcast). Callers that need -+ * (unknown unicast, multicast, broadcast). Callers that need - * different forwarding behavior must call mxl862xx_bridge_config_fwd() - * after allocation. - * -@@ -404,6 +665,9 @@ static int mxl862xx_add_single_port_brid + static int mxl862xx_allocate_bridge(struct mxl862xx_priv *priv, u16 *bridge_id) + { + struct mxl862xx_bridge_alloc br_alloc = {}; +@@ -392,6 +620,9 @@ static int mxl862xx_add_single_port_brid static int mxl862xx_setup(struct dsa_switch *ds) { struct mxl862xx_priv *priv = ds->priv; @@ -720,7 +679,7 @@ Signed-off-by: Daniel Golle int ret; ret = mxl862xx_reset(priv); -@@ -414,6 +678,50 @@ static int mxl862xx_setup(struct dsa_swi +@@ -402,6 +633,50 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; @@ -771,7 +730,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_setup_drop_meter(ds); if (ret) return ret; -@@ -495,27 +803,616 @@ static int mxl862xx_configure_sp_tag_pro +@@ -483,27 +758,616 @@ static int mxl862xx_configure_sp_tag_pro return MXL862XX_API_WRITE(ds->priv, MXL862XX_SS_SPTAG_SET, tag); } @@ -1392,7 +1351,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port, const struct dsa_bridge bridge, bool *tx_fwd_offload, -@@ -565,6 +1462,22 @@ static void mxl862xx_port_bridge_leave(s +@@ -553,6 +1417,22 @@ static void mxl862xx_port_bridge_leave(s bitmap_zero(p->portmap, MXL862XX_MAX_BRIDGE_PORTS); __set_bit(dp->cpu_dp->index, p->portmap); p->flood_block = 0; @@ -1415,7 +1374,7 @@ Signed-off-by: Daniel Golle err = mxl862xx_set_bridge_port(ds, port); if (err) dev_err(ds->dev, -@@ -614,6 +1527,28 @@ static int mxl862xx_port_setup(struct ds +@@ -602,6 +1482,28 @@ static int mxl862xx_port_setup(struct ds if (ret) return ret; @@ -1444,37 +1403,7 @@ Signed-off-by: Daniel Golle priv->ports[port].setup_done = true; return 0; -@@ -808,7 +1743,7 @@ static int mxl862xx_port_mdb_del(struct - mxl862xx_fw_portmap_clear_bit(qparam.port_map, port); - - if (mxl862xx_fw_portmap_is_empty(qparam.port_map)) { -- /* No ports left — remove the entry entirely */ -+ /* No ports left -- remove the entry entirely */ - rparam.fid = cpu_to_le16(fid); - rparam.tci = cpu_to_le16(FIELD_PREP(MXL862XX_TCI_VLAN_ID, mdb->vid)); - ether_addr_copy(rparam.mac, mdb->addr); -@@ -899,7 +1834,7 @@ static void mxl862xx_port_stp_state_set( - /* Deferred work handler for host flood configuration. - * - * port_set_host_flood is called from atomic context (under -- * netif_addr_lock), so firmware calls must be deferred. The worker -+ * netif_addr_lock), so firmware calls must be deferred. The worker - * acquires rtnl_lock() to serialize with DSA callbacks that access the - * same driver state. - */ -@@ -924,9 +1859,9 @@ static void mxl862xx_host_flood_work_fn( - mc = p->host_flood_mc; - - /* The hardware controls unknown-unicast/multicast forwarding per FID -- * (bridge), not per source port. For bridged ports all members share -+ * (bridge), not per source port. For bridged ports all members share - * one FID, so we cannot selectively suppress flooding to the CPU for -- * one source port while allowing it for another. Silently ignore the -+ * one source port while allowing it for another. Silently ignore the - * request -- the excess flooding towards the CPU is harmless. - */ - if (!dsa_port_bridge_dev_get(dsa_to_port(ds, port))) -@@ -1026,6 +1961,9 @@ static const struct dsa_switch_ops mxl86 +@@ -1012,6 +1914,9 @@ static const struct dsa_switch_ops mxl86 .port_fdb_dump = mxl862xx_port_fdb_dump, .port_mdb_add = mxl862xx_port_mdb_add, .port_mdb_del = mxl862xx_port_mdb_del, @@ -1484,15 +1413,6 @@ Signed-off-by: Daniel Golle }; static void mxl862xx_phylink_mac_config(struct phylink_config *config, -@@ -1111,7 +2049,7 @@ static void mxl862xx_remove(struct mdio_ - - /* Cancel any pending host flood work. dsa_unregister_switch() - * has already called port_teardown (which sets setup_done=false), -- * but a worker could still be blocked on rtnl_lock(). Since we -+ * but a worker could still be blocked on rtnl_lock(). Since we - * are now outside RTNL, cancel_work_sync() will not deadlock. - */ - for (i = 0; i < MXL862XX_MAX_PORTS; i++) --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h @@ -13,6 +13,8 @@ struct mxl862xx_priv; @@ -1504,7 +1424,7 @@ Signed-off-by: Daniel Golle /* Number of __le16 words in a firmware portmap (128-bit bitmap). */ #define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16) -@@ -86,12 +88,72 @@ static inline bool mxl862xx_fw_portmap_i +@@ -86,6 +88,66 @@ static inline bool mxl862xx_fw_portmap_i } /** @@ -1571,15 +1491,6 @@ Signed-off-by: Daniel Golle * struct mxl862xx_port - per-port state tracked by the driver * @priv: back-pointer to switch private data; needed by * deferred work handlers to access ds and priv -- * @fid: firmware FID for the permanent single-port bridge; -- * kept alive for the lifetime of the port so traffic is -- * never forwarded while the port is unbridged -+ * @fid: firmware FID for the permanent single-port bridge; kept -+ * alive for the lifetime of the port so traffic is never -+ * forwarded while the port is unbridged - * @portmap: bitmap of switch port indices that share the current - * bridge with this port - * @flood_block: bitmask of firmware meter indices that are currently @@ -101,6 +163,11 @@ static inline bool mxl862xx_fw_portmap_i * @setup_done: set at end of port_setup, cleared at start of * port_teardown; guards deferred work against diff --git a/target/linux/generic/pending-6.18/760-06-net-dsa-mxl862xx-add-ethtool-statistics-support.patch b/target/linux/generic/pending-6.18/760-06-net-dsa-mxl862xx-add-ethtool-statistics-support.patch index a1517ccde0..9788fb4021 100644 --- a/target/linux/generic/pending-6.18/760-06-net-dsa-mxl862xx-add-ethtool-statistics-support.patch +++ b/target/linux/generic/pending-6.18/760-06-net-dsa-mxl862xx-add-ethtool-statistics-support.patch @@ -1,7 +1,7 @@ -From 03b583e774835f771dd7c3c265be5903f008e8e5 Mon Sep 17 00:00:00 2001 +From 0067d79d10becfc5779fb50d5c0ac152cc5dc303 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 22 Mar 2026 00:57:33 +0000 -Subject: [PATCH 15/35] net: dsa: mxl862xx: add ethtool statistics support +Subject: [PATCH 06/26] net: dsa: mxl862xx: add ethtool statistics support The MxL862xx firmware exposes per-port RMON counters through the RMON_PORT_GET command, covering standard IEEE 802.3 MAC statistics @@ -257,7 +257,7 @@ Signed-off-by: Daniel Golle #define MXL862XX_SDMA_PCTRLP(p) (0xbc0 + ((p) * 0x6)) #define MXL862XX_SDMA_PCTRL_EN BIT(0) -@@ -1940,6 +1998,110 @@ static int mxl862xx_port_bridge_flags(st +@@ -1893,6 +1951,110 @@ static int mxl862xx_port_bridge_flags(st return 0; } @@ -368,7 +368,7 @@ Signed-off-by: Daniel Golle static const struct dsa_switch_ops mxl862xx_switch_ops = { .get_tag_protocol = mxl862xx_get_tag_protocol, .setup = mxl862xx_setup, -@@ -1964,6 +2126,12 @@ static const struct dsa_switch_ops mxl86 +@@ -1917,6 +2079,12 @@ static const struct dsa_switch_ops mxl86 .port_vlan_filtering = mxl862xx_port_vlan_filtering, .port_vlan_add = mxl862xx_port_vlan_add, .port_vlan_del = mxl862xx_port_vlan_del, diff --git a/target/linux/generic/pending-6.18/760-07-net-dsa-mxl862xx-implement-.get_stats64.patch b/target/linux/generic/pending-6.18/760-07-net-dsa-mxl862xx-implement-.get_stats64.patch index 9d4d93bc2d..55b81a7023 100644 --- a/target/linux/generic/pending-6.18/760-07-net-dsa-mxl862xx-implement-.get_stats64.patch +++ b/target/linux/generic/pending-6.18/760-07-net-dsa-mxl862xx-implement-.get_stats64.patch @@ -1,7 +1,7 @@ -From 8b66d20f7e5226f4854a39cfb9f25a0591a5bb83 Mon Sep 17 00:00:00 2001 +From bab5a69e3872a693069e430a1fa0d2825ea83b4f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 04:14:38 +0000 -Subject: [PATCH 16/35] net: dsa: mxl862xx: implement .get_stats64 +Subject: [PATCH 07/26] net: dsa: mxl862xx: implement .get_stats64 Poll free-running firmware RMON counters every 2 seconds and accumulate deltas into 64-bit per-port statistics. 32-bit packet counters wrap @@ -11,10 +11,49 @@ that counters are always up to date when queried. Signed-off-by: Daniel Golle --- - drivers/net/dsa/mxl862xx/mxl862xx.c | 167 ++++++++++++++++++++++++++++ - drivers/net/dsa/mxl862xx/mxl862xx.h | 51 +++++++++ - 2 files changed, 218 insertions(+) + drivers/net/dsa/mxl862xx/mxl862xx-host.c | 8 +- + drivers/net/dsa/mxl862xx/mxl862xx.c | 174 +++++++++++++++++++++++ + drivers/net/dsa/mxl862xx/mxl862xx.h | 63 +++++++- + 3 files changed, 238 insertions(+), 7 deletions(-) +--- a/drivers/net/dsa/mxl862xx/mxl862xx-host.c ++++ b/drivers/net/dsa/mxl862xx/mxl862xx-host.c +@@ -48,7 +48,7 @@ static void mxl862xx_crc_err_work_fn(str + dev_close(dp->conduit); + rtnl_unlock(); + +- clear_bit(0, &priv->crc_err); ++ clear_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags); + } + + /* Firmware CRC error codes (outside normal Zephyr errno range). */ +@@ -247,7 +247,7 @@ static int mxl862xx_issue_cmd(struct mxl + + ret = mxl862xx_crc6_verify(ctrl_enc, len_enc, &fw_result); + if (ret) { +- if (!test_and_set_bit(0, &priv->crc_err)) ++ if (!test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags)) + schedule_work(&priv->crc_err_work); + return -EIO; + } +@@ -314,7 +314,7 @@ static int mxl862xx_send_cmd(struct mxl8 + if (ret < 0) { + if ((ret == MXL862XX_FW_CRC6_ERR || + ret == MXL862XX_FW_CRC16_ERR) && +- !test_and_set_bit(0, &priv->crc_err)) ++ !test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags)) + schedule_work(&priv->crc_err_work); + if (!quiet) + dev_err(&priv->mdiodev->dev, +@@ -458,7 +458,7 @@ int mxl862xx_api_wrap(struct mxl862xx_pr + } + + if (crc16(0xffff, (const u8 *)data, size) != crc) { +- if (!test_and_set_bit(0, &priv->crc_err)) ++ if (!test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags)) + schedule_work(&priv->crc_err_work); + ret = -EIO; + goto out; --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c @@ -30,6 +30,12 @@ @@ -30,7 +69,7 @@ Signed-off-by: Daniel Golle struct mxl862xx_mib_desc { unsigned int size; unsigned int offset; -@@ -784,6 +790,9 @@ static int mxl862xx_setup(struct dsa_swi +@@ -739,6 +745,9 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; @@ -40,7 +79,7 @@ Signed-off-by: Daniel Golle return mxl862xx_setup_mdio(ds); } -@@ -2102,6 +2111,156 @@ static void mxl862xx_get_pause_stats(str +@@ -2055,6 +2064,158 @@ static void mxl862xx_get_pause_stats(str pause_stats->rx_pause_frames = le32_to_cpu(cnt.rx_good_pause_pkts); } @@ -160,8 +199,9 @@ Signed-off-by: Daniel Golle + dsa_switch_for_each_available_port(dp, ds) + mxl862xx_stats_poll(ds, dp->index); + -+ schedule_delayed_work(&priv->stats_work, -+ MXL862XX_STATS_POLL_INTERVAL); ++ if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags)) ++ schedule_delayed_work(&priv->stats_work, ++ MXL862XX_STATS_POLL_INTERVAL); +} + +static void mxl862xx_get_stats64(struct dsa_switch *ds, int port, @@ -189,15 +229,16 @@ Signed-off-by: Daniel Golle + spin_unlock_bh(&priv->ports[port].stats_lock); + + /* Trigger a fresh poll so the next read sees up-to-date counters. -+ * No-op if the work is already pending or running. ++ * No-op if the work is already pending, running, or teardown started. + */ -+ schedule_delayed_work(&priv->stats_work, 0); ++ if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags)) ++ schedule_delayed_work(&priv->stats_work, 0); +} + static const struct dsa_switch_ops mxl862xx_switch_ops = { .get_tag_protocol = mxl862xx_get_tag_protocol, .setup = mxl862xx_setup, -@@ -2132,6 +2291,7 @@ static const struct dsa_switch_ops mxl86 +@@ -2085,6 +2246,7 @@ static const struct dsa_switch_ops mxl86 .get_eth_mac_stats = mxl862xx_get_eth_mac_stats, .get_eth_ctrl_stats = mxl862xx_get_eth_ctrl_stats, .get_pause_stats = mxl862xx_get_pause_stats, @@ -205,7 +246,7 @@ Signed-off-by: Daniel Golle }; static void mxl862xx_phylink_mac_config(struct phylink_config *config, -@@ -2193,8 +2353,11 @@ static int mxl862xx_probe(struct mdio_de +@@ -2146,16 +2308,22 @@ static int mxl862xx_probe(struct mdio_de priv->ports[i].priv = priv; INIT_WORK(&priv->ports[i].host_flood_work, mxl862xx_host_flood_work_fn); @@ -216,20 +257,33 @@ Signed-off-by: Daniel Golle + dev_set_drvdata(dev, ds); - return dsa_register_switch(ds); -@@ -2213,6 +2376,8 @@ static void mxl862xx_remove(struct mdio_ + err = dsa_register_switch(ds); + if (err) { ++ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); ++ cancel_delayed_work_sync(&priv->stats_work); + mxl862xx_host_shutdown(priv); + for (i = 0; i < MXL862XX_MAX_PORTS; i++) + cancel_work_sync(&priv->ports[i].host_flood_work); + } ++ + return err; + } - dsa_unregister_switch(ds); +@@ -2170,6 +2338,9 @@ static void mxl862xx_remove(struct mdio_ + priv = ds->priv; + ++ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); + cancel_delayed_work_sync(&priv->stats_work); + - mxl862xx_host_shutdown(priv); + dsa_unregister_switch(ds); - /* Cancel any pending host flood work. dsa_unregister_switch() -@@ -2237,6 +2402,8 @@ static void mxl862xx_shutdown(struct mdi + mxl862xx_host_shutdown(priv); +@@ -2196,6 +2367,9 @@ static void mxl862xx_shutdown(struct mdi dsa_switch_shutdown(ds); ++ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); + cancel_delayed_work_sync(&priv->stats_work); + mxl862xx_host_shutdown(priv); @@ -296,7 +350,7 @@ Signed-off-by: Daniel Golle */ struct mxl862xx_port { struct mxl862xx_priv *priv; -@@ -195,6 +240,9 @@ struct mxl862xx_port { +@@ -195,16 +240,25 @@ struct mxl862xx_port { bool host_flood_uc; bool host_flood_mc; struct work_struct host_flood_work; @@ -305,8 +359,26 @@ Signed-off-by: Daniel Golle + spinlock_t stats_lock; }; ++/* Bit indices for struct mxl862xx_priv::flags */ ++#define MXL862XX_FLAG_CRC_ERR 0 ++#define MXL862XX_FLAG_WORK_STOPPED 1 ++ /** -@@ -216,6 +264,8 @@ struct mxl862xx_port { + * struct mxl862xx_priv - driver private data for an MxL862xx switch + * @ds: pointer to the DSA switch instance + * @mdiodev: MDIO device used to communicate with the switch firmware + * @crc_err_work: deferred work for shutting down all ports on MDIO CRC + * errors +- * @crc_err: set atomically before CRC-triggered shutdown, cleared +- * after ++ * @flags: atomic status flags; %MXL862XX_FLAG_CRC_ERR is set ++ * before CRC-triggered shutdown and cleared after; ++ * %MXL862XX_FLAG_WORK_STOPPED is set before cancelling ++ * stats_work to prevent rescheduling during teardown + * @drop_meter: index of the single shared zero-rate firmware meter + * used to unconditionally drop traffic (used to block + * flooding) +@@ -216,18 +270,21 @@ struct mxl862xx_port { * @evlan_ingress_size: per-port ingress Extended VLAN block size * @evlan_egress_size: per-port egress Extended VLAN block size * @vf_block_size: per-port VLAN Filter block size @@ -315,7 +387,13 @@ Signed-off-by: Daniel Golle */ struct mxl862xx_priv { struct dsa_switch *ds; -@@ -228,6 +278,7 @@ struct mxl862xx_priv { + struct mdio_device *mdiodev; + struct work_struct crc_err_work; +- unsigned long crc_err; ++ unsigned long flags; + u16 drop_meter; + struct mxl862xx_port ports[MXL862XX_MAX_PORTS]; + u16 bridges[MXL862XX_MAX_BRIDGES + 1]; u16 evlan_ingress_size; u16 evlan_egress_size; u16 vf_block_size; diff --git a/target/linux/generic/pending-6.18/760-08-net-dsa-mxl862xx-store-firmware-version-for-feature-.patch b/target/linux/generic/pending-6.18/760-08-net-dsa-mxl862xx-store-firmware-version-for-feature-.patch index d62b466029..03aeb8c9b7 100644 --- a/target/linux/generic/pending-6.18/760-08-net-dsa-mxl862xx-store-firmware-version-for-feature-.patch +++ b/target/linux/generic/pending-6.18/760-08-net-dsa-mxl862xx-store-firmware-version-for-feature-.patch @@ -1,7 +1,7 @@ -From fecfbea928cd762b19ff17aa16fb1ab143d73db1 Mon Sep 17 00:00:00 2001 +From da12469e73282da814163125153f381823e33f20 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 17:56:35 +0000 -Subject: [PATCH 17/35] net: dsa: mxl862xx: store firmware version for feature +Subject: [PATCH 08/26] net: dsa: mxl862xx: store firmware version for feature gating Query the firmware version at init (already done in wait_ready), @@ -40,10 +40,11 @@ Signed-off-by: Daniel Golle #include #include #include -@@ -246,6 +247,38 @@ struct mxl862xx_port { +@@ -245,6 +246,38 @@ struct mxl862xx_port { + spinlock_t stats_lock; }; - /** ++/** + * union mxl862xx_fw_version - firmware version for comparison and display + * @major: firmware major version + * @minor: firmware minor version @@ -75,11 +76,10 @@ Signed-off-by: Daniel Golle +#define MXL862XX_FW_VER_MIN(priv, maj, min, rev) \ + ((priv)->fw_version.raw >= MXL862XX_FW_VER(maj, min, rev)) + -+/** - * struct mxl862xx_priv - driver private data for an MxL862xx switch - * @ds: pointer to the DSA switch instance - * @mdiodev: MDIO device used to communicate with the switch firmware -@@ -256,6 +289,8 @@ struct mxl862xx_port { + /* Bit indices for struct mxl862xx_priv::flags */ + #define MXL862XX_FLAG_CRC_ERR 0 + #define MXL862XX_FLAG_WORK_STOPPED 1 +@@ -262,6 +295,8 @@ struct mxl862xx_port { * @drop_meter: index of the single shared zero-rate firmware meter * used to unconditionally drop traffic (used to block * flooding) @@ -88,9 +88,9 @@ Signed-off-by: Daniel Golle * @ports: per-port state, indexed by switch port number * @bridges: maps DSA bridge number to firmware bridge ID; * zero means no firmware bridge allocated for that -@@ -273,6 +308,7 @@ struct mxl862xx_priv { +@@ -279,6 +314,7 @@ struct mxl862xx_priv { struct work_struct crc_err_work; - unsigned long crc_err; + unsigned long flags; u16 drop_meter; + union mxl862xx_fw_version fw_version; struct mxl862xx_port ports[MXL862XX_MAX_PORTS]; diff --git a/target/linux/generic/pending-6.18/760-09-net-dsa-mxl862xx-move-phylink-stubs-to-mxl862xx-phyl.patch b/target/linux/generic/pending-6.18/760-09-net-dsa-mxl862xx-move-phylink-stubs-to-mxl862xx-phyl.patch index 833ec0642e..2ce4d1fb0e 100644 --- a/target/linux/generic/pending-6.18/760-09-net-dsa-mxl862xx-move-phylink-stubs-to-mxl862xx-phyl.patch +++ b/target/linux/generic/pending-6.18/760-09-net-dsa-mxl862xx-move-phylink-stubs-to-mxl862xx-phyl.patch @@ -1,7 +1,7 @@ -From 3cb224514226928df80e43ca2280c7dca654bdfe Mon Sep 17 00:00:00 2001 +From f7606470d398e4091e1bc405bf2125dc5fc99919 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 21:39:30 +0000 -Subject: [PATCH 18/35] net: dsa: mxl862xx: move phylink stubs to +Subject: [PATCH 09/26] net: dsa: mxl862xx: move phylink stubs to mxl862xx-phylink.c Move the phylink MAC operations and get_caps callback from mxl862xx.c @@ -110,7 +110,7 @@ Signed-off-by: Daniel Golle #define MXL862XX_API_WRITE(dev, cmd, data) \ mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), false, false) -@@ -1642,16 +1643,6 @@ static void mxl862xx_port_teardown(struc +@@ -1597,16 +1598,6 @@ static void mxl862xx_port_teardown(struc priv->ports[port].setup_done = false; } @@ -127,7 +127,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_get_fid(struct dsa_switch *ds, struct dsa_db db) { struct mxl862xx_priv *priv = ds->priv; -@@ -2297,33 +2288,6 @@ static const struct dsa_switch_ops mxl86 +@@ -2252,33 +2243,6 @@ static const struct dsa_switch_ops mxl86 .get_stats64 = mxl862xx_get_stats64, }; diff --git a/target/linux/generic/pending-6.18/760-10-net-dsa-mxl862xx-move-API-macros-to-mxl862xx-host.h.patch b/target/linux/generic/pending-6.18/760-10-net-dsa-mxl862xx-move-API-macros-to-mxl862xx-host.h.patch index 01013eec3e..7ac42cb3a6 100644 --- a/target/linux/generic/pending-6.18/760-10-net-dsa-mxl862xx-move-API-macros-to-mxl862xx-host.h.patch +++ b/target/linux/generic/pending-6.18/760-10-net-dsa-mxl862xx-move-API-macros-to-mxl862xx-host.h.patch @@ -1,7 +1,7 @@ -From de41d438c4e90876449715a307dd03fa37338742 Mon Sep 17 00:00:00 2001 +From e583eeeb907f0abeef2082162293a5d63b9fd6fa Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 26 Mar 2026 01:50:00 +0000 -Subject: [PATCH 19/35] net: dsa: mxl862xx: move API macros to mxl862xx-host.h +Subject: [PATCH 10/26] net: dsa: mxl862xx: move API macros to mxl862xx-host.h Move the MXL862XX_API_WRITE, MXL862XX_API_READ and MXL862XX_API_READ_QUIET convenience macros from mxl862xx.c to diff --git a/target/linux/generic/pending-6.18/760-11-net-dsa-mxl862xx-add-support-for-SerDes-ports.patch b/target/linux/generic/pending-6.18/760-11-net-dsa-mxl862xx-add-support-for-SerDes-ports.patch index 5680ac1747..ebd51cee4e 100644 --- a/target/linux/generic/pending-6.18/760-11-net-dsa-mxl862xx-add-support-for-SerDes-ports.patch +++ b/target/linux/generic/pending-6.18/760-11-net-dsa-mxl862xx-add-support-for-SerDes-ports.patch @@ -1,7 +1,7 @@ -From 88f46eb32d1aed296af2005c3ed8f23a6eea64c3 Mon Sep 17 00:00:00 2001 +From e25f0886853607e4a6d1157ae84e43e8224cf3b7 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 22 Mar 2026 00:57:44 +0000 -Subject: [PATCH 20/35] net: dsa: mxl862xx: add support for SerDes ports +Subject: [PATCH 11/26] net: dsa: mxl862xx: add support for SerDes ports The MxL862xx has two XPCS/SerDes interfaces (XPCS0 for ports 9-12, XPCS1 for ports 13-16). Each can operate in various single-lane @@ -1007,7 +1007,7 @@ Signed-off-by: Daniel Golle #endif /* __MXL862XX_PHYLINK_H */ --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -729,7 +729,7 @@ static int mxl862xx_setup(struct dsa_swi +@@ -684,7 +684,7 @@ static int mxl862xx_setup(struct dsa_swi int n_user_ports = 0, max_vlans; int ingress_finals, vid_rules; struct dsa_port *dp; @@ -1016,7 +1016,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_reset(priv); if (ret) -@@ -739,6 +739,9 @@ static int mxl862xx_setup(struct dsa_swi +@@ -694,6 +694,9 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; @@ -1051,7 +1051,7 @@ Signed-off-by: Daniel Golle * union mxl862xx_fw_version - firmware version for comparison and display * @major: firmware major version * @minor: firmware minor version -@@ -291,6 +307,8 @@ union mxl862xx_fw_version { +@@ -297,6 +313,8 @@ union mxl862xx_fw_version { * flooding) * @fw_version: cached firmware version, populated at probe and * compared with MXL862XX_FW_VER_MIN() @@ -1060,8 +1060,8 @@ Signed-off-by: Daniel Golle * @ports: per-port state, indexed by switch port number * @bridges: maps DSA bridge number to firmware bridge ID; * zero means no firmware bridge allocated for that -@@ -309,6 +327,7 @@ struct mxl862xx_priv { - unsigned long crc_err; +@@ -315,6 +333,7 @@ struct mxl862xx_priv { + unsigned long flags; u16 drop_meter; union mxl862xx_fw_version fw_version; + struct mxl862xx_pcs serdes_ports[8]; diff --git a/target/linux/generic/pending-6.18/760-12-net-dsa-mxl862xx-add-SerDes-ethtool-statistics.patch b/target/linux/generic/pending-6.18/760-12-net-dsa-mxl862xx-add-SerDes-ethtool-statistics.patch index 26c0452fb8..b5738eebc7 100644 --- a/target/linux/generic/pending-6.18/760-12-net-dsa-mxl862xx-add-SerDes-ethtool-statistics.patch +++ b/target/linux/generic/pending-6.18/760-12-net-dsa-mxl862xx-add-SerDes-ethtool-statistics.patch @@ -1,7 +1,7 @@ -From d40565e2e00fc2c8f04b9c571fcbea2f146db844 Mon Sep 17 00:00:00 2001 +From 24d752291784e30d7329bed15744bbbc6a3e2485 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:14:33 +0000 -Subject: [PATCH 21/35] net: dsa: mxl862xx: add SerDes ethtool statistics +Subject: [PATCH 12/26] net: dsa: mxl862xx: add SerDes ethtool statistics Expose SerDes equalization and signal detect parameters as ethtool statistics on ports 9-16 (XPCS-backed ports). Uses the XPCS EQ_GET @@ -239,7 +239,7 @@ Signed-off-by: Daniel Golle #endif /* __MXL862XX_PHYLINK_H */ --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -2007,6 +2007,8 @@ static void mxl862xx_get_strings(struct +@@ -1960,6 +1960,8 @@ static void mxl862xx_get_strings(struct for (i = 0; i < ARRAY_SIZE(mxl862xx_mib); i++) ethtool_puts(&data, mxl862xx_mib[i].name); @@ -248,7 +248,7 @@ Signed-off-by: Daniel Golle } static int mxl862xx_get_sset_count(struct dsa_switch *ds, int port, int sset) -@@ -2014,7 +2016,7 @@ static int mxl862xx_get_sset_count(struc +@@ -1967,7 +1969,7 @@ static int mxl862xx_get_sset_count(struc if (sset != ETH_SS_STATS) return 0; @@ -257,7 +257,7 @@ Signed-off-by: Daniel Golle } static int mxl862xx_read_rmon(struct dsa_switch *ds, int port, -@@ -2050,6 +2052,8 @@ static void mxl862xx_get_ethtool_stats(s +@@ -2003,6 +2005,8 @@ static void mxl862xx_get_ethtool_stats(s else *data++ = le64_to_cpu(*(__le64 *)field); } diff --git a/target/linux/generic/pending-6.18/760-13-net-dsa-mxl862xx-add-SerDes-self-test-via-PRBS-and-B.patch b/target/linux/generic/pending-6.18/760-13-net-dsa-mxl862xx-add-SerDes-self-test-via-PRBS-and-B.patch index 1fb76182d3..5760db143e 100644 --- a/target/linux/generic/pending-6.18/760-13-net-dsa-mxl862xx-add-SerDes-self-test-via-PRBS-and-B.patch +++ b/target/linux/generic/pending-6.18/760-13-net-dsa-mxl862xx-add-SerDes-self-test-via-PRBS-and-B.patch @@ -1,7 +1,7 @@ -From 54dd5fabc543f8538202367a863eb0e9161bacab Mon Sep 17 00:00:00 2001 +From ee227a5e4c74f599cc1b34578b32214d5873ad2f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:15:32 +0000 -Subject: [PATCH 22/35] net: dsa: mxl862xx: add SerDes self-test via PRBS and +Subject: [PATCH 13/26] net: dsa: mxl862xx: add SerDes self-test via PRBS and BERT Implement the dsa_switch_ops.self_test callback for SerDes ports @@ -198,7 +198,7 @@ Signed-off-by: Daniel Golle #endif /* __MXL862XX_PHYLINK_H */ --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -2286,6 +2286,7 @@ static const struct dsa_switch_ops mxl86 +@@ -2241,6 +2241,7 @@ static const struct dsa_switch_ops mxl86 .get_eth_ctrl_stats = mxl862xx_get_eth_ctrl_stats, .get_pause_stats = mxl862xx_get_pause_stats, .get_stats64 = mxl862xx_get_stats64, diff --git a/target/linux/generic/pending-6.18/760-14-net-dsa-mxl862xx-trap-link-local-frames-to-the-CPU-p.patch b/target/linux/generic/pending-6.18/760-14-net-dsa-mxl862xx-trap-link-local-frames-to-the-CPU-p.patch index 385e44f480..56d3612310 100644 --- a/target/linux/generic/pending-6.18/760-14-net-dsa-mxl862xx-trap-link-local-frames-to-the-CPU-p.patch +++ b/target/linux/generic/pending-6.18/760-14-net-dsa-mxl862xx-trap-link-local-frames-to-the-CPU-p.patch @@ -1,7 +1,7 @@ -From dd62e68cd0bd29934c3efbce687d5e103cc4b331 Mon Sep 17 00:00:00 2001 +From 43eb3eed250ea4e7e83371fcbf2bfb8d626eade6 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:51:13 +0000 -Subject: [PATCH 23/35] net: dsa: mxl862xx: trap link-local frames to the CPU +Subject: [PATCH 14/26] net: dsa: mxl862xx: trap link-local frames to the CPU port Install per-CTP PCE rules on each user port that trap IEEE 802.1D @@ -817,7 +817,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port) { struct mxl862xx_bridge_port_config br_port_cfg = {}; -@@ -1594,6 +1658,11 @@ static int mxl862xx_port_setup(struct ds +@@ -1549,6 +1613,11 @@ static int mxl862xx_port_setup(struct ds if (ret) return ret; diff --git a/target/linux/generic/pending-6.18/760-15-net-dsa-mxl862xx-warn-about-old-firmware-default-PCE.patch b/target/linux/generic/pending-6.18/760-15-net-dsa-mxl862xx-warn-about-old-firmware-default-PCE.patch index 38dc45c594..d590f54f47 100644 --- a/target/linux/generic/pending-6.18/760-15-net-dsa-mxl862xx-warn-about-old-firmware-default-PCE.patch +++ b/target/linux/generic/pending-6.18/760-15-net-dsa-mxl862xx-warn-about-old-firmware-default-PCE.patch @@ -1,7 +1,7 @@ -From 3bba25f7ba35e3bca8230bd37ffb612944dbf301 Mon Sep 17 00:00:00 2001 +From e18f5b235d8df21209c73f4f0bbc00cc3a1973ba Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:51:21 +0000 -Subject: [PATCH 24/35] net: dsa: mxl862xx: warn about old firmware default PCE +Subject: [PATCH 15/26] net: dsa: mxl862xx: warn about old firmware default PCE rules Firmware versions older than 1.0.80 install global PCE rules at @@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -854,6 +854,10 @@ static int mxl862xx_setup(struct dsa_swi +@@ -809,6 +809,10 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; diff --git a/target/linux/generic/pending-6.18/760-16-net-dsa-add-802.1Q-VLAN-based-tag-driver-for-MxL862x.patch b/target/linux/generic/pending-6.18/760-16-net-dsa-add-802.1Q-VLAN-based-tag-driver-for-MxL862x.patch index 8663883077..9b7a719db0 100644 --- a/target/linux/generic/pending-6.18/760-16-net-dsa-add-802.1Q-VLAN-based-tag-driver-for-MxL862x.patch +++ b/target/linux/generic/pending-6.18/760-16-net-dsa-add-802.1Q-VLAN-based-tag-driver-for-MxL862x.patch @@ -1,7 +1,7 @@ -From 1687c5632dfd80461b12425b943e30555faa3dd4 Mon Sep 17 00:00:00 2001 +From 04929904d3a7d824593587e52e3ed21d6f0f109a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 22 Mar 2026 00:58:04 +0000 -Subject: [PATCH 25/35] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx +Subject: [PATCH 16/26] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx The MxL862xx native 8-byte special tag (SpTag) requires firmware support on the switch CPU and is not compatible with all SoC Ethernet @@ -23,12 +23,12 @@ Signed-off-by: Daniel Golle drivers/net/dsa/mxl862xx/mxl862xx-api.h | 221 +++ drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 + drivers/net/dsa/mxl862xx/mxl862xx.c | 1626 ++++++++++++++++++++--- - drivers/net/dsa/mxl862xx/mxl862xx.h | 21 +- + drivers/net/dsa/mxl862xx/mxl862xx.h | 13 + include/net/dsa.h | 2 + net/dsa/Kconfig | 7 + net/dsa/Makefile | 1 + net/dsa/tag_mxl862xx_8021q.c | 59 + - 9 files changed, 1738 insertions(+), 202 deletions(-) + 9 files changed, 1736 insertions(+), 196 deletions(-) create mode 100644 net/dsa/tag_mxl862xx_8021q.c --- a/drivers/net/dsa/mxl862xx/Kconfig @@ -511,7 +511,7 @@ Signed-off-by: Daniel Golle err = mxl862xx_set_bridge_port(ds, port); if (err) -@@ -762,7 +909,6 @@ static void mxl862xx_free_bridge(struct +@@ -717,7 +864,6 @@ static void mxl862xx_free_bridge(struct static int mxl862xx_add_single_port_bridge(struct dsa_switch *ds, int port) { @@ -519,7 +519,7 @@ Signed-off-by: Daniel Golle struct mxl862xx_priv *priv = ds->priv; int ret; -@@ -774,15 +920,27 @@ static int mxl862xx_add_single_port_brid +@@ -729,15 +875,27 @@ static int mxl862xx_add_single_port_brid priv->ports[port].learning = false; bitmap_zero(priv->ports[port].portmap, MXL862XX_MAX_BRIDGE_PORTS); @@ -533,7 +533,6 @@ Signed-off-by: Daniel Golle - /* Standalone ports should not flood unknown unicast or multicast - * towards the CPU by default; only broadcast is needed initially. -- */ + /* In tag_8021q mode the TX path goes through the bridge engine + * (CTP ingress EVLAN reassigns to a virtual bridge port which + * then forwards via the bridge). With learning disabled on @@ -543,7 +542,7 @@ Signed-off-by: Daniel Golle + * In native SpTag mode, TX bypasses the bridge engine entirely + * (the special tag selects the egress port directly), so flood + * control only affects CPU-bound traffic and can be restrictive. -+ */ + */ + if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q) + return mxl862xx_bridge_config_fwd(ds, priv->ports[port].fid, + true, true, true); @@ -551,7 +550,7 @@ Signed-off-by: Daniel Golle return mxl862xx_bridge_config_fwd(ds, priv->ports[port].fid, false, false, true); } -@@ -790,10 +948,12 @@ static int mxl862xx_add_single_port_brid +@@ -745,10 +903,12 @@ static int mxl862xx_add_single_port_brid static int mxl862xx_setup(struct dsa_switch *ds) { struct mxl862xx_priv *priv = ds->priv; @@ -566,7 +565,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_reset(priv); if (ret) -@@ -806,7 +966,7 @@ static int mxl862xx_setup(struct dsa_swi +@@ -761,7 +921,7 @@ static int mxl862xx_setup(struct dsa_swi for (i = 0; i < 8; i++) mxl862xx_setup_pcs(priv, &priv->serdes_ports[i], i + 9); @@ -575,7 +574,7 @@ Signed-off-by: Daniel Golle * With VLAN Filter handling VID membership checks: * Ingress: only final catchall rules (PVID insertion, 802.1Q * accept, non-8021Q TPID handling, discard). -@@ -814,40 +974,67 @@ static int mxl862xx_setup(struct dsa_swi +@@ -769,40 +929,67 @@ static int mxl862xx_setup(struct dsa_swi * ingress EVLAN rules are needed. (7 entries.) * Egress: 2 rules per VID that needs tag stripping (untagged VIDs). * No egress final catchalls -- VLAN Filter does the discard. @@ -657,7 +656,7 @@ Signed-off-by: Daniel Golle } ret = mxl862xx_setup_drop_meter(ds); -@@ -858,6 +1045,68 @@ static int mxl862xx_setup(struct dsa_swi +@@ -813,6 +1000,68 @@ static int mxl862xx_setup(struct dsa_swi dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules " "that interfere with DSA operation, please update\n"); @@ -726,7 +725,7 @@ Signed-off-by: Daniel Golle schedule_delayed_work(&priv->stats_work, MXL862XX_STATS_POLL_INTERVAL); -@@ -939,6 +1188,52 @@ static int mxl862xx_configure_sp_tag_pro +@@ -894,6 +1143,52 @@ static int mxl862xx_configure_sp_tag_pro } /** @@ -779,7 +778,7 @@ Signed-off-by: Daniel Golle * mxl862xx_evlan_write_rule - Write a single Extended VLAN rule to hardware * @priv: driver private data * @block_id: HW Extended VLAN block ID -@@ -947,6 +1242,7 @@ static int mxl862xx_configure_sp_tag_pro +@@ -902,6 +1197,7 @@ static int mxl862xx_configure_sp_tag_pro * @vid: VLAN ID for VID-specific rules (ignored when !desc->match_vid) * @untagged: strip tag on egress for EVLAN_STRIP_IF_UNTAGGED action * @pvid: port VLAN ID for PVID insertion rules (0 = no PVID) @@ -787,7 +786,7 @@ Signed-off-by: Daniel Golle * * Translates a compact rule descriptor into a full firmware * mxl862xx_extendedvlan_config struct and writes it via the API. -@@ -954,7 +1250,8 @@ static int mxl862xx_configure_sp_tag_pro +@@ -909,7 +1205,8 @@ static int mxl862xx_configure_sp_tag_pro static int mxl862xx_evlan_write_rule(struct mxl862xx_priv *priv, u16 block_id, u16 entry_index, const struct mxl862xx_evlan_rule_desc *desc, @@ -797,7 +796,7 @@ Signed-off-by: Daniel Golle { struct mxl862xx_extendedvlan_config cfg = {}; struct mxl862xx_extendedvlan_filter_vlan *fv; -@@ -1044,6 +1341,31 @@ static int mxl862xx_evlan_write_rule(str +@@ -999,6 +1296,31 @@ static int mxl862xx_evlan_write_rule(str cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM); } break; @@ -829,7 +828,7 @@ Signed-off-by: Daniel Golle } return MXL862XX_API_WRITE(priv, MXL862XX_EXTENDEDVLAN_SET, cfg); -@@ -1104,7 +1426,7 @@ static int mxl862xx_evlan_write_final_ru +@@ -1059,7 +1381,7 @@ static int mxl862xx_evlan_write_final_ru for (i = 0; i < n_rules; i++) { ret = mxl862xx_evlan_write_rule(priv, blk->block_id, start_idx + i, &rules[i], @@ -838,7 +837,7 @@ Signed-off-by: Daniel Golle if (ret) return ret; } -@@ -1273,6 +1595,27 @@ static int mxl862xx_vf_del_vid(struct mx +@@ -1228,6 +1550,27 @@ static int mxl862xx_vf_del_vid(struct mx } /** @@ -866,7 +865,7 @@ Signed-off-by: Daniel Golle * mxl862xx_evlan_program_ingress - Write the fixed ingress catchall rules * @priv: driver private data * @port: port number -@@ -1323,8 +1666,8 @@ static int mxl862xx_evlan_program_egress +@@ -1278,8 +1621,8 @@ static int mxl862xx_evlan_program_egress const struct mxl862xx_evlan_rule_desc *vid_rules; struct mxl862xx_vf_vid *vfv; u16 old_active = blk->n_active; @@ -876,7 +875,7 @@ Signed-off-by: Daniel Golle if (p->vlan_filtering) { vid_rules = vid_accept_standard; -@@ -1341,13 +1684,23 @@ static int mxl862xx_evlan_program_egress +@@ -1296,13 +1639,23 @@ static int mxl862xx_evlan_program_egress if (p->vlan_filtering && !vfv->untagged) continue; @@ -901,7 +900,7 @@ Signed-off-by: Daniel Golle if (ret) return ret; -@@ -1356,7 +1709,29 @@ static int mxl862xx_evlan_program_egress +@@ -1311,7 +1664,29 @@ static int mxl862xx_evlan_program_egress idx++, &vid_rules[1], vfv->vid, vfv->untagged, @@ -932,7 +931,7 @@ Signed-off-by: Daniel Golle if (ret) return ret; } -@@ -1368,8 +1743,7 @@ static int mxl862xx_evlan_program_egress +@@ -1323,8 +1698,7 @@ static int mxl862xx_evlan_program_egress */ for (i = idx; i < old_active; i++) { ret = mxl862xx_evlan_deactivate_entry(priv, @@ -942,7 +941,7 @@ Signed-off-by: Daniel Golle if (ret) return ret; } -@@ -1393,13 +1767,16 @@ static int mxl862xx_port_vlan_filtering( +@@ -1348,13 +1722,16 @@ static int mxl862xx_port_vlan_filtering( /* Reprogram Extended VLAN rules if filtering mode changed */ if (changed) { @@ -964,7 +963,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_evlan_program_ingress(priv, port); if (ret) -@@ -1536,18 +1913,19 @@ static int mxl862xx_setup_cpu_bridge(str +@@ -1491,18 +1868,19 @@ static int mxl862xx_setup_cpu_bridge(str /* include all assigned user ports in the CPU portmap */ bitmap_zero(p->portmap, MXL862XX_MAX_BRIDGE_PORTS); @@ -990,7 +989,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port, const struct dsa_bridge bridge, bool *tx_fwd_offload, -@@ -1580,7 +1958,6 @@ static int mxl862xx_port_bridge_join(str +@@ -1535,7 +1913,6 @@ static int mxl862xx_port_bridge_join(str static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port, const struct dsa_bridge bridge) { @@ -998,7 +997,7 @@ Signed-off-by: Daniel Golle struct mxl862xx_priv *priv = ds->priv; struct mxl862xx_port *p = &priv->ports[port]; int err; -@@ -1595,34 +1972,587 @@ static void mxl862xx_port_bridge_leave(s +@@ -1550,34 +1927,587 @@ static void mxl862xx_port_bridge_leave(s * single-port bridge */ bitmap_zero(p->portmap, MXL862XX_MAX_BRIDGE_PORTS); @@ -1010,14 +1009,14 @@ Signed-off-by: Daniel Golle - /* Detach EVLAN and VF blocks from the bridge port BEFORE freeing - * them. The firmware tracks a usage count per block and rejects - * FREE while the count is non-zero. +- * +- * For EVLAN: setting in_use=false makes set_bridge_port send +- * enable=false, which decrements the firmware refcount. + /* Reset VLAN state for standalone mode. Ingress EVLAN is not + * needed outside a VLAN-aware bridge. Egress EVLAN is + * reprogrammed below -- in tag_8021q mode it gets the + * management VID strip catchalls, in SpTag mode it is cleared. * -- * For EVLAN: setting in_use=false makes set_bridge_port send -- * enable=false, which decrements the firmware refcount. -- * - * For VF: set_bridge_port sees dp->bridge == NULL (DSA already - * cleared it) and sends vlan_filter_enable=0, which decrements - * the firmware VF refcount. @@ -1597,7 +1596,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_port_setup(struct dsa_switch *ds, int port) { struct mxl862xx_priv *priv = ds->priv; -@@ -1642,55 +2572,30 @@ static int mxl862xx_port_setup(struct ds +@@ -1597,55 +2527,30 @@ static int mxl862xx_port_setup(struct ds dsa_port_is_dsa(dp)) return 0; @@ -1660,7 +1659,7 @@ Signed-off-by: Daniel Golle return 0; } -@@ -1712,7 +2617,7 @@ static void mxl862xx_port_teardown(struc +@@ -1667,7 +2572,7 @@ static void mxl862xx_port_teardown(struc priv->ports[port].setup_done = false; } @@ -1669,7 +1668,7 @@ Signed-off-by: Daniel Golle { struct mxl862xx_priv *priv = ds->priv; -@@ -1730,23 +2635,244 @@ static int mxl862xx_get_fid(struct dsa_s +@@ -1685,23 +2590,244 @@ static int mxl862xx_get_fid(struct dsa_s } } @@ -1702,7 +1701,8 @@ Signed-off-by: Daniel Golle + if (dsa_is_cpu_port(ds, port) && priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && + db.type == DSA_DB_PORT) { + bp_cpu = priv->ports[db.dp->index].bridge_port_cpu; -+ + +- param.port_id = cpu_to_le32(port); + if (bp_cpu) + return bp_cpu; + } @@ -1719,8 +1719,7 @@ Signed-off-by: Daniel Golle +{ + struct mxl862xx_mac_table_add param = {}; + struct mxl862xx_priv *priv = ds->priv; - -- param.port_id = cpu_to_le32(port); ++ + param.port_id = cpu_to_le32(port_id); param.static_entry = true; param.fid = cpu_to_le16(fid); @@ -1922,7 +1921,7 @@ Signed-off-by: Daniel Golle if (ret) dev_err(ds->dev, "failed to add FDB entry on port %d\n", port); -@@ -1756,18 +2882,25 @@ static int mxl862xx_port_fdb_add(struct +@@ -1711,18 +2837,25 @@ static int mxl862xx_port_fdb_add(struct static int mxl862xx_port_fdb_del(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid, const struct dsa_db db) { @@ -1955,7 +1954,7 @@ Signed-off-by: Daniel Golle if (ret) dev_err(ds->dev, "failed to remove FDB entry on port %d\n", port); -@@ -1806,88 +2939,147 @@ static int mxl862xx_port_fdb_dump(struct +@@ -1761,88 +2894,147 @@ static int mxl862xx_port_fdb_dump(struct return 0; } @@ -2097,7 +2096,7 @@ Signed-off-by: Daniel Golle - int fid = mxl862xx_get_fid(ds, db), ret; struct mxl862xx_priv *priv = ds->priv; + int fid, ret; -+ + + /* tag_8021q host MDB for bridged ports: clear all VBP bits */ + if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && dsa_is_cpu_port(ds, port) && + db.type == DSA_DB_BRIDGE) { @@ -2107,7 +2106,7 @@ Signed-off-by: Daniel Golle + return mxl862xx_mac_del_host_bridge(ds, mdb->addr, + mdb->vid, &db.bridge); + } - ++ + fid = mxl862xx_get_fid(ds, db); if (fid < 0) return fid; @@ -2154,7 +2153,7 @@ Signed-off-by: Daniel Golle return ret; } -@@ -1975,7 +3167,9 @@ static void mxl862xx_host_flood_work_fn( +@@ -1930,7 +3122,9 @@ static void mxl862xx_host_flood_work_fn( struct mxl862xx_priv *priv = p->priv; struct dsa_switch *ds = priv->ds; int port = p - priv->ports; @@ -2164,7 +2163,7 @@ Signed-off-by: Daniel Golle rtnl_lock(); -@@ -1988,14 +3182,31 @@ static void mxl862xx_host_flood_work_fn( +@@ -1943,14 +3137,35 @@ static void mxl862xx_host_flood_work_fn( uc = p->host_flood_uc; mc = p->host_flood_mc; @@ -2195,8 +2194,12 @@ Signed-off-by: Daniel Golle + port, ERR_PTR(ret)); + } + } else { -+ /* SpTag mode: per-FID forwarding, only works for -+ * standalone ports (each has its own FID). ++ /* The hardware controls unknown-unicast/multicast forwarding ++ * per FID (bridge), not per source port. For bridged ports all ++ * members share one FID, so we cannot selectively suppress ++ * flooding to the CPU for one source port while allowing it ++ * for another. Silently ignore the request -- the excess ++ * flooding towards the CPU is harmless. + */ + if (!dsa_port_bridge_dev_get(dsa_to_port(ds, port))) + mxl862xx_bridge_config_fwd(ds, p->fid, uc, mc, true); @@ -2204,7 +2207,7 @@ Signed-off-by: Daniel Golle rtnl_unlock(); } -@@ -2330,7 +3541,9 @@ static void mxl862xx_get_stats64(struct +@@ -2285,7 +3500,9 @@ static void mxl862xx_get_stats64(struct static const struct dsa_switch_ops mxl862xx_switch_ops = { .get_tag_protocol = mxl862xx_get_tag_protocol, @@ -2214,7 +2217,7 @@ Signed-off-by: Daniel Golle .port_setup = mxl862xx_port_setup, .port_teardown = mxl862xx_port_teardown, .phylink_get_caps = mxl862xx_phylink_get_caps, -@@ -2352,6 +3565,8 @@ static const struct dsa_switch_ops mxl86 +@@ -2307,6 +3524,8 @@ static const struct dsa_switch_ops mxl86 .port_vlan_filtering = mxl862xx_port_vlan_filtering, .port_vlan_add = mxl862xx_port_vlan_add, .port_vlan_del = mxl862xx_port_vlan_del, @@ -2223,7 +2226,7 @@ Signed-off-by: Daniel Golle .get_strings = mxl862xx_get_strings, .get_sset_count = mxl862xx_get_sset_count, .get_ethtool_stats = mxl862xx_get_ethtool_stats, -@@ -2399,6 +3614,8 @@ static int mxl862xx_probe(struct mdio_de +@@ -2354,6 +3573,8 @@ static int mxl862xx_probe(struct mdio_de INIT_DELAYED_WORK(&priv->stats_work, mxl862xx_stats_work_fn); @@ -2231,10 +2234,10 @@ Signed-off-by: Daniel Golle + dev_set_drvdata(dev, ds); - return dsa_register_switch(ds); -@@ -2415,16 +3632,29 @@ static void mxl862xx_remove(struct mdio_ - - priv = ds->priv; + err = dsa_register_switch(ds); +@@ -2382,6 +3603,19 @@ static void mxl862xx_remove(struct mdio_ + set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); + cancel_delayed_work_sync(&priv->stats_work); + /* Tear down tag_8021q under RTNL before dsa_unregister_switch(). + * dsa_tag_8021q_unregister() calls vlan_vid_del() which needs @@ -2251,39 +2254,9 @@ Signed-off-by: Daniel Golle + dsa_unregister_switch(ds); - cancel_delayed_work_sync(&priv->stats_work); - mxl862xx_host_shutdown(priv); - -- /* Cancel any pending host flood work. dsa_unregister_switch() -+ /* Cancel any pending host flood work. dsa_unregister_switch() - * has already called port_teardown (which sets setup_done=false), - * but a worker could still be blocked on rtnl_lock(). Since we -- * are now outside RTNL, cancel_work_sync() will not deadlock. -+ * are now outside RTNL, cancel_work_sync() won't deadlock. - */ - for (i = 0; i < MXL862XX_MAX_PORTS; i++) - cancel_work_sync(&priv->ports[i].host_flood_work); --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h -@@ -8,8 +8,6 @@ - #include - #include - --struct mxl862xx_priv; -- - #define MXL862XX_MAX_PORTS 17 - #define MXL862XX_DEFAULT_BRIDGE 0 - #define MXL862XX_MAX_BRIDGES 48 -@@ -20,6 +18,8 @@ struct mxl862xx_priv; - /* Number of __le16 words in a firmware portmap (128-bit bitmap). */ - #define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16) - -+struct mxl862xx_priv; -+ - /** - * mxl862xx_fw_portmap_from_bitmap - convert a kernel bitmap to a firmware - * portmap (__le16[8]) @@ -210,6 +210,9 @@ struct mxl862xx_port_stats { * @vf: per-port VLAN Filter block state * @ingress_evlan: ingress extended VLAN block state @@ -2317,39 +2290,31 @@ Signed-off-by: Daniel Golle /* Hardware stats accumulation */ struct mxl862xx_port_stats stats; spinlock_t stats_lock; -@@ -302,6 +311,7 @@ union mxl862xx_fw_version { - * errors - * @crc_err: set atomically before CRC-triggered shutdown, cleared - * after +@@ -308,6 +317,7 @@ union mxl862xx_fw_version { + * before CRC-triggered shutdown and cleared after; + * %MXL862XX_FLAG_WORK_STOPPED is set before cancelling + * stats_work to prevent rescheduling during teardown + * @tag_proto: active DSA tag protocol (native or 8021q) * @drop_meter: index of the single shared zero-rate firmware meter * used to unconditionally drop traffic (used to block * flooding) -@@ -310,12 +320,13 @@ union mxl862xx_fw_version { - * @serdes_ports: SerDes interfaces incl. sub-interfaces in case of - * 10G_QXGMII - * @ports: per-port state, indexed by switch port number -+ * @evlan_ingress_size: per-port ingress Extended VLAN block size -+ * @evlan_egress_size: per-port egress Extended VLAN block size -+ * @cpu_evlan_ingress_size: CPU port ingress EVLAN block size (tag_8021q) - * @bridges: maps DSA bridge number to firmware bridge ID; - * zero means no firmware bridge allocated for that - * DSA bridge number. Indexed by dsa_bridge.num +@@ -322,6 +332,7 @@ union mxl862xx_fw_version { * (0 .. ds->max_num_bridges). -- * @evlan_ingress_size: per-port ingress Extended VLAN block size -- * @evlan_egress_size: per-port egress Extended VLAN block size + * @evlan_ingress_size: per-port ingress Extended VLAN block size + * @evlan_egress_size: per-port egress Extended VLAN block size ++ * @cpu_evlan_ingress_size: CPU port ingress EVLAN block size (tag_8021q) * @vf_block_size: per-port VLAN Filter block size * @stats_work: periodic work item that polls RMON hardware counters * and accumulates them into 64-bit per-port stats -@@ -325,6 +336,7 @@ struct mxl862xx_priv { +@@ -331,6 +342,7 @@ struct mxl862xx_priv { struct mdio_device *mdiodev; struct work_struct crc_err_work; - unsigned long crc_err; + unsigned long flags; + enum dsa_tag_protocol tag_proto; u16 drop_meter; union mxl862xx_fw_version fw_version; struct mxl862xx_pcs serdes_ports[8]; -@@ -332,6 +344,7 @@ struct mxl862xx_priv { +@@ -338,6 +350,7 @@ struct mxl862xx_priv { u16 bridges[MXL862XX_MAX_BRIDGES + 1]; u16 evlan_ingress_size; u16 evlan_egress_size; @@ -2359,16 +2324,15 @@ Signed-off-by: Daniel Golle }; --- a/include/net/dsa.h +++ b/include/net/dsa.h -@@ -56,6 +56,8 @@ struct tc_action; +@@ -56,6 +56,7 @@ struct tc_action; #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28 #define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29 #define DSA_TAG_PROTO_MXL862_VALUE 30 +#define DSA_TAG_PROTO_MXL862_8021Q_VALUE 31 -+ enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, -@@ -89,6 +91,7 @@ enum dsa_tag_protocol { +@@ -89,6 +90,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE, DSA_TAG_PROTO_VSC73XX_8021Q = DSA_TAG_PROTO_VSC73XX_8021Q_VALUE, DSA_TAG_PROTO_MXL862 = DSA_TAG_PROTO_MXL862_VALUE, diff --git a/target/linux/generic/pending-6.18/760-17-net-dsa-mxl862xx-add-link-aggregation-support.patch b/target/linux/generic/pending-6.18/760-17-net-dsa-mxl862xx-add-link-aggregation-support.patch index d373f6511f..0e4074254b 100644 --- a/target/linux/generic/pending-6.18/760-17-net-dsa-mxl862xx-add-link-aggregation-support.patch +++ b/target/linux/generic/pending-6.18/760-17-net-dsa-mxl862xx-add-link-aggregation-support.patch @@ -1,7 +1,7 @@ -From 31359e8b7673e656d0591a9eb5014b45911383ae Mon Sep 17 00:00:00 2001 +From 4e1d854199c166f617b93b7542e863e6a8ad2ccb Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 03:44:41 +0000 -Subject: [PATCH 26/35] net: dsa: mxl862xx: add link aggregation support +Subject: [PATCH 17/26] net: dsa: mxl862xx: add link aggregation support Implement LAG offloading via the firmware's trunking engine. A dedicated firmware bridge port is allocated per LAG and remains @@ -234,7 +234,7 @@ Signed-off-by: Daniel Golle return ret; } -@@ -1926,6 +2018,408 @@ static int mxl862xx_setup_cpu_bridge(str +@@ -1881,6 +1973,408 @@ static int mxl862xx_setup_cpu_bridge(str return mxl862xx_set_bridge_port(ds, port); } @@ -643,7 +643,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port, const struct dsa_bridge bridge, bool *tx_fwd_offload, -@@ -1952,7 +2446,18 @@ static int mxl862xx_port_bridge_join(str +@@ -1907,7 +2401,18 @@ static int mxl862xx_port_bridge_join(str return 0; } @@ -663,7 +663,7 @@ Signed-off-by: Daniel Golle } static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port, -@@ -2011,6 +2516,17 @@ static void mxl862xx_port_bridge_leave(s +@@ -1966,6 +2471,17 @@ static void mxl862xx_port_bridge_leave(s "failed to update CPU VBP for port %d: %pe\n", port, ERR_PTR(err)); @@ -681,7 +681,7 @@ Signed-off-by: Daniel Golle if (!dsa_bridge_ports(ds, bridge.dev)) mxl862xx_free_bridge(ds, &bridge); } -@@ -2636,18 +3152,17 @@ static int mxl862xx_get_fid(struct dsa_s +@@ -2591,18 +3107,17 @@ static int mxl862xx_get_fid(struct dsa_s } /** @@ -707,7 +707,7 @@ Signed-off-by: Daniel Golle */ static int mxl862xx_fdb_bridge_port(struct dsa_switch *ds, int port, const struct dsa_db db) -@@ -2663,7 +3178,7 @@ static int mxl862xx_fdb_bridge_port(stru +@@ -2618,7 +3133,7 @@ static int mxl862xx_fdb_bridge_port(stru return bp_cpu; } @@ -716,7 +716,7 @@ Signed-off-by: Daniel Golle } /** -@@ -2907,11 +3422,43 @@ static int mxl862xx_port_fdb_del(struct +@@ -2862,11 +3377,43 @@ static int mxl862xx_port_fdb_del(struct return ret; } @@ -760,7 +760,7 @@ Signed-off-by: Daniel Golle u32 entry_port_id; int ret; -@@ -2925,7 +3472,7 @@ static int mxl862xx_port_fdb_dump(struct +@@ -2880,7 +3427,7 @@ static int mxl862xx_port_fdb_dump(struct entry_port_id = le32_to_cpu(param.port_id); @@ -769,7 +769,7 @@ Signed-off-by: Daniel Golle ret = cb(param.mac, FIELD_GET(MXL862XX_TCI_VLAN_ID, le16_to_cpu(param.tci)), param.static_entry, data); -@@ -3562,6 +4109,11 @@ static const struct dsa_switch_ops mxl86 +@@ -3521,6 +4068,11 @@ static const struct dsa_switch_ops mxl86 .port_fdb_dump = mxl862xx_port_fdb_dump, .port_mdb_add = mxl862xx_port_mdb_add, .port_mdb_del = mxl862xx_port_mdb_del, @@ -781,7 +781,7 @@ Signed-off-by: Daniel Golle .port_vlan_filtering = mxl862xx_port_vlan_filtering, .port_vlan_add = mxl862xx_port_vlan_add, .port_vlan_del = mxl862xx_port_vlan_del, -@@ -3602,6 +4154,7 @@ static int mxl862xx_probe(struct mdio_de +@@ -3561,6 +4113,7 @@ static int mxl862xx_probe(struct mdio_de ds->num_ports = MXL862XX_MAX_PORTS; ds->fdb_isolation = true; ds->max_num_bridges = MXL862XX_MAX_BRIDGES; @@ -791,7 +791,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h -@@ -14,6 +14,19 @@ +@@ -16,6 +16,19 @@ struct mxl862xx_priv; #define MXL862XX_MAX_BRIDGE_PORTS 128 #define MXL862XX_TOTAL_EVLAN_ENTRIES 1024 #define MXL862XX_TOTAL_VF_ENTRIES 1024 @@ -835,9 +835,9 @@ Signed-off-by: Daniel Golle /* Hardware stats accumulation */ struct mxl862xx_port_stats stats; spinlock_t stats_lock; -@@ -328,6 +351,15 @@ union mxl862xx_fw_version { - * DSA bridge number. Indexed by dsa_bridge.num - * (0 .. ds->max_num_bridges). +@@ -334,6 +357,15 @@ union mxl862xx_fw_version { + * @evlan_egress_size: per-port egress Extended VLAN block size + * @cpu_evlan_ingress_size: CPU port ingress EVLAN block size (tag_8021q) * @vf_block_size: per-port VLAN Filter block size + * @lag_bridge_ports: maps DSA LAG ID to firmware bridge port ID; + * zero means no bridge port allocated for that LAG. @@ -851,7 +851,7 @@ Signed-off-by: Daniel Golle * @stats_work: periodic work item that polls RMON hardware counters * and accumulates them into 64-bit per-port stats */ -@@ -346,6 +378,8 @@ struct mxl862xx_priv { +@@ -352,6 +384,8 @@ struct mxl862xx_priv { u16 evlan_egress_size; u16 cpu_evlan_ingress_size; u16 vf_block_size; diff --git a/target/linux/generic/pending-6.18/760-18-net-dsa-mxl862xx-add-support-for-mirror-port.patch b/target/linux/generic/pending-6.18/760-18-net-dsa-mxl862xx-add-support-for-mirror-port.patch index faf69c0c0e..cdcbaee869 100644 --- a/target/linux/generic/pending-6.18/760-18-net-dsa-mxl862xx-add-support-for-mirror-port.patch +++ b/target/linux/generic/pending-6.18/760-18-net-dsa-mxl862xx-add-support-for-mirror-port.patch @@ -1,7 +1,7 @@ -From fbfa1b0649c578e0d43e3a61617b53a9a722efad Mon Sep 17 00:00:00 2001 +From 5528f38c3d709417625eb7f36628be31727a8221 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 12:05:29 +0000 -Subject: [PATCH 27/35] net: dsa: mxl862xx: add support for mirror port +Subject: [PATCH 18/26] net: dsa: mxl862xx: add support for mirror port The MxL862xx hardware supports a single monitor port which can be configured to mirror any other port's ingress and/or egress traffic. @@ -50,7 +50,7 @@ Signed-off-by: Daniel Golle #define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2) --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c -@@ -1129,6 +1129,8 @@ static int mxl862xx_setup(struct dsa_swi +@@ -1084,6 +1084,8 @@ static int mxl862xx_setup(struct dsa_swi (n_user_ports + n_cpu_ports); } @@ -59,7 +59,7 @@ Signed-off-by: Daniel Golle ret = mxl862xx_setup_drop_meter(ds); if (ret) return ret; -@@ -2018,6 +2020,120 @@ static int mxl862xx_setup_cpu_bridge(str +@@ -1973,6 +1975,120 @@ static int mxl862xx_setup_cpu_bridge(str return mxl862xx_set_bridge_port(ds, port); } @@ -180,7 +180,7 @@ Signed-off-by: Daniel Golle /** * mxl862xx_lag_master_port - Find the LAG master (lowest-numbered member) * @ds: DSA switch -@@ -4109,6 +4225,8 @@ static const struct dsa_switch_ops mxl86 +@@ -4068,6 +4184,8 @@ static const struct dsa_switch_ops mxl86 .port_fdb_dump = mxl862xx_port_fdb_dump, .port_mdb_add = mxl862xx_port_mdb_add, .port_mdb_del = mxl862xx_port_mdb_del, @@ -210,7 +210,7 @@ Signed-off-by: Daniel Golle /* LAG state */ struct dsa_lag *lag; bool lag_tx_enabled; -@@ -360,6 +365,8 @@ union mxl862xx_fw_version { +@@ -366,6 +371,8 @@ union mxl862xx_fw_version { * @trunk_hash: current global hash field bitmask (6 bits, * MXL862XX_TRUNK_HASH_*); union of all active LAGs' * hash requirements @@ -219,7 +219,7 @@ Signed-off-by: Daniel Golle * @stats_work: periodic work item that polls RMON hardware counters * and accumulates them into 64-bit per-port stats */ -@@ -380,6 +387,7 @@ struct mxl862xx_priv { +@@ -386,6 +393,7 @@ struct mxl862xx_priv { u16 vf_block_size; u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1]; u8 trunk_hash; diff --git a/target/linux/generic/pending-6.18/760-19-net-dsa-wire-flash_update-devlink-callback-to-driver.patch b/target/linux/generic/pending-6.18/760-19-net-dsa-wire-flash_update-devlink-callback-to-driver.patch index 98144a4c0d..2ab03a5d26 100644 --- a/target/linux/generic/pending-6.18/760-19-net-dsa-wire-flash_update-devlink-callback-to-driver.patch +++ b/target/linux/generic/pending-6.18/760-19-net-dsa-wire-flash_update-devlink-callback-to-driver.patch @@ -1,7 +1,7 @@ -From 67f82834819b71417b58dc1293c20f71b990264f Mon Sep 17 00:00:00 2001 +From 4059d35a5bbf1901b2e0eb7126369cd713cacfce Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 16:30:08 +0000 -Subject: [PATCH 28/35] net: dsa: wire flash_update devlink callback to drivers +Subject: [PATCH 19/26] net: dsa: wire flash_update devlink callback to drivers Add a devlink_flash_update callback to dsa_switch_ops so that DSA drivers can support devlink dev flash without open-coding the devlink @@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle --- a/include/net/dsa.h +++ b/include/net/dsa.h -@@ -1172,6 +1172,9 @@ struct dsa_switch_ops { +@@ -1171,6 +1171,9 @@ struct dsa_switch_ops { int (*devlink_info_get)(struct dsa_switch *ds, struct devlink_info_req *req, struct netlink_ext_ack *extack); diff --git a/target/linux/generic/pending-6.18/760-20-net-dsa-mxl862xx-add-SMDIO-clause-22-register-access.patch b/target/linux/generic/pending-6.18/760-20-net-dsa-mxl862xx-add-SMDIO-clause-22-register-access.patch index 17668b9734..2986143175 100644 --- a/target/linux/generic/pending-6.18/760-20-net-dsa-mxl862xx-add-SMDIO-clause-22-register-access.patch +++ b/target/linux/generic/pending-6.18/760-20-net-dsa-mxl862xx-add-SMDIO-clause-22-register-access.patch @@ -1,7 +1,7 @@ -From 1a87b829ef3280d646dc480f7b261d9e32896899 Mon Sep 17 00:00:00 2001 +From 0145151dc68aa318d8addb6fe7f12c0967f951da Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 16:30:17 +0000 -Subject: [PATCH 29/35] net: dsa: mxl862xx: add SMDIO clause-22 register access +Subject: [PATCH 20/26] net: dsa: mxl862xx: add SMDIO clause-22 register access Add mxl862xx_smdio_read() and mxl862xx_smdio_write() for clause-22 SMDIO register access. MCUboot rescue mode only exposes clause-22 diff --git a/target/linux/generic/pending-6.18/760-21-net-dsa-mxl862xx-add-devlink-flash_update-and-info_g.patch b/target/linux/generic/pending-6.18/760-21-net-dsa-mxl862xx-add-devlink-flash_update-and-info_g.patch index 28b91f8021..d731ec1b08 100644 --- a/target/linux/generic/pending-6.18/760-21-net-dsa-mxl862xx-add-devlink-flash_update-and-info_g.patch +++ b/target/linux/generic/pending-6.18/760-21-net-dsa-mxl862xx-add-devlink-flash_update-and-info_g.patch @@ -1,7 +1,7 @@ -From b7e8f8fd4493b255f0f01fe790a73ad61b5e8ce8 Mon Sep 17 00:00:00 2001 +From bdbca48510e3e96ed9210f20fa4244dd6df5d44a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 16:30:31 +0000 -Subject: [PATCH 30/35] net: dsa: mxl862xx: add devlink flash_update and +Subject: [PATCH 21/26] net: dsa: mxl862xx: add devlink flash_update and info_get Implement runtime firmware upgrade via "devlink dev flash" and version @@ -546,7 +546,7 @@ Signed-off-by: Daniel Golle #include "mxl862xx-host.h" #include "mxl862xx-phylink.h" -@@ -4245,6 +4246,9 @@ static const struct dsa_switch_ops mxl86 +@@ -4204,6 +4205,9 @@ static const struct dsa_switch_ops mxl86 .get_pause_stats = mxl862xx_get_pause_stats, .get_stats64 = mxl862xx_get_stats64, .self_test = mxl862xx_serdes_self_test, @@ -558,7 +558,7 @@ Signed-off-by: Daniel Golle static int mxl862xx_probe(struct mdio_device *mdiodev) --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h -@@ -388,6 +388,8 @@ struct mxl862xx_priv { +@@ -394,6 +394,8 @@ struct mxl862xx_priv { u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1]; u8 trunk_hash; int mirror_dest; diff --git a/target/linux/generic/pending-6.18/760-22-net-dsa-mxl862xx-implement-port-MTU-configuration.patch b/target/linux/generic/pending-6.18/760-22-net-dsa-mxl862xx-implement-port-MTU-configuration.patch index 1869a9f17c..1a22bba1f1 100644 --- a/target/linux/generic/pending-6.18/760-22-net-dsa-mxl862xx-implement-port-MTU-configuration.patch +++ b/target/linux/generic/pending-6.18/760-22-net-dsa-mxl862xx-implement-port-MTU-configuration.patch @@ -1,7 +1,7 @@ -From 2cb9aeb3a8d7ebac20331e0a533dcfbd73fa4237 Mon Sep 17 00:00:00 2001 +From 8deb5be9638f7eb3009ed3eb619eedadee1df523 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 23:42:18 +0000 -Subject: [PATCH 31/35] net: dsa: mxl862xx: implement port MTU configuration +Subject: [PATCH 22/26] net: dsa: mxl862xx: implement port MTU configuration The firmware exposes a global max_packet_len register via MXL862XX_COMMON_CFGSET. Since this is switch-wide rather than @@ -25,7 +25,7 @@ Signed-off-by: Daniel Golle #include #include #include -@@ -3768,6 +3769,53 @@ static int mxl862xx_set_ageing_time(stru +@@ -3723,6 +3724,53 @@ static int mxl862xx_set_ageing_time(stru return ret; } @@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle static void mxl862xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { -@@ -4215,6 +4263,8 @@ static const struct dsa_switch_ops mxl86 +@@ -4174,6 +4222,8 @@ static const struct dsa_switch_ops mxl86 .port_disable = mxl862xx_port_disable, .port_fast_age = mxl862xx_port_fast_age, .set_ageing_time = mxl862xx_set_ageing_time, diff --git a/target/linux/generic/pending-6.18/760-23-net-dsa-mxl862xx-support-BR_HAIRPIN_MODE-bridge-flag.patch b/target/linux/generic/pending-6.18/760-23-net-dsa-mxl862xx-support-BR_HAIRPIN_MODE-bridge-flag.patch index bf4d2f0ca7..dfbf953754 100644 --- a/target/linux/generic/pending-6.18/760-23-net-dsa-mxl862xx-support-BR_HAIRPIN_MODE-bridge-flag.patch +++ b/target/linux/generic/pending-6.18/760-23-net-dsa-mxl862xx-support-BR_HAIRPIN_MODE-bridge-flag.patch @@ -1,7 +1,7 @@ -From d55ca68eb0d20a66c32d531b0a454871b486c1b1 Mon Sep 17 00:00:00 2001 +From 13a4c918cd9ded7207f38033511ab13f7aff9bd2 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 01:47:19 +0000 -Subject: [PATCH 32/35] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag +Subject: [PATCH 23/26] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag Implement hairpin mode by including the port's own bridge port ID in its forwarding portmap. When hairpin is enabled, bridged frames whose @@ -18,9 +18,9 @@ bridge member rebuild since only the calling port is affected. Signed-off-by: Daniel Golle --- - drivers/net/dsa/mxl862xx/mxl862xx.c | 30 ++++++++++++++++++++++++++++- + drivers/net/dsa/mxl862xx/mxl862xx.c | 29 +++++++++++++++++++++++++++-- drivers/net/dsa/mxl862xx/mxl862xx.h | 6 ++++++ - 2 files changed, 35 insertions(+), 1 deletion(-) + 2 files changed, 33 insertions(+), 2 deletions(-) --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c @@ -40,7 +40,7 @@ Signed-off-by: Daniel Golle err = mxl862xx_set_bridge_port(ds, port); if (err) ret = err; -@@ -3939,7 +3948,7 @@ static int mxl862xx_port_pre_bridge_flag +@@ -3898,7 +3907,7 @@ static int mxl862xx_port_pre_bridge_flag struct netlink_ext_ack *extack) { if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | @@ -49,20 +49,19 @@ Signed-off-by: Daniel Golle return -EINVAL; return 0; -@@ -3954,6 +3963,7 @@ static int mxl862xx_port_bridge_flags(st +@@ -3912,6 +3921,7 @@ static int mxl862xx_port_bridge_flags(st + unsigned long old_block = priv->ports[port].flood_block; unsigned long block = old_block; - bool need_update = false; int ret; + u16 bp; if (flags.mask & BR_FLOOD) { if (flags.val & BR_FLOOD) -@@ -3988,6 +3998,24 @@ static int mxl862xx_port_bridge_flags(st - ret = mxl862xx_set_bridge_port(ds, port); - if (ret) - return ret; -+ } -+ +@@ -3940,7 +3950,22 @@ static int mxl862xx_port_bridge_flags(st + if (flags.mask & BR_LEARNING) + priv->ports[port].learning = !!(flags.val & BR_LEARNING); + +- if ((block != old_block) || (flags.mask & BR_LEARNING)) { + if (flags.mask & BR_HAIRPIN_MODE) { + bp = mxl862xx_lag_bridge_port(priv, port); + priv->ports[port].hairpin = !!(flags.val & BR_HAIRPIN_MODE); @@ -75,13 +74,13 @@ Signed-off-by: Daniel Golle + __set_bit(bp, priv->ports[port].portmap); + else + __clear_bit(bp, priv->ports[port].portmap); ++ } + -+ ret = mxl862xx_set_bridge_port(ds, port); -+ if (ret) -+ return ret; - } - - return 0; ++ if ((block != old_block) || ++ (flags.mask & (BR_LEARNING | BR_HAIRPIN_MODE))) { + priv->ports[port].flood_block = block; + ret = mxl862xx_set_bridge_port(ds, port); + if (ret) --- a/drivers/net/dsa/mxl862xx/mxl862xx.h +++ b/drivers/net/dsa/mxl862xx/mxl862xx.h @@ -241,6 +241,10 @@ struct mxl862xx_port_stats { diff --git a/target/linux/generic/pending-6.18/760-24-net-dsa-mxl862xx-support-BR_ISOLATED-bridge-flag.patch b/target/linux/generic/pending-6.18/760-24-net-dsa-mxl862xx-support-BR_ISOLATED-bridge-flag.patch index a524d157e5..c67d95d5c5 100644 --- a/target/linux/generic/pending-6.18/760-24-net-dsa-mxl862xx-support-BR_ISOLATED-bridge-flag.patch +++ b/target/linux/generic/pending-6.18/760-24-net-dsa-mxl862xx-support-BR_ISOLATED-bridge-flag.patch @@ -1,7 +1,7 @@ -From 74b6654ba74eb142340de4c51b97c0221cfcae37 Mon Sep 17 00:00:00 2001 +From d49d1f8bee29269def7593f980d0e08bfb5c3ef8 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Mar 2026 01:51:33 +0000 -Subject: [PATCH 33/35] net: dsa: mxl862xx: support BR_ISOLATED bridge flag +Subject: [PATCH 24/26] net: dsa: mxl862xx: support BR_ISOLATED bridge flag Implement port isolation by excluding isolated ports from each other's forwarding portmaps in sync_bridge_members. Non-isolated ports can @@ -34,7 +34,7 @@ Signed-off-by: Daniel Golle if (member != port) { bp = mxl862xx_lag_bridge_port(priv, member); -@@ -3948,7 +3956,7 @@ static int mxl862xx_port_pre_bridge_flag +@@ -3907,7 +3915,7 @@ static int mxl862xx_port_pre_bridge_flag struct netlink_ext_ack *extack) { if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | @@ -43,15 +43,15 @@ Signed-off-by: Daniel Golle return -EINVAL; return 0; -@@ -3962,6 +3970,7 @@ static int mxl862xx_port_bridge_flags(st +@@ -3920,6 +3928,7 @@ static int mxl862xx_port_bridge_flags(st + struct mxl862xx_priv *priv = ds->priv; unsigned long old_block = priv->ports[port].flood_block; unsigned long block = old_block; - bool need_update = false; + struct dsa_port *dp; int ret; u16 bp; -@@ -4018,6 +4027,21 @@ static int mxl862xx_port_bridge_flags(st +@@ -3972,6 +3981,21 @@ static int mxl862xx_port_bridge_flags(st return ret; } diff --git a/target/linux/generic/pending-6.18/760-25-DO-NOT-SUBMIT-net-dsa-mxl862xx-re-introduce-PCE-work.patch b/target/linux/generic/pending-6.18/760-25-DO-NOT-SUBMIT-net-dsa-mxl862xx-re-introduce-PCE-work.patch index 98cfb44d48..6e5d25069d 100644 --- a/target/linux/generic/pending-6.18/760-25-DO-NOT-SUBMIT-net-dsa-mxl862xx-re-introduce-PCE-work.patch +++ b/target/linux/generic/pending-6.18/760-25-DO-NOT-SUBMIT-net-dsa-mxl862xx-re-introduce-PCE-work.patch @@ -1,7 +1,7 @@ -From 0902a6790750714445c75a66d60f1bc4897126ce Mon Sep 17 00:00:00 2001 +From c2fb7f0df63ac994850f766e7f2eb50c6c5ef2cf Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:17:49 +0000 -Subject: [PATCH 34/35] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE +Subject: [PATCH 25/26] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE workaround for old firmware Re-introduce the mxl862xx_disable_fw_global_rules() function that @@ -64,7 +64,7 @@ Signed-off-by: Daniel Golle /* Per-CTP offset used for the link-local trap rule. Each port's CTP * flow-table block is pre-allocated by the firmware during init (44 -@@ -1154,9 +1191,11 @@ static int mxl862xx_setup(struct dsa_swi +@@ -1109,9 +1146,11 @@ static int mxl862xx_setup(struct dsa_swi if (ret) return ret; diff --git a/target/linux/generic/pending-6.18/760-26-DO-NOT-SUBMIT-net-dsa-mxl862xx-legacy-SFP-API-fallba.patch b/target/linux/generic/pending-6.18/760-26-DO-NOT-SUBMIT-net-dsa-mxl862xx-legacy-SFP-API-fallba.patch index 8a96401456..ddf7da101b 100644 --- a/target/linux/generic/pending-6.18/760-26-DO-NOT-SUBMIT-net-dsa-mxl862xx-legacy-SFP-API-fallba.patch +++ b/target/linux/generic/pending-6.18/760-26-DO-NOT-SUBMIT-net-dsa-mxl862xx-legacy-SFP-API-fallba.patch @@ -1,7 +1,7 @@ -From 0ac876d5b952218ab79ea0a0815cf6fd1290b1d0 Mon Sep 17 00:00:00 2001 +From f0548f842b9ff31f19452a2fc72a16f937d86008 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Mar 2026 18:19:56 +0000 -Subject: [PATCH 35/35] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API +Subject: [PATCH 26/26] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API fallback for old firmware Re-introduce the SYS_MISC_SFP_SET-based PCS implementation as a