kernel: update MxL862xx DSA driver

Introduce fix which prevents the kernel from crashing in case the mxl862xx
driver fails to probe due to outdated firmware running on the switch.
Cancel all pending work and prevent rescheduling of counter polling in case
the driver errors out during probe.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2026-03-31 03:13:41 +01:00
parent 598b90107e
commit 5ee6ddb461
54 changed files with 735 additions and 763 deletions

View File

@ -0,0 +1,37 @@
From 3fd163f5bb88de426ca9847549f94b4296170ef0 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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)

View File

@ -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 <daniel@makrotopia.org>
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.

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+/* 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
};
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 <daniel@makrotopia.org>
+
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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);

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
};
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 <daniel@makrotopia.org>
/* 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 <daniel@makrotopia.org>
* 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

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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,

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
};
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 <daniel@makrotopia.org>
+
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 <daniel@makrotopia.org>
*/
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
*/
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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#include <linux/mdio.h>
#include <linux/workqueue.h>
#include <net/dsa.h>
@@ -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 <daniel@makrotopia.org>
+#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 <daniel@makrotopia.org>
* @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];

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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,
};

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
* 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 <daniel@makrotopia.org>
* @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];

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
}
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);
}

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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,

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
--- 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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
- /* 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 <daniel@makrotopia.org>
+ * 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
* 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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
* 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 <daniel@makrotopia.org>
*
* 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 <daniel@makrotopia.org>
{
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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
* 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
- /* 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
{
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+{
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
- 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
.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 <daniel@makrotopia.org>
.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 <daniel@makrotopia.org>
+
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 <daniel@makrotopia.org>
+
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 <linux/workqueue.h>
#include <net/dsa.h>
-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 <daniel@makrotopia.org>
/* 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 <daniel@makrotopia.org>
};
--- 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,

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
*/
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 <daniel@makrotopia.org>
}
/**
@@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
.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 <daniel@makrotopia.org>
--- 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 <daniel@makrotopia.org>
/* 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 <daniel@makrotopia.org>
* @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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
/**
* 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 <daniel@makrotopia.org>
/* 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 <daniel@makrotopia.org>
* @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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
--- 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);

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
@@ -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 <daniel@makrotopia.org>
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,

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ __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 {

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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;
}

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
/* 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;

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -0,0 +1,37 @@
From 3fd163f5bb88de426ca9847549f94b4296170ef0 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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)

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+/* 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
};
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 <daniel@makrotopia.org>
+
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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);

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
};
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 <daniel@makrotopia.org>
/* 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 <daniel@makrotopia.org>
* 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

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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,

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
};
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 <daniel@makrotopia.org>
+
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 <daniel@makrotopia.org>
*/
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
*/
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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#include <linux/mdio.h>
#include <linux/workqueue.h>
#include <net/dsa.h>
@@ -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 <daniel@makrotopia.org>
+#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 <daniel@makrotopia.org>
* @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];

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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,
};

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
* 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 <daniel@makrotopia.org>
* @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];

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
}
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);
}

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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,

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
--- 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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
- /* 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 <daniel@makrotopia.org>
+ * 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
* 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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
* 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 <daniel@makrotopia.org>
*
* 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 <daniel@makrotopia.org>
{
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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
* 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
- /* 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
{
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
+{
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
- 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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ 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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
.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 <daniel@makrotopia.org>
.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 <daniel@makrotopia.org>
+
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 <daniel@makrotopia.org>
+
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 <linux/workqueue.h>
#include <net/dsa.h>
-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 <daniel@makrotopia.org>
/* 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 <daniel@makrotopia.org>
};
--- 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,

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
}
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
*/
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 <daniel@makrotopia.org>
}
/**
@@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
.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 <daniel@makrotopia.org>
--- 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 <daniel@makrotopia.org>
/* 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 <daniel@makrotopia.org>
* @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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
/**
* 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 <daniel@makrotopia.org>
/* 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 <daniel@makrotopia.org>
* @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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
--- 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);

View File

@ -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 <daniel@makrotopia.org>
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

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#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 <daniel@makrotopia.org>
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;

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
@@ -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 <daniel@makrotopia.org>
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,

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
---
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
+ __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 {

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
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;
}

View File

@ -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 <daniel@makrotopia.org>
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 <daniel@makrotopia.org>
/* 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;

View File

@ -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 <daniel@makrotopia.org>
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