From 245f8d364f2b7d92bb9bc9f0047c1ccd128ceffa Mon Sep 17 00:00:00 2001 From: Julius Bairaktaris Date: Wed, 9 Sep 2026 16:26:56 +0200 Subject: [PATCH] qualcommax: qca_ppe: leave the loopback port's transmit gate open ppe_mac_hw_init() enables the loopback, waits 100 ms for it and opens that port's PPE_PORT_BRIDGE_CTRL_TXMAC_EN, the gate the fabric needs before it will hand a port a frame. Two paths shut it again. qca_ppe_setup() walks every port and clears the bit for all but the CPU port, and the loopback port is described by no board, so DSA also sees it as unused and calls port_disable() on it. Nothing reopens it: the port has no phylink, so no link event ever runs, and the loopback probe configured stays unreachable for the life of the boot. Give the bit one owner. ppe_port_bridge_txmac_set() refuses to close the loopback port's gate, and the setup walk stops writing the bit at all - it was only ever setting it for the CPU port, whose gate qca_ppe_port_enable() opens a moment later when DSA enables that port. A user port's gate is still opened by qca_ppe_mac_link_up() and closed by its link going down. Tested on IPQ8074 (Xiaomi AX3600, kernel 6.18.44): PPE_PORT_BRIDGE_CTRL(7) reads 0x0002ff08 before this change and 0x0003ff08 after it, the two differing only in TXMAC_EN. The CPU port and the four user ports read the bit set and the two ports no board describes read it clear. Forwarding, offload and dmesg are unchanged. Fixes: 142104bb90b3 ("qualcommax: add PPE driver") Assisted-by: Claude:claude-opus-5 Signed-off-by: Julius Bairaktaris Link: https://github.com/openwrt/openwrt/pull/25084 Signed-off-by: Robert Marko --- .../drivers/net/ethernet/qualcomm/qca_ppe_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_ppe_main.c b/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_ppe_main.c index 09e75f55243..4d2f17ba6e8 100644 --- a/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_ppe_main.c +++ b/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_ppe_main.c @@ -61,6 +61,13 @@ static void ppe_port_xgmac_set(struct qca_ppe_priv *priv, int port, static void ppe_port_bridge_txmac_set(struct qca_ppe_priv *priv, int port, bool enable) { + /* The loopback port is internal and has no link of its own: probe + * opens its gate once and nothing that walks the ports may close it, + * because nothing would open it again. + */ + if (!enable && port == priv->data->loopback_port) + return; + regmap_update_bits(priv->regmap, PPE_PORT_BRIDGE_CTRL(port), PPE_PORT_BRIDGE_CTRL_TXMAC_EN, enable ? PPE_PORT_BRIDGE_CTRL_TXMAC_EN : 0); @@ -538,13 +545,10 @@ static int qca_ppe_setup(struct dsa_switch *ds) val = PPE_BRIDGE_NEW_LRN_EN | PPE_BRIDGE_STA_MOVE_EN | FIELD_PREP(PPE_BRIDGE_PORT_ISOL, port_mask); - if (dsa_is_cpu_port(ds, i)) - val |= PPE_PORT_BRIDGE_CTRL_TXMAC_EN; regmap_update_bits(priv->regmap, PPE_PORT_BRIDGE_CTRL(i), PPE_BRIDGE_NEW_LRN_EN | PPE_BRIDGE_STA_MOVE_EN | - PPE_BRIDGE_PORT_ISOL | - PPE_PORT_BRIDGE_CTRL_TXMAC_EN, + PPE_BRIDGE_PORT_ISOL, val); ppe_port_cnt_enable(priv, i);