kernel: add qualcommax patches to generic

Move upstreamed patches to backports.

Move the others to pending.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/24013
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
This commit is contained in:
Rosen Penev authored and Jonas Jelonek committed 2026-07-05 13:02:07 +02:00
1 parent 8614a2ba68
commit 9716066e80
27 files changed
+604 -288

No files matched your search

@@ -0,0 +1,68 @@
From e0a77b1ed9001bdd0c73b99c67abb90f4bd7d7f5 Mon Sep 17 00:00:00 2001
From: George Moussalem <george.moussalem@outlook.com>
Date: Fri, 5 Jun 2026 12:11:29 +0400
Subject: [PATCH] net: dsa: qca8k: Add support for force mode for fixed link
topology
A fixed link topology is commonly used to connect this switch (on port
0 or 6) to a SoC's MAC over SGMII. When inband negotiation is not used,
the switch needs to be configured to operate in force mode. As such,
enable support for force mode.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://patch.msgid.link/20260605-qca8337-force-mode-v2-1-d9a6b6545bfa@outlook.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 22 ++++++++++++++++------
drivers/net/dsa/qca/qca8k.h | 1 +
2 files changed, 17 insertions(+), 6 deletions(-)
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1538,7 +1538,7 @@ static int qca8k_pcs_config(struct phyli
{
struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv;
int cpu_port_index, ret, port;
- u32 reg, val;
+ u32 mask, reg, val;
port = pcs_to_qca8k_pcs(pcs)->port;
switch (port) {
@@ -1611,11 +1611,21 @@ static int qca8k_pcs_config(struct phyli
if (priv->ports_config.sgmii_tx_clk_falling_edge)
val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE;
- if (val)
- ret = qca8k_rmw(priv, reg,
- QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
- QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
- val);
+ mask = (val) ? (QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE) : 0;
+
+ /*
+ * (Un)set force mode on QCA8337 only, don't include it in the mask for
+ * others. It is written to the PORT0 PAD register for both port 0 and 6.
+ */
+ if (priv->switch_id == QCA8K_ID_QCA8337) {
+ if (neg_mode == PHYLINK_PCS_NEG_OUTBAND)
+ val |= QCA8K_PORT_PAD_SGMII_FORCE_MODE;
+ mask |= QCA8K_PORT_PAD_SGMII_FORCE_MODE;
+ }
+
+ if (mask)
+ ret = qca8k_rmw(priv, reg, mask, val);
return 0;
}
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -58,6 +58,7 @@
#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
+#define QCA8K_PORT_PAD_SGMII_FORCE_MODE BIT(3)
#define QCA8K_REG_PWS 0x010
#define QCA8K_PWS_POWER_ON_SEL BIT(31)
/* This reg is only valid for QCA832x and toggle the package
@@ -1,21 +1,25 @@
From ec0031908d3abb24e791af2d5be9f3b0e265c945 Mon Sep 17 00:00:00 2001
From 0b7b378ce6cafbb948786cb6f17f406d94016c8c Mon Sep 17 00:00:00 2001
From: George Moussalem <george.moussalem@outlook.com>
Date: Fri, 25 Apr 2025 10:51:28 +0400
Subject: [PATCH] net: dsa: qca8k: fix led devicename when using external mdio bus
Date: Mon, 8 Jun 2026 11:22:08 +0400
Subject: [PATCH] net: dsa: qca8k: fix led devicename when using external mdio
bus
The qca8k dsa switch can use either an external or internal mdio bus.
This depends on whether the mdio node is defined under the switch node
itself and, as such, the internal_mdio_mask is populated with its
internal phys. Upon registering the internal mdio bus, the slave_mii_bus
itself. Upon registering the internal mdio bus, the internal_mdio_bus
of the dsa switch is assigned to this bus. When an external mdio bus is
used, it is left unassigned, though its id is used to create the device
names of the leds.
This leads to the leds being named '(efault):00:green:lan' and so on as
the slave_mii_bus is null. So let's fix this by adding a null check and
used, the driver still uses the internal_mdio_bus id which is used to
create the device names of the leds.
This leads to the leds being prefixed with '(efault)' as the
internal_mii_bus is null. So let's fix this by adding a null check and
use the devicename of the external bus instead when an external bus is
configured.
Fixes: 1e264f9d2918 ("net: dsa: qca8k: add LEDs basic support")
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20260608-qca8k-leds-fix-v3-1-a915bb2f37ae@outlook.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/dsa/qca/qca8k-leds.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
@@ -0,0 +1,68 @@
From e0a77b1ed9001bdd0c73b99c67abb90f4bd7d7f5 Mon Sep 17 00:00:00 2001
From: George Moussalem <george.moussalem@outlook.com>
Date: Fri, 5 Jun 2026 12:11:29 +0400
Subject: [PATCH] net: dsa: qca8k: Add support for force mode for fixed link
topology
A fixed link topology is commonly used to connect this switch (on port
0 or 6) to a SoC's MAC over SGMII. When inband negotiation is not used,
the switch needs to be configured to operate in force mode. As such,
enable support for force mode.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://patch.msgid.link/20260605-qca8337-force-mode-v2-1-d9a6b6545bfa@outlook.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 22 ++++++++++++++++------
drivers/net/dsa/qca/qca8k.h | 1 +
2 files changed, 17 insertions(+), 6 deletions(-)
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1538,7 +1538,7 @@ static int qca8k_pcs_config(struct phyli
{
struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv;
int cpu_port_index, ret, port;
- u32 reg, val;
+ u32 mask, reg, val;
port = pcs_to_qca8k_pcs(pcs)->port;
switch (port) {
@@ -1611,11 +1611,21 @@ static int qca8k_pcs_config(struct phyli
if (priv->ports_config.sgmii_tx_clk_falling_edge)
val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE;
- if (val)
- ret = qca8k_rmw(priv, reg,
- QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
- QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
- val);
+ mask = (val) ? (QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE) : 0;
+
+ /*
+ * (Un)set force mode on QCA8337 only, don't include it in the mask for
+ * others. It is written to the PORT0 PAD register for both port 0 and 6.
+ */
+ if (priv->switch_id == QCA8K_ID_QCA8337) {
+ if (neg_mode == PHYLINK_PCS_NEG_OUTBAND)
+ val |= QCA8K_PORT_PAD_SGMII_FORCE_MODE;
+ mask |= QCA8K_PORT_PAD_SGMII_FORCE_MODE;
+ }
+
+ if (mask)
+ ret = qca8k_rmw(priv, reg, mask, val);
return 0;
}
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -58,6 +58,7 @@
#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
+#define QCA8K_PORT_PAD_SGMII_FORCE_MODE BIT(3)
#define QCA8K_REG_PWS 0x010
#define QCA8K_PWS_POWER_ON_SEL BIT(31)
/* This reg is only valid for QCA832x and toggle the package
@@ -0,0 +1,38 @@
From 0b7b378ce6cafbb948786cb6f17f406d94016c8c Mon Sep 17 00:00:00 2001
From: George Moussalem <george.moussalem@outlook.com>
Date: Mon, 8 Jun 2026 11:22:08 +0400
Subject: [PATCH] net: dsa: qca8k: fix led devicename when using external mdio
bus
The qca8k dsa switch can use either an external or internal mdio bus.
This depends on whether the mdio node is defined under the switch node
itself. Upon registering the internal mdio bus, the internal_mdio_bus
of the dsa switch is assigned to this bus. When an external mdio bus is
used, the driver still uses the internal_mdio_bus id which is used to
create the device names of the leds.
This leads to the leds being prefixed with '(efault)' as the
internal_mii_bus is null. So let's fix this by adding a null check and
use the devicename of the external bus instead when an external bus is
configured.
Fixes: 1e264f9d2918 ("net: dsa: qca8k: add LEDs basic support")
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20260608-qca8k-leds-fix-v3-1-a915bb2f37ae@outlook.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/dsa/qca/qca8k-leds.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/net/dsa/qca/qca8k-leds.c
+++ b/drivers/net/dsa/qca/qca8k-leds.c
@@ -429,7 +429,8 @@ qca8k_parse_port_leds(struct qca8k_priv
init_data.fwnode = led;
init_data.devname_mandatory = true;
init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d",
- priv->internal_mdio_bus->id,
+ priv->internal_mdio_bus ?
+ priv->internal_mdio_bus->id : priv->bus->id,
port_num);
if (!init_data.devicename) {
fwnode_handle_put(led);
@@ -16,7 +16,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -2031,6 +2031,8 @@ static const struct dsa_switch_ops qca8k
@@ -2041,6 +2041,8 @@ static const struct dsa_switch_ops qca8k
.port_fdb_add = qca8k_port_fdb_add,
.port_fdb_del = qca8k_port_fdb_del,
.port_fdb_dump = qca8k_port_fdb_dump,
@@ -72,7 +72,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
u32 val;
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -592,5 +592,11 @@ int qca8k_port_lag_join(struct dsa_switc
@@ -593,5 +593,11 @@ int qca8k_port_lag_join(struct dsa_switc
struct netlink_ext_ack *extack);
int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
struct dsa_lag lag);
@@ -14,7 +14,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1913,15 +1913,12 @@ qca8k_setup(struct dsa_switch *ds)
@@ -1923,15 +1923,12 @@ qca8k_setup(struct dsa_switch *ds)
}
}
@@ -26,7 +26,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1750,6 +1750,117 @@ qca8k_get_tag_protocol(struct dsa_switch
@@ -1760,6 +1760,117 @@ qca8k_get_tag_protocol(struct dsa_switch
return DSA_TAG_PROTO_QCA;
}
@@ -144,7 +144,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
static void
qca8k_conduit_change(struct dsa_switch *ds, const struct net_device *conduit,
bool operational)
@@ -2039,8 +2150,9 @@ static const struct dsa_switch_ops qca8k
@@ -2049,8 +2160,9 @@ static const struct dsa_switch_ops qca8k
.port_vlan_del = qca8k_port_vlan_del,
.phylink_get_caps = qca8k_phylink_get_caps,
.get_phy_flags = qca8k_get_phy_flags,
@@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kevin Staley <glaciertablet@gmail.com>
Date: Mon, 29 Dec 2025 00:00:00 +0000
Subject: [PATCH] net: dsa: qca8k: merge host FDB for multi-CPU setups
In multi-CPU-port setups, DSA may install the same host FDB entry on
multiple upstream-facing ports when bridged user ports use different
conduits. qca8k_port_fdb_add currently overwrites any existing entry for
the same {MAC, VID}, so the last CPU port wins and host reachability can
break for ports serviced by the other CPU port (e.g. Netgear R7800 when
wan is bridged into br-lan).
Use the existing search-and-insert/delete helpers for CPU and DSA ports
so the destination port mask is merged instead of replaced.
Fixes: openwrt/openwrt#17891
Signed-off-by: Kevin Staley <glaciertablet@gmail.com>
---
drivers/net/dsa/qca/qca8k-common.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -836,6 +836,13 @@ int qca8k_port_fdb_add(struct dsa_switch
struct qca8k_priv *priv = ds->priv;
u16 port_mask = BIT(port);
+ if (!vid)
+ vid = QCA8K_PORT_VID_DEF;
+
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid,
+ QCA8K_ATU_STATUS_STATIC);
+
return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
}
@@ -849,6 +856,9 @@ int qca8k_port_fdb_del(struct dsa_switch
if (!vid)
vid = QCA8K_PORT_VID_DEF;
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
+
return qca8k_fdb_del(priv, addr, port_mask, vid);
}
@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Olaf Marzocchi <lists@marzocchi.net>
Date: Fri, 26 Jun 2026 00:00:00 +0000
Subject: [PATCH] net: dsa: qca8k: don't program unicast host FDB entries on
CPU ports
DSA installs host FDB entries for the same {MAC, VID} once per CPU port
in use. qca8k used to overwrite the single ATU entry, so the last CPU
port won and host reachability broke for user ports served by the other
CPU port (e.g. Netgear R7800 with wan bridged into br-lan). Merging the
CPU port bits into the destination mask instead is no better: the ATU
forwards a unicast hit to every port set in the mask, so a host entry
spanning both CPU ports makes the switch deliver one copy of each
host-bound frame per CPU port. This duplicated nearly all host traffic
and halved throughput on TP-Link TGR1900, Archer C2600 and ASUS
RT-AX89X, with "failed to delete ... from fdb: -22" log spam from the
asymmetric delete path.
Host FDB entries are a pure optimization on this switch: the unknown
unicast forward mask in GLOBAL_FW_CTRL1 already contains all CPU ports
and is filtered per ingress port by PORT_LOOKUP_CTRL members, so a
host-bound frame with no ATU entry reaches exactly one CPU port, the
conduit of its ingress port, and the tag parser delivers it to the
correct user netdevice from either conduit. The conduits run in
promiscuous mode (qca8k does not implement FDB isolation), so no RX
filtering relies on these entries either.
Skip programming unicast host FDB entries on CPU ports entirely. This
fixes the multi-CPU bridged setups without ever creating a unicast
destination mask with more than one CPU port bit, regardless of how a
board assigns its conduits.
Disclaimer: patch generated via Fable 5 and tested by @xback
Fixes: openwrt/openwrt#21317
Signed-off-by: Olaf Marzocchi <lists@marzocchi.net>
---
drivers/net/dsa/qca/qca8k-common.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -836,6 +836,17 @@ int qca8k_port_fdb_add(struct dsa_switch
struct qca8k_priv *priv = ds->priv;
u16 port_mask = BIT(port);
+ /* The ATU forwards a unicast hit to every port set in the
+ * destination mask, so a host entry spanning multiple CPU ports
+ * would deliver one copy of each host-bound frame per CPU port.
+ * Skip host entries entirely: unknown unicast is already forwarded
+ * to all CPU ports by GLOBAL_FW_CTRL1 and filtered by the ingress
+ * port LOOKUP_MEMBER, so host-bound frames reach exactly one CPU
+ * port, the conduit of the ingress port.
+ */
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+ return 0;
+
return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
}
@@ -846,6 +857,9 @@ int qca8k_port_fdb_del(struct dsa_switch
struct qca8k_priv *priv = ds->priv;
u16 port_mask = BIT(port);
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+ return 0;
+
if (!vid)
vid = QCA8K_PORT_VID_DEF;
@@ -0,0 +1,30 @@
From a4918445f34b80589a76cc047dd7d907b28b37ce Mon Sep 17 00:00:00 2001
From: Rosen Penev <rosenp@gmail.com>
Date: Sat, 27 Jun 2026 14:50:13 -0700
Subject: [PATCH] net: dsa: qca8k: fall back to ethernet-ports node name for
LEDs
The device tree binding allows both "ports" and "ethernet-ports" as
the container node name. Try "ethernet-ports" when "ports" is absent
so that newer DTBs with the preferred name work.
This matches the handling already present in qca8k-8xxx.c
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/dsa/qca/qca8k-leds.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/net/dsa/qca/qca8k-leds.c
+++ b/drivers/net/dsa/qca/qca8k-leds.c
@@ -457,6 +457,9 @@ qca8k_setup_led_ctrl(struct qca8k_priv *
int ret;
ports = device_get_named_child_node(priv->dev, "ports");
+ if (!ports)
+ ports = device_get_named_child_node(priv->dev, "ethernet-ports");
+
if (!ports) {
dev_info(priv->dev, "No ports node specified in device tree!");
return 0;
@@ -57,7 +57,7 @@ Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
/* Parse CPU port config to be later used in phy_link mac_config */
ret = qca8k_parse_port_config(priv);
if (ret)
@@ -2051,17 +2027,12 @@ qca8k_setup(struct dsa_switch *ds)
@@ -2045,17 +2021,12 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
@@ -76,7 +76,7 @@ Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_MEMBER,
@@ -2069,6 +2040,11 @@ qca8k_setup(struct dsa_switch *ds)
@@ -2068,6 +2039,11 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
@@ -30,7 +30,7 @@ Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
static int qca8k_port_change_master(struct dsa_switch *ds, int port,
struct net_device *master,
struct netlink_ext_ack *extack)
@@ -2144,6 +2156,7 @@ static const struct dsa_switch_ops qca8k
@@ -2140,6 +2152,7 @@ static const struct dsa_switch_ops qca8k
.get_phy_flags = qca8k_get_phy_flags,
.port_lag_join = qca8xxx_port_lag_join,
.port_lag_leave = qca8xxx_port_lag_leave,
@@ -33,7 +33,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
}
/* Forward all unknown frames to CPU port for Linux processing */
@@ -2051,11 +2057,6 @@ qca8k_setup(struct dsa_switch *ds)
@@ -2046,11 +2052,6 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
@@ -42,9 +42,9 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
- if (ret)
- return ret;
-
/* For port based vlans to work we need to set the
* default egress vid
*/
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
BIT(port), BIT(port));
if (ret)
@@ -2107,6 +2108,9 @@ qca8k_setup(struct dsa_switch *ds)
/* Set max number of LAGs supported */
ds->num_lag_ids = QCA8K_NUM_LAGS;
@@ -16,7 +16,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -2030,6 +2030,8 @@ static const struct dsa_switch_ops qca8k
@@ -2040,6 +2040,8 @@ static const struct dsa_switch_ops qca8k
.port_fdb_add = qca8k_port_fdb_add,
.port_fdb_del = qca8k_port_fdb_del,
.port_fdb_dump = qca8k_port_fdb_dump,
@@ -72,7 +72,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
u32 val;
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -591,5 +591,11 @@ int qca8k_port_lag_join(struct dsa_switc
@@ -592,5 +592,11 @@ int qca8k_port_lag_join(struct dsa_switc
struct netlink_ext_ack *extack);
int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
struct dsa_lag lag);
@@ -14,7 +14,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1912,15 +1912,12 @@ qca8k_setup(struct dsa_switch *ds)
@@ -1922,15 +1922,12 @@ qca8k_setup(struct dsa_switch *ds)
}
}
@@ -26,7 +26,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1749,6 +1749,117 @@ qca8k_get_tag_protocol(struct dsa_switch
@@ -1759,6 +1759,117 @@ qca8k_get_tag_protocol(struct dsa_switch
return DSA_TAG_PROTO_QCA;
}
@@ -144,7 +144,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
static void
qca8k_conduit_change(struct dsa_switch *ds, const struct net_device *conduit,
bool operational)
@@ -2038,8 +2149,9 @@ static const struct dsa_switch_ops qca8k
@@ -2048,8 +2159,9 @@ static const struct dsa_switch_ops qca8k
.port_vlan_del = qca8k_port_vlan_del,
.phylink_get_caps = qca8k_phylink_get_caps,
.get_phy_flags = qca8k_get_phy_flags,
@@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kevin Staley <glaciertablet@gmail.com>
Date: Mon, 29 Dec 2025 00:00:00 +0000
Subject: [PATCH] net: dsa: qca8k: merge host FDB for multi-CPU setups
In multi-CPU-port setups, DSA may install the same host FDB entry on
multiple upstream-facing ports when bridged user ports use different
conduits. qca8k_port_fdb_add currently overwrites any existing entry for
the same {MAC, VID}, so the last CPU port wins and host reachability can
break for ports serviced by the other CPU port (e.g. Netgear R7800 when
wan is bridged into br-lan).
Use the existing search-and-insert/delete helpers for CPU and DSA ports
so the destination port mask is merged instead of replaced.
Fixes: openwrt/openwrt#17891
Signed-off-by: Kevin Staley <glaciertablet@gmail.com>
---
drivers/net/dsa/qca/qca8k-common.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -829,6 +829,13 @@ int qca8k_port_fdb_add(struct dsa_switch
struct qca8k_priv *priv = ds->priv;
u16 port_mask = BIT(port);
+ if (!vid)
+ vid = QCA8K_PORT_VID_DEF;
+
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid,
+ QCA8K_ATU_STATUS_STATIC);
+
return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
}
@@ -842,6 +849,9 @@ int qca8k_port_fdb_del(struct dsa_switch
if (!vid)
vid = QCA8K_PORT_VID_DEF;
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
+
return qca8k_fdb_del(priv, addr, port_mask, vid);
}
@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Olaf Marzocchi <lists@marzocchi.net>
Date: Fri, 26 Jun 2026 00:00:00 +0000
Subject: [PATCH] net: dsa: qca8k: don't program unicast host FDB entries on
CPU ports
DSA installs host FDB entries for the same {MAC, VID} once per CPU port
in use. qca8k used to overwrite the single ATU entry, so the last CPU
port won and host reachability broke for user ports served by the other
CPU port (e.g. Netgear R7800 with wan bridged into br-lan). Merging the
CPU port bits into the destination mask instead is no better: the ATU
forwards a unicast hit to every port set in the mask, so a host entry
spanning both CPU ports makes the switch deliver one copy of each
host-bound frame per CPU port. This duplicated nearly all host traffic
and halved throughput on TP-Link TGR1900, Archer C2600 and ASUS
RT-AX89X, with "failed to delete ... from fdb: -22" log spam from the
asymmetric delete path.
Host FDB entries are a pure optimization on this switch: the unknown
unicast forward mask in GLOBAL_FW_CTRL1 already contains all CPU ports
and is filtered per ingress port by PORT_LOOKUP_CTRL members, so a
host-bound frame with no ATU entry reaches exactly one CPU port, the
conduit of its ingress port, and the tag parser delivers it to the
correct user netdevice from either conduit. The conduits run in
promiscuous mode (qca8k does not implement FDB isolation), so no RX
filtering relies on these entries either.
Skip programming unicast host FDB entries on CPU ports entirely. This
fixes the multi-CPU bridged setups without ever creating a unicast
destination mask with more than one CPU port bit, regardless of how a
board assigns its conduits.
Disclaimer: patch generated via Fable 5 and tested by @xback
Fixes: openwrt/openwrt#21317
Signed-off-by: Olaf Marzocchi <lists@marzocchi.net>
---
drivers/net/dsa/qca/qca8k-common.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -829,6 +829,17 @@ int qca8k_port_fdb_add(struct dsa_switch
struct qca8k_priv *priv = ds->priv;
u16 port_mask = BIT(port);
+ /* The ATU forwards a unicast hit to every port set in the
+ * destination mask, so a host entry spanning multiple CPU ports
+ * would deliver one copy of each host-bound frame per CPU port.
+ * Skip host entries entirely: unknown unicast is already forwarded
+ * to all CPU ports by GLOBAL_FW_CTRL1 and filtered by the ingress
+ * port LOOKUP_MEMBER, so host-bound frames reach exactly one CPU
+ * port, the conduit of the ingress port.
+ */
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+ return 0;
+
return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
}
@@ -839,6 +850,9 @@ int qca8k_port_fdb_del(struct dsa_switch
struct qca8k_priv *priv = ds->priv;
u16 port_mask = BIT(port);
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+ return 0;
+
if (!vid)
vid = QCA8K_PORT_VID_DEF;
@@ -0,0 +1,30 @@
From a4918445f34b80589a76cc047dd7d907b28b37ce Mon Sep 17 00:00:00 2001
From: Rosen Penev <rosenp@gmail.com>
Date: Sat, 27 Jun 2026 14:50:13 -0700
Subject: [PATCH] net: dsa: qca8k: fall back to ethernet-ports node name for
LEDs
The device tree binding allows both "ports" and "ethernet-ports" as
the container node name. Try "ethernet-ports" when "ports" is absent
so that newer DTBs with the preferred name work.
This matches the handling already present in qca8k-8xxx.c
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/dsa/qca/qca8k-leds.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/net/dsa/qca/qca8k-leds.c
+++ b/drivers/net/dsa/qca/qca8k-leds.c
@@ -457,6 +457,9 @@ qca8k_setup_led_ctrl(struct qca8k_priv *
int ret;
ports = device_get_named_child_node(priv->dev, "ports");
+ if (!ports)
+ ports = device_get_named_child_node(priv->dev, "ethernet-ports");
+
if (!ports) {
dev_info(priv->dev, "No ports node specified in device tree!");
return 0;
@@ -0,0 +1,58 @@
From e82cfa658fc4a0429b3d159d0e1bedb6b5cc6d38 Mon Sep 17 00:00:00 2001
From: Ziyang Huang <hzyitc@outlook.com>
Date: Sat, 18 Jan 2025 16:18:40 +0800
Subject: [PATCH 1/3] net: dsa: qca8k: support PHY-to-PHY CPU link
PHY-to-PHY CPU link is a common/demo design in IPQ50xx platform, since it only has a SGMII/SGMII+ link and a MDI link.
For DSA, CPU tag is the only requirement. Fortunately, qca8337 can enable it on any port. So it's ok to trust a PHY-to-PHY link as a CPU link.
Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1014,7 +1014,7 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
return ret;
}
- if (!dsa_is_user_port(priv->ds, reg))
+ if (reg == 0 || reg == 6)
continue;
of_get_phy_mode(port, &mode);
@@ -1089,17 +1089,19 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri
static int qca8k_find_cpu_port(struct dsa_switch *ds)
{
- struct qca8k_priv *priv = ds->priv;
+ int i;
- /* Find the connected cpu port. Valid port are 0 or 6 */
if (dsa_is_cpu_port(ds, 0))
return 0;
- dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6");
-
if (dsa_is_cpu_port(ds, 6))
return 6;
+ /* PHY-to-PHY link */
+ for (i = 1; i <= 5; i++)
+ if (dsa_is_cpu_port(ds, i))
+ return i;
+
return -EINVAL;
}
@@ -1960,7 +1962,7 @@ qca8k_setup(struct dsa_switch *ds)
cpu_port = qca8k_find_cpu_port(ds);
if (cpu_port < 0) {
- dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6");
+ dev_err(priv->dev, "No cpu port configured");
return cpu_port;
}
@@ -0,0 +1,90 @@
From 08740093ef69e94613f19323f3abc55cb5d6863d Mon Sep 17 00:00:00 2001
From: Ziyang Huang <hzyitc@outlook.com>
Date: Wed, 14 Jan 2026 23:38:30 +0800
Subject: [PATCH 2/3] net: dsa: qca8k: use correct CPU port when having multi
CPU ports
DSA framework call dsa_tree_setup_cpu_ports() to find a default CPU port.
If .preferred_default_local_cpu_port() isn't implemented, it will use the
first CPU port, which is different from qca8k_find_cpu_port().
Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 38 ++++++--------------------------
1 file changed, 7 insertions(+), 31 deletions(-)
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1087,24 +1087,6 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri
return ret;
}
-static int qca8k_find_cpu_port(struct dsa_switch *ds)
-{
- int i;
-
- if (dsa_is_cpu_port(ds, 0))
- return 0;
-
- if (dsa_is_cpu_port(ds, 6))
- return 6;
-
- /* PHY-to-PHY link */
- for (i = 1; i <= 5; i++)
- if (dsa_is_cpu_port(ds, i))
- return i;
-
- return -EINVAL;
-}
-
static int
qca8k_setup_of_pws_reg(struct qca8k_priv *priv)
{
@@ -1957,15 +1939,9 @@ qca8k_setup(struct dsa_switch *ds)
{
struct qca8k_priv *priv = ds->priv;
struct dsa_port *dp;
- int cpu_port, ret;
+ int ret;
u32 mask;
- cpu_port = qca8k_find_cpu_port(ds);
- if (cpu_port < 0) {
- dev_err(priv->dev, "No cpu port configured");
- return cpu_port;
- }
-
/* Parse CPU port config to be later used in phy_link mac_config */
ret = qca8k_parse_port_config(priv);
if (ret)
@@ -2044,17 +2020,12 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
- /* CPU port gets connected to all user ports of the switch */
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
- if (ret)
- return ret;
-
/* Setup connection between CPU port & user ports
* Individual user ports get connected to CPU port only
*/
dsa_switch_for_each_user_port(dp, ds) {
u8 port = dp->index;
+ u8 cpu_port = dp->cpu_dp->index;
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_MEMBER,
@@ -2067,6 +2038,11 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
+ BIT(port), BIT(port));
+ if (ret)
+ return ret;
+
/* For port based vlans to work we need to set the
* default egress vid
*/
@@ -0,0 +1,40 @@
From a572f1020159294fe980606996e7e3af5fa7ba9a Mon Sep 17 00:00:00 2001
From: Ziyang Huang <hzyitc@outlook.com>
Date: Wed, 14 Jan 2026 23:38:30 +0800
Subject: [PATCH 3/3] net: dsa: qca8k: implement
ds->ops->preferred_default_local_cpu_port()
Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1743,6 +1743,18 @@ qca8k_get_tag_protocol(struct dsa_switch
return DSA_TAG_PROTO_QCA;
}
+static struct dsa_port *
+qca8k_preferred_default_local_cpu_port(struct dsa_switch *ds)
+{
+ if (dsa_is_cpu_port(ds, 0))
+ return dsa_to_port(ds, 0);
+
+ if (dsa_is_cpu_port(ds, 6))
+ return dsa_to_port(ds, 6);
+
+ return NULL;
+}
+
static int qca8k_port_change_master(struct dsa_switch *ds, int port,
struct net_device *master,
struct netlink_ext_ack *extack)
@@ -2139,6 +2151,7 @@ static const struct dsa_switch_ops qca8k
.get_phy_flags = qca8k_get_phy_flags,
.port_lag_join = qca8xxx_port_lag_join,
.port_lag_leave = qca8xxx_port_lag_leave,
+ .preferred_default_local_cpu_port = qca8k_preferred_default_local_cpu_port,
.port_change_conduit = qca8k_port_change_master,
.conduit_state_change = qca8k_conduit_change,
.connect_tag_protocol = qca8k_connect_tag_protocol,
@@ -33,7 +33,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
}
/* Forward all unknown frames to CPU port for Linux processing */
@@ -2050,11 +2056,6 @@ qca8k_setup(struct dsa_switch *ds)
@@ -2045,11 +2051,6 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
@@ -42,9 +42,9 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
- if (ret)
- return ret;
-
/* For port based vlans to work we need to set the
* default egress vid
*/
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
BIT(port), BIT(port));
if (ret)
@@ -2106,6 +2107,9 @@ qca8k_setup(struct dsa_switch *ds)
/* Set max number of LAGs supported */
ds->num_lag_ids = QCA8K_NUM_LAGS;
@@ -1048,7 +1048,7 @@ Signed-off-by: Robert Marko <robert.marko@sartura.hr>
#define QCA8K_QCA832X_MIB_COUNT 39
#define QCA8K_QCA833X_MIB_COUNT 41
@@ -265,6 +269,7 @@
@@ -266,6 +270,7 @@
#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3)
#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4)
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
@@ -1056,7 +1056,7 @@ Signed-off-by: Robert Marko <robert.marko@sartura.hr>
#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700
@@ -341,6 +346,53 @@
@@ -342,6 +347,53 @@
#define MII_ATH_MMD_ADDR 0x0d
#define MII_ATH_MMD_DATA 0x0e
@@ -1110,7 +1110,7 @@ Signed-off-by: Robert Marko <robert.marko@sartura.hr>
enum {
QCA8K_PORT_SPEED_10M = 0,
QCA8K_PORT_SPEED_100M = 1,
@@ -468,6 +520,10 @@ struct qca8k_priv {
@@ -469,6 +521,10 @@ struct qca8k_priv {
struct qca8k_pcs pcs_port_6;
const struct qca8k_match_data *info;
struct qca8k_led ports_led[QCA8K_LED_COUNT];
@@ -1061,7 +1061,7 @@ Signed-off-by: Robert Marko <robert.marko@sartura.hr>
#define QCA8K_QCA832X_MIB_COUNT 39
#define QCA8K_QCA833X_MIB_COUNT 41
@@ -265,6 +269,7 @@
@@ -266,6 +270,7 @@
#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3)
#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4)
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
@@ -1069,7 +1069,7 @@ Signed-off-by: Robert Marko <robert.marko@sartura.hr>
#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700
@@ -341,6 +346,53 @@
@@ -342,6 +347,53 @@
#define MII_ATH_MMD_ADDR 0x0d
#define MII_ATH_MMD_DATA 0x0e
@@ -1123,7 +1123,7 @@ Signed-off-by: Robert Marko <robert.marko@sartura.hr>
enum {
QCA8K_PORT_SPEED_10M = 0,
QCA8K_PORT_SPEED_100M = 1,
@@ -468,6 +520,10 @@ struct qca8k_priv {
@@ -469,6 +521,10 @@ struct qca8k_priv {
struct qca8k_pcs pcs_port_6;
const struct qca8k_match_data *info;
struct qca8k_led ports_led[QCA8K_LED_COUNT];
@@ -1,158 +0,0 @@
From patchwork Fri Jun 5 08:11:29 2026
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: George Moussalem <george.moussalem@outlook.com>
X-Patchwork-Id: 14612861
X-Patchwork-Delegate: kuba@kernel.org
Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org
[10.30.226.201])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(No client certificate requested)
by smtp.subspace.kernel.org (Postfix) with ESMTPS id A30B6495510;
Fri, 5 Jun 2026 08:11:31 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
arc=none smtp.client-ip=10.30.226.201
ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
t=1780647091; cv=none;
b=izElTZnAl4VU4jMwjDaYCFw9xgx5Jdm3nvzLj6yKtIxqBkHhndvHgZTl1ps4ZXGZY7WuzqrPlnZzKvjqbmLl9zMojNhz9bfdRUSxAHckbIK7FvDAqJkdGnW7vUVhM2Y2vqBfHF8y99Y7jlplG33EUJvsGus3U3Nwb3XrMMA+TEk=
ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org;
s=arc-20240116; t=1780647091; c=relaxed/simple;
bh=wVsP7qwG8BJu2wprX0HV2M1fTkH7tQV3G1mR8NtSBaw=;
h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc;
b=YkSoB8rVHO59IG66zmiHuYuyYWLzbyGnZ4+Pyj30JYpjAyBu7MB3zgNmma5FE0yJ7yiQycoKrPcRux8qX7HpzavyQwPsDNmhSJ3eRqrE70gLAOVn8Aia4AnJW0rE5tcNyS6PhhYfflZLwAMqrMF9wuhVOgl8HQ/nT/H2Xry/x8Q=
ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org
header.b=Hbrnqrg9; arc=none smtp.client-ip=10.30.226.201
Authentication-Results: smtp.subspace.kernel.org;
dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org
header.b="Hbrnqrg9"
Received: by smtp.kernel.org (Postfix) with ESMTPS id 4CA61C2BCC6;
Fri, 5 Jun 2026 08:11:31 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;
s=k20201202; t=1780647091;
bh=wVsP7qwG8BJu2wprX0HV2M1fTkH7tQV3G1mR8NtSBaw=;
h=From:Date:Subject:To:Cc:Reply-To:From;
b=Hbrnqrg9RhUWrD93DON6WYHKiUY/P9JoQoOKcBb0/KJWXzbzKUzy1aiEPRDNCz74l
unOk46jE02c/euDZYR1gDWxh9Uxacss0xlUunTTj86g+Uk7iSNaM04wzH4DGgAqWuP
QOK6c9mcDNCgEQ6otxAJVE8JDdQ6Rci/uyPf3YSW6lk2Xc5jca5/hSBn1Ed49K5Ycp
e3VdODdZns9EJlfW2FyX1pLCLijdAZOhdw0+BdfL7Jl8v1NW3lPx68kX0BRG1rAFRs
fIOgpgls+EJeJW0zsiaY65LScSz0F1I6vkcMUyGlEv/qY6jPK7TwZ9GbG+DUyC7SF3
jl5FVBD61KZUQ==
Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org
(localhost.localdomain [127.0.0.1])
by smtp.lore.kernel.org (Postfix) with ESMTP id 305B6CD6E5D;
Fri, 5 Jun 2026 08:11:31 +0000 (UTC)
Date: Fri, 05 Jun 2026 12:11:29 +0400
Subject: [PATCH next-next v2] net: dsa: qca8k: Add support for force mode
for fixed link topology
Precedence: bulk
X-Mailing-List: netdev@vger.kernel.org
List-Id: <netdev.vger.kernel.org>
List-Subscribe: <mailto:netdev+subscribe@vger.kernel.org>
List-Unsubscribe: <mailto:netdev+unsubscribe@vger.kernel.org>
MIME-Version: 1.0
Message-Id: <20260605-qca8337-force-mode-v2-1-d9a6b6545bfa@outlook.com>
X-B4-Tracking: v=1; b=H4sIAAAAAAAC/32NTQ6CMBCFr0Jm7ZjSYlFX3sOwKGUqjdLRFgmGc
HcrB3Dzki/vb4FE0VOCc7FApMknzyGD3BVgexNuhL7LDFJILbRQ+LLmqFSNjqMlHLgjdK1tzUG
edFVpyMVnJOfnbfQKgeYRfwJNtnqfRo6f7W4qt8C/5anEEq1xta6Fc6ZVF36PD+b73vIAzbquX
0/JJvLBAAAA
X-Change-ID: 20260603-qca8337-force-mode-fbcba5296446
To: Andrew Lunn <andrew@lunn.ch>, Vladimir Oltean <olteanv@gmail.com>,
"David S. Miller" <davem@davemloft.net>, Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
George Moussalem <george.moussalem@outlook.com>
X-Mailer: b4 0.14.3
X-Developer-Signature: v=1; a=ed25519-sha256; t=1780647089; l=3187;
i=george.moussalem@outlook.com; s=20250321; h=from:subject:message-id;
bh=/1K49g/Q0+wrB8ffa0QJHaW9eANv5Yae+dqQkwbdI4U=;
b=Xn7RwqPiLUqBSMkfjxaoyatDwqn+EhlJZVxXog3mgyAtwLsVAImKiBsVWVvKVPlXJ//K6hwlv
IPyVfdFw1CBAI5t89drX8j9nLQevPmF9+g75OyKnuqOsk4jD9ZFIckZ
X-Developer-Key: i=george.moussalem@outlook.com; a=ed25519;
pk=/PuRTSI9iYiHwcc6Nrde8qF4ZDhJBlUgpHdhsIjnqIk=
X-Endpoint-Received: by B4 Relay for george.moussalem@outlook.com/20250321
with auth_id=364
X-Original-From: George Moussalem <george.moussalem@outlook.com>
Reply-To: george.moussalem@outlook.com
From: George Moussalem <george.moussalem@outlook.com>
X-Patchwork-Delegate: kuba@kernel.org
From: George Moussalem <george.moussalem@outlook.com>
A fixed link topology is commonly used to connect this switch (on port
0 or 6) to a SoC's MAC over SGMII. When inband negotiation is not used,
the switch needs to be configured to operate in force mode. As such,
enable support for force mode.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
Changes in v2:
- Added check for QCA8337 switch ID and build up the register mask
accordingly before writing the force mode bit to avoid overwriting the
bit on switches other than QCA8337 for which there's no documentation
on whether force mode is supported or not.
- Added comment to state that regardless of port used (0 or 6), the
force mode bit is written to the PORT0 PAD register as per vendor SDK.
- Link to v1: https://lore.kernel.org/r/20260603-qca8337-force-mode-v1-1-caf7670ffab3@outlook.com
---
drivers/net/dsa/qca/qca8k-8xxx.c | 22 ++++++++++++++++------
drivers/net/dsa/qca/qca8k.h | 1 +
2 files changed, 17 insertions(+), 6 deletions(-)
---
base-commit: b7bee4ca5688e30ca50fbc87b1b8f7eed7006c17
change-id: 20260603-qca8337-force-mode-fbcba5296446
Best regards,
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1538,7 +1538,7 @@ static int qca8k_pcs_config(struct phyli
{
struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv;
int cpu_port_index, ret, port;
- u32 reg, val;
+ u32 mask, reg, val;
port = pcs_to_qca8k_pcs(pcs)->port;
switch (port) {
@@ -1611,11 +1611,21 @@ static int qca8k_pcs_config(struct phyli
if (priv->ports_config.sgmii_tx_clk_falling_edge)
val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE;
- if (val)
- ret = qca8k_rmw(priv, reg,
- QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
- QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
- val);
+ mask = (val) ? (QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE) : 0;
+
+ /*
+ * (Un)set force mode on QCA8337 only, don't include it in the mask for
+ * others. It is written to the PORT0 PAD register for both port 0 and 6.
+ */
+ if (priv->switch_id == QCA8K_ID_QCA8337) {
+ if (neg_mode == PHYLINK_PCS_NEG_OUTBAND)
+ val |= QCA8K_PORT_PAD_SGMII_FORCE_MODE;
+ mask |= QCA8K_PORT_PAD_SGMII_FORCE_MODE;
+ }
+
+ if (mask)
+ ret = qca8k_rmw(priv, reg, mask, val);
return 0;
}
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -58,6 +58,7 @@
#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
+#define QCA8K_PORT_PAD_SGMII_FORCE_MODE BIT(3)
#define QCA8K_REG_PWS 0x010
#define QCA8K_PWS_POWER_ON_SEL BIT(31)
/* This reg is only valid for QCA832x and toggle the package