mirror of
https://git.openwrt.org/openwrt/openwrt.git
synced 2026-05-04 17:36:12 +02:00
generic: 6.12: sync MxL862xx driver with upstream Linux
Swap pending with accepted patches, rebase remaining pending patches on top of new upstream. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
parent
0d21956ecd
commit
f0f6fa2e28
@ -1,13 +1,16 @@
|
||||
From 3fd163f5bb88de426ca9847549f94b4296170ef0 Mon Sep 17 00:00:00 2001
|
||||
From e9abf1da0af3f787a03b249945e5ca726c1b8013 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Mon, 30 Mar 2026 23:40:53 +0100
|
||||
Date: Mon, 30 Mar 2026 23:52:09 +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)"
|
||||
Fixes: a319d0c8c8ce ("net: dsa: mxl862xx: add CRC for MDIO communication")
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Link: https://patch.msgid.link/3fd163f5bb88de426ca9847549f94b4296170ef0.1774911025.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
@ -1,7 +1,7 @@
|
||||
From cd698f1ae94c16499e2714b31dd6048e6f9f068d Mon Sep 17 00:00:00 2001
|
||||
From b0a79590d10847f190ed377d2664377d7068191d Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 17:54:11 +0000
|
||||
Subject: [PATCH 01/26] net: dsa: move dsa_bridge_ports() helper to dsa.h
|
||||
Date: Wed, 1 Apr 2026 14:34:30 +0100
|
||||
Subject: [PATCH 1/4] 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.
|
||||
@ -10,9 +10,11 @@ Move the helper as static inline function into dsa.h, so other driver
|
||||
can make use of it as well.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/4f8bbfce3e4e3a02064fc4dc366263136c6e0383.1775049897.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
include/net/dsa.h | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
include/net/dsa.h | 13 +++++++++++++
|
||||
2 files changed, 13 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@ -1,7 +1,7 @@
|
||||
From c161533e1605a7282563c139323a3913890fdb72 Mon Sep 17 00:00:00 2001
|
||||
From f259e08494c47c614ce7b6d3079d1e0d3f30ae66 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 17:54:41 +0000
|
||||
Subject: [PATCH 02/26] net: dsa: add bridge member iteration macro
|
||||
Date: Wed, 1 Apr 2026 14:34:42 +0100
|
||||
Subject: [PATCH 2/4] 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
|
||||
@ -15,6 +15,8 @@ directly, and use it for the existing dsa_bridge_ports() inline
|
||||
helper.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/e7136aaa26773f39e805a00fe4ecf13cd2b83fc0.1775049897.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
include/net/dsa.h | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
@ -1,7 +1,7 @@
|
||||
From 753efe27a9afee52c4ad42098a9b9278366d63cc Mon Sep 17 00:00:00 2001
|
||||
From 4250ff1640ea1ede99bfe02ca949acbcc6c0927f Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 17:54:52 +0000
|
||||
Subject: [PATCH 03/26] dsa: tag_mxl862xx: set dsa_default_offload_fwd_mark()
|
||||
Date: Wed, 1 Apr 2026 14:34:52 +0100
|
||||
Subject: [PATCH 3/4] 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
|
||||
@ -11,6 +11,8 @@ Link-local frames are directly trapped to the CPU port only, so don't
|
||||
set dsa_default_offload_fwd_mark() on those.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/e1161c90894ddc519c57dc0224b3a0f6bfa1d2d6.1775049897.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
net/dsa/tag_mxl862xx.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
@ -1,7 +1,7 @@
|
||||
From ce0664ff8f75c3ab01101c3f0f8569924d948775 Mon Sep 17 00:00:00 2001
|
||||
From 340bdf984613c4a9241d678915e513824f5a9b19 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 17:55:08 +0000
|
||||
Subject: [PATCH 04/26] net: dsa: mxl862xx: implement bridge offloading
|
||||
Date: Wed, 1 Apr 2026 14:35:01 +0100
|
||||
Subject: [PATCH 4/4] 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
|
||||
@ -24,9 +24,17 @@ dsa_switch_for_each_bridge_member().
|
||||
|
||||
As there are now more users of the BRIDGEPORT_CONFIG_SET API and the
|
||||
state of each port is cached locally, introduce a helper function
|
||||
mxl862xx_set_bridge_port(struct dsa_switch *ds, int port) which is
|
||||
then used to replace the direct calls to the API in
|
||||
mxl862xx_setup_cpu_bridge() and mxl862xx_add_single_port_bridge().
|
||||
mxl862xx_set_bridge_port(struct dsa_switch *ds, int port) which
|
||||
applies the cached per-port state to hardware. For standalone user
|
||||
ports (dp->bridge == NULL), it additionally resets the port to
|
||||
single-port bridge state: CPU-only portmap, learning and flooding
|
||||
disabled. The CPU port path sets its state explicitly before calling
|
||||
this helper and is therefore not affected by the reset.
|
||||
|
||||
Note that MASK_VLAN_BASED_MAC_LEARNING is intentionally absent from
|
||||
the firmware write mask. After mxl862xx_reset(), the firmware
|
||||
initialises all VLAN-based MAC learning fields to 0 (disabled), so
|
||||
SVL is the active mode by default without having to set it explicitly.
|
||||
|
||||
Note that there is no convenient way to control flooding on per-port
|
||||
level, so the driver is using a 0-rate QoS meter setup as a stopper in
|
||||
@ -36,12 +44,14 @@ registers -- without that at least one 64-byte packet could still
|
||||
pass before the meter would change from 'yellow' into 'red' state.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/dd079180e2098e5f9626fcd149b9bad9a1b5a1b2.1775049897.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 225 ++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 225 +++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 20 +-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 743 ++++++++++++++++++++++--
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 133 +++++
|
||||
4 files changed, 1076 insertions(+), 45 deletions(-)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 736 ++++++++++++++++++++++--
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 99 ++++
|
||||
4 files changed, 1022 insertions(+), 58 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@ -384,7 +394,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,213 @@ static int mxl862xx_setup_mdio(struct ds
|
||||
@@ -168,6 +182,199 @@ static int mxl862xx_setup_mdio(struct ds
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -479,11 +489,40 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_port *p = &priv->ports[port];
|
||||
+ u16 bridge_id = dp->bridge ?
|
||||
+ priv->bridges[dp->bridge->num] : p->fid;
|
||||
+ struct dsa_port *member_dp;
|
||||
+ u16 bridge_id;
|
||||
+ bool enable;
|
||||
+ int i, idx;
|
||||
+
|
||||
+ if (!p->setup_done)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (dsa_port_is_cpu(dp)) {
|
||||
+ dsa_switch_for_each_user_port(member_dp, ds) {
|
||||
+ if (member_dp->cpu_dp->index != port)
|
||||
+ continue;
|
||||
+ mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
+ member_dp->index);
|
||||
+ }
|
||||
+ } else if (dp->bridge) {
|
||||
+ dsa_switch_for_each_bridge_member(member_dp, ds,
|
||||
+ dp->bridge->dev) {
|
||||
+ if (member_dp->index == port)
|
||||
+ continue;
|
||||
+ mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
+ member_dp->index);
|
||||
+ }
|
||||
+ mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
+ dp->cpu_dp->index);
|
||||
+ } else {
|
||||
+ mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
+ dp->cpu_dp->index);
|
||||
+ p->flood_block = 0;
|
||||
+ p->learning = false;
|
||||
+ }
|
||||
+
|
||||
+ bridge_id = dp->bridge ? priv->bridges[dp->bridge->num] : p->fid;
|
||||
+
|
||||
+ br_port_cfg.bridge_port_id = cpu_to_le16(port);
|
||||
+ br_port_cfg.bridge_id = cpu_to_le16(bridge_id);
|
||||
+ br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_ID |
|
||||
@ -492,8 +531,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ MXL862XX_BRIDGE_PORT_CONFIG_MASK_EGRESS_SUB_METER);
|
||||
+ br_port_cfg.src_mac_learning_disable = !p->learning;
|
||||
+
|
||||
+ mxl862xx_fw_portmap_from_bitmap(br_port_cfg.bridge_port_map, p->portmap);
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(mxl862xx_flood_meters); i++) {
|
||||
+ idx = mxl862xx_flood_meters[i];
|
||||
+ enable = !!(p->flood_block & BIT(idx));
|
||||
@ -510,24 +547,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+static int mxl862xx_sync_bridge_members(struct dsa_switch *ds,
|
||||
+ const struct dsa_bridge *bridge)
|
||||
+{
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct dsa_port *dp, *member_dp;
|
||||
+ int port, err, ret = 0;
|
||||
+ struct dsa_port *dp;
|
||||
+ int ret = 0, err;
|
||||
+
|
||||
+ dsa_switch_for_each_bridge_member(dp, ds, bridge->dev) {
|
||||
+ port = dp->index;
|
||||
+
|
||||
+ bitmap_zero(priv->ports[port].portmap,
|
||||
+ MXL862XX_MAX_BRIDGE_PORTS);
|
||||
+
|
||||
+ dsa_switch_for_each_bridge_member(member_dp, ds, bridge->dev) {
|
||||
+ if (member_dp->index != port)
|
||||
+ __set_bit(member_dp->index,
|
||||
+ priv->ports[port].portmap);
|
||||
+ }
|
||||
+ __set_bit(dp->cpu_dp->index, priv->ports[port].portmap);
|
||||
+
|
||||
+ err = mxl862xx_set_bridge_port(ds, port);
|
||||
+ err = mxl862xx_set_bridge_port(ds, dp->index);
|
||||
+ if (err)
|
||||
+ ret = err;
|
||||
+ }
|
||||
@ -535,7 +559,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int mxl862xx_allocate_bridge(struct mxl862xx_priv *priv, u16 *bridge_id)
|
||||
+static int mxl862xx_allocate_bridge(struct mxl862xx_priv *priv)
|
||||
+{
|
||||
+ struct mxl862xx_bridge_alloc br_alloc = {};
|
||||
+ int ret;
|
||||
@ -544,8 +568,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ *bridge_id = le16_to_cpu(br_alloc.bridge_id);
|
||||
+ return 0;
|
||||
+ return le16_to_cpu(br_alloc.bridge_id);
|
||||
+}
|
||||
+
|
||||
+static void mxl862xx_free_bridge(struct dsa_switch *ds,
|
||||
@ -567,38 +590,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+ priv->bridges[bridge->num] = 0;
|
||||
+}
|
||||
+
|
||||
+static int mxl862xx_add_single_port_bridge(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = mxl862xx_allocate_bridge(priv, &priv->ports[port].fid);
|
||||
+ if (ret) {
|
||||
+ dev_err(ds->dev, "failed to allocate a bridge for port %d\n", port);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ priv->ports[port].learning = false;
|
||||
+ bitmap_zero(priv->ports[port].portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
+ __set_bit(dp->cpu_dp->index, priv->ports[port].portmap);
|
||||
+
|
||||
+ ret = mxl862xx_set_bridge_port(ds, port);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Standalone ports should not flood unknown unicast or multicast
|
||||
+ * towards the CPU by default; only broadcast is needed initially.
|
||||
+ */
|
||||
+ return mxl862xx_bridge_config_fwd(ds, priv->ports[port].fid,
|
||||
+ false, false, true);
|
||||
+}
|
||||
+
|
||||
static int mxl862xx_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
@@ -181,6 +402,10 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -181,6 +388,10 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -609,66 +605,49 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return mxl862xx_setup_mdio(ds);
|
||||
}
|
||||
|
||||
@@ -260,66 +485,87 @@ static int mxl862xx_configure_sp_tag_pro
|
||||
@@ -260,99 +471,137 @@ static int mxl862xx_configure_sp_tag_pro
|
||||
|
||||
static int mxl862xx_setup_cpu_bridge(struct dsa_switch *ds, int port)
|
||||
{
|
||||
- struct mxl862xx_bridge_port_config br_port_cfg = {};
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
- u16 bridge_port_map = 0;
|
||||
struct dsa_port *dp;
|
||||
- struct dsa_port *dp;
|
||||
|
||||
- /* CPU port bridge setup */
|
||||
- br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
|
||||
- MXL862XX_BRIDGE_PORT_CONFIG_MASK_MC_SRC_MAC_LEARNING |
|
||||
- MXL862XX_BRIDGE_PORT_CONFIG_MASK_VLAN_BASED_MAC_LEARNING);
|
||||
-
|
||||
+ priv->ports[port].fid = MXL862XX_DEFAULT_BRIDGE;
|
||||
+ priv->ports[port].learning = true;
|
||||
|
||||
- br_port_cfg.bridge_port_id = cpu_to_le16(port);
|
||||
- br_port_cfg.src_mac_learning_disable = false;
|
||||
- br_port_cfg.vlan_src_mac_vid_enable = true;
|
||||
- br_port_cfg.vlan_dst_mac_vid_enable = true;
|
||||
+ priv->ports[port].fid = MXL862XX_DEFAULT_BRIDGE;
|
||||
+ priv->ports[port].learning = true;
|
||||
|
||||
/* include all assigned user ports in the CPU portmap */
|
||||
+ bitmap_zero(priv->ports[port].portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
dsa_switch_for_each_user_port(dp, ds) {
|
||||
/* it's safe to rely on cpu_dp being valid for user ports */
|
||||
if (dp->cpu_dp->index != port)
|
||||
continue;
|
||||
|
||||
- bridge_port_map |= BIT(dp->index);
|
||||
+ __set_bit(dp->index, priv->ports[port].portmap);
|
||||
}
|
||||
- br_port_cfg.bridge_port_map[0] |= cpu_to_le16(bridge_port_map);
|
||||
|
||||
- return MXL862XX_API_WRITE(priv, MXL862XX_BRIDGEPORT_CONFIGSET, br_port_cfg);
|
||||
+ return mxl862xx_set_bridge_port(ds, port);
|
||||
}
|
||||
+}
|
||||
|
||||
-static int mxl862xx_add_single_port_bridge(struct dsa_switch *ds, int port)
|
||||
- /* include all assigned user ports in the CPU portmap */
|
||||
- dsa_switch_for_each_user_port(dp, ds) {
|
||||
- /* it's safe to rely on cpu_dp being valid for user ports */
|
||||
- if (dp->cpu_dp->index != port)
|
||||
- continue;
|
||||
+static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port,
|
||||
+ const struct dsa_bridge bridge,
|
||||
+ bool *tx_fwd_offload,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
{
|
||||
- struct mxl862xx_bridge_port_config br_port_cfg = {};
|
||||
- struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
- struct mxl862xx_bridge_alloc br_alloc = {};
|
||||
+{
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ u16 fw_id;
|
||||
int ret;
|
||||
+ int ret;
|
||||
|
||||
- ret = MXL862XX_API_READ(ds->priv, MXL862XX_BRIDGE_ALLOC, br_alloc);
|
||||
- if (ret) {
|
||||
- dev_err(ds->dev, "failed to allocate a bridge for port %d\n", port);
|
||||
- return ret;
|
||||
- bridge_port_map |= BIT(dp->index);
|
||||
+ if (!priv->bridges[bridge.num]) {
|
||||
+ ret = mxl862xx_allocate_bridge(priv, &fw_id);
|
||||
+ if (ret)
|
||||
+ ret = mxl862xx_allocate_bridge(priv);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ priv->bridges[bridge.num] = fw_id;
|
||||
+ priv->bridges[bridge.num] = ret;
|
||||
+
|
||||
+ /* Free bridge here on error, DSA rollback won't. */
|
||||
+ ret = mxl862xx_sync_bridge_members(ds, &bridge);
|
||||
@ -679,6 +658,32 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
- br_port_cfg.bridge_port_map[0] |= cpu_to_le16(bridge_port_map);
|
||||
|
||||
- return MXL862XX_API_WRITE(priv, MXL862XX_BRIDGEPORT_CONFIGSET, br_port_cfg);
|
||||
+ return mxl862xx_sync_bridge_members(ds, &bridge);
|
||||
}
|
||||
|
||||
-static int mxl862xx_add_single_port_bridge(struct dsa_switch *ds, int port)
|
||||
+static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
+ const struct dsa_bridge bridge)
|
||||
{
|
||||
- struct mxl862xx_bridge_port_config br_port_cfg = {};
|
||||
- struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
- struct mxl862xx_bridge_alloc br_alloc = {};
|
||||
- int ret;
|
||||
+ int err;
|
||||
|
||||
- ret = MXL862XX_API_READ(ds->priv, MXL862XX_BRIDGE_ALLOC, br_alloc);
|
||||
- if (ret) {
|
||||
- dev_err(ds->dev, "failed to allocate a bridge for port %d\n", port);
|
||||
- return ret;
|
||||
- }
|
||||
+ err = mxl862xx_sync_bridge_members(ds, &bridge);
|
||||
+ if (err)
|
||||
+ dev_err(ds->dev,
|
||||
+ "failed to sync bridge members after port %d left: %pe\n",
|
||||
+ port, ERR_PTR(err));
|
||||
|
||||
- br_port_cfg.bridge_id = br_alloc.bridge_id;
|
||||
- br_port_cfg.bridge_port_id = cpu_to_le16(port);
|
||||
@ -691,30 +696,10 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
- br_port_cfg.vlan_dst_mac_vid_enable = false;
|
||||
- /* As this function is only called for user ports it is safe to rely on
|
||||
- * cpu_dp being valid
|
||||
+ return mxl862xx_sync_bridge_members(ds, &bridge);
|
||||
+}
|
||||
+
|
||||
+static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
+ const struct dsa_bridge bridge)
|
||||
+{
|
||||
+ struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_port *p = &priv->ports[port];
|
||||
+ int err;
|
||||
+
|
||||
+ err = mxl862xx_sync_bridge_members(ds, &bridge);
|
||||
+ if (err)
|
||||
+ dev_err(ds->dev,
|
||||
+ "failed to sync bridge members after port %d left: %pe\n",
|
||||
+ port, ERR_PTR(err));
|
||||
+
|
||||
+ /* Revert leaving port, omitted by the sync above, to its
|
||||
+ * single-port bridge
|
||||
*/
|
||||
- br_port_cfg.bridge_port_map[0] = cpu_to_le16(BIT(dp->cpu_dp->index));
|
||||
+ bitmap_zero(p->portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
+ __set_bit(dp->cpu_dp->index, p->portmap);
|
||||
+ p->flood_block = 0;
|
||||
+ err = mxl862xx_set_bridge_port(ds, port);
|
||||
+ if (err)
|
||||
+ dev_err(ds->dev,
|
||||
@ -732,12 +717,54 @@ 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 +598,31 @@ static int mxl862xx_port_setup(struct ds
|
||||
|
||||
- /* disable port and flush MAC entries */
|
||||
ret = mxl862xx_port_state(ds, port, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mxl862xx_port_fast_age(ds, port);
|
||||
|
||||
- /* skip setup for unused and DSA ports */
|
||||
if (dsa_port_is_unused(dp) ||
|
||||
dsa_port_is_dsa(dp))
|
||||
return 0;
|
||||
|
||||
- /* configure tag protocol */
|
||||
ret = mxl862xx_configure_sp_tag_proto(ds, port, is_cpu_port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- /* assign CTP port IDs */
|
||||
ret = mxl862xx_configure_ctp_port(ds, port, port,
|
||||
is_cpu_port ? 32 - port : 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (is_cpu_port)
|
||||
- /* assign user ports to CPU port bridge */
|
||||
return mxl862xx_setup_cpu_bridge(ds, port);
|
||||
|
||||
/* setup single-port bridge for user ports */
|
||||
- /* setup single-port bridge for user ports */
|
||||
- return mxl862xx_add_single_port_bridge(ds, port);
|
||||
+ ret = mxl862xx_add_single_port_bridge(ds, port);
|
||||
+ /* setup single-port bridge for user ports.
|
||||
+ * If this fails, the FID is leaked -- but the port then transitions
|
||||
+ * to unused, and the FID pool is sized to tolerate this.
|
||||
+ */
|
||||
+ ret = mxl862xx_allocate_bridge(priv);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(ds->dev, "failed to allocate a bridge for port %d\n", port);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ priv->ports[port].fid = ret;
|
||||
+ /* Standalone ports should not flood unknown unicast or multicast
|
||||
+ * towards the CPU by default; only broadcast is needed initially.
|
||||
+ */
|
||||
+ ret = mxl862xx_bridge_config_fwd(ds, priv->ports[port].fid,
|
||||
+ false, false, true);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = mxl862xx_set_bridge_port(ds, port);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
@ -765,7 +792,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
static void mxl862xx_phylink_get_caps(struct dsa_switch *ds, int port,
|
||||
@@ -365,14 +635,383 @@ static void mxl862xx_phylink_get_caps(st
|
||||
@@ -365,14 +614,371 @@ static void mxl862xx_phylink_get_caps(st
|
||||
config->supported_interfaces);
|
||||
}
|
||||
|
||||
@ -876,7 +903,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ if (fid < 0)
|
||||
+ return fid;
|
||||
+
|
||||
+ /* Look up existing entry by {MAC, FID, TCI} */
|
||||
+ ether_addr_copy(qparam.mac, mdb->addr);
|
||||
+ qparam.fid = cpu_to_le16(fid);
|
||||
+ qparam.tci = cpu_to_le16(FIELD_PREP(MXL862XX_TCI_VLAN_ID, mdb->vid));
|
||||
@ -892,7 +918,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ aparam.static_entry = true;
|
||||
+ aparam.port_id = cpu_to_le32(MXL862XX_PORTMAP_FLAG);
|
||||
+
|
||||
+ /* Merge with existing portmap if entry already exists */
|
||||
+ if (qparam.found)
|
||||
+ memcpy(aparam.port_map, qparam.port_map,
|
||||
+ sizeof(aparam.port_map));
|
||||
@ -915,7 +940,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ if (fid < 0)
|
||||
+ return fid;
|
||||
+
|
||||
+ /* Look up existing entry */
|
||||
+ qparam.fid = cpu_to_le16(fid);
|
||||
+ qparam.tci = cpu_to_le16(FIELD_PREP(MXL862XX_TCI_VLAN_ID, mdb->vid));
|
||||
+ ether_addr_copy(qparam.mac, mdb->addr);
|
||||
@ -930,7 +954,6 @@ 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 */
|
||||
+ 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);
|
||||
@ -1007,8 +1030,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * LEARNING or FORWARDING state (per 802.1D defaults).
|
||||
+ * Re-apply the driver's intended learning and metering config so that
|
||||
+ * standalone ports keep learning disabled.
|
||||
+ * This is likely to get fixed in future firmware releases, however,
|
||||
+ * the additional API call even then doesn't hurt much.
|
||||
+ */
|
||||
+ ret = mxl862xx_set_bridge_port(ds, port);
|
||||
+ if (ret)
|
||||
@ -1031,8 +1052,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ host_flood_work);
|
||||
+ struct mxl862xx_priv *priv = p->priv;
|
||||
+ struct dsa_switch *ds = priv->ds;
|
||||
+ int port = p - priv->ports;
|
||||
+ bool uc, mc;
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+
|
||||
@ -1042,17 +1061,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ uc = p->host_flood_uc;
|
||||
+ 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
|
||||
+ * 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.
|
||||
+ /* Always write to the standalone FID. When standalone it takes effect
|
||||
+ * immediately; when bridged the port uses the shared bridge FID so the
|
||||
+ * write is a no-op for current forwarding, but the state is preserved
|
||||
+ * in hardware and is ready once the port returns to standalone.
|
||||
+ */
|
||||
+ if (!dsa_port_bridge_dev_get(dsa_to_port(ds, port)))
|
||||
+ mxl862xx_bridge_config_fwd(ds, p->fid, uc, mc, true);
|
||||
+ mxl862xx_bridge_config_fwd(ds, p->fid, p->host_flood_uc,
|
||||
+ p->host_flood_mc, true);
|
||||
+
|
||||
+ rtnl_unlock();
|
||||
+}
|
||||
@ -1115,7 +1130,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ if (flags.mask & BR_LEARNING)
|
||||
+ priv->ports[port].learning = !!(flags.val & BR_LEARNING);
|
||||
+
|
||||
+ if ((block != old_block) || (flags.mask & BR_LEARNING)) {
|
||||
+ if (block != old_block || (flags.mask & BR_LEARNING)) {
|
||||
+ priv->ports[port].flood_block = block;
|
||||
+ ret = mxl862xx_set_bridge_port(ds, port);
|
||||
+ if (ret)
|
||||
@ -1149,7 +1164,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
};
|
||||
|
||||
static void mxl862xx_phylink_mac_config(struct phylink_config *config,
|
||||
@@ -407,7 +1046,7 @@ static int mxl862xx_probe(struct mdio_de
|
||||
@@ -407,7 +1013,7 @@ static int mxl862xx_probe(struct mdio_de
|
||||
struct device *dev = &mdiodev->dev;
|
||||
struct mxl862xx_priv *priv;
|
||||
struct dsa_switch *ds;
|
||||
@ -1158,7 +1173,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
@@ -425,14 +1064,25 @@ static int mxl862xx_probe(struct mdio_de
|
||||
@@ -425,14 +1031,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;
|
||||
@ -1186,7 +1201,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -440,6 +1090,7 @@ static void mxl862xx_remove(struct mdio_
|
||||
@@ -440,6 +1057,7 @@ static void mxl862xx_remove(struct mdio_
|
||||
{
|
||||
struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
|
||||
struct mxl862xx_priv *priv;
|
||||
@ -1194,7 +1209,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
if (!ds)
|
||||
return;
|
||||
@@ -449,12 +1100,21 @@ static void mxl862xx_remove(struct mdio_
|
||||
@@ -449,12 +1067,21 @@ static void mxl862xx_remove(struct mdio_
|
||||
dsa_unregister_switch(ds);
|
||||
|
||||
mxl862xx_host_shutdown(priv);
|
||||
@ -1216,7 +1231,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
if (!ds)
|
||||
return;
|
||||
@@ -465,6 +1125,9 @@ static void mxl862xx_shutdown(struct mdi
|
||||
@@ -465,6 +1092,9 @@ static void mxl862xx_shutdown(struct mdi
|
||||
|
||||
mxl862xx_host_shutdown(priv);
|
||||
|
||||
@ -1228,7 +1243,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -4,15 +4,148 @@
|
||||
@@ -4,15 +4,114 @@
|
||||
#define __MXL862XX_H
|
||||
|
||||
#include <linux/mdio.h>
|
||||
@ -1246,37 +1261,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+#define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16)
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_fw_portmap_from_bitmap - convert a kernel bitmap to a firmware
|
||||
+ * portmap (__le16[8])
|
||||
+ * @dst: firmware portmap array (MXL862XX_FW_PORTMAP_WORDS entries)
|
||||
+ * @src: kernel bitmap of at least MXL862XX_MAX_BRIDGE_PORTS bits
|
||||
+ */
|
||||
+static inline void
|
||||
+mxl862xx_fw_portmap_from_bitmap(__le16 *dst, const unsigned long *src)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < MXL862XX_FW_PORTMAP_WORDS; i++)
|
||||
+ dst[i] = cpu_to_le16(bitmap_read(src, i * 16, 16));
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_fw_portmap_to_bitmap - convert a firmware portmap (__le16[8]) to
|
||||
+ * a kernel bitmap
|
||||
+ * @dst: kernel bitmap of at least MXL862XX_MAX_BRIDGE_PORTS bits
|
||||
+ * @src: firmware portmap array (MXL862XX_FW_PORTMAP_WORDS entries)
|
||||
+ */
|
||||
+static inline void
|
||||
+mxl862xx_fw_portmap_to_bitmap(unsigned long *dst, const __le16 *src)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ bitmap_zero(dst, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
+ for (i = 0; i < MXL862XX_FW_PORTMAP_WORDS; i++)
|
||||
+ bitmap_write(dst, le16_to_cpu(src[i]), i * 16, 16);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_fw_portmap_set_bit - set a single port bit in a firmware portmap
|
||||
+ * @map: firmware portmap array (MXL862XX_FW_PORTMAP_WORDS entries)
|
||||
+ * @port: port index (0..MXL862XX_MAX_BRIDGE_PORTS-1)
|
||||
@ -1320,8 +1304,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * @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
|
||||
+ * rate-limiting flood traffic on this port (zero-rate
|
||||
+ * meters used to block flooding)
|
||||
@ -1343,7 +1325,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+struct mxl862xx_port {
|
||||
+ struct mxl862xx_priv *priv;
|
||||
+ u16 fid;
|
||||
+ DECLARE_BITMAP(portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
+ unsigned long flood_block;
|
||||
+ bool learning;
|
||||
+ bool setup_done;
|
||||
@ -0,0 +1,50 @@
|
||||
From 3a4056ec7ec8f71ae9722f86d3cfbc4589deeac4 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 7 Apr 2026 18:30:27 +0100
|
||||
Subject: [PATCH 1/2] net: dsa: mxl862xx: reject DSA_PORT_TYPE_DSA
|
||||
|
||||
DSA links aren't supported by the mxl862xx driver.
|
||||
|
||||
Instead of returning early from .port_setup when called for
|
||||
DSA_PORT_TYPE_DSA ports rather return -EOPNOTSUPP and show an error
|
||||
message.
|
||||
|
||||
The desired side-effect is that the framework will switch the port to
|
||||
DSA_PORT_TYPE_UNUSED, so we can stop caring about DSA_PORT_TYPE_DSA in
|
||||
all other places.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/b686f3a22d8a6e7d470e7aa98da811a996a229b9.1775581804.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -544,10 +544,14 @@ static int mxl862xx_port_setup(struct ds
|
||||
|
||||
mxl862xx_port_fast_age(ds, port);
|
||||
|
||||
- if (dsa_port_is_unused(dp) ||
|
||||
- dsa_port_is_dsa(dp))
|
||||
+ if (dsa_port_is_unused(dp))
|
||||
return 0;
|
||||
|
||||
+ if (dsa_port_is_dsa(dp)) {
|
||||
+ dev_err(ds->dev, "port %d: DSA links not supported\n", port);
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
ret = mxl862xx_configure_sp_tag_proto(ds, port, is_cpu_port);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -591,7 +595,7 @@ static void mxl862xx_port_teardown(struc
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
|
||||
- if (dsa_port_is_unused(dp) || dsa_port_is_dsa(dp))
|
||||
+ if (dsa_port_is_unused(dp))
|
||||
return;
|
||||
|
||||
/* Prevent deferred host_flood_work from acting on stale state.
|
||||
@ -0,0 +1,38 @@
|
||||
From 71934b9e6f36b1786bd969c0e1d2de8f9bd65f0f Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 7 Apr 2026 18:30:35 +0100
|
||||
Subject: [PATCH 2/2] net: dsa: mxl862xx: don't skip early bridge port
|
||||
configuration
|
||||
|
||||
mxl862xx_bridge_port_set() is currently guarded by the
|
||||
mxl8622_port->setup_done flag, as the early call to
|
||||
mxl862xx_bridge_port_set() from mxl862xx_port_stp_state_set() would
|
||||
otherwise cause a NULL-pointer dereference on unused ports which don't
|
||||
have dp->cpu_dp despite not being a CPU port.
|
||||
|
||||
Using the setup_done flag (which is never set for unused ports),
|
||||
however, also prevents mxl862xx_bridge_port_set() from configuring
|
||||
user ports' single-port bridges early, which was unintended.
|
||||
|
||||
Fix this by returning early from mxl862xx_bridge_port_set() in case
|
||||
dsa_port_is_unused().
|
||||
|
||||
Fixes: 340bdf984613c ("net: dsa: mxl862xx: implement bridge offloading")
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/15962aac29ebe0a6eb77565451acff880c41ef33.1775581804.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -278,7 +278,7 @@ static int mxl862xx_set_bridge_port(stru
|
||||
bool enable;
|
||||
int i, idx;
|
||||
|
||||
- if (!p->setup_done)
|
||||
+ if (dsa_port_is_unused(dp))
|
||||
return 0;
|
||||
|
||||
if (dsa_port_is_cpu(dp)) {
|
||||
@ -1,7 +1,7 @@
|
||||
From 0d88d02cc9dccad01ff88f54e1beee867107b942 Mon Sep 17 00:00:00 2001
|
||||
From d587f9b6dcc98c1e8aeb5c189a7bfac60d6d29ac Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 10 Mar 2026 02:36:00 +0000
|
||||
Subject: [PATCH 05/26] net: dsa: mxl862xx: implement VLAN functionality
|
||||
Date: Tue, 7 Apr 2026 18:31:01 +0100
|
||||
Subject: [PATCH] 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
|
||||
@ -16,8 +16,8 @@ egress rules at all, so they consume only a VF entry.
|
||||
Both engines draw from shared 1024-entry hardware pools. The VF pool
|
||||
is divided equally among user ports for VID membership, while the
|
||||
EVLAN pool is partitioned into small fixed-size ingress blocks (7
|
||||
entries of catchall rules per port) and variable-size egress blocks
|
||||
for tag stripping.
|
||||
entries of catchall rules per port) and fixed-size egress blocks for
|
||||
tag stripping.
|
||||
|
||||
With 5 user ports this yields up to 204 VIDs per port (limited by VF),
|
||||
of which up to 98 can be untagged (limited by EVLAN egress budget).
|
||||
@ -34,12 +34,14 @@ rather than worst-case pre-allocation, or by sharing EVLAN egress and
|
||||
VLAN Filter blocks across ports with identical VID sets.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/9be29637675342b109a85fa08f5378800d9f7b78.1775581804.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.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 | 915 +++++++++++++++++++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 104 ++-
|
||||
4 files changed, 1344 insertions(+), 16 deletions(-)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 781 +++++++++++++++++++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 103 +++-
|
||||
4 files changed, 1211 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@ -101,14 +103,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+/**
|
||||
+ * enum mxl862xx_extended_vlan_treatment_priority - Treatment priority mode
|
||||
+ * @MXL862XX_EXTENDEDVLAN_TREATMENT_PRIORITY_VAL: Use explicit value
|
||||
+ * @MXL862XX_EXTENDEDVLAN_TREATMENT_INNER_PRORITY: Copy from inner tag
|
||||
+ * @MXL862XX_EXTENDEDVLAN_TREATMENT_OUTER_PRORITY: Copy from outer tag
|
||||
+ * @MXL862XX_EXTENDEDVLAN_TREATMENT_INNER_PRIORITY: Copy from inner tag
|
||||
+ * @MXL862XX_EXTENDEDVLAN_TREATMENT_OUTER_PRIORITY: Copy from outer tag
|
||||
+ * @MXL862XX_EXTENDEDVLAN_TREATMENT_DSCP: Derive from DSCP
|
||||
+ */
|
||||
+enum mxl862xx_extended_vlan_treatment_priority {
|
||||
+ MXL862XX_EXTENDEDVLAN_TREATMENT_PRIORITY_VAL = 0,
|
||||
+ MXL862XX_EXTENDEDVLAN_TREATMENT_INNER_PRORITY = 1,
|
||||
+ MXL862XX_EXTENDEDVLAN_TREATMENT_OUTER_PRORITY = 2,
|
||||
+ MXL862XX_EXTENDEDVLAN_TREATMENT_INNER_PRIORITY = 1,
|
||||
+ MXL862XX_EXTENDEDVLAN_TREATMENT_OUTER_PRIORITY = 2,
|
||||
+ MXL862XX_EXTENDEDVLAN_TREATMENT_DSCP = 3,
|
||||
+};
|
||||
+
|
||||
@ -409,16 +411,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#define MXL862XX_STP_PORTCFGSET (MXL862XX_STP_MAGIC + 0x2)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -50,6 +50,88 @@ static const int mxl862xx_flood_meters[]
|
||||
@@ -50,6 +50,85 @@ static const int mxl862xx_flood_meters[]
|
||||
MXL862XX_BRIDGE_PORT_EGRESS_METER_BROADCAST,
|
||||
};
|
||||
|
||||
+enum mxl862xx_evlan_action {
|
||||
+ EVLAN_ACCEPT, /* pass-through, no tag removal */
|
||||
+ EVLAN_STRIP_IF_UNTAGGED, /* remove 1 tag if entry's untagged flag set */
|
||||
+ EVLAN_DISCARD, /* discard upstream */
|
||||
+ EVLAN_PVID_OR_DISCARD, /* insert PVID tag or discard if no PVID */
|
||||
+ EVLAN_PVID_OR_PASS, /* insert PVID tag or pass-through */
|
||||
+ EVLAN_STRIP1_AND_PVID_OR_DISCARD,/* strip 1 tag + insert PVID, or discard */
|
||||
+};
|
||||
+
|
||||
@ -457,7 +457,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * regardless of TPID, so without the ACCEPT guard, it would also
|
||||
+ * catch standard 802.1Q VID>0 frames and corrupt them. With the
|
||||
+ * guard, 802.1Q VID>0 frames match the ACCEPT rules first and
|
||||
+ * pass through untouched; only non-8021Q TPID frames fall through
|
||||
+ * pass through untouched; only non-8021Q TPID frames pass through
|
||||
+ * to the NO_FILTER catchalls.
|
||||
+ */
|
||||
+static const struct mxl862xx_evlan_rule_desc ingress_aware_final[] = {
|
||||
@ -486,27 +486,26 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * VID-specific accept rules for VLAN-unaware egress.
|
||||
+ * The HW sees the MxL tag as outer, real VLAN tag as inner.
|
||||
+ * match on inner VID with outer=NO_FILTER.
|
||||
+ * Egress tag-stripping rules for VLAN-unaware mode (2 per untagged VID).
|
||||
+ * The HW sees the MxL tag as outer; the real VLAN tag, if any, is inner.
|
||||
+ */
|
||||
+static const struct mxl862xx_evlan_rule_desc vid_accept_egress_unaware[] = {
|
||||
+ { FT_NO_FILTER, FT_NORMAL, TP_NONE, TP_8021Q, true, EVLAN_STRIP_IF_UNTAGGED },
|
||||
+ { FT_NO_FILTER, FT_NO_TAG, TP_NONE, TP_NONE, true, EVLAN_STRIP_IF_UNTAGGED },
|
||||
+ { FT_NO_FILTER, FT_NORMAL, TP_NONE, TP_8021Q, true, EVLAN_STRIP_IF_UNTAGGED },
|
||||
+ { FT_NO_FILTER, FT_NO_TAG, TP_NONE, TP_NONE, false, EVLAN_STRIP_IF_UNTAGGED },
|
||||
+};
|
||||
+
|
||||
static enum dsa_tag_protocol mxl862xx_get_tag_protocol(struct dsa_switch *ds,
|
||||
int port,
|
||||
enum dsa_tag_protocol m)
|
||||
@@ -275,6 +357,7 @@ static int mxl862xx_set_bridge_port(stru
|
||||
@@ -275,6 +354,7 @@ static int mxl862xx_set_bridge_port(stru
|
||||
struct mxl862xx_port *p = &priv->ports[port];
|
||||
u16 bridge_id = dp->bridge ?
|
||||
priv->bridges[dp->bridge->num] : p->fid;
|
||||
struct dsa_port *member_dp;
|
||||
u16 bridge_id;
|
||||
+ u16 vf_scan;
|
||||
bool enable;
|
||||
int i, idx;
|
||||
|
||||
@@ -283,9 +366,69 @@ static int mxl862xx_set_bridge_port(stru
|
||||
@@ -312,9 +392,69 @@ static int mxl862xx_set_bridge_port(stru
|
||||
br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_ID |
|
||||
MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
|
||||
MXL862XX_BRIDGE_PORT_CONFIG_MASK_MC_SRC_MAC_LEARNING |
|
||||
@ -574,23 +573,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ br_port_cfg.vlan_src_mac_vid_enable = p->vlan_filtering;
|
||||
+ br_port_cfg.vlan_dst_mac_vid_enable = p->vlan_filtering;
|
||||
+
|
||||
mxl862xx_fw_portmap_from_bitmap(br_port_cfg.bridge_port_map, p->portmap);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mxl862xx_flood_meters); i++) {
|
||||
@@ -329,6 +472,91 @@ static int mxl862xx_sync_bridge_members(
|
||||
idx = mxl862xx_flood_meters[i];
|
||||
enable = !!(p->flood_block & BIT(idx));
|
||||
@@ -343,6 +483,72 @@ static int mxl862xx_sync_bridge_members(
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static void mxl862xx_evlan_block_init(struct mxl862xx_evlan_block *blk,
|
||||
+ u16 size)
|
||||
+{
|
||||
+ blk->allocated = false;
|
||||
+ blk->in_use = false;
|
||||
+ blk->block_id = 0;
|
||||
+ blk->block_size = size;
|
||||
+ blk->n_active = 0;
|
||||
+}
|
||||
+
|
||||
+static int mxl862xx_evlan_block_alloc(struct mxl862xx_priv *priv,
|
||||
+ struct mxl862xx_evlan_block *blk)
|
||||
+{
|
||||
@ -609,15 +598,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void mxl862xx_vf_init(struct mxl862xx_vf_block *vf, u16 size)
|
||||
+{
|
||||
+ vf->allocated = false;
|
||||
+ vf->block_id = 0;
|
||||
+ vf->block_size = size;
|
||||
+ vf->active_count = 0;
|
||||
+ INIT_LIST_HEAD(&vf->vids);
|
||||
+}
|
||||
+
|
||||
+static int mxl862xx_vf_block_alloc(struct mxl862xx_priv *priv,
|
||||
+ u16 size, u16 *block_id)
|
||||
+{
|
||||
@ -666,10 +646,10 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return mxl862xx_vf_entry_discard(priv, vf->block_id, 0);
|
||||
+}
|
||||
+
|
||||
static int mxl862xx_allocate_bridge(struct mxl862xx_priv *priv, u16 *bridge_id)
|
||||
static int mxl862xx_allocate_bridge(struct mxl862xx_priv *priv)
|
||||
{
|
||||
struct mxl862xx_bridge_alloc br_alloc = {};
|
||||
@@ -392,6 +620,9 @@ static int mxl862xx_add_single_port_brid
|
||||
@@ -378,6 +584,9 @@ static void mxl862xx_free_bridge(struct
|
||||
static int mxl862xx_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
@ -679,7 +659,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
int ret;
|
||||
|
||||
ret = mxl862xx_reset(priv);
|
||||
@@ -402,6 +633,50 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -388,6 +597,50 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -695,7 +675,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * through without EVLAN processing.
|
||||
+ *
|
||||
+ * Total EVLAN budget:
|
||||
+ * n_user_ports * (ingress + egress) ≤ 1024.
|
||||
+ * n_user_ports * (ingress + egress) <= 1024.
|
||||
+ * Ingress blocks are small (7 entries), so almost all capacity
|
||||
+ * goes to egress VID rules.
|
||||
+ */
|
||||
@ -730,23 +710,10 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
ret = mxl862xx_setup_drop_meter(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -483,27 +758,616 @@ static int mxl862xx_configure_sp_tag_pro
|
||||
@@ -469,12 +722,509 @@ static int mxl862xx_configure_sp_tag_pro
|
||||
return MXL862XX_API_WRITE(ds->priv, MXL862XX_SS_SPTAG_SET, tag);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * mxl862xx_evlan_write_rule - Write a single Extended VLAN rule to hardware
|
||||
+ * @priv: driver private data
|
||||
+ * @block_id: HW Extended VLAN block ID
|
||||
+ * @entry_index: entry index within the block
|
||||
+ * @desc: rule descriptor (filter type + action)
|
||||
+ * @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)
|
||||
+ *
|
||||
+ * Translates a compact rule descriptor into a full firmware
|
||||
+ * mxl862xx_extendedvlan_config struct and writes it via the API.
|
||||
+ */
|
||||
+static int mxl862xx_evlan_write_rule(struct mxl862xx_priv *priv,
|
||||
+ u16 block_id, u16 entry_index,
|
||||
+ const struct mxl862xx_evlan_rule_desc *desc,
|
||||
@ -788,11 +755,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ MXL862XX_EXTENDEDVLAN_TREATMENT_NOT_REMOVE_TAG);
|
||||
+ break;
|
||||
+
|
||||
+ case EVLAN_DISCARD:
|
||||
+ cfg.treatment.remove_tag =
|
||||
+ cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM);
|
||||
+ break;
|
||||
+
|
||||
+ case EVLAN_PVID_OR_DISCARD:
|
||||
+ if (pvid) {
|
||||
+ cfg.treatment.remove_tag =
|
||||
@ -809,22 +771,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case EVLAN_PVID_OR_PASS:
|
||||
+ if (pvid) {
|
||||
+ cfg.treatment.remove_tag =
|
||||
+ cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_NOT_REMOVE_TAG);
|
||||
+ cfg.treatment.add_outer_vlan = 1;
|
||||
+ cfg.treatment.outer_vlan.vid_mode =
|
||||
+ cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_VID_VAL);
|
||||
+ cfg.treatment.outer_vlan.vid_val = cpu_to_le32(pvid);
|
||||
+ cfg.treatment.outer_vlan.tpid =
|
||||
+ cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_8021Q);
|
||||
+ } else {
|
||||
+ cfg.treatment.remove_tag =
|
||||
+ cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_NOT_REMOVE_TAG);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case EVLAN_STRIP1_AND_PVID_OR_DISCARD:
|
||||
+ if (pvid) {
|
||||
+ cfg.treatment.remove_tag =
|
||||
@ -845,15 +791,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return MXL862XX_API_WRITE(priv, MXL862XX_EXTENDEDVLAN_SET, cfg);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_evlan_deactivate_entry - Reset an Extended VLAN entry to no-op
|
||||
+ * @priv: driver private data
|
||||
+ * @block_id: HW Extended VLAN block ID
|
||||
+ * @entry_index: entry index within the block
|
||||
+ *
|
||||
+ * Writes a zeroed-out config to the firmware, which deactivates the
|
||||
+ * rule (making it transparent / no-op).
|
||||
+ */
|
||||
+static int mxl862xx_evlan_deactivate_entry(struct mxl862xx_priv *priv,
|
||||
+ u16 block_id, u16 entry_index)
|
||||
+{
|
||||
@ -876,19 +813,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return MXL862XX_API_WRITE(priv, MXL862XX_EXTENDEDVLAN_SET, cfg);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_evlan_write_final_rules - Write catchall rules to the ingress block
|
||||
+ * @priv: driver private data
|
||||
+ * @blk: Extended VLAN block (already allocated)
|
||||
+ * @rules: array of rule descriptors for the final rules
|
||||
+ * @n_rules: number of final rules
|
||||
+ * @pvid: port VLAN ID (for PVID insertion rules)
|
||||
+ *
|
||||
+ * Writes final catchall rules starting at block_size - n_rules. With
|
||||
+ * VLAN Filter handling VID membership, only the ingress block uses
|
||||
+ * finals, and the block is sized to exactly fit them (no VID entries),
|
||||
+ * so the rules fill the entire block.
|
||||
+ */
|
||||
+static int mxl862xx_evlan_write_final_rules(struct mxl862xx_priv *priv,
|
||||
+ struct mxl862xx_evlan_block *blk,
|
||||
+ const struct mxl862xx_evlan_rule_desc *rules,
|
||||
@ -908,15 +832,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_vf_entry_set - Write a single VLAN Filter entry
|
||||
+ * @priv: driver private data
|
||||
+ * @block_id: HW VLAN Filter block ID
|
||||
+ * @index: entry index within the block
|
||||
+ * @vid: VLAN ID to allow
|
||||
+ *
|
||||
+ * Writes an ALLOW entry (discard_matched=false) for the given VID.
|
||||
+ */
|
||||
+static int mxl862xx_vf_entry_set(struct mxl862xx_priv *priv,
|
||||
+ u16 block_id, u16 index, u16 vid)
|
||||
+{
|
||||
@ -931,13 +846,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return MXL862XX_API_WRITE(priv, MXL862XX_VLANFILTER_SET, cfg);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_vf_find_vid - Find a VID entry in a VF block
|
||||
+ * @vf: VLAN Filter block to search
|
||||
+ * @vid: VLAN ID to find
|
||||
+ */
|
||||
+static struct mxl862xx_vf_vid *
|
||||
+mxl862xx_vf_find_vid(struct mxl862xx_vf_block *vf, u16 vid)
|
||||
+static struct mxl862xx_vf_vid *mxl862xx_vf_find_vid(struct mxl862xx_vf_block *vf,
|
||||
+ u16 vid)
|
||||
+{
|
||||
+ struct mxl862xx_vf_vid *ve;
|
||||
+
|
||||
@ -948,17 +858,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_vf_add_vid - Add a VID to a port's VLAN Filter block
|
||||
+ * @priv: driver private data
|
||||
+ * @vf: VLAN Filter block
|
||||
+ * @vid: VLAN ID to add
|
||||
+ * @untagged: whether this VID should strip tags on egress
|
||||
+ *
|
||||
+ * Idempotent. Writes an ALLOW entry at active_count and increments
|
||||
+ * active_count. If the VID already exists, only the untagged flag
|
||||
+ * is updated. The HW block must be allocated before calling this.
|
||||
+ */
|
||||
+static int mxl862xx_vf_add_vid(struct mxl862xx_priv *priv,
|
||||
+ struct mxl862xx_vf_block *vf,
|
||||
+ u16 vid, bool untagged)
|
||||
@ -995,17 +894,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_vf_del_vid - Remove a VID from a port's VLAN Filter block
|
||||
+ * @priv: driver private data
|
||||
+ * @vf: VLAN Filter block
|
||||
+ * @vid: VLAN ID to remove
|
||||
+ *
|
||||
+ * Swap-compacts: the last active entry is moved into the gap,
|
||||
+ * active_count is decremented, and the old last slot is plugged
|
||||
+ * with DISCARD. When active_count drops to 0, a DISCARD sentinel
|
||||
+ * is restored at index 0.
|
||||
+ */
|
||||
+static int mxl862xx_vf_del_vid(struct mxl862xx_priv *priv,
|
||||
+ struct mxl862xx_vf_block *vf, u16 vid)
|
||||
+{
|
||||
@ -1035,12 +923,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return ret;
|
||||
+ } else if (gap < last) {
|
||||
+ /* Swap: move the last ALLOW entry into the gap */
|
||||
+ last_ve = NULL;
|
||||
+ list_for_each_entry(last_ve, &vf->vids, list)
|
||||
+ if (last_ve->index == last)
|
||||
+ break;
|
||||
+
|
||||
+ if (WARN_ON(!last_ve || last_ve->index != last))
|
||||
+ if (WARN_ON(list_entry_is_head(last_ve, &vf->vids, list)))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ret = mxl862xx_vf_entry_set(priv, vf->block_id,
|
||||
@ -1049,16 +936,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return ret;
|
||||
+
|
||||
+ last_ve->index = gap;
|
||||
+
|
||||
+ /* Plug the old last slot with DISCARD */
|
||||
+ ret = mxl862xx_vf_entry_discard(priv, vf->block_id, last);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ } else {
|
||||
+ /* Deleting the last entry -- just plug it */
|
||||
+ ret = mxl862xx_vf_entry_discard(priv, vf->block_id, last);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ list_del(&ve->list);
|
||||
@ -1068,20 +945,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_evlan_program_ingress - Write the fixed ingress catchall rules
|
||||
+ * @priv: driver private data
|
||||
+ * @port: port number
|
||||
+ *
|
||||
+ * In VLAN-aware mode the ingress EVLAN block handles PVID insertion for
|
||||
+ * untagged/priority-tagged frames, passes through standard 802.1Q
|
||||
+ * tagged frames for VF membership checking, and treats non-8021Q TPID
|
||||
+ * frames as untagged. The block is sized to exactly fit the 7 catchall
|
||||
+ * rules and is rewritten whenever PVID changes.
|
||||
+ *
|
||||
+ * In VLAN-unaware mode the firmware passes frames through unchanged when
|
||||
+ * no ingress block is assigned, so nothing is programmed.
|
||||
+ */
|
||||
+static int mxl862xx_evlan_program_ingress(struct mxl862xx_priv *priv, int port)
|
||||
+{
|
||||
+ struct mxl862xx_port *p = &priv->ports[port];
|
||||
@ -1099,19 +962,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ p->pvid);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mxl862xx_evlan_program_egress - Reprogram all egress tag-stripping rules
|
||||
+ * @priv: driver private data
|
||||
+ * @port: port number
|
||||
+ *
|
||||
+ * Walks the port's VF VID list and writes 2 EVLAN rules per VID that
|
||||
+ * needs egress tag stripping. In VLAN-aware mode only untagged VIDs
|
||||
+ * need rules (tagged VIDs pass through EVLAN untouched). In unaware
|
||||
+ * mode every VID gets rules.
|
||||
+ *
|
||||
+ * Entries are packed starting at index 0, and the scan window
|
||||
+ * (n_active) is narrowed so stale entries beyond it are never matched.
|
||||
+ */
|
||||
+static int mxl862xx_evlan_program_egress(struct mxl862xx_priv *priv, int port)
|
||||
+{
|
||||
+ struct mxl862xx_port *p = &priv->ports[port];
|
||||
@ -1131,10 +981,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ }
|
||||
+
|
||||
+ list_for_each_entry(vfv, &p->vf.vids, list) {
|
||||
+ /* In VLAN-aware mode tagged-only VIDs need no EVLAN
|
||||
+ * rules -- VLAN Filter handles membership.
|
||||
+ */
|
||||
+ if (p->vlan_filtering && !vfv->untagged)
|
||||
+ if (!vfv->untagged)
|
||||
+ continue;
|
||||
+
|
||||
+ if (idx + n_vid > blk->block_size)
|
||||
@ -1182,12 +1029,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+{
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_port *p = &priv->ports[port];
|
||||
+ bool old_vlan_filtering = p->vlan_filtering;
|
||||
+ bool old_in_use = p->ingress_evlan.in_use;
|
||||
+ bool changed = (p->vlan_filtering != vlan_filtering);
|
||||
+ int ret;
|
||||
+
|
||||
+ p->vlan_filtering = vlan_filtering;
|
||||
+
|
||||
+ /* Reprogram Extended VLAN rules if filtering mode changed */
|
||||
+ if (changed) {
|
||||
+ /* When leaving VLAN-aware mode, release the ingress HW
|
||||
+ * block. The firmware passes frames through unchanged
|
||||
@ -1199,17 +1047,20 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+ ret = mxl862xx_evlan_program_ingress(priv, port);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ goto err_restore;
|
||||
+
|
||||
+ ret = mxl862xx_evlan_program_egress(priv, port);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ goto err_restore;
|
||||
+ }
|
||||
+
|
||||
+ /* Push VLAN-based MAC learning flags and (possibly newly
|
||||
+ * allocated) ingress block to hardware.
|
||||
+ */
|
||||
+ return mxl862xx_set_bridge_port(ds, port);
|
||||
+
|
||||
+ /* No HW rollback -- restoring SW state is sufficient for a correct retry. */
|
||||
+err_restore:
|
||||
+ p->vlan_filtering = old_vlan_filtering;
|
||||
+ p->ingress_evlan.in_use = old_in_use;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int mxl862xx_port_vlan_add(struct dsa_switch *ds, int port,
|
||||
@ -1255,21 +1106,32 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ if (pvid_changed) {
|
||||
+ ret = mxl862xx_evlan_program_ingress(priv, port);
|
||||
+ if (ret)
|
||||
+ goto err_pvid;
|
||||
+ goto err_rollback;
|
||||
+ }
|
||||
+
|
||||
+ /* Reprogram egress tag-stripping rules (walks VF VID list) */
|
||||
+ ret = mxl862xx_evlan_program_egress(priv, port);
|
||||
+ if (ret)
|
||||
+ goto err_pvid;
|
||||
+ goto err_rollback;
|
||||
+
|
||||
+ /* Apply VLAN block IDs and MAC learning flags to bridge port */
|
||||
+ ret = mxl862xx_set_bridge_port(ds, port);
|
||||
+ if (ret)
|
||||
+ goto err_pvid;
|
||||
+ goto err_rollback;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_rollback:
|
||||
+ /* Best-effort: undo VF add and restore consistent hardware state.
|
||||
+ * A retry of port_vlan_add will converge since vf_add_vid is
|
||||
+ * idempotent.
|
||||
+ */
|
||||
+ p->pvid = old_pvid;
|
||||
+ mxl862xx_vf_del_vid(priv, &p->vf, vid);
|
||||
+ mxl862xx_evlan_program_ingress(priv, port);
|
||||
+ mxl862xx_evlan_program_egress(priv, port);
|
||||
+ mxl862xx_set_bridge_port(ds, port);
|
||||
+ return ret;
|
||||
+err_pvid:
|
||||
+ p->pvid = old_pvid;
|
||||
+ return ret;
|
||||
@ -1280,13 +1142,22 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+{
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_port *p = &priv->ports[port];
|
||||
+ u16 vid = vlan->vid;
|
||||
+ struct mxl862xx_vf_vid *ve;
|
||||
+ bool pvid_changed = false;
|
||||
+ u16 vid = vlan->vid;
|
||||
+ bool old_untagged;
|
||||
+ u16 old_pvid;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (dsa_is_cpu_port(ds, port))
|
||||
+ return 0;
|
||||
+
|
||||
+ ve = mxl862xx_vf_find_vid(&p->vf, vid);
|
||||
+ if (!ve)
|
||||
+ return 0;
|
||||
+ old_untagged = ve->untagged;
|
||||
+ old_pvid = p->pvid;
|
||||
+
|
||||
+ /* Clear PVID if we're deleting it */
|
||||
+ if (p->pvid == vid) {
|
||||
+ p->pvid = 0;
|
||||
@ -1299,28 +1170,45 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ */
|
||||
+ ret = mxl862xx_vf_del_vid(priv, &p->vf, vid);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ goto err_pvid;
|
||||
+
|
||||
+ /* Reprogram egress tag-stripping rules (VID is now gone) */
|
||||
+ ret = mxl862xx_evlan_program_egress(priv, port);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ goto err_rollback;
|
||||
+
|
||||
+ /* If PVID changed, reprogram ingress finals */
|
||||
+ if (pvid_changed) {
|
||||
+ ret = mxl862xx_evlan_program_ingress(priv, port);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ goto err_rollback;
|
||||
+ }
|
||||
+
|
||||
+ return mxl862xx_set_bridge_port(ds, port);
|
||||
+ ret = mxl862xx_set_bridge_port(ds, port);
|
||||
+ if (ret)
|
||||
+ goto err_rollback;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_rollback:
|
||||
+ /* Best-effort: re-add the VID and restore consistent hardware
|
||||
+ * state. A retry of port_vlan_del will converge.
|
||||
+ */
|
||||
+ p->pvid = old_pvid;
|
||||
+ mxl862xx_vf_add_vid(priv, &p->vf, vid, old_untagged);
|
||||
+ mxl862xx_evlan_program_egress(priv, port);
|
||||
+ mxl862xx_evlan_program_ingress(priv, port);
|
||||
+ mxl862xx_set_bridge_port(ds, port);
|
||||
+ return ret;
|
||||
+err_pvid:
|
||||
+ p->pvid = old_pvid;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int mxl862xx_setup_cpu_bridge(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_port *p = &priv->ports[port];
|
||||
struct dsa_port *dp;
|
||||
|
||||
- priv->ports[port].fid = MXL862XX_DEFAULT_BRIDGE;
|
||||
- priv->ports[port].learning = true;
|
||||
@ -1332,41 +1220,21 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * assignment need to be configured.
|
||||
+ */
|
||||
|
||||
/* include all assigned user ports in the CPU portmap */
|
||||
- bitmap_zero(priv->ports[port].portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
+ bitmap_zero(p->portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
dsa_switch_for_each_user_port(dp, ds) {
|
||||
/* it's safe to rely on cpu_dp being valid for user ports */
|
||||
if (dp->cpu_dp->index != port)
|
||||
continue;
|
||||
|
||||
- __set_bit(dp->index, priv->ports[port].portmap);
|
||||
+ __set_bit(dp->index, p->portmap);
|
||||
}
|
||||
|
||||
return mxl862xx_set_bridge_port(ds, port);
|
||||
}
|
||||
@@ -510,6 +1260,8 @@ static int mxl862xx_port_bridge_join(str
|
||||
static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
const struct dsa_bridge bridge)
|
||||
{
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_port *p = &priv->ports[port];
|
||||
int err;
|
||||
|
||||
+
|
||||
static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port,
|
||||
const struct dsa_bridge bridge,
|
||||
bool *tx_fwd_offload,
|
||||
@@ -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;
|
||||
+
|
||||
+ /* 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.
|
||||
+ *
|
||||
+ * 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.
|
||||
+ */
|
||||
err = mxl862xx_sync_bridge_members(ds, &bridge);
|
||||
@@ -521,6 +1273,10 @@ static void mxl862xx_port_bridge_leave(s
|
||||
/* Revert leaving port, omitted by the sync above, to its
|
||||
* single-port bridge
|
||||
*/
|
||||
+ p->pvid = 0;
|
||||
+ p->ingress_evlan.in_use = false;
|
||||
+ p->egress_evlan.in_use = false;
|
||||
@ -1374,28 +1242,22 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
err = mxl862xx_set_bridge_port(ds, port);
|
||||
if (err)
|
||||
dev_err(ds->dev,
|
||||
@@ -602,6 +1482,28 @@ static int mxl862xx_port_setup(struct ds
|
||||
@@ -585,6 +1341,22 @@ static int mxl862xx_port_setup(struct ds
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ /* Initialize and pre-allocate per-port EVLAN and VF blocks for
|
||||
+ * user ports. CPU ports do not use EVLAN or VF -- frames pass
|
||||
+ * through without processing. Pre-allocation avoids firmware
|
||||
+ * EVLAN table fragmentation and simplifies control flow.
|
||||
+ */
|
||||
+ mxl862xx_evlan_block_init(&priv->ports[port].ingress_evlan,
|
||||
+ priv->evlan_ingress_size);
|
||||
+ priv->ports[port].ingress_evlan.block_size = priv->evlan_ingress_size;
|
||||
+ ret = mxl862xx_evlan_block_alloc(priv, &priv->ports[port].ingress_evlan);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ mxl862xx_evlan_block_init(&priv->ports[port].egress_evlan,
|
||||
+ priv->evlan_egress_size);
|
||||
+ priv->ports[port].egress_evlan.block_size = priv->evlan_egress_size;
|
||||
+ ret = mxl862xx_evlan_block_alloc(priv, &priv->ports[port].egress_evlan);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ mxl862xx_vf_init(&priv->ports[port].vf, priv->vf_block_size);
|
||||
+ priv->ports[port].vf.block_size = priv->vf_block_size;
|
||||
+ INIT_LIST_HEAD(&priv->ports[port].vf.vids);
|
||||
+ ret = mxl862xx_vf_alloc(priv, &priv->ports[port].vf);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
@ -1403,7 +1265,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
priv->ports[port].setup_done = true;
|
||||
|
||||
return 0;
|
||||
@@ -1012,6 +1914,9 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -983,6 +1755,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,
|
||||
@ -1424,7 +1286,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,6 +88,66 @@ static inline bool mxl862xx_fw_portmap_i
|
||||
@@ -55,6 +57,66 @@ static inline bool mxl862xx_fw_portmap_i
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1491,7 +1353,7 @@ 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
|
||||
@@ -101,6 +163,11 @@ static inline bool mxl862xx_fw_portmap_i
|
||||
@@ -68,6 +130,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
|
||||
* acting on torn-down state
|
||||
@ -1503,11 +1365,10 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @host_flood_uc: desired host unicast flood state (true = flood);
|
||||
* updated atomically by port_set_host_flood, consumed
|
||||
* by the deferred host_flood_work
|
||||
@@ -119,6 +186,12 @@ struct mxl862xx_port {
|
||||
@@ -85,6 +152,11 @@ struct mxl862xx_port {
|
||||
unsigned long flood_block;
|
||||
bool learning;
|
||||
bool setup_done;
|
||||
+ /* VLAN state */
|
||||
+ u16 pvid;
|
||||
+ bool vlan_filtering;
|
||||
+ struct mxl862xx_vf_block vf;
|
||||
@ -1516,7 +1377,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
bool host_flood_uc;
|
||||
bool host_flood_mc;
|
||||
struct work_struct host_flood_work;
|
||||
@@ -126,17 +199,23 @@ struct mxl862xx_port {
|
||||
@@ -92,17 +164,23 @@ struct mxl862xx_port {
|
||||
|
||||
/**
|
||||
* struct mxl862xx_priv - driver private data for an MxL862xx switch
|
||||
@ -1551,7 +1412,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
struct mxl862xx_priv {
|
||||
struct dsa_switch *ds;
|
||||
@@ -146,6 +225,9 @@ struct mxl862xx_priv {
|
||||
@@ -112,6 +190,9 @@ struct mxl862xx_priv {
|
||||
u16 drop_meter;
|
||||
struct mxl862xx_port ports[MXL862XX_MAX_PORTS];
|
||||
u16 bridges[MXL862XX_MAX_BRIDGES + 1];
|
||||
@ -1,7 +1,7 @@
|
||||
From 0067d79d10becfc5779fb50d5c0ac152cc5dc303 Mon Sep 17 00:00:00 2001
|
||||
From e6295d124644b14a12b55edf5d3e89cf86a4a2ce Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Sun, 22 Mar 2026 00:57:33 +0000
|
||||
Subject: [PATCH 06/26] net: dsa: mxl862xx: add ethtool statistics support
|
||||
Date: Sun, 12 Apr 2026 01:01:57 +0100
|
||||
Subject: [PATCH 1/2] 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
|
||||
@ -16,11 +16,13 @@ legacy ethtool -S support. Implement .get_eth_mac_stats,
|
||||
IEEE 802.3 statistics interface.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/480be14d5ed51f3db7b1681b298044dbf8e87494.1775951347.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 142 ++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 142 +++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 3 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 168 ++++++++++++++++++++++++
|
||||
3 files changed, 313 insertions(+)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 173 ++++++++++++++++++++++++
|
||||
3 files changed, 318 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@ -120,7 +122,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * @tx_good_bytes: Transmitted good byte count (64-bit)
|
||||
+ */
|
||||
+struct mxl862xx_rmon_port_cnt {
|
||||
+ enum mxl862xx_port_type port_type;
|
||||
+ __le32 port_type; /* enum mxl862xx_port_type */
|
||||
+ __le16 port_id;
|
||||
+ __le16 sub_if_id_group;
|
||||
+ u8 pce_bypass;
|
||||
@ -192,7 +194,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#define MXL862XX_MAC_TABLEENTRYQUERY (MXL862XX_SWMAC_MAGIC + 0x4)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -30,6 +30,64 @@
|
||||
@@ -30,6 +30,38 @@
|
||||
#define MXL862XX_API_READ_QUIET(dev, cmd, data) \
|
||||
mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), true, true)
|
||||
|
||||
@ -209,60 +211,34 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ .offset = offsetof(struct mxl862xx_rmon_port_cnt, _element) \
|
||||
+}
|
||||
+
|
||||
+/* Hardware-specific counters not covered by any standardized stats callback. */
|
||||
+static const struct mxl862xx_mib_desc mxl862xx_mib[] = {
|
||||
+ MIB_DESC(1, "TxGoodPkts", tx_good_pkts),
|
||||
+ MIB_DESC(1, "TxUnicastPkts", tx_unicast_pkts),
|
||||
+ MIB_DESC(1, "TxBroadcastPkts", tx_broadcast_pkts),
|
||||
+ MIB_DESC(1, "TxMulticastPkts", tx_multicast_pkts),
|
||||
+ MIB_DESC(1, "Tx64BytePkts", tx64byte_pkts),
|
||||
+ MIB_DESC(1, "Tx127BytePkts", tx127byte_pkts),
|
||||
+ MIB_DESC(1, "Tx255BytePkts", tx255byte_pkts),
|
||||
+ MIB_DESC(1, "Tx511BytePkts", tx511byte_pkts),
|
||||
+ MIB_DESC(1, "Tx1023BytePkts", tx1023byte_pkts),
|
||||
+ MIB_DESC(1, "TxMaxBytePkts", tx_max_byte_pkts),
|
||||
+ MIB_DESC(1, "TxDroppedPkts", tx_dropped_pkts),
|
||||
+ MIB_DESC(1, "TxAcmDroppedPkts", tx_acm_dropped_pkts),
|
||||
+ MIB_DESC(2, "TxGoodBytes", tx_good_bytes),
|
||||
+ MIB_DESC(1, "TxSingleCollCount", tx_single_coll_count),
|
||||
+ MIB_DESC(1, "TxMultCollCount", tx_mult_coll_count),
|
||||
+ MIB_DESC(1, "TxLateCollCount", tx_late_coll_count),
|
||||
+ MIB_DESC(1, "TxExcessCollCount", tx_excess_coll_count),
|
||||
+ MIB_DESC(1, "TxCollCount", tx_coll_count),
|
||||
+ MIB_DESC(1, "TxPauseCount", tx_pause_count),
|
||||
+ MIB_DESC(1, "RxGoodPkts", rx_good_pkts),
|
||||
+ MIB_DESC(1, "RxUnicastPkts", rx_unicast_pkts),
|
||||
+ MIB_DESC(1, "RxBroadcastPkts", rx_broadcast_pkts),
|
||||
+ MIB_DESC(1, "RxMulticastPkts", rx_multicast_pkts),
|
||||
+ MIB_DESC(1, "RxFCSErrorPkts", rx_fcserror_pkts),
|
||||
+ MIB_DESC(1, "RxUnderSizeGoodPkts", rx_under_size_good_pkts),
|
||||
+ MIB_DESC(1, "RxOversizeGoodPkts", rx_oversize_good_pkts),
|
||||
+ MIB_DESC(1, "RxUnderSizeErrorPkts", rx_under_size_error_pkts),
|
||||
+ MIB_DESC(1, "RxOversizeErrorPkts", rx_oversize_error_pkts),
|
||||
+ MIB_DESC(1, "RxFilteredPkts", rx_filtered_pkts),
|
||||
+ MIB_DESC(1, "Rx64BytePkts", rx64byte_pkts),
|
||||
+ MIB_DESC(1, "Rx127BytePkts", rx127byte_pkts),
|
||||
+ MIB_DESC(1, "Rx255BytePkts", rx255byte_pkts),
|
||||
+ MIB_DESC(1, "Rx511BytePkts", rx511byte_pkts),
|
||||
+ MIB_DESC(1, "Rx1023BytePkts", rx1023byte_pkts),
|
||||
+ MIB_DESC(1, "RxMaxBytePkts", rx_max_byte_pkts),
|
||||
+ MIB_DESC(1, "RxDroppedPkts", rx_dropped_pkts),
|
||||
+ MIB_DESC(1, "RxExtendedVlanDiscardPkts", rx_extended_vlan_discard_pkts),
|
||||
+ MIB_DESC(1, "MtuExceedDiscardPkts", mtu_exceed_discard_pkts),
|
||||
+ MIB_DESC(2, "RxGoodBytes", rx_good_bytes),
|
||||
+ MIB_DESC(2, "RxBadBytes", rx_bad_bytes),
|
||||
+ MIB_DESC(1, "RxGoodPausePkts", rx_good_pause_pkts),
|
||||
+ MIB_DESC(1, "RxAlignErrorPkts", rx_align_error_pkts),
|
||||
+};
|
||||
+
|
||||
+static const struct ethtool_rmon_hist_range mxl862xx_rmon_ranges[] = {
|
||||
+ { 0, 64 },
|
||||
+ { 65, 127 },
|
||||
+ { 128, 255 },
|
||||
+ { 256, 511 },
|
||||
+ { 512, 1023 },
|
||||
+ { 1024, 10240 },
|
||||
+ {}
|
||||
+};
|
||||
+
|
||||
#define MXL862XX_SDMA_PCTRLP(p) (0xbc0 + ((p) * 0x6))
|
||||
#define MXL862XX_SDMA_PCTRL_EN BIT(0)
|
||||
|
||||
@@ -1893,6 +1951,110 @@ static int mxl862xx_port_bridge_flags(st
|
||||
@@ -1734,6 +1766,140 @@ static int mxl862xx_port_bridge_flags(st
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void mxl862xx_get_strings(struct dsa_switch *ds, int port,
|
||||
+ u32 stringset, u8 *data)
|
||||
+ u32 stringset, u8 *data)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
@ -285,7 +261,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ struct mxl862xx_rmon_port_cnt *cnt)
|
||||
+{
|
||||
+ memset(cnt, 0, sizeof(*cnt));
|
||||
+ cnt->port_type = MXL862XX_CTP_PORT;
|
||||
+ cnt->port_type = cpu_to_le32(MXL862XX_CTP_PORT);
|
||||
+ cnt->port_id = cpu_to_le16(port);
|
||||
+
|
||||
+ return MXL862XX_API_READ(ds->priv, MXL862XX_RMON_PORT_GET, *cnt);
|
||||
@ -365,10 +341,40 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ pause_stats->rx_pause_frames = le32_to_cpu(cnt.rx_good_pause_pkts);
|
||||
+}
|
||||
+
|
||||
+static void mxl862xx_get_rmon_stats(struct dsa_switch *ds, int port,
|
||||
+ struct ethtool_rmon_stats *rmon_stats,
|
||||
+ const struct ethtool_rmon_hist_range **ranges)
|
||||
+{
|
||||
+ struct mxl862xx_rmon_port_cnt cnt;
|
||||
+
|
||||
+ if (mxl862xx_read_rmon(ds, port, &cnt))
|
||||
+ return;
|
||||
+
|
||||
+ rmon_stats->undersize_pkts = le32_to_cpu(cnt.rx_under_size_good_pkts);
|
||||
+ rmon_stats->oversize_pkts = le32_to_cpu(cnt.rx_oversize_good_pkts);
|
||||
+ rmon_stats->fragments = le32_to_cpu(cnt.rx_under_size_error_pkts);
|
||||
+ rmon_stats->jabbers = le32_to_cpu(cnt.rx_oversize_error_pkts);
|
||||
+
|
||||
+ rmon_stats->hist[0] = le32_to_cpu(cnt.rx64byte_pkts);
|
||||
+ rmon_stats->hist[1] = le32_to_cpu(cnt.rx127byte_pkts);
|
||||
+ rmon_stats->hist[2] = le32_to_cpu(cnt.rx255byte_pkts);
|
||||
+ rmon_stats->hist[3] = le32_to_cpu(cnt.rx511byte_pkts);
|
||||
+ rmon_stats->hist[4] = le32_to_cpu(cnt.rx1023byte_pkts);
|
||||
+ rmon_stats->hist[5] = le32_to_cpu(cnt.rx_max_byte_pkts);
|
||||
+
|
||||
+ rmon_stats->hist_tx[0] = le32_to_cpu(cnt.tx64byte_pkts);
|
||||
+ rmon_stats->hist_tx[1] = le32_to_cpu(cnt.tx127byte_pkts);
|
||||
+ rmon_stats->hist_tx[2] = le32_to_cpu(cnt.tx255byte_pkts);
|
||||
+ rmon_stats->hist_tx[3] = le32_to_cpu(cnt.tx511byte_pkts);
|
||||
+ rmon_stats->hist_tx[4] = le32_to_cpu(cnt.tx1023byte_pkts);
|
||||
+ rmon_stats->hist_tx[5] = le32_to_cpu(cnt.tx_max_byte_pkts);
|
||||
+
|
||||
+ *ranges = mxl862xx_rmon_ranges;
|
||||
+}
|
||||
static const struct dsa_switch_ops mxl862xx_switch_ops = {
|
||||
.get_tag_protocol = mxl862xx_get_tag_protocol,
|
||||
.setup = mxl862xx_setup,
|
||||
@@ -1917,6 +2079,12 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -1758,6 +1924,13 @@ 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,
|
||||
@ -378,6 +384,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ .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,
|
||||
+ .get_rmon_stats = mxl862xx_get_rmon_stats,
|
||||
};
|
||||
|
||||
static void mxl862xx_phylink_mac_config(struct phylink_config *config,
|
||||
@ -1,20 +1,22 @@
|
||||
From bab5a69e3872a693069e430a1fa0d2825ea83b4f Mon Sep 17 00:00:00 2001
|
||||
From a21d33a5265f0b31d935a8b9b2b6faefb5185911 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 04:14:38 +0000
|
||||
Subject: [PATCH 07/26] net: dsa: mxl862xx: implement .get_stats64
|
||||
Date: Sun, 12 Apr 2026 01:02:05 +0100
|
||||
Subject: [PATCH 2/2] 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
|
||||
in ~880s at 2.5 Gbps line rate; the 2s polling interval provides a
|
||||
comfortable margin. The .get_stats64 callback forces a fresh poll so
|
||||
that counters are always up to date when queried.
|
||||
in ~220s at 10 Gbps line rate with minimum-size frames; the 2s polling
|
||||
interval provides a comfortable margin. The .get_stats64 callback
|
||||
forces a fresh poll so that counters are always up to date when queried.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Link: https://patch.msgid.link/fa38548ba05866879e8912721edc91947ce4ff12.1775951347.git.daniel@makrotopia.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
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(-)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 175 +++++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 94 +++++++++++-
|
||||
3 files changed, 270 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-host.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-host.c
|
||||
@ -69,7 +71,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
struct mxl862xx_mib_desc {
|
||||
unsigned int size;
|
||||
unsigned int offset;
|
||||
@@ -739,6 +745,9 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -677,6 +683,9 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -79,10 +81,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return mxl862xx_setup_mdio(ds);
|
||||
}
|
||||
|
||||
@@ -2055,6 +2064,158 @@ static void mxl862xx_get_pause_stats(str
|
||||
pause_stats->rx_pause_frames = le32_to_cpu(cnt.rx_good_pause_pkts);
|
||||
}
|
||||
@@ -1900,6 +1909,159 @@ static void mxl862xx_get_rmon_stats(stru
|
||||
|
||||
*ranges = mxl862xx_rmon_ranges;
|
||||
}
|
||||
+
|
||||
+/* Compute the delta between two 32-bit free-running counter snapshots,
|
||||
+ * handling a single wrap-around correctly via unsigned subtraction.
|
||||
+ */
|
||||
@ -238,15 +241,15 @@ 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,
|
||||
@@ -2085,6 +2246,7 @@ static const struct dsa_switch_ops mxl86
|
||||
.get_eth_mac_stats = mxl862xx_get_eth_mac_stats,
|
||||
@@ -1931,6 +2093,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_rmon_stats = mxl862xx_get_rmon_stats,
|
||||
+ .get_stats64 = mxl862xx_get_stats64,
|
||||
};
|
||||
|
||||
static void mxl862xx_phylink_mac_config(struct phylink_config *config,
|
||||
@@ -2146,16 +2308,22 @@ static int mxl862xx_probe(struct mdio_de
|
||||
@@ -1992,16 +2155,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);
|
||||
@ -269,7 +272,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -2170,6 +2338,9 @@ static void mxl862xx_remove(struct mdio_
|
||||
@@ -2016,6 +2185,9 @@ static void mxl862xx_remove(struct mdio_
|
||||
|
||||
priv = ds->priv;
|
||||
|
||||
@ -279,7 +282,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
dsa_unregister_switch(ds);
|
||||
|
||||
mxl862xx_host_shutdown(priv);
|
||||
@@ -2196,6 +2367,9 @@ static void mxl862xx_shutdown(struct mdi
|
||||
@@ -2042,6 +2214,9 @@ static void mxl862xx_shutdown(struct mdi
|
||||
|
||||
dsa_switch_shutdown(ds);
|
||||
|
||||
@ -291,11 +294,45 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
for (i = 0; i < MXL862XX_MAX_PORTS; i++)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -148,6 +148,47 @@ struct mxl862xx_evlan_block {
|
||||
@@ -117,6 +117,79 @@ struct mxl862xx_evlan_block {
|
||||
};
|
||||
|
||||
/**
|
||||
+ * struct mxl862xx_port_stats - 64-bit accumulated hardware port statistics
|
||||
+ * @rx_packets: total received packets
|
||||
+ * @tx_packets: total transmitted packets
|
||||
+ * @rx_bytes: total received bytes
|
||||
+ * @tx_bytes: total transmitted bytes
|
||||
+ * @rx_errors: total receive errors
|
||||
+ * @tx_errors: total transmit errors
|
||||
+ * @rx_dropped: total received packets dropped
|
||||
+ * @tx_dropped: total transmitted packets dropped
|
||||
+ * @multicast: total received multicast packets
|
||||
+ * @collisions: total transmit collisions
|
||||
+ * @rx_length_errors: received length errors (undersize + oversize)
|
||||
+ * @rx_crc_errors: received FCS errors
|
||||
+ * @rx_frame_errors: received alignment errors
|
||||
+ * @prev_rx_good_pkts: previous snapshot of rx good packet counter
|
||||
+ * @prev_tx_good_pkts: previous snapshot of tx good packet counter
|
||||
+ * @prev_rx_good_bytes: previous snapshot of rx good byte counter
|
||||
+ * @prev_tx_good_bytes: previous snapshot of tx good byte counter
|
||||
+ * @prev_rx_fcserror_pkts: previous snapshot of rx FCS error counter
|
||||
+ * @prev_rx_under_size_error_pkts: previous snapshot of rx undersize
|
||||
+ * error counter
|
||||
+ * @prev_rx_oversize_error_pkts: previous snapshot of rx oversize
|
||||
+ * error counter
|
||||
+ * @prev_rx_align_error_pkts: previous snapshot of rx alignment
|
||||
+ * error counter
|
||||
+ * @prev_tx_dropped_pkts: previous snapshot of tx dropped counter
|
||||
+ * @prev_rx_dropped_pkts: previous snapshot of rx dropped counter
|
||||
+ * @prev_rx_evlan_discard_pkts: previous snapshot of extended VLAN
|
||||
+ * discard counter
|
||||
+ * @prev_mtu_exceed_discard_pkts: previous snapshot of MTU exceed
|
||||
+ * discard counter
|
||||
+ * @prev_tx_acm_dropped_pkts: previous snapshot of tx ACM dropped
|
||||
+ * counter
|
||||
+ * @prev_rx_multicast_pkts: previous snapshot of rx multicast counter
|
||||
+ * @prev_tx_coll_count: previous snapshot of tx collision counter
|
||||
+ *
|
||||
+ * The firmware RMON counters are 32-bit free-running (64-bit for byte
|
||||
+ * counters). This structure holds 64-bit accumulators alongside the
|
||||
@ -303,7 +340,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * handling 32-bit wrap correctly via unsigned subtraction.
|
||||
+ */
|
||||
+struct mxl862xx_port_stats {
|
||||
+ /* 64-bit accumulators */
|
||||
+ u64 rx_packets;
|
||||
+ u64 tx_packets;
|
||||
+ u64 rx_bytes;
|
||||
@ -317,7 +353,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ u64 rx_length_errors;
|
||||
+ u64 rx_crc_errors;
|
||||
+ u64 rx_frame_errors;
|
||||
+ /* Previous raw RMON values for delta computation */
|
||||
+ u32 prev_rx_good_pkts;
|
||||
+ u32 prev_tx_good_pkts;
|
||||
+ u64 prev_rx_good_bytes;
|
||||
@ -339,7 +374,7 @@ 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
|
||||
@@ -178,6 +219,10 @@ struct mxl862xx_evlan_block {
|
||||
@@ -145,6 +218,10 @@ struct mxl862xx_evlan_block {
|
||||
* The worker acquires rtnl_lock() to serialize with
|
||||
* DSA callbacks and checks @setup_done to avoid
|
||||
* acting on torn-down ports.
|
||||
@ -350,13 +385,12 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
struct mxl862xx_port {
|
||||
struct mxl862xx_priv *priv;
|
||||
@@ -195,16 +240,25 @@ struct mxl862xx_port {
|
||||
@@ -160,16 +237,24 @@ struct mxl862xx_port {
|
||||
bool host_flood_uc;
|
||||
bool host_flood_mc;
|
||||
struct work_struct host_flood_work;
|
||||
+ /* Hardware stats accumulation */
|
||||
+ struct mxl862xx_port_stats stats;
|
||||
+ spinlock_t stats_lock;
|
||||
+ spinlock_t stats_lock; /* protects stats accumulators */
|
||||
};
|
||||
|
||||
+/* Bit indices for struct mxl862xx_priv::flags */
|
||||
@ -378,7 +412,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @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 {
|
||||
@@ -181,18 +266,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
|
||||
@ -1,7 +1,7 @@
|
||||
From da12469e73282da814163125153f381823e33f20 Mon Sep 17 00:00:00 2001
|
||||
From 60a23e663e0c607ae4ed871aaa24d257051ad557 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 17:56:35 +0000
|
||||
Subject: [PATCH 08/26] net: dsa: mxl862xx: store firmware version for feature
|
||||
Subject: [PATCH 01/19] net: dsa: mxl862xx: store firmware version for feature
|
||||
gating
|
||||
|
||||
Query the firmware version at init (already done in wait_ready),
|
||||
@ -20,7 +20,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -286,6 +286,9 @@ static int mxl862xx_wait_ready(struct ds
|
||||
@@ -257,6 +257,9 @@ static int mxl862xx_wait_ready(struct ds
|
||||
ver.iv_major, ver.iv_minor,
|
||||
le16_to_cpu(ver.iv_revision),
|
||||
le32_to_cpu(ver.iv_build_num));
|
||||
@ -40,8 +40,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/dsa.h>
|
||||
@@ -245,6 +246,38 @@ struct mxl862xx_port {
|
||||
spinlock_t stats_lock;
|
||||
@@ -241,6 +242,38 @@ struct mxl862xx_port {
|
||||
spinlock_t stats_lock; /* protects stats accumulators */
|
||||
};
|
||||
|
||||
+/**
|
||||
@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
/* 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 {
|
||||
@@ -258,6 +291,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,7 +88,7 @@ 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
|
||||
@@ -279,6 +314,7 @@ struct mxl862xx_priv {
|
||||
@@ -275,6 +310,7 @@ struct mxl862xx_priv {
|
||||
struct work_struct crc_err_work;
|
||||
unsigned long flags;
|
||||
u16 drop_meter;
|
||||
@ -1,7 +1,7 @@
|
||||
From f7606470d398e4091e1bc405bf2125dc5fc99919 Mon Sep 17 00:00:00 2001
|
||||
From cefa0447dc95a4ddd5093f7b8cf35e654870283f Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 21:39:30 +0000
|
||||
Subject: [PATCH 09/26] net: dsa: mxl862xx: move phylink stubs to
|
||||
Subject: [PATCH 02/19] 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)
|
||||
@@ -1597,16 +1598,6 @@ static void mxl862xx_port_teardown(struc
|
||||
@@ -1424,16 +1425,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;
|
||||
@@ -2252,33 +2243,6 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -2099,33 +2090,6 @@ static const struct dsa_switch_ops mxl86
|
||||
.get_stats64 = mxl862xx_get_stats64,
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
From e583eeeb907f0abeef2082162293a5d63b9fd6fa Mon Sep 17 00:00:00 2001
|
||||
From 3c1d77006daca1df20d612850535bc6050e266ee Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 26 Mar 2026 01:50:00 +0000
|
||||
Subject: [PATCH 10/26] net: dsa: mxl862xx: move API macros to mxl862xx-host.h
|
||||
Subject: [PATCH 03/19] 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
|
||||
@ -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
|
||||
@@ -684,7 +684,7 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -622,7 +622,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)
|
||||
@@ -694,6 +694,9 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -632,6 +632,9 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1011,7 +1011,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* Ingress: only final catchall rules (PVID insertion, 802.1Q
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -247,6 +247,22 @@ struct mxl862xx_port {
|
||||
@@ -243,6 +243,22 @@ struct mxl862xx_port {
|
||||
};
|
||||
|
||||
/**
|
||||
@ -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
|
||||
@@ -297,6 +313,8 @@ union mxl862xx_fw_version {
|
||||
@@ -293,6 +309,8 @@ union mxl862xx_fw_version {
|
||||
* flooding)
|
||||
* @fw_version: cached firmware version, populated at probe and
|
||||
* compared with MXL862XX_FW_VER_MIN()
|
||||
@ -1043,7 +1043,7 @@ 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
|
||||
@@ -315,6 +333,7 @@ struct mxl862xx_priv {
|
||||
@@ -311,6 +329,7 @@ struct mxl862xx_priv {
|
||||
unsigned long flags;
|
||||
u16 drop_meter;
|
||||
union mxl862xx_fw_version fw_version;
|
||||
@ -1,7 +1,7 @@
|
||||
From 24d752291784e30d7329bed15744bbbc6a3e2485 Mon Sep 17 00:00:00 2001
|
||||
From 3659914c43a587a1ca6418867834831aa518ac35 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:14:33 +0000
|
||||
Subject: [PATCH 12/26] net: dsa: mxl862xx: add SerDes ethtool statistics
|
||||
Subject: [PATCH 05/19] 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
|
||||
@@ -1960,6 +1960,8 @@ static void mxl862xx_get_strings(struct
|
||||
@@ -1775,6 +1775,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)
|
||||
@@ -1967,7 +1969,7 @@ static int mxl862xx_get_sset_count(struc
|
||||
@@ -1782,7 +1784,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,
|
||||
@@ -2003,6 +2005,8 @@ static void mxl862xx_get_ethtool_stats(s
|
||||
@@ -1818,6 +1820,8 @@ static void mxl862xx_get_ethtool_stats(s
|
||||
else
|
||||
*data++ = le64_to_cpu(*(__le64 *)field);
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
From ee227a5e4c74f599cc1b34578b32214d5873ad2f Mon Sep 17 00:00:00 2001
|
||||
From ce66c0be462c8500dfc483395e68be4326ebf296 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:15:32 +0000
|
||||
Subject: [PATCH 13/26] net: dsa: mxl862xx: add SerDes self-test via PRBS and
|
||||
Subject: [PATCH 06/19] net: dsa: mxl862xx: add SerDes self-test via PRBS and
|
||||
BERT
|
||||
|
||||
Implement the dsa_switch_ops.self_test callback for SerDes ports
|
||||
@ -198,9 +198,9 @@ 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
|
||||
@@ -2241,6 +2241,7 @@ static const struct dsa_switch_ops mxl86
|
||||
.get_eth_ctrl_stats = mxl862xx_get_eth_ctrl_stats,
|
||||
@@ -2088,6 +2088,7 @@ static const struct dsa_switch_ops mxl86
|
||||
.get_pause_stats = mxl862xx_get_pause_stats,
|
||||
.get_rmon_stats = mxl862xx_get_rmon_stats,
|
||||
.get_stats64 = mxl862xx_get_stats64,
|
||||
+ .self_test = mxl862xx_serdes_self_test,
|
||||
};
|
||||
@ -1,14 +1,28 @@
|
||||
From 43eb3eed250ea4e7e83371fcbf2bfb8d626eade6 Mon Sep 17 00:00:00 2001
|
||||
From e6defbd42db6e64c2bb203f82b7d7f8c0691a052 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:51:13 +0000
|
||||
Subject: [PATCH 14/26] net: dsa: mxl862xx: trap link-local frames to the CPU
|
||||
port
|
||||
Subject: [PATCH 07/19] net: dsa: mxl862xx: trap link-local and multicast
|
||||
snooping frames to CPU
|
||||
|
||||
Install per-CTP PCE rules on each user port that trap IEEE 802.1D
|
||||
link-local frames (01:80:c2:00:00:0x) to the CPU port via an
|
||||
explicit forwarding portmap with cross-state enabled, ensuring the
|
||||
frames reach the host even when the bridge port is in BLOCKING or
|
||||
LEARNING state.
|
||||
link-local frames (01:80:c2:00:00:0x) and IP multicast snooping
|
||||
frames (IGMP, MLDv1, MLDv2) to the CPU port.
|
||||
|
||||
All trap rules share a common action helper,
|
||||
mxl862xx_fill_cpu_trap_action(), which sets PORTMAP_ALTERNATIVE to
|
||||
redirect frames to the CPU and enables cross-state forwarding so
|
||||
that frames reach the host even when the bridge port is in BLOCKING
|
||||
or LEARNING state.
|
||||
|
||||
A dedicated bridge FID (cpu_trap_fid) is allocated during setup with
|
||||
all flood modes enabled. Each trap rule points the bridge engine at
|
||||
this FID via bFidEnable so that IGMP and MLD frames are never
|
||||
silently dropped by the ingress port's private flood policy.
|
||||
|
||||
Three multicast snooping rules are installed per port:
|
||||
offset 2 -- IPv4 IGMP (IP protocol 2, all versions)
|
||||
offset 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
|
||||
offset 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
|
||||
|
||||
Add the PCE rule firmware API structures, command definitions, and
|
||||
the rule block allocation interface.
|
||||
@ -17,8 +31,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 684 ++++++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 5 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 69 +++
|
||||
3 files changed, 758 insertions(+)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 186 +++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 8 +
|
||||
4 files changed, 883 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@ -736,7 +751,15 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#define MXL862XX_BRIDGE_CONFIGGET (MXL862XX_BRDG_MAGIC + 0x3)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -280,9 +280,11 @@ static int mxl862xx_wait_ready(struct ds
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/etherdevice.h>
|
||||
+#include <linux/icmpv6.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
@@ -251,9 +252,11 @@ static int mxl862xx_wait_ready(struct ds
|
||||
ver.iv_major, ver.iv_minor,
|
||||
le16_to_cpu(ver.iv_revision),
|
||||
le32_to_cpu(ver.iv_build_num));
|
||||
@ -748,17 +771,54 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return 0;
|
||||
|
||||
not_ready_yet:
|
||||
@@ -410,6 +412,68 @@ static int mxl862xx_setup_drop_meter(str
|
||||
@@ -381,6 +384,158 @@ static int mxl862xx_setup_drop_meter(str
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
|
||||
}
|
||||
|
||||
+
|
||||
+/* 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
|
||||
+ * entries per port on a 10-port SKU, of which offset 0 is reserved
|
||||
+ * for flow-control marking). Offset 1 is the first unused slot.
|
||||
+/* Per-CTP offsets for protocol trap rules. Each port's CTP flow-table
|
||||
+ * block is pre-allocated by the firmware during init (44 entries per
|
||||
+ * port on a 10-port SKU, of which offset 0 is reserved for flow-control
|
||||
+ * marking). Offsets 1-4 are used for link-local and multicast snooping
|
||||
+ * traps; all others remain free.
|
||||
+ */
|
||||
+#define MXL862XX_LINK_LOCAL_CTP_OFFSET 1
|
||||
+#define MXL862XX_IGMP_CTP_OFFSET 2
|
||||
+#define MXL862XX_MLDV1_CTP_OFFSET 3
|
||||
+#define MXL862XX_MLDV2_CTP_OFFSET 4
|
||||
+
|
||||
+/* Fill the action fields of a PCE rule that traps ingress frames to
|
||||
+ * the CPU port. Used by both the link-local trap and the multicast
|
||||
+ * snooping traps. The caller must already have set the rule header
|
||||
+ * (logicalportid, subifidgroup, region) and the pattern fields.
|
||||
+ *
|
||||
+ * PORTMAP_ALTERNATIVE redirects the frame to the CPU port but does
|
||||
+ * not by itself bypass downstream flood gates. In SpTag mode the
|
||||
+ * ingress port's private FID may have forward_unknown_multicast=false,
|
||||
+ * which silently drops IGMP/MLD before they reach the CPU.
|
||||
+ * Setting bFidEnable to cpu_trap_fid (a dedicated bridge with all
|
||||
+ * flood modes enabled) overrides the FID used by the bridge engine,
|
||||
+ * so the frame is never classified as blocked unknown MC regardless
|
||||
+ * of the ingress port's standalone flood policy.
|
||||
+ *
|
||||
+ * Cross-state is enabled so trapped frames bypass STP port state.
|
||||
+ */
|
||||
+static void mxl862xx_fill_cpu_trap_action(struct dsa_switch *ds, int port,
|
||||
+ struct mxl862xx_pce_rule *rule)
|
||||
+{
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ int cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
+
|
||||
+ rule->action.port_map_action =
|
||||
+ cpu_to_le32(MXL862XX_PCE_ACTION_PORTMAP_ALTERNATIVE);
|
||||
+ mxl862xx_fw_portmap_set_bit(rule->action.forward_port_map, cpu_port);
|
||||
+
|
||||
+ rule->action.cross_state_action =
|
||||
+ cpu_to_le32(MXL862XX_PCE_ACTION_CROSS_STATE_CROSS);
|
||||
+
|
||||
+ rule->action.fid_enable = 1;
|
||||
+ rule->action.fid = priv->cpu_trap_fid;
|
||||
+}
|
||||
+
|
||||
+/* Install a PCE rule that traps IEEE 802.1D link-local frames
|
||||
+ * (01:80:c2:00:00:0x) to the CPU port for a single user port,
|
||||
@ -778,54 +838,164 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ */
|
||||
+static int mxl862xx_setup_link_local_trap(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ DECLARE_BITMAP(portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
+ struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_pce_rule rule = {};
|
||||
+ int cpu_port = dp->cpu_dp->index;
|
||||
+ int i;
|
||||
+
|
||||
+ /* Address this port's CTP flow-table block */
|
||||
+ rule.logicalportid = port;
|
||||
+ rule.subifidgroup = 0;
|
||||
+ rule.region = cpu_to_le32(MXL862XX_PCE_RULE_CTP);
|
||||
+
|
||||
+ /* Pattern: link-local MAC on this specific ingress port */
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_LINK_LOCAL_CTP_OFFSET);
|
||||
+ rule.pattern.enable = 1;
|
||||
+ rule.pattern.mac_dst_enable = 1;
|
||||
+ memcpy(rule.pattern.mac_dst, eth_reserved_addr_base, ETH_ALEN);
|
||||
+ rule.pattern.mac_dst_mask = cpu_to_le16(0x0001);
|
||||
+
|
||||
+ /* Action: forward to the CPU port via explicit portmap */
|
||||
+ rule.action.port_map_action =
|
||||
+ cpu_to_le32(MXL862XX_PCE_ACTION_PORTMAP_ALTERNATIVE);
|
||||
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
|
||||
+
|
||||
+ bitmap_zero(portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
+ __set_bit(cpu_port, portmap);
|
||||
+ for (i = 0; i < ARRAY_SIZE(rule.action.forward_port_map); i++)
|
||||
+ rule.action.forward_port_map[i] =
|
||||
+ cpu_to_le16(bitmap_read(portmap, i * 16, 16));
|
||||
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+}
|
||||
+
|
||||
+ /* Bypass STP port state */
|
||||
+ rule.action.cross_state_action =
|
||||
+ cpu_to_le32(MXL862XX_PCE_ACTION_CROSS_STATE_CROSS);
|
||||
+/* Install PCE rules that trap IGMP and MLD frames to the CPU port for
|
||||
+ * a single user port. PORTMAP_ALTERNATIVE overrides the bridge
|
||||
+ * forwarding portmap to the CPU port. bFidEnable points the bridge
|
||||
+ * engine at cpu_trap_fid (all flood modes enabled) so the frames are
|
||||
+ * never classified as blocked unknown MC regardless of the ingress
|
||||
+ * port's standalone flood policy.
|
||||
+ *
|
||||
+ * Three rules are installed per port:
|
||||
+ * offset 2 -- IPv4 IGMP (IP protocol 2, all versions)
|
||||
+ * offset 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
|
||||
+ * offset 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
|
||||
+ *
|
||||
+ * The MLDv1 rule uses range mode on the first two bytes after the IP
|
||||
+ * header (ICMPv6 type + code): lower bound 0x8200 (type 130, code 0)
|
||||
+ * to upper bound 0x84ff (type 132, code 255). The MLDv2 rule uses
|
||||
+ * nibble mask 0x3 to match type 143 with any code byte.
|
||||
+ */
|
||||
+static int mxl862xx_setup_snooping_traps(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_pce_rule rule = {};
|
||||
+ int ret;
|
||||
+
|
||||
+ return MXL862XX_API_WRITE(ds->priv, MXL862XX_TFLOW_PCERULEWRITE,
|
||||
+ rule);
|
||||
+ rule.logicalportid = port;
|
||||
+ rule.region = cpu_to_le32(MXL862XX_PCE_RULE_CTP);
|
||||
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
|
||||
+
|
||||
+ /* IGMP: IPv4 protocol 2, all versions */
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_IGMP_CTP_OFFSET);
|
||||
+ rule.pattern.enable = 1;
|
||||
+ rule.pattern.protocol = IPPROTO_IGMP;
|
||||
+ rule.pattern.protocol_enable = 1;
|
||||
+
|
||||
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* MLDv1: ICMPv6 types 130 (query), 131 (report), 132 (done).
|
||||
+ * Range mode covers all three types with any code value.
|
||||
+ */
|
||||
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV1_CTP_OFFSET);
|
||||
+ rule.pattern.enable = 1;
|
||||
+ rule.pattern.protocol = IPPROTO_ICMPV6;
|
||||
+ rule.pattern.protocol_enable = 1;
|
||||
+ rule.pattern.app_data_msb =
|
||||
+ cpu_to_le16((u16)ICMPV6_MGM_QUERY << 8);
|
||||
+ rule.pattern.app_mask_range_msb =
|
||||
+ cpu_to_le16(((u16)ICMPV6_MGM_REDUCTION << 8) | 0xff);
|
||||
+ rule.pattern.app_data_msb_enable = 1;
|
||||
+ rule.pattern.app_mask_range_msb_select = 1; /* range mode */
|
||||
+
|
||||
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* MLDv2: ICMPv6 type 143 (Listener Report v2), any code byte.
|
||||
+ * Nibble mask 0x3 masks nibbles 0-1 (lower byte = code field).
|
||||
+ */
|
||||
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV2_CTP_OFFSET);
|
||||
+ rule.pattern.enable = 1;
|
||||
+ rule.pattern.protocol = IPPROTO_ICMPV6;
|
||||
+ rule.pattern.protocol_enable = 1;
|
||||
+ rule.pattern.app_data_msb = cpu_to_le16((u16)ICMPV6_MLD2_REPORT << 8);
|
||||
+ rule.pattern.app_mask_range_msb = cpu_to_le16(0x0003);
|
||||
+ rule.pattern.app_data_msb_enable = 1;
|
||||
+ /* app_mask_range_msb_select = 0: nibble mask mode (default) */
|
||||
+
|
||||
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+}
|
||||
+
|
||||
static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct mxl862xx_bridge_port_config br_port_cfg = {};
|
||||
@@ -1549,6 +1613,11 @@ static int mxl862xx_port_setup(struct ds
|
||||
@@ -683,6 +838,28 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ /* install link-local trap for this user port */
|
||||
+
|
||||
+ /* Allocate a dedicated PCE snooping FID with all flood modes enabled.
|
||||
+ * Per-port PCE trap rules (link-local, IGMP, MLD) set bFidEnable to
|
||||
+ * this FID so that the bridge engine uses it for its flood-permission
|
||||
+ * check instead of the ingress port's private FID (which has
|
||||
+ * mc_flood=false to restrict unknown MC from reaching the CPU in the
|
||||
+ * normal path). The hardware PCE FID action field is 6 bits wide, so
|
||||
+ * the allocated ID must be in range 0..63.
|
||||
+ */
|
||||
+ ret = mxl862xx_allocate_bridge(priv);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (WARN_ON_ONCE(ret > 0x3F))
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ priv->cpu_trap_fid = ret;
|
||||
+
|
||||
+ ret = mxl862xx_bridge_config_fwd(ds, priv->cpu_trap_fid,
|
||||
+ true, true, true);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
schedule_delayed_work(&priv->stats_work,
|
||||
MXL862XX_STATS_POLL_INTERVAL);
|
||||
|
||||
@@ -1382,6 +1559,15 @@ static int mxl862xx_port_setup(struct ds
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ /* install link-local and multicast snooping traps */
|
||||
+ ret = mxl862xx_setup_link_local_trap(ds, port);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
/* Initialize and pre-allocate per-port EVLAN and VF blocks for
|
||||
* user ports. CPU ports do not use EVLAN or VF -- frames pass
|
||||
* through without processing. Pre-allocation avoids firmware
|
||||
+ ret = mxl862xx_setup_snooping_traps(ds, port);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
priv->ports[port].ingress_evlan.block_size = priv->evlan_ingress_size;
|
||||
ret = mxl862xx_evlan_block_alloc(priv, &priv->ports[port].ingress_evlan);
|
||||
if (ret)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -319,6 +319,13 @@ union mxl862xx_fw_version {
|
||||
* @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
|
||||
+ * @cpu_trap_fid: firmware bridge FID allocated for PCE-trapped frames;
|
||||
+ * configured with uc/mc/bc flood all enabled so that
|
||||
+ * IGMP, MLD, and link-local frames always reach the CPU
|
||||
+ * regardless of the ingress port's private FID flood
|
||||
+ * policy. Set once in setup() and referenced by
|
||||
+ * fill_cpu_trap_action() via bFidEnable. The PCE FID
|
||||
+ * action field is 6 bits, so this value must be <= 63.
|
||||
* @stats_work: periodic work item that polls RMON hardware counters
|
||||
* and accumulates them into 64-bit per-port stats
|
||||
*/
|
||||
@@ -335,6 +342,7 @@ struct mxl862xx_priv {
|
||||
u16 evlan_ingress_size;
|
||||
u16 evlan_egress_size;
|
||||
u16 vf_block_size;
|
||||
+ u16 cpu_trap_fid;
|
||||
struct delayed_work stats_work;
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
From e18f5b235d8df21209c73f4f0bbc00cc3a1973ba Mon Sep 17 00:00:00 2001
|
||||
From 264838ee8ee3ad611a84df96d889429f1ded2148 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:51:21 +0000
|
||||
Subject: [PATCH 15/26] net: dsa: mxl862xx: warn about old firmware default PCE
|
||||
Subject: [PATCH 08/19] net: dsa: mxl862xx: warn about old firmware default PCE
|
||||
rules
|
||||
|
||||
Firmware versions older than 1.0.80 install global PCE rules at
|
||||
@ -19,14 +19,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -809,6 +809,10 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -860,6 +860,10 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
true, true, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+
|
||||
+ if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
|
||||
+ dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules "
|
||||
+ "that interfere with DSA operation, please update\n");
|
||||
+
|
||||
schedule_delayed_work(&priv->stats_work,
|
||||
MXL862XX_STATS_POLL_INTERVAL);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
From 4e1d854199c166f617b93b7542e863e6a8ad2ccb Mon Sep 17 00:00:00 2001
|
||||
From a32f6a9c09b90e767a03ddac34d061545a0cf15e Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 03:44:41 +0000
|
||||
Subject: [PATCH 17/26] net: dsa: mxl862xx: add link aggregation support
|
||||
Subject: [PATCH 10/20] 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
|
||||
@ -33,9 +33,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 22 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 4 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 587 +++++++++++++++++++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 34 ++
|
||||
4 files changed, 630 insertions(+), 17 deletions(-)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 578 +++++++++++++++++++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 33 ++
|
||||
4 files changed, 621 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@ -90,8 +90,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#define INT_GPHY_READ (GPY_GPY2XX_MAGIC + 0x1)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -620,7 +620,42 @@ static int mxl862xx_setup_link_local_tra
|
||||
rule);
|
||||
@@ -680,7 +680,42 @@ static int mxl862xx_setup_snooping_traps
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
}
|
||||
|
||||
-static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
|
||||
@ -134,16 +134,31 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
{
|
||||
struct mxl862xx_bridge_port_config br_port_cfg = {};
|
||||
struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
@@ -632,7 +667,7 @@ static int mxl862xx_set_bridge_port(stru
|
||||
bool enable;
|
||||
int i, idx;
|
||||
@@ -713,8 +748,12 @@ static int mxl862xx_set_bridge_port(stru
|
||||
dp->bridge->dev) {
|
||||
if (member_dp->index == port)
|
||||
continue;
|
||||
- mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
- member_dp->index);
|
||||
+ if (!mxl862xx_is_lag_master(priv, member_dp->index))
|
||||
+ continue;
|
||||
+ mxl862xx_fw_portmap_set_bit(
|
||||
+ br_port_cfg.bridge_port_map,
|
||||
+ mxl862xx_lag_bridge_port(priv,
|
||||
+ member_dp->index));
|
||||
}
|
||||
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
mxl862xx_cpu_bridge_port_id(ds, port));
|
||||
@@ -727,7 +766,7 @@ static int mxl862xx_set_bridge_port(stru
|
||||
|
||||
bridge_id = dp->bridge ? priv->bridges[dp->bridge->num] : p->fid;
|
||||
|
||||
- br_port_cfg.bridge_port_id = cpu_to_le16(port);
|
||||
+ br_port_cfg.bridge_port_id = cpu_to_le16(bp_id);
|
||||
br_port_cfg.bridge_id = cpu_to_le16(bridge_id);
|
||||
br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_ID |
|
||||
MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
|
||||
@@ -715,12 +750,38 @@ static int mxl862xx_set_bridge_port(stru
|
||||
@@ -808,11 +847,38 @@ static int mxl862xx_set_bridge_port(stru
|
||||
br_port_cfg);
|
||||
}
|
||||
|
||||
@ -174,41 +189,16 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
static int mxl862xx_sync_bridge_members(struct dsa_switch *ds,
|
||||
const struct dsa_bridge *bridge)
|
||||
{
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
struct dsa_port *dp, *member_dp;
|
||||
- int port, err, ret = 0;
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct mxl862xx_port *p;
|
||||
+ int port, member, err, ret = 0;
|
||||
+ u16 lag_bp, bp;
|
||||
struct dsa_port *dp;
|
||||
- int ret = 0, err;
|
||||
+ u16 lag_bp;
|
||||
+ int err, ret = 0;
|
||||
|
||||
dsa_switch_for_each_bridge_member(dp, ds, bridge->dev) {
|
||||
port = dp->index;
|
||||
@@ -729,9 +790,21 @@ static int mxl862xx_sync_bridge_members(
|
||||
MXL862XX_MAX_BRIDGE_PORTS);
|
||||
|
||||
dsa_switch_for_each_bridge_member(member_dp, ds, bridge->dev) {
|
||||
- if (member_dp->index != port)
|
||||
- __set_bit(member_dp->index,
|
||||
- priv->ports[port].portmap);
|
||||
+ member = member_dp->index;
|
||||
+
|
||||
+ /* For LAG members, only include the LAG's
|
||||
+ * dedicated bridge port in the portmap.
|
||||
+ * Non-master members are skipped to avoid
|
||||
+ * duplicates (they share the same LAG bridge
|
||||
+ * port).
|
||||
+ */
|
||||
+ if (!mxl862xx_is_lag_master(priv, member))
|
||||
+ continue;
|
||||
+ if (member != port) {
|
||||
+ bp = mxl862xx_lag_bridge_port(priv,
|
||||
+ member);
|
||||
+ __set_bit(bp, priv->ports[port].portmap);
|
||||
+ }
|
||||
}
|
||||
__set_bit(mxl862xx_cpu_bridge_port_id(ds, port),
|
||||
priv->ports[port].portmap);
|
||||
@@ -741,6 +814,25 @@ static int mxl862xx_sync_bridge_members(
|
||||
err = mxl862xx_set_bridge_port(ds, dp->index);
|
||||
@@ -820,6 +886,25 @@ static int mxl862xx_sync_bridge_members(
|
||||
ret = err;
|
||||
}
|
||||
|
||||
@ -234,7 +224,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1881,6 +1973,408 @@ static int mxl862xx_setup_cpu_bridge(str
|
||||
@@ -1859,6 +1944,408 @@ static int mxl862xx_setup_cpu_bridge(str
|
||||
return mxl862xx_set_bridge_port(ds, port);
|
||||
}
|
||||
|
||||
@ -643,7 +633,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,
|
||||
@@ -1907,7 +2401,18 @@ static int mxl862xx_port_bridge_join(str
|
||||
@@ -1884,7 +2371,18 @@ static int mxl862xx_port_bridge_join(str
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -663,7 +653,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
@@ -1966,6 +2471,17 @@ static void mxl862xx_port_bridge_leave(s
|
||||
@@ -1935,6 +2433,17 @@ static void mxl862xx_port_bridge_leave(s
|
||||
"failed to update CPU VBP for port %d: %pe\n", port,
|
||||
ERR_PTR(err));
|
||||
|
||||
@ -681,7 +671,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (!dsa_bridge_ports(ds, bridge.dev))
|
||||
mxl862xx_free_bridge(ds, &bridge);
|
||||
}
|
||||
@@ -2591,18 +3107,17 @@ static int mxl862xx_get_fid(struct dsa_s
|
||||
@@ -2593,18 +3102,17 @@ static int mxl862xx_get_fid(struct dsa_s
|
||||
}
|
||||
|
||||
/**
|
||||
@ -707,7 +697,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)
|
||||
@@ -2618,7 +3133,7 @@ static int mxl862xx_fdb_bridge_port(stru
|
||||
@@ -2620,7 +3128,7 @@ static int mxl862xx_fdb_bridge_port(stru
|
||||
return bp_cpu;
|
||||
}
|
||||
|
||||
@ -716,7 +706,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2862,11 +3377,43 @@ static int mxl862xx_port_fdb_del(struct
|
||||
@@ -2867,11 +3375,43 @@ static int mxl862xx_port_fdb_del(struct
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -760,7 +750,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
u32 entry_port_id;
|
||||
int ret;
|
||||
|
||||
@@ -2880,7 +3427,7 @@ static int mxl862xx_port_fdb_dump(struct
|
||||
@@ -2885,7 +3425,7 @@ static int mxl862xx_port_fdb_dump(struct
|
||||
|
||||
entry_port_id = le32_to_cpu(param.port_id);
|
||||
|
||||
@ -769,7 +759,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);
|
||||
@@ -3521,6 +4068,11 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -3556,6 +4096,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 +771,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,
|
||||
@@ -3561,6 +4113,7 @@ static int mxl862xx_probe(struct mdio_de
|
||||
@@ -3597,6 +4142,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;
|
||||
@ -811,7 +801,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)
|
||||
@@ -228,6 +241,12 @@ struct mxl862xx_port_stats {
|
||||
@@ -227,6 +240,12 @@ struct mxl862xx_port_stats {
|
||||
* @stats_lock: protects accumulator reads in .get_stats64 against
|
||||
* concurrent updates from the polling work
|
||||
* @tag_8021q_vid: currently assigned tag_8021q management VID
|
||||
@ -824,21 +814,20 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
struct mxl862xx_port {
|
||||
struct mxl862xx_priv *priv;
|
||||
@@ -250,6 +269,10 @@ struct mxl862xx_port {
|
||||
@@ -246,6 +265,9 @@ struct mxl862xx_port {
|
||||
struct work_struct host_flood_work;
|
||||
u16 tag_8021q_vid;
|
||||
struct mxl862xx_evlan_block cpu_egress_evlan;
|
||||
+ /* LAG state */
|
||||
+ struct dsa_lag *lag;
|
||||
+ bool lag_tx_enabled;
|
||||
+ u8 lag_hash_bits;
|
||||
/* Hardware stats accumulation */
|
||||
struct mxl862xx_port_stats stats;
|
||||
spinlock_t stats_lock;
|
||||
@@ -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
|
||||
spinlock_t stats_lock; /* protects stats accumulators */
|
||||
};
|
||||
@@ -336,6 +358,15 @@ union mxl862xx_fw_version {
|
||||
* policy. Set once in setup() and referenced by
|
||||
* fill_cpu_trap_action() via bFidEnable. The PCE FID
|
||||
* action field is 6 bits, so this value must be <= 63.
|
||||
+ * @lag_bridge_ports: maps DSA LAG ID to firmware bridge port ID;
|
||||
+ * zero means no bridge port allocated for that LAG.
|
||||
+ * Indexed by lag->id (entry 0 is unused).
|
||||
@ -851,10 +840,10 @@ 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
|
||||
*/
|
||||
@@ -352,6 +384,8 @@ struct mxl862xx_priv {
|
||||
u16 evlan_egress_size;
|
||||
@@ -355,6 +386,8 @@ struct mxl862xx_priv {
|
||||
u16 cpu_evlan_ingress_size;
|
||||
u16 vf_block_size;
|
||||
u16 cpu_trap_fid;
|
||||
+ u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
|
||||
+ u8 trunk_hash;
|
||||
struct delayed_work stats_work;
|
||||
@ -1,7 +1,7 @@
|
||||
From 5528f38c3d709417625eb7f36628be31727a8221 Mon Sep 17 00:00:00 2001
|
||||
From d919c2f8da9dbd4dda57ceebb5c8b103805b58d1 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 12:05:29 +0000
|
||||
Subject: [PATCH 18/26] net: dsa: mxl862xx: add support for mirror port
|
||||
Subject: [PATCH 11/19] 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.
|
||||
@ -14,8 +14,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 12 +++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 118 ++++++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 8 ++
|
||||
4 files changed, 139 insertions(+)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 7 ++
|
||||
4 files changed, 138 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@ -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
|
||||
@@ -1084,6 +1084,8 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -1100,6 +1100,8 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
(n_user_ports + n_cpu_ports);
|
||||
}
|
||||
|
||||
@ -59,8 +59,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
ret = mxl862xx_setup_drop_meter(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1973,6 +1975,120 @@ static int mxl862xx_setup_cpu_bridge(str
|
||||
return mxl862xx_set_bridge_port(ds, port);
|
||||
@@ -3167,6 +3169,120 @@ static int mxl862xx_fdb_del_per_fid(stru
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYREMOVE, param);
|
||||
}
|
||||
|
||||
+static int mxl862xx_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
@ -178,9 +178,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* mxl862xx_lag_master_port - Find the LAG master (lowest-numbered member)
|
||||
* @ds: DSA switch
|
||||
@@ -4068,6 +4184,8 @@ static const struct dsa_switch_ops mxl86
|
||||
* mxl862xx_mac_portmap_add - Set port bits in a MAC table entry's portmap
|
||||
* @priv: driver private data
|
||||
@@ -4096,6 +4212,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,
|
||||
@ -191,7 +191,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
.port_lag_change = mxl862xx_port_lag_change,
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -241,6 +241,8 @@ struct mxl862xx_port_stats {
|
||||
@@ -240,6 +240,8 @@ struct mxl862xx_port_stats {
|
||||
* @stats_lock: protects accumulator reads in .get_stats64 against
|
||||
* concurrent updates from the polling work
|
||||
* @tag_8021q_vid: currently assigned tag_8021q management VID
|
||||
@ -200,17 +200,16 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @lag: non-NULL when port is member of a LAG group;
|
||||
* points to the DSA LAG structure
|
||||
* @lag_tx_enabled: true when this port is active for TX in its LAG
|
||||
@@ -269,6 +271,9 @@ struct mxl862xx_port {
|
||||
@@ -265,6 +267,8 @@ struct mxl862xx_port {
|
||||
struct work_struct host_flood_work;
|
||||
u16 tag_8021q_vid;
|
||||
struct mxl862xx_evlan_block cpu_egress_evlan;
|
||||
+ /* Mirror state */
|
||||
+ bool ingress_mirror;
|
||||
+ bool egress_mirror;
|
||||
/* LAG state */
|
||||
struct dsa_lag *lag;
|
||||
bool lag_tx_enabled;
|
||||
@@ -366,6 +371,8 @@ union mxl862xx_fw_version {
|
||||
u8 lag_hash_bits;
|
||||
@@ -367,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,8 +218,8 @@ 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
|
||||
*/
|
||||
@@ -386,6 +393,7 @@ struct mxl862xx_priv {
|
||||
u16 vf_block_size;
|
||||
@@ -388,6 +394,7 @@ struct mxl862xx_priv {
|
||||
u16 cpu_trap_fid;
|
||||
u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
|
||||
u8 trunk_hash;
|
||||
+ int mirror_dest;
|
||||
@ -1,7 +1,7 @@
|
||||
From 4059d35a5bbf1901b2e0eb7126369cd713cacfce Mon Sep 17 00:00:00 2001
|
||||
From 64269d9d809962a0f7e68e9b618d81e561e3eb6f Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 16:30:08 +0000
|
||||
Subject: [PATCH 19/26] net: dsa: wire flash_update devlink callback to drivers
|
||||
Subject: [PATCH 12/19] 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
|
||||
@ -1,7 +1,7 @@
|
||||
From 0145151dc68aa318d8addb6fe7f12c0967f951da Mon Sep 17 00:00:00 2001
|
||||
From fed4225f75b6fe6898e48f472cbbee0aaa046760 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 16:30:17 +0000
|
||||
Subject: [PATCH 20/26] net: dsa: mxl862xx: add SMDIO clause-22 register access
|
||||
Subject: [PATCH 13/19] 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
|
||||
@ -1,7 +1,7 @@
|
||||
From bdbca48510e3e96ed9210f20fa4244dd6df5d44a Mon Sep 17 00:00:00 2001
|
||||
From fa186b09e346e0b7f2504232731bc9e4dee0c600 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 16:30:31 +0000
|
||||
Subject: [PATCH 21/26] net: dsa: mxl862xx: add devlink flash_update and
|
||||
Subject: [PATCH 14/19] net: dsa: mxl862xx: add devlink flash_update and
|
||||
info_get
|
||||
|
||||
Implement runtime firmware upgrade via "devlink dev flash" and version
|
||||
@ -538,7 +538,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
mutex_lock_nested(&priv->mdiodev->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -22,6 +22,7 @@
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "mxl862xx.h"
|
||||
#include "mxl862xx-api.h"
|
||||
#include "mxl862xx-cmd.h"
|
||||
@ -546,8 +546,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#include "mxl862xx-host.h"
|
||||
#include "mxl862xx-phylink.h"
|
||||
|
||||
@@ -4204,6 +4205,9 @@ static const struct dsa_switch_ops mxl86
|
||||
.get_pause_stats = mxl862xx_get_pause_stats,
|
||||
@@ -4233,6 +4234,9 @@ static const struct dsa_switch_ops mxl86
|
||||
.get_rmon_stats = mxl862xx_get_rmon_stats,
|
||||
.get_stats64 = mxl862xx_get_stats64,
|
||||
.self_test = mxl862xx_serdes_self_test,
|
||||
+ .devlink_info_get = mxl862xx_devlink_info_get,
|
||||
@ -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
|
||||
@@ -394,6 +394,8 @@ struct mxl862xx_priv {
|
||||
@@ -395,6 +395,8 @@ struct mxl862xx_priv {
|
||||
u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
|
||||
u8 trunk_hash;
|
||||
int mirror_dest;
|
||||
@ -1,7 +1,7 @@
|
||||
From 8deb5be9638f7eb3009ed3eb619eedadee1df523 Mon Sep 17 00:00:00 2001
|
||||
From 05bc981690d6ef03143a094f28714aa0171ab571 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 23:42:18 +0000
|
||||
Subject: [PATCH 22/26] net: dsa: mxl862xx: implement port MTU configuration
|
||||
Date: Wed, 1 Apr 2026 13:43:08 +0100
|
||||
Subject: [PATCH 15/19] 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
|
||||
@ -12,20 +12,20 @@ the effective maximum does not change.
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 50 +++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 4 +++
|
||||
2 files changed, 54 insertions(+)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 3 ++
|
||||
2 files changed, 53 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/delay.h>
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/if_bridge.h>
|
||||
+#include <linux/if_vlan.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_mdio.h>
|
||||
@@ -3723,6 +3724,53 @@ static int mxl862xx_set_ageing_time(stru
|
||||
@@ -3727,6 +3728,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)
|
||||
{
|
||||
@@ -4174,6 +4222,8 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -4202,6 +4250,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,
|
||||
@ -90,7 +90,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
.port_pre_bridge_flags = mxl862xx_port_pre_bridge_flags,
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -249,6 +249,8 @@ struct mxl862xx_port_stats {
|
||||
@@ -248,6 +248,8 @@ struct mxl862xx_port_stats {
|
||||
* @lag_hash_bits: hash field bitmask (MXL862XX_TRUNK_HASH_*) requested
|
||||
* when this port joined its LAG; used to recompute the
|
||||
* global trunk_hash when a LAG is destroyed
|
||||
@ -99,12 +99,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
struct mxl862xx_port {
|
||||
struct mxl862xx_priv *priv;
|
||||
@@ -278,6 +280,8 @@ struct mxl862xx_port {
|
||||
@@ -272,6 +274,7 @@ struct mxl862xx_port {
|
||||
struct dsa_lag *lag;
|
||||
bool lag_tx_enabled;
|
||||
u8 lag_hash_bits;
|
||||
+ /* MTU */
|
||||
+ int mtu;
|
||||
/* Hardware stats accumulation */
|
||||
struct mxl862xx_port_stats stats;
|
||||
spinlock_t stats_lock;
|
||||
spinlock_t stats_lock; /* protects stats accumulators */
|
||||
};
|
||||
@ -1,7 +1,7 @@
|
||||
From 13a4c918cd9ded7207f38033511ab13f7aff9bd2 Mon Sep 17 00:00:00 2001
|
||||
From b723f7484006aadbaa51e16b870f3c98390605b1 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 01:47:19 +0000
|
||||
Subject: [PATCH 23/26] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag
|
||||
Date: Wed, 1 Apr 2026 13:43:12 +0100
|
||||
Subject: [PATCH 16/19] 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,29 +18,24 @@ bridge member rebuild since only the calling port is affected.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 29 +++++++++++++++++++++++++++--
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 6 ++++++
|
||||
2 files changed, 33 insertions(+), 2 deletions(-)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 12 ++++++++++--
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 5 +++++
|
||||
2 files changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -811,6 +811,15 @@ static int mxl862xx_sync_bridge_members(
|
||||
__set_bit(mxl862xx_cpu_bridge_port_id(ds, port),
|
||||
priv->ports[port].portmap);
|
||||
|
||||
+ /* Hairpin: include the port's own bridge port so bridged
|
||||
+ * frames can egress the ingress port.
|
||||
+ * For LAG ports this adds the LAG bridge port, which
|
||||
+ * propagates to the LAG BP in the second loop below.
|
||||
+ */
|
||||
+ if (priv->ports[port].hairpin)
|
||||
+ __set_bit(mxl862xx_lag_bridge_port(priv, port),
|
||||
+ priv->ports[port].portmap);
|
||||
+
|
||||
err = mxl862xx_set_bridge_port(ds, port);
|
||||
if (err)
|
||||
ret = err;
|
||||
@@ -3898,7 +3907,7 @@ static int mxl862xx_port_pre_bridge_flag
|
||||
@@ -759,6 +759,10 @@ static int __mxl862xx_set_bridge_port(st
|
||||
}
|
||||
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
mxl862xx_cpu_bridge_port_id(ds, port));
|
||||
+ if (p->hairpin)
|
||||
+ mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
+ mxl862xx_lag_bridge_port(priv,
|
||||
+ port));
|
||||
} else {
|
||||
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
mxl862xx_cpu_bridge_port_id(ds, port));
|
||||
@@ -3895,7 +3899,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,33 +44,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -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;
|
||||
int ret;
|
||||
+ u16 bp;
|
||||
|
||||
if (flags.mask & BR_FLOOD) {
|
||||
if (flags.val & BR_FLOOD)
|
||||
@@ -3940,7 +3950,22 @@ static int mxl862xx_port_bridge_flags(st
|
||||
@@ -3937,7 +3941,11 @@ 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);
|
||||
- if (block != old_block || (flags.mask & BR_LEARNING)) {
|
||||
+ if (flags.mask & BR_HAIRPIN_MODE)
|
||||
+ priv->ports[port].hairpin = !!(flags.val & BR_HAIRPIN_MODE);
|
||||
+
|
||||
+ /* Hairpin adds/removes the port's own bridge port from its
|
||||
+ * cached portmap. Only this port is affected -- push the
|
||||
+ * updated portmap directly.
|
||||
+ */
|
||||
+ if (flags.val & BR_HAIRPIN_MODE)
|
||||
+ __set_bit(bp, priv->ports[port].portmap);
|
||||
+ else
|
||||
+ __clear_bit(bp, priv->ports[port].portmap);
|
||||
+ }
|
||||
+
|
||||
+ if ((block != old_block) ||
|
||||
+ (flags.mask & (BR_LEARNING | BR_HAIRPIN_MODE))) {
|
||||
priv->ports[port].flood_block = block;
|
||||
@ -83,7 +59,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -241,6 +241,10 @@ struct mxl862xx_port_stats {
|
||||
@@ -240,6 +240,10 @@ struct mxl862xx_port_stats {
|
||||
* @stats_lock: protects accumulator reads in .get_stats64 against
|
||||
* concurrent updates from the polling work
|
||||
* @tag_8021q_vid: currently assigned tag_8021q management VID
|
||||
@ -94,12 +70,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @ingress_mirror: true when ingress mirroring is active on this port
|
||||
* @egress_mirror: true when egress mirroring is active on this port
|
||||
* @lag: non-NULL when port is member of a LAG group;
|
||||
@@ -273,6 +277,8 @@ struct mxl862xx_port {
|
||||
@@ -269,6 +273,7 @@ struct mxl862xx_port {
|
||||
struct work_struct host_flood_work;
|
||||
u16 tag_8021q_vid;
|
||||
struct mxl862xx_evlan_block cpu_egress_evlan;
|
||||
+ /* Hairpin state */
|
||||
+ bool hairpin;
|
||||
/* Mirror state */
|
||||
bool ingress_mirror;
|
||||
bool egress_mirror;
|
||||
struct dsa_lag *lag;
|
||||
@ -1,7 +1,7 @@
|
||||
From d49d1f8bee29269def7593f980d0e08bfb5c3ef8 Mon Sep 17 00:00:00 2001
|
||||
From d8f20ba50ce0f93f34a41a9b833be76a5d1d2714 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 01:51:33 +0000
|
||||
Subject: [PATCH 24/26] net: dsa: mxl862xx: support BR_ISOLATED bridge flag
|
||||
Subject: [PATCH 17/19] 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
|
||||
@ -13,28 +13,22 @@ rebuilt via sync_bridge_members since multiple ports are affected.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 26 +++++++++++++++++++++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 20 +++++++++++++++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 4 ++++
|
||||
2 files changed, 29 insertions(+), 1 deletion(-)
|
||||
2 files changed, 23 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -802,6 +802,14 @@ static int mxl862xx_sync_bridge_members(
|
||||
*/
|
||||
if (!mxl862xx_is_lag_master(priv, member))
|
||||
@@ -752,6 +752,8 @@ static int __mxl862xx_set_bridge_port(st
|
||||
continue;
|
||||
+
|
||||
+ /* Isolated ports cannot forward to each other.
|
||||
+ * Non-isolated ports can reach everyone.
|
||||
+ */
|
||||
+ if (priv->ports[port].isolated &&
|
||||
+ priv->ports[member].isolated)
|
||||
if (!mxl862xx_is_lag_master(priv, member_dp->index))
|
||||
continue;
|
||||
+ if (p->isolated && priv->ports[member_dp->index].isolated)
|
||||
+ continue;
|
||||
+
|
||||
if (member != port) {
|
||||
bp = mxl862xx_lag_bridge_port(priv,
|
||||
member);
|
||||
@@ -3907,7 +3915,7 @@ static int mxl862xx_port_pre_bridge_flag
|
||||
mxl862xx_fw_portmap_set_bit(
|
||||
br_port_cfg.bridge_port_map,
|
||||
mxl862xx_lag_bridge_port(priv,
|
||||
@@ -3899,7 +3901,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 +37,15 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -3920,6 +3928,7 @@ static int mxl862xx_port_bridge_flags(st
|
||||
@@ -3912,6 +3914,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;
|
||||
+ struct dsa_port *dp;
|
||||
int ret;
|
||||
u16 bp;
|
||||
|
||||
@@ -3972,6 +3981,21 @@ static int mxl862xx_port_bridge_flags(st
|
||||
if (flags.mask & BR_FLOOD) {
|
||||
@@ -3952,6 +3955,21 @@ static int mxl862xx_port_bridge_flags(st
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -75,7 +69,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -214,6 +214,9 @@ struct mxl862xx_port_stats {
|
||||
@@ -213,6 +213,9 @@ struct mxl862xx_port_stats {
|
||||
* @flood_block: bitmask of firmware meter indices that are currently
|
||||
* rate-limiting flood traffic on this port (zero-rate
|
||||
* meters used to block flooding)
|
||||
@ -85,11 +79,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @learning: true when address learning is enabled on this port
|
||||
* @setup_done: set at end of port_setup, cleared at start of
|
||||
* port_teardown; guards deferred work against
|
||||
@@ -261,6 +264,7 @@ struct mxl862xx_port {
|
||||
@@ -259,6 +262,7 @@ struct mxl862xx_port {
|
||||
struct mxl862xx_priv *priv;
|
||||
u16 fid;
|
||||
DECLARE_BITMAP(portmap, MXL862XX_MAX_BRIDGE_PORTS);
|
||||
unsigned long flood_block;
|
||||
+ bool isolated;
|
||||
bool learning;
|
||||
bool setup_done;
|
||||
/* VLAN state */
|
||||
u16 pvid;
|
||||
@ -1,7 +1,7 @@
|
||||
From c2fb7f0df63ac994850f766e7f2eb50c6c5ef2cf Mon Sep 17 00:00:00 2001
|
||||
From 8856f7610167a3005ecef401c8528111d153b554 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:17:49 +0000
|
||||
Subject: [PATCH 25/26] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE
|
||||
Subject: [PATCH 18/19] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE
|
||||
workaround for old firmware
|
||||
|
||||
Re-introduce the mxl862xx_disable_fw_global_rules() function that
|
||||
@ -20,7 +20,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -477,6 +477,43 @@ static int mxl862xx_setup_drop_meter(str
|
||||
@@ -449,6 +449,43 @@ static int mxl862xx_setup_drop_meter(str
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
|
||||
}
|
||||
|
||||
@ -62,9 +62,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
/* 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
|
||||
@@ -1109,9 +1146,11 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
/* Per-CTP offsets for protocol trap rules. Each port's CTP flow-table
|
||||
* block is pre-allocated by the firmware during init (44 entries per
|
||||
@@ -1114,9 +1151,11 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
From df0c747216063041ba0d786b01f9b1e2aba5316a Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 22 Apr 2026 15:15:52 +0100
|
||||
Subject: [PATCH] DO NOT SUBMIT: net: dsa: mxl862xx: increase CMD timeout
|
||||
|
||||
Lift the command timeout by 10x from 500ms to 5s.
|
||||
This is done because older firmware can be extremely slow to respond
|
||||
and cause -ETIMEOUT during setup, or crash the PHY state machine.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-host.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-host.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-host.c
|
||||
@@ -207,7 +207,7 @@ static int mxl862xx_busy_wait(struct mxl
|
||||
int val;
|
||||
|
||||
return readx_poll_timeout(mxl862xx_ctrl_read, priv, val,
|
||||
- !(val & CTRL_BUSY_MASK), 15, 500000);
|
||||
+ !(val & CTRL_BUSY_MASK), 50, 5000000);
|
||||
}
|
||||
|
||||
/* Issue a firmware command with CRC-6 protection on the ctrl and len_ret
|
||||
Loading…
x
Reference in New Issue
Block a user