From d4083ed9ee5d154fc89ee52fb34f1c8e8e4f524e Mon Sep 17 00:00:00 2001 From: Yalei Zang Date: Wed, 14 Oct 2026 20:44:16 +0800 Subject: [PATCH] airoha: backport on-demand GDM3/GDM4 QoS configuration Backport the change that configures GDM3/GDM4 as WAN and enables GDM2 loopback when HTB hardware offload is requested, instead of enabling them during device initialization. This lets GDM3/GDM4 operate as LAN ports until hardware QoS requires the WAN path. The change also handles QDMA migration on running interfaces when switching port roles. Link: https://patch.msgid.link/20260725-airoha-ethtool-priv_flags-v12-3-5136a30b2157@kernel.org Signed-off-by: Yalei Zang Link: https://github.com/openwrt/openwrt/pull/25901 Signed-off-by: Robert Marko --- ...e-airoha_priv_flags-to-airoha_dev_fl.patch | 70 ++ ...TS-QoS-stats-counter-underflow-and-c.patch | 84 +++ ...-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch | 616 ++++++++++++++++++ ...-airoha-deassert-XSI-line-on-hw-init.patch | 2 +- ...nitial-fixup-for-GDM3-4-port-support.patch | 4 +- ...7-airoha-ethernet-drop-xsi-mac-reset.patch | 4 +- ...10-10-net-airoha-add-phylink-support.patch | 41 +- ...w-QoS-parameter-according-to-the-pac.patch | 12 +- ...-airoha-Implement-HW-GRO-TCP-support.patch | 69 +- ...-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch | 560 ++-------------- ...-net-airoha-Rework-MTU-configuration.patch | 15 +- ...-airoha-fix-wrong-airoha_get_fe_port.patch | 2 +- 12 files changed, 890 insertions(+), 589 deletions(-) create mode 100644 target/linux/airoha/patches-6.18/193-01-v7.2-net-airoha-rename-airoha_priv_flags-to-airoha_dev_fl.patch create mode 100644 target/linux/airoha/patches-6.18/193-02-v7.2-net-airoha-fix-ETS-QoS-stats-counter-underflow-and-c.patch create mode 100644 target/linux/airoha/patches-6.18/193-03-v7.2-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch diff --git a/target/linux/airoha/patches-6.18/193-01-v7.2-net-airoha-rename-airoha_priv_flags-to-airoha_dev_fl.patch b/target/linux/airoha/patches-6.18/193-01-v7.2-net-airoha-rename-airoha_priv_flags-to-airoha_dev_fl.patch new file mode 100644 index 00000000000..16bab4aa253 --- /dev/null +++ b/target/linux/airoha/patches-6.18/193-01-v7.2-net-airoha-rename-airoha_priv_flags-to-airoha_dev_fl.patch @@ -0,0 +1,70 @@ +From 0040ff44cd5b59f85ea2feac9ad6b6d9eed66833 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sat, 25 Jul 2026 22:41:40 +0200 +Subject: [PATCH 38/50] net: airoha: rename airoha_priv_flags to + airoha_dev_flags + +Rename the airoha_priv_flags enum to airoha_dev_flags and the +AIROHA_PRIV_F_WAN flag to AIROHA_DEV_F_WAN. The "priv_flags" naming +dates back to an earlier design that used ethtool private flags; since +this series switched to tc qdisc offload for LAN/WAN configuration, +align the naming to reflect that these are per-device flags rather than +ethtool private flags. + +While at it, switch to test_bit()/set_bit()/clear_bit() APIs and +convert the flags field from u32 to unsigned long to make flags +manipulation atomic. + +Reviewed-by: Simon Horman +Reviewed-by: Alexander Lobakin +Reviewed-by: Jacob Keller +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260725-airoha-ethtool-priv_flags-v12-1-5136a30b2157@kernel.org +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/airoha/airoha_eth.c | 2 +- + drivers/net/ethernet/airoha/airoha_eth.h | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2078,7 +2078,7 @@ static int airoha_dev_init(struct net_de + fallthrough; + case AIROHA_GDM2_IDX: + /* GDM2 is always used as wan */ +- dev->flags |= AIROHA_PRIV_F_WAN; ++ set_bit(AIROHA_DEV_F_WAN, &dev->flags); + break; + default: + break; +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -573,8 +573,8 @@ struct airoha_qdma { + DECLARE_BITMAP(qos_channel_map, AIROHA_NUM_QOS_CHANNELS); + }; + +-enum airoha_priv_flags { +- AIROHA_PRIV_F_WAN = BIT(0), ++enum airoha_dev_flags { ++ AIROHA_DEV_F_WAN, + }; + + struct airoha_gdm_dev { +@@ -587,7 +587,7 @@ struct airoha_gdm_dev { + u64 cpu_tx_packets; + u64 fwd_tx_packets; + +- u32 flags; ++ unsigned long flags; + int nbq; + + struct airoha_hw_stats stats; +@@ -697,7 +697,7 @@ static inline u16 airoha_qdma_get_txq(st + + static inline bool airoha_is_lan_gdm_dev(struct airoha_gdm_dev *dev) + { +- return !(dev->flags & AIROHA_PRIV_F_WAN); ++ return !test_bit(AIROHA_DEV_F_WAN, &dev->flags); + } + + static inline bool airoha_is_7581(struct airoha_eth *eth) diff --git a/target/linux/airoha/patches-6.18/193-02-v7.2-net-airoha-fix-ETS-QoS-stats-counter-underflow-and-c.patch b/target/linux/airoha/patches-6.18/193-02-v7.2-net-airoha-fix-ETS-QoS-stats-counter-underflow-and-c.patch new file mode 100644 index 00000000000..5f8a40c5089 --- /dev/null +++ b/target/linux/airoha/patches-6.18/193-02-v7.2-net-airoha-fix-ETS-QoS-stats-counter-underflow-and-c.patch @@ -0,0 +1,84 @@ +From 8b9a508819880c0c41d70f5b655bbd0baa231395 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sat, 25 Jul 2026 22:41:41 +0200 +Subject: [PATCH 39/50] net: airoha: fix ETS QoS stats counter underflow and + cross-channel corruption + +airoha_qdma_get_tx_ets_stats() has two bugs: +- The hardware counters read via airoha_qdma_rr() are 32-bit values + but are stored in u64 locals and subtracted from u64 baselines. When + a 32-bit hardware counter wraps around, the subtraction produces a + large underflow value passed to _bstats_update(). +- The baseline counters (cpu_tx_packets, fwd_tx_packets) are stored as + single per-device fields, but airoha_qdma_get_tx_ets_stats() is + called with different channel values (0-3). Each call reads a + different channel's hardware counter but overwrites the same + baseline, corrupting the delta computation for other channels. + +Fix both by: +- Narrowing the counter locals and baselines to u32 so that 32-bit + unsigned subtraction handles wrap-around naturally. +- Grouping the baselines into a per-channel qos_stats array so each + channel tracks its own previous counter value independently. +- Splitting the delta addition into two statements so the first u32 + delta is widened to u64 on assignment and the second is added in + u64 arithmetic, preventing overflow when both deltas are large. + +Fixes: 20bf7d07c956 ("net: airoha: Add sched ETS offload support") +Reviewed-by: Simon Horman +Reviewed-by: Alexander Lobakin +Reviewed-by: Jacob Keller +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260725-airoha-ethtool-priv_flags-v12-2-5136a30b2157@kernel.org +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/airoha/airoha_eth.c | 18 +++++++++++------- + drivers/net/ethernet/airoha/airoha_eth.h | 7 ++++--- + 2 files changed, 15 insertions(+), 10 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2521,16 +2521,20 @@ static int airoha_qdma_get_tx_ets_stats( + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_qdma *qdma = dev->qdma; ++ u32 cpu_tx_packets, fwd_tx_packets; ++ u64 tx_packets; + +- u64 cpu_tx_packets = airoha_qdma_rr(qdma, REG_CNTR_VAL(channel << 1)); +- u64 fwd_tx_packets = airoha_qdma_rr(qdma, +- REG_CNTR_VAL((channel << 1) + 1)); +- u64 tx_packets = (cpu_tx_packets - dev->cpu_tx_packets) + +- (fwd_tx_packets - dev->fwd_tx_packets); ++ cpu_tx_packets = airoha_qdma_rr(qdma, REG_CNTR_VAL(channel << 1)); ++ fwd_tx_packets = airoha_qdma_rr(qdma, ++ REG_CNTR_VAL((channel << 1) + 1)); ++ tx_packets = (u32)(cpu_tx_packets - ++ dev->qos_stats[channel].cpu_tx_packets); ++ tx_packets += (u32)(fwd_tx_packets - ++ dev->qos_stats[channel].fwd_tx_packets); + + _bstats_update(opt->stats.bstats, 0, tx_packets); +- dev->cpu_tx_packets = cpu_tx_packets; +- dev->fwd_tx_packets = fwd_tx_packets; ++ dev->qos_stats[channel].cpu_tx_packets = cpu_tx_packets; ++ dev->qos_stats[channel].fwd_tx_packets = fwd_tx_packets; + + return 0; + } +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -583,9 +583,10 @@ struct airoha_gdm_dev { + struct airoha_eth *eth; + + DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); +- /* qos stats counters */ +- u64 cpu_tx_packets; +- u64 fwd_tx_packets; ++ struct { ++ u32 cpu_tx_packets; ++ u32 fwd_tx_packets; ++ } qos_stats[AIROHA_NUM_QOS_CHANNELS]; + + unsigned long flags; + int nbq; diff --git a/target/linux/airoha/patches-6.18/193-03-v7.2-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch b/target/linux/airoha/patches-6.18/193-03-v7.2-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch new file mode 100644 index 00000000000..ce84d59e08d --- /dev/null +++ b/target/linux/airoha/patches-6.18/193-03-v7.2-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch @@ -0,0 +1,616 @@ +From 78a35725e533eef0afe83f6f96cffd69be9eaac7 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sat, 25 Jul 2026 22:41:42 +0200 +Subject: [PATCH 40/50] net: airoha: defer GDM3/GDM4 WAN mode and GDM2 loopback + to QoS offload + +GDM3 and GDM4 ports require GDM2 loopback to be enabled for hardware +QoS offload to function. Without it, HTB and ETS offload on these ports +do not work. +Previously, GDM3/GDM4 ports were automatically configured as WAN with +GDM2 loopback enabled during ndo_init(). +Add the capability to configure GDM3/GDM4 as WAN/LAN on demand when QoS +offload is created or destroyed. +Hook airoha_enable_qos_for_gdm34() into TC_HTB_CREATE so that requesting +HTB offload on a GDM3/GDM4 LAN port switches it to WAN mode and enables +GDM2 loopback. +Introduce the AIROHA_DEV_F_TX_QOS flag to track whether a device has an +active TX HTB qdisc; set it in airoha_tc_setup_qdisc_htb() on successful +TC_HTB_CREATE and clear it on TC_HTB_DESTROY. The device keeps its WAN +role after qdisc teardown so that its configuration is preserved until +another device explicitly needs the WAN role for QoS offload. +If another GDM3/GDM4 device already holds the WAN role without an active +TX qdisc, demote it to LAN before promoting the requesting device. Skip +the demotion when the requesting device is itself already the WAN device. +Since airoha_dev_set_qdma() can now be called on a running device to +migrate between QDMA blocks, make dev->qdma an RCU pointer so the TX path +can safely dereference it without holding RTNL. +When migrating between QDMA blocks, stop TX queues, swap the pointer via +rcu_assign_pointer(), then synchronize_rcu() to ensure no in-flight +ndo_start_xmit holds the old pointer. +Serialize netdev_tx_completed_queue() calls via per-TX-queue spinlocks +txq_lock[] so that both the old and new QDMA NAPI instances can complete +packets concurrently on the same netdev TX queues without racing on +dql_completed(). +Hold flow_offload_mutex in airoha_enable_qos_for_gdm34() and +airoha_disable_qos_for_gdm34() around the dev->flags update, +airoha_dev_set_qdma() and GDM2 loopback configuration, serializing +against concurrent airoha_ppe_hw_init() in the TC_SETUP_CLSFLOWER +offload path. +Introduce airoha_qdma_deref() helper that wraps rcu_dereference_protected() +with a lockdep condition accepting either rtnl_lock or flow_offload_mutex, +and use it across all control-path dereferences of the RCU-protected +dev->qdma pointer. +Add airoha_disable_gdm2_loopback() to disable GDM2 hw loopback. + +Tested-by: Madhur Agarwal +Reviewed-by: Alexander Lobakin +Reviewed-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260725-airoha-ethtool-priv_flags-v12-3-5136a30b2157@kernel.org +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/airoha/airoha_eth.c | 245 +++++++++++++++++++--- + drivers/net/ethernet/airoha/airoha_eth.h | 18 +- + drivers/net/ethernet/airoha/airoha_ppe.c | 9 +- + drivers/net/ethernet/airoha/airoha_regs.h | 1 + + 4 files changed, 243 insertions(+), 30 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -934,7 +934,7 @@ static void airoha_qdma_wake_netdev_txqs + if (!dev) + continue; + +- if (dev->qdma != qdma) ++ if (rcu_access_pointer(dev->qdma) != qdma) + continue; + + netdev = netdev_from_priv(dev); +@@ -1038,10 +1038,16 @@ static int airoha_qdma_tx_napi_poll(stru + q->queued--; + + if (skb) { ++ struct airoha_gdm_dev *dev = netdev_priv(skb->dev); ++ u16 qidx = skb_get_queue_mapping(skb); + struct netdev_queue *txq; + + txq = skb_get_tx_queue(skb->dev, skb); ++ ++ spin_lock_bh(&dev->txq_lock[qidx]); + netdev_tx_completed_queue(txq, 1, skb->len); ++ spin_unlock_bh(&dev->txq_lock[qidx]); ++ + dev_kfree_skb_any(skb); + } + +@@ -1905,8 +1911,8 @@ static int airoha_dev_open(struct net_de + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; +- struct airoha_qdma *qdma = dev->qdma; + u32 pse_port = FE_PSE_PORT_PPE1; ++ struct airoha_qdma *qdma; + int err; + + netif_tx_start_all_queues(netdev); +@@ -1914,6 +1920,7 @@ static int airoha_dev_open(struct net_de + if (err) + return err; + ++ qdma = airoha_qdma_deref(dev); + if (netdev_uses_dsa(netdev)) + airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id), + GDM_STAG_EN_MASK); +@@ -1937,7 +1944,6 @@ static int airoha_dev_stop(struct net_de + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; +- struct airoha_qdma *qdma = dev->qdma; + + netif_tx_disable(netdev); + airoha_set_vip_for_gdm_port(dev, false); +@@ -1945,7 +1951,7 @@ static int airoha_dev_stop(struct net_de + if (--port->users) + airoha_ppe_set_xmit_frame_size(dev); + else +- airoha_set_gdm_port_fwd_cfg(qdma->eth, ++ airoha_set_gdm_port_fwd_cfg(dev->eth, + REG_GDM_FWD_CFG(port->id), + FE_PSE_PORT_DROP); + return 0; +@@ -2028,6 +2034,53 @@ static int airoha_enable_gdm2_loopback(s + return 0; + } + ++static int airoha_disable_gdm2_loopback(struct airoha_gdm_dev *dev) ++{ ++ struct airoha_gdm_port *port = dev->port; ++ struct airoha_eth *eth = dev->eth; ++ int i, src_port; ++ u32 pse_port; ++ ++ src_port = eth->soc->ops.get_sport(dev->port, dev->nbq); ++ if (src_port < 0) ++ return src_port; ++ ++ airoha_fe_clear(eth, ++ REG_SP_DFT_CPORT(src_port >> fls(SP_CPORT_DFT_MASK)), ++ SP_CPORT_MASK(src_port & SP_CPORT_DFT_MASK)); ++ ++ airoha_fe_set(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), ++ GDM_STRIP_CRC_MASK); ++ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), ++ FE_PSE_PORT_DROP); ++ airoha_fe_clear(eth, REG_GDM_LPBK_CFG(AIROHA_GDM2_IDX), ++ LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK); ++ pse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2 ++ : FE_PSE_PORT_PPE1; ++ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), ++ pse_port); ++ ++ airoha_fe_rmw(eth, REG_FE_WAN_PORT, WAN0_MASK, ++ FIELD_PREP(WAN0_MASK, AIROHA_GDM2_IDX)); ++ ++ for (i = 0; i < eth->soc->num_ppe; i++) ++ airoha_fe_clear(eth, REG_PPE_DFT_CPORT(i, AIROHA_GDM2_IDX), ++ DFT_CPORT_MASK(AIROHA_GDM2_IDX)); ++ ++ /* Enable VIP and IFC for GDM2 */ ++ airoha_fe_set(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX)); ++ airoha_fe_set(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX)); ++ ++ if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) { ++ u32 mask = FC_ID_OF_SRC_PORT_MASK(dev->nbq); ++ ++ airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, mask, ++ FC_MAP6_DEF_VALUE & mask); ++ } ++ ++ return 0; ++} ++ + static struct airoha_gdm_dev * + airoha_get_wan_gdm_dev(struct airoha_eth *eth) + { +@@ -2054,15 +2107,37 @@ airoha_get_wan_gdm_dev(struct airoha_eth + static void airoha_dev_set_qdma(struct airoha_gdm_dev *dev) + { + struct net_device *netdev = netdev_from_priv(dev); ++ struct airoha_qdma *cur_qdma, *qdma; + struct airoha_eth *eth = dev->eth; +- int ppe_id; ++ int i, ppe_id; + + /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ +- dev->qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; +- netdev->irq = dev->qdma->irq_banks[0].irq; ++ qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; ++ cur_qdma = airoha_qdma_deref(dev); ++ ++ if (cur_qdma) ++ netif_tx_stop_all_queues(netdev); ++ ++ rcu_assign_pointer(dev->qdma, qdma); ++ netdev->irq = qdma->irq_banks[0].irq; ++ synchronize_rcu(); + + ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1); + airoha_ppe_set_cpu_port(dev, ppe_id, airoha_get_fe_port(dev)); ++ ++ /* Seed qos_stats baselines with the new QDMA block's current ++ * counter values to avoid a spurious spike on the first stats ++ * query after init or migration. ++ */ ++ for (i = 0; i < ARRAY_SIZE(dev->qos_stats); i++) { ++ dev->qos_stats[i].cpu_tx_packets = ++ airoha_qdma_rr(qdma, REG_CNTR_VAL(i << 1)); ++ dev->qos_stats[i].fwd_tx_packets = ++ airoha_qdma_rr(qdma, REG_CNTR_VAL((i << 1) + 1)); ++ } ++ ++ if (cur_qdma) ++ netif_tx_wake_all_queues(netdev); + } + + static int airoha_dev_init(struct net_device *netdev) +@@ -2217,9 +2292,9 @@ static netdev_tx_t airoha_dev_xmit(struc + struct net_device *netdev) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_qdma *qdma = dev->qdma; + u32 nr_frags, tag, msg0, msg1, len; + struct airoha_queue_entry *e; ++ struct airoha_qdma *qdma; + struct netdev_queue *txq; + struct airoha_queue *q; + LIST_HEAD(tx_list); +@@ -2228,6 +2303,8 @@ static netdev_tx_t airoha_dev_xmit(struc + u16 index; + u8 fport; + ++ rcu_read_lock(); ++ qdma = rcu_dereference(dev->qdma); + qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb)); + tag = airoha_get_dsa_tag(skb, netdev); + +@@ -2277,6 +2354,8 @@ static netdev_tx_t airoha_dev_xmit(struc + netif_tx_stop_queue(txq); + q->txq_stopped = true; + spin_unlock_bh(&q->lock); ++ rcu_read_unlock(); ++ + return NETDEV_TX_BUSY; + } + +@@ -2342,6 +2421,7 @@ static netdev_tx_t airoha_dev_xmit(struc + FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); + + spin_unlock_bh(&q->lock); ++ rcu_read_unlock(); + + return NETDEV_TX_OK; + +@@ -2354,6 +2434,7 @@ error_unlock: + error: + dev_kfree_skb_any(skb); + netdev->stats.tx_dropped++; ++ rcu_read_unlock(); + + return NETDEV_TX_OK; + } +@@ -2433,17 +2514,19 @@ static int airoha_qdma_set_chan_tx_sched + const u16 *weights, u8 n_weights) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_qdma *qdma; + int i; + ++ qdma = airoha_qdma_deref(dev); + for (i = 0; i < AIROHA_NUM_QOS_QUEUES; i++) +- airoha_qdma_clear(dev->qdma, REG_QUEUE_CLOSE_CFG(channel), ++ airoha_qdma_clear(qdma, REG_QUEUE_CLOSE_CFG(channel), + TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i)); + + for (i = 0; i < n_weights; i++) { + u32 status; + int err; + +- airoha_qdma_wr(dev->qdma, REG_TXWRR_WEIGHT_CFG, ++ airoha_qdma_wr(qdma, REG_TXWRR_WEIGHT_CFG, + TWRR_RW_CMD_MASK | + FIELD_PREP(TWRR_CHAN_IDX_MASK, channel) | + FIELD_PREP(TWRR_QUEUE_IDX_MASK, i) | +@@ -2451,12 +2534,12 @@ static int airoha_qdma_set_chan_tx_sched + err = read_poll_timeout(airoha_qdma_rr, status, + status & TWRR_RW_CMD_DONE, + USEC_PER_MSEC, 10 * USEC_PER_MSEC, +- true, dev->qdma, REG_TXWRR_WEIGHT_CFG); ++ true, qdma, REG_TXWRR_WEIGHT_CFG); + if (err) + return err; + } + +- airoha_qdma_rmw(dev->qdma, REG_CHAN_QOS_MODE(channel >> 3), ++ airoha_qdma_rmw(qdma, REG_CHAN_QOS_MODE(channel >> 3), + CHAN_QOS_MODE_MASK(channel), + __field_prep(CHAN_QOS_MODE_MASK(channel), mode)); + +@@ -2520,10 +2603,11 @@ static int airoha_qdma_get_tx_ets_stats( + struct tc_ets_qopt_offload *opt) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_qdma *qdma = dev->qdma; + u32 cpu_tx_packets, fwd_tx_packets; ++ struct airoha_qdma *qdma; + u64 tx_packets; + ++ qdma = airoha_qdma_deref(dev); + cpu_tx_packets = airoha_qdma_rr(qdma, REG_CNTR_VAL(channel << 1)); + fwd_tx_packets = airoha_qdma_rr(qdma, + REG_CNTR_VAL((channel << 1) + 1)); +@@ -2809,16 +2893,18 @@ static int airoha_qdma_set_tx_rate_limit + u32 bucket_size) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_qdma *qdma; + int i, err; + ++ qdma = airoha_qdma_deref(dev); + for (i = 0; i <= TRTCM_PEAK_MODE; i++) { +- err = airoha_qdma_set_trtcm_config(dev->qdma, channel, ++ err = airoha_qdma_set_trtcm_config(qdma, channel, + REG_EGRESS_TRTCM_CFG, i, + !!rate, TRTCM_METER_MODE); + if (err) + return err; + +- err = airoha_qdma_set_trtcm_token_bucket(dev->qdma, channel, ++ err = airoha_qdma_set_trtcm_token_bucket(qdma, channel, + REG_EGRESS_TRTCM_CFG, + i, rate, bucket_size); + if (err) +@@ -2854,11 +2940,12 @@ static int airoha_tc_htb_alloc_leaf_queu + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; + int err, num_tx_queues = AIROHA_NUM_TX_RING + channel + 1; + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_qdma *qdma = dev->qdma; ++ struct airoha_qdma *qdma; + + /* Here we need to check the requested QDMA channel is not already + * in use by another net_device running on the same QDMA block. + */ ++ qdma = airoha_qdma_deref(dev); + if (test_and_set_bit(channel, qdma->qos_channel_map)) { + NL_SET_ERR_MSG_MOD(opt->extack, + "qdma qos channel already in use"); +@@ -2894,7 +2981,7 @@ static int airoha_qdma_set_rx_meter(stru + u32 rate, u32 bucket_size, + enum trtcm_unit_type unit_type) + { +- struct airoha_qdma *qdma = dev->qdma; ++ struct airoha_qdma *qdma = airoha_qdma_deref(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { +@@ -3069,10 +3156,11 @@ static void airoha_tc_remove_htb_queue(s + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); + int num_tx_queues = AIROHA_NUM_TX_RING; +- struct airoha_qdma *qdma = dev->qdma; ++ struct airoha_qdma *qdma; + + airoha_qdma_set_tx_rate_limit(netdev, queue, 0, 0); + ++ qdma = airoha_qdma_deref(dev); + clear_bit(queue, qdma->qos_channel_map); + clear_bit(queue, dev->qos_sq_bmap); + +@@ -3098,6 +3186,98 @@ static int airoha_tc_htb_delete_leaf_que + return 0; + } + ++static void airoha_disable_qos_for_gdm34(struct net_device *netdev) ++{ ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; ++ int err; ++ ++ if (port->id != AIROHA_GDM3_IDX && ++ port->id != AIROHA_GDM4_IDX) ++ return; ++ ++ err = airoha_disable_gdm2_loopback(dev); ++ if (err) ++ netdev_warn(netdev, ++ "failed disabling GDM2 loopback: %d\n", err); ++ ++ clear_bit(AIROHA_DEV_F_WAN, &dev->flags); ++ airoha_dev_set_qdma(dev); ++ ++ airoha_set_macaddr(dev, netdev->dev_addr); ++ airoha_ppe_set_xmit_frame_size(dev); ++ ++ if (netif_running(netdev)) ++ airoha_set_gdm_port_fwd_cfg(dev->eth, ++ REG_GDM_FWD_CFG(port->id), ++ FE_PSE_PORT_PPE1); ++} ++ ++static int airoha_enable_qos_for_gdm34(struct net_device *netdev, ++ struct netlink_ext_ack *extack) ++{ ++ struct airoha_gdm_dev *wan_dev, *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; ++ struct airoha_eth *eth = dev->eth; ++ int err = -EBUSY; ++ ++ if (port->id != AIROHA_GDM3_IDX && ++ port->id != AIROHA_GDM4_IDX) { ++ /* HW QoS is always supported by GDM1 and GDM2 */ ++ return 0; ++ } ++ ++ if (!airoha_is_lan_gdm_dev(dev)) /* Already enabled */ ++ return 0; ++ ++ mutex_lock(&flow_offload_mutex); ++ ++ wan_dev = airoha_get_wan_gdm_dev(eth); ++ if (wan_dev) { ++ if (test_bit(AIROHA_DEV_F_TX_QOS, &wan_dev->flags) || ++ wan_dev->port->id == AIROHA_GDM2_IDX) { ++ NL_SET_ERR_MSG_MOD(extack, ++ "QoS configured for WAN device"); ++ goto error_unlock; ++ } ++ airoha_disable_qos_for_gdm34(netdev_from_priv(wan_dev)); ++ } ++ ++ set_bit(AIROHA_DEV_F_WAN, &dev->flags); ++ airoha_dev_set_qdma(dev); ++ err = airoha_enable_gdm2_loopback(dev); ++ if (err) ++ goto error_disable_wan; ++ ++ err = airoha_set_macaddr(dev, netdev->dev_addr); ++ if (err) ++ goto error_disable_loopback; ++ ++ airoha_dev_set_xmit_frame_size(netdev); ++ if (netif_running(netdev)) { ++ u32 pse_port; ++ ++ pse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2 ++ : FE_PSE_PORT_PPE1; ++ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id), ++ pse_port); ++ } ++ ++ mutex_unlock(&flow_offload_mutex); ++ ++ return 0; ++ ++error_disable_loopback: ++ airoha_disable_gdm2_loopback(dev); ++error_disable_wan: ++ clear_bit(AIROHA_DEV_F_WAN, &dev->flags); ++ airoha_dev_set_qdma(dev); ++error_unlock: ++ mutex_unlock(&flow_offload_mutex); ++ ++ return err; ++} ++ + static int airoha_tc_htb_destroy(struct net_device *netdev) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +@@ -3106,6 +3286,8 @@ static int airoha_tc_htb_destroy(struct + for_each_set_bit(q, dev->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS) + airoha_tc_remove_htb_queue(netdev, q); + ++ clear_bit(AIROHA_DEV_F_TX_QOS, &dev->flags); ++ + return 0; + } + +@@ -3125,24 +3307,33 @@ static int airoha_tc_get_htb_get_leaf_qu + return 0; + } + +-static int airoha_tc_setup_qdisc_htb(struct net_device *dev, ++static int airoha_tc_setup_qdisc_htb(struct net_device *netdev, + struct tc_htb_qopt_offload *opt) + { + switch (opt->command) { +- case TC_HTB_CREATE: ++ case TC_HTB_CREATE: { ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ int err; ++ ++ err = airoha_enable_qos_for_gdm34(netdev, opt->extack); ++ if (err) ++ return err; ++ ++ set_bit(AIROHA_DEV_F_TX_QOS, &dev->flags); + break; ++ } + case TC_HTB_DESTROY: +- return airoha_tc_htb_destroy(dev); ++ return airoha_tc_htb_destroy(netdev); + case TC_HTB_NODE_MODIFY: +- return airoha_tc_htb_modify_queue(dev, opt); ++ return airoha_tc_htb_modify_queue(netdev, opt); + case TC_HTB_LEAF_ALLOC_QUEUE: +- return airoha_tc_htb_alloc_leaf_queue(dev, opt); ++ return airoha_tc_htb_alloc_leaf_queue(netdev, opt); + case TC_HTB_LEAF_DEL: + case TC_HTB_LEAF_DEL_LAST: + case TC_HTB_LEAF_DEL_LAST_FORCE: +- return airoha_tc_htb_delete_leaf_queue(dev, opt); ++ return airoha_tc_htb_delete_leaf_queue(netdev, opt); + case TC_HTB_LEAF_QUERY_QUEUE: +- return airoha_tc_get_htb_get_leaf_queue(dev, opt); ++ return airoha_tc_get_htb_get_leaf_queue(netdev, opt); + default: + return -EOPNOTSUPP; + } +@@ -3244,8 +3435,8 @@ static int airoha_alloc_gdm_device(struc + { + struct net_device *netdev; + struct airoha_gdm_dev *dev; ++ int err, i; + u8 index; +- int err; + + netdev = devm_alloc_etherdev_mqs(eth->dev, sizeof(*dev), + AIROHA_NUM_NETDEV_TX_RINGS, +@@ -3296,6 +3487,8 @@ static int airoha_alloc_gdm_device(struc + netdev->dev.of_node = of_node_get(np); + dev = netdev_priv(netdev); + u64_stats_init(&dev->stats.syncp); ++ for (i = 0; i < ARRAY_SIZE(dev->txq_lock); i++) ++ spin_lock_init(&dev->txq_lock[i]); + dev->port = port; + dev->eth = eth; + dev->nbq = nbq; +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -575,11 +575,12 @@ struct airoha_qdma { + + enum airoha_dev_flags { + AIROHA_DEV_F_WAN, ++ AIROHA_DEV_F_TX_QOS, + }; + + struct airoha_gdm_dev { ++ struct airoha_qdma __rcu *qdma; + struct airoha_gdm_port *port; +- struct airoha_qdma *qdma; + struct airoha_eth *eth; + + DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); +@@ -592,6 +593,11 @@ struct airoha_gdm_dev { + int nbq; + + struct airoha_hw_stats stats; ++ ++ /* Serialize netdev_tx_completed_queue() calls per TX queue during ++ * QDMA migration. ++ */ ++ spinlock_t txq_lock[AIROHA_NUM_NETDEV_TX_RINGS]; + }; + + struct airoha_gdm_port { +@@ -715,6 +721,16 @@ int airoha_get_fe_port(struct airoha_gdm + bool airoha_is_valid_gdm_dev(struct airoha_eth *eth, + struct airoha_gdm_dev *dev); + ++extern struct mutex flow_offload_mutex; ++ ++static inline struct airoha_qdma * ++airoha_qdma_deref(struct airoha_gdm_dev *dev) ++{ ++ return rcu_dereference_protected(dev->qdma, ++ lockdep_rtnl_is_held() || ++ lockdep_is_held(&flow_offload_mutex)); ++} ++ + void airoha_ppe_set_xmit_frame_size(struct airoha_gdm_dev *dev); + void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport); + bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index); +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -15,7 +15,10 @@ + #include "airoha_regs.h" + #include "airoha_eth.h" + +-static DEFINE_MUTEX(flow_offload_mutex); ++/* Serialize airoha_gdm_dev flags, QDMA pointer and PPE CPU port ++ * configuration. ++ */ ++DEFINE_MUTEX(flow_offload_mutex); + static DEFINE_SPINLOCK(ppe_lock); + + static const struct rhashtable_params airoha_flow_table_params = { +@@ -86,8 +89,8 @@ static u32 airoha_ppe_get_timestamp(stru + + void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport) + { +- struct airoha_qdma *qdma = dev->qdma; +- struct airoha_eth *eth = qdma->eth; ++ struct airoha_qdma *qdma = airoha_qdma_deref(dev); ++ struct airoha_eth *eth = dev->eth; + u8 qdma_id = qdma - ð->qdma[0]; + u32 fe_cpu_port; + +--- a/drivers/net/ethernet/airoha/airoha_regs.h ++++ b/drivers/net/ethernet/airoha/airoha_regs.h +@@ -375,6 +375,7 @@ + + #define REG_SRC_PORT_FC_MAP6 0x2298 + #define FC_ID_OF_SRC_PORT_MASK(_n) GENMASK(4 + ((_n) << 3), ((_n) << 3)) ++#define FC_MAP6_DEF_VALUE 0x1b1a1918 + + #define REG_WAN_MTU0 0x2300 + #define WAN_MTU1_MASK GENMASK(29, 16) diff --git a/target/linux/airoha/patches-6.18/310-02-net-airoha-deassert-XSI-line-on-hw-init.patch b/target/linux/airoha/patches-6.18/310-02-net-airoha-deassert-XSI-line-on-hw-init.patch index d85aa6a753b..e3c362cd969 100644 --- a/target/linux/airoha/patches-6.18/310-02-net-airoha-deassert-XSI-line-on-hw-init.patch +++ b/target/linux/airoha/patches-6.18/310-02-net-airoha-deassert-XSI-line-on-hw-init.patch @@ -13,7 +13,7 @@ Signed-off-by: Christian Marangi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -1617,6 +1617,10 @@ static int airoha_hw_init(struct platfor +@@ -1623,6 +1623,10 @@ static int airoha_hw_init(struct platfor if (err) return err; diff --git a/target/linux/airoha/patches-6.18/310-06-net-airoha-add-initial-fixup-for-GDM3-4-port-support.patch b/target/linux/airoha/patches-6.18/310-06-net-airoha-add-initial-fixup-for-GDM3-4-port-support.patch index e6aed8b4953..bc836f6f725 100644 --- a/target/linux/airoha/patches-6.18/310-06-net-airoha-add-initial-fixup-for-GDM3-4-port-support.patch +++ b/target/linux/airoha/patches-6.18/310-06-net-airoha-add-initial-fixup-for-GDM3-4-port-support.patch @@ -28,10 +28,10 @@ Signed-off-by: Christian Marangi /* Enable split for MIB counters for GDM3 and GDM4 */ airoha_fe_set(eth, REG_FE_GDM_MIB_CFG(AIROHA_GDM3_IDX), -@@ -1918,7 +1920,8 @@ static int airoha_dev_open(struct net_de - if (err) +@@ -1925,7 +1927,8 @@ static int airoha_dev_open(struct net_de return err; + qdma = airoha_qdma_deref(dev); - if (netdev_uses_dsa(netdev)) + /* It seems GDM3 and GDM4 needs SPORT enabled to correctly work */ + if (netdev_uses_dsa(netdev) || port->id > 2) diff --git a/target/linux/airoha/patches-6.18/310-07-airoha-ethernet-drop-xsi-mac-reset.patch b/target/linux/airoha/patches-6.18/310-07-airoha-ethernet-drop-xsi-mac-reset.patch index 34e3443f9f2..e1546bf14df 100644 --- a/target/linux/airoha/patches-6.18/310-07-airoha-ethernet-drop-xsi-mac-reset.patch +++ b/target/linux/airoha/patches-6.18/310-07-airoha-ethernet-drop-xsi-mac-reset.patch @@ -15,7 +15,7 @@ Signed-off-by: Christian Marangi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -3585,7 +3585,6 @@ static void airoha_remove(struct platfor +@@ -3782,7 +3782,6 @@ static void airoha_remove(struct platfor } static const char * const en7581_xsi_rsts_names[] = { @@ -23,7 +23,7 @@ Signed-off-by: Christian Marangi "hsi0-mac", "hsi1-mac", "hsi-mac", -@@ -3672,7 +3671,6 @@ static int airoha_en7581_get_dev_from_sp +@@ -3869,7 +3868,6 @@ static int airoha_en7581_get_dev_from_sp } static const char * const an7583_xsi_rsts_names[] = { diff --git a/target/linux/airoha/patches-6.18/310-10-net-airoha-add-phylink-support.patch b/target/linux/airoha/patches-6.18/310-10-net-airoha-add-phylink-support.patch index 9fba2f81c42..96bb580558b 100644 --- a/target/linux/airoha/patches-6.18/310-10-net-airoha-add-phylink-support.patch +++ b/target/linux/airoha/patches-6.18/310-10-net-airoha-add-phylink-support.patch @@ -42,7 +42,7 @@ Signed-off-by: Christian Marangi #include #include #include -@@ -1699,7 +1700,7 @@ static void airoha_update_hw_stats(struc +@@ -1705,7 +1706,7 @@ static void airoha_update_hw_stats(struc u32 val, i = 0; u64 data; @@ -51,7 +51,7 @@ Signed-off-by: Christian Marangi /* Read relevant MIB for GDM with multiple port attached */ if (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX) -@@ -1893,7 +1894,7 @@ static void airoha_update_hw_stats(struc +@@ -1899,7 +1900,7 @@ static void airoha_update_hw_stats(struc u64_stats_update_end(&dev->stats.syncp); @@ -60,8 +60,8 @@ Signed-off-by: Christian Marangi } static void airoha_dev_set_xmit_frame_size(struct net_device *netdev) -@@ -1915,6 +1916,14 @@ static int airoha_dev_open(struct net_de - u32 pse_port = FE_PSE_PORT_PPE1; +@@ -1921,6 +1922,14 @@ static int airoha_dev_open(struct net_de + struct airoha_qdma *qdma; int err; + err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0); @@ -75,17 +75,18 @@ Signed-off-by: Christian Marangi netif_tx_start_all_queues(netdev); err = airoha_set_vip_for_gdm_port(dev, true); if (err) -@@ -2032,6 +2041,9 @@ static int airoha_enable_gdm2_loopback(s - __field_prep(mask, AIROHA_GDM2_IDX)); - } - +@@ -1961,6 +1970,10 @@ static int airoha_dev_stop(struct net_de + airoha_set_gdm_port_fwd_cfg(dev->eth, + REG_GDM_FWD_CFG(port->id), + FE_PSE_PORT_DROP); ++ + phylink_stop(dev->phylink); + phylink_disconnect_phy(dev->phylink); + return 0; } -@@ -2435,6 +2447,24 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2516,6 +2529,24 @@ airoha_ethtool_get_rmon_stats(struct net } while (u64_stats_fetch_retry(&dev->stats.syncp, start)); } @@ -110,7 +111,7 @@ Signed-off-by: Christian Marangi static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev, int channel, enum tx_sched_mode mode, const u16 *weights, u8 n_weights) -@@ -3185,7 +3215,8 @@ static const struct ethtool_ops airoha_e +@@ -3380,7 +3411,8 @@ static const struct ethtool_ops airoha_e .get_drvinfo = airoha_ethtool_get_drvinfo, .get_eth_mac_stats = airoha_ethtool_get_mac_stats, .get_rmon_stats = airoha_ethtool_get_rmon_stats, @@ -120,7 +121,7 @@ Signed-off-by: Christian Marangi .get_link = ethtool_op_get_link, }; -@@ -3241,6 +3272,155 @@ bool airoha_is_valid_gdm_dev(struct airo +@@ -3436,6 +3468,155 @@ bool airoha_is_valid_gdm_dev(struct airo return false; } @@ -276,7 +277,7 @@ Signed-off-by: Christian Marangi static int airoha_alloc_gdm_device(struct airoha_eth *eth, struct airoha_gdm_port *port, int nbq, struct device_node *np) -@@ -3304,7 +3484,7 @@ static int airoha_alloc_gdm_device(struc +@@ -3501,7 +3682,7 @@ static int airoha_alloc_gdm_device(struc dev->nbq = nbq; port->devs[index] = dev; @@ -285,7 +286,7 @@ Signed-off-by: Christian Marangi } static int airoha_alloc_gdm_port(struct airoha_eth *eth, -@@ -3339,7 +3519,7 @@ static int airoha_alloc_gdm_port(struct +@@ -3536,7 +3717,7 @@ static int airoha_alloc_gdm_port(struct return -ENOMEM; port->id = id; @@ -294,7 +295,7 @@ Signed-off-by: Christian Marangi eth->ports[p] = port; err = airoha_metadata_dst_alloc(port); -@@ -3536,6 +3716,8 @@ error_napi_stop: +@@ -3733,6 +3914,8 @@ error_napi_stop: netdev = netdev_from_priv(dev); if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); @@ -303,7 +304,7 @@ Signed-off-by: Christian Marangi of_node_put(netdev->dev.of_node); } airoha_metadata_dst_free(port); -@@ -3574,6 +3756,7 @@ static void airoha_remove(struct platfor +@@ -3771,6 +3954,7 @@ static void airoha_remove(struct platfor netdev = netdev_from_priv(dev); unregister_netdev(netdev); @@ -313,17 +314,17 @@ Signed-off-by: Christian Marangi airoha_metadata_dst_free(port); --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -591,6 +591,9 @@ struct airoha_gdm_dev { - int nbq; - - struct airoha_hw_stats stats; +@@ -598,6 +598,9 @@ struct airoha_gdm_dev { + * QDMA migration. + */ + spinlock_t txq_lock[AIROHA_NUM_NETDEV_TX_RINGS]; + + struct phylink *phylink; + struct phylink_config phylink_config; }; struct airoha_gdm_port { -@@ -598,8 +601,8 @@ struct airoha_gdm_port { +@@ -605,8 +608,8 @@ struct airoha_gdm_port { int id; int users; diff --git a/target/linux/airoha/patches-6.18/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch b/target/linux/airoha/patches-6.18/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch index 92edd6d3718..5be5e40968d 100644 --- a/target/linux/airoha/patches-6.18/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch +++ b/target/linux/airoha/patches-6.18/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch @@ -25,7 +25,7 @@ Signed-off-by: Lorenzo Bianconi #include "airoha_regs.h" #include "airoha_eth.h" -@@ -331,7 +332,7 @@ static int airoha_ppe_foe_entry_prepare( +@@ -334,7 +335,7 @@ static int airoha_ppe_foe_entry_prepare( struct airoha_foe_entry *hwe, struct net_device *netdev, int type, struct airoha_flow_data *data, @@ -34,7 +34,7 @@ Signed-off-by: Lorenzo Bianconi { u32 qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f), ports_pad, val; int wlan_etype = -EINVAL, dsa_port = airoha_get_dsa_port(&netdev); -@@ -366,7 +367,7 @@ static int airoha_ppe_foe_entry_prepare( +@@ -369,7 +370,7 @@ static int airoha_ppe_foe_entry_prepare( } else { struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port; @@ -43,7 +43,7 @@ Signed-off-by: Lorenzo Bianconi if (!airoha_is_valid_gdm_dev(eth, dev)) return -EINVAL; -@@ -386,11 +387,13 @@ static int airoha_ppe_foe_entry_prepare( +@@ -389,11 +390,13 @@ static int airoha_ppe_foe_entry_prepare( */ channel = dsa_port >= 0 ? dsa_port : port->id; channel = channel % AIROHA_NUM_QOS_CHANNELS; @@ -57,7 +57,7 @@ Signed-off-by: Lorenzo Bianconi AIROHA_FOE_IB2_PSE_QOS; /* For downlink traffic consume SRAM memory for hw * forwarding descriptors queue. -@@ -1081,7 +1084,7 @@ static int airoha_ppe_flow_offload_repla +@@ -1084,7 +1087,7 @@ static int airoha_ppe_flow_offload_repla struct airoha_flow_data data = {}; struct net_device *odev = NULL; struct flow_action_entry *act; @@ -66,7 +66,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_foe_entry hwe; int err, i, offload_type; u16 addr_type = 0; -@@ -1114,6 +1117,13 @@ static int airoha_ppe_flow_offload_repla +@@ -1117,6 +1120,13 @@ static int airoha_ppe_flow_offload_repla return -EOPNOTSUPP; } @@ -80,7 +80,7 @@ Signed-off-by: Lorenzo Bianconi switch (addr_type) { case 0: offload_type = PPE_PKT_TYPE_BRIDGE; -@@ -1179,7 +1189,7 @@ static int airoha_ppe_flow_offload_repla +@@ -1182,7 +1192,7 @@ static int airoha_ppe_flow_offload_repla return -EINVAL; err = airoha_ppe_foe_entry_prepare(eth, &hwe, odev, offload_type, diff --git a/target/linux/airoha/patches-6.18/916-02-net-airoha-Implement-HW-GRO-TCP-support.patch b/target/linux/airoha/patches-6.18/916-02-net-airoha-Implement-HW-GRO-TCP-support.patch index dbdbb7f8d39..04b73b708ce 100644 --- a/target/linux/airoha/patches-6.18/916-02-net-airoha-Implement-HW-GRO-TCP-support.patch +++ b/target/linux/airoha/patches-6.18/916-02-net-airoha-Implement-HW-GRO-TCP-support.patch @@ -72,7 +72,7 @@ Signed-off-by: Lorenzo Bianconi + +static void airoha_dev_lro_enable(struct airoha_gdm_dev *dev) +{ -+ struct airoha_qdma *qdma = dev->qdma; ++ struct airoha_qdma *qdma = airoha_qdma_deref(dev); + struct airoha_eth *eth = qdma->eth; + int qdma_id = qdma - ð->qdma[0]; + int i, lro_queue_index = 0; @@ -365,7 +365,7 @@ Signed-off-by: Lorenzo Bianconi WRITE_ONCE(desc->ctrl, 0); WRITE_ONCE(desc->addr, 0); WRITE_ONCE(desc->data, 0); -@@ -1908,13 +2135,52 @@ static void airoha_dev_set_xmit_frame_si +@@ -1914,13 +2141,56 @@ static void airoha_dev_set_xmit_frame_si VLAN_ETH_HLEN + netdev->mtu)); } @@ -387,8 +387,8 @@ Signed-off-by: Lorenzo Bianconi + + if (!iter_dev || iter_dev == dev) + continue; -+ -+ if (iter_dev->qdma != dev->qdma) ++ if (rcu_access_pointer(iter_dev->qdma) != ++ rcu_access_pointer(dev->qdma)) + continue; + + netdev = netdev_from_priv(iter_dev); @@ -404,11 +404,15 @@ Signed-off-by: Lorenzo Bianconi { struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; - struct airoha_qdma *qdma = dev->qdma; -+ struct airoha_eth *eth = qdma->eth; u32 pse_port = FE_PSE_PORT_PPE1; + struct airoha_qdma *qdma; - int err; -+ int err, qdma_id = qdma - ð->qdma[0]; ++ struct airoha_eth *eth; ++ int err, qdma_id; ++ ++ qdma = airoha_qdma_deref(dev); ++ eth = qdma->eth; ++ qdma_id = qdma - ð->qdma[0]; + + /* HW LRO is shared by all netdevs using the same QDMA. */ + if (qdma->users && airoha_fe_lro_is_enabled(eth, qdma_id)) { @@ -419,8 +423,11 @@ Signed-off-by: Lorenzo Bianconi err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0); if (err) { -@@ -1931,21 +2197,27 @@ static int airoha_dev_open(struct net_de +@@ -1935,24 +2205,29 @@ static int airoha_dev_open(struct net_de + if (err) + return err; +- qdma = airoha_qdma_deref(dev); /* It seems GDM3 and GDM4 needs SPORT enabled to correctly work */ if (netdev_uses_dsa(netdev) || port->id > 2) - airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id), @@ -451,30 +458,26 @@ Signed-off-by: Lorenzo Bianconi return 0; } -@@ -1964,6 +2236,12 @@ static int airoha_dev_stop(struct net_de - airoha_set_gdm_port_fwd_cfg(qdma->eth, +@@ -1960,6 +2235,7 @@ static int airoha_dev_stop(struct net_de + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; ++ struct airoha_qdma *qdma; + + netif_tx_disable(netdev); + airoha_set_vip_for_gdm_port(dev, false); +@@ -1971,6 +2247,10 @@ static int airoha_dev_stop(struct net_de REG_GDM_FWD_CFG(port->id), FE_PSE_PORT_DROP); + ++ qdma = airoha_qdma_deref(dev); + qdma->users--; + airoha_update_netdev_features(dev); + -+ phylink_stop(dev->phylink); -+ phylink_disconnect_phy(dev->phylink); -+ - return 0; - } + phylink_stop(dev->phylink); + phylink_disconnect_phy(dev->phylink); -@@ -2041,9 +2319,6 @@ static int airoha_enable_gdm2_loopback(s - __field_prep(mask, AIROHA_GDM2_IDX)); - } - -- phylink_stop(dev->phylink); -- phylink_disconnect_phy(dev->phylink); -- - return 0; - } - -@@ -2232,6 +2507,36 @@ int airoha_get_fe_port(struct airoha_gdm +@@ -2308,6 +2588,38 @@ int airoha_get_fe_port(struct airoha_gdm } } @@ -482,8 +485,10 @@ Signed-off-by: Lorenzo Bianconi + netdev_features_t features) +{ + struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_qdma *qdma; + -+ if (dev->qdma->users > 1) ++ qdma = airoha_qdma_deref(dev); ++ if (qdma->users > 1) + features &= ~NETIF_F_GRO_HW; + + return features; @@ -494,7 +499,7 @@ Signed-off-by: Lorenzo Bianconi +{ + netdev_features_t diff = netdev->features ^ features; + struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_qdma *qdma = dev->qdma; ++ struct airoha_qdma *qdma = airoha_qdma_deref(dev); + int qdma_id = qdma - &dev->eth->qdma[0]; + + if (!(diff & NETIF_F_GRO_HW)) @@ -511,7 +516,7 @@ Signed-off-by: Lorenzo Bianconi static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, struct net_device *netdev) { -@@ -3205,6 +3510,8 @@ static const struct net_device_ops airoh +@@ -3401,6 +3713,8 @@ static const struct net_device_ops airoh .ndo_stop = airoha_dev_stop, .ndo_change_mtu = airoha_dev_change_mtu, .ndo_select_queue = airoha_dev_select_queue, @@ -520,7 +525,7 @@ Signed-off-by: Lorenzo Bianconi .ndo_start_xmit = airoha_dev_xmit, .ndo_get_stats64 = airoha_dev_get_stats64, .ndo_set_mac_address = airoha_dev_set_macaddr, -@@ -3442,11 +3749,9 @@ static int airoha_alloc_gdm_device(struc +@@ -3638,11 +3952,9 @@ static int airoha_alloc_gdm_device(struc netdev->ethtool_ops = &airoha_ethtool_ops; netdev->max_mtu = AIROHA_MAX_MTU; netdev->watchdog_timeo = 5 * HZ; @@ -565,7 +570,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_irq_bank irq_banks[AIROHA_MAX_NUM_IRQ_BANKS]; -@@ -713,6 +727,18 @@ static inline bool airoha_is_7583(struct +@@ -720,6 +734,18 @@ static inline bool airoha_is_7583(struct return eth->soc->version == 0x7583; } @@ -607,7 +612,7 @@ Signed-off-by: Lorenzo Bianconi #define REG_GDM_FWD_CFG(_n) GDM_BASE(_n) #define GDM_PAD_EN_MASK BIT(28) #define GDM_DROP_CRC_ERR_MASK BIT(23) -@@ -898,9 +912,15 @@ +@@ -899,9 +913,15 @@ #define QDMA_ETH_RXMSG_SPORT_MASK GENMASK(25, 21) #define QDMA_ETH_RXMSG_CRSN_MASK GENMASK(20, 16) #define QDMA_ETH_RXMSG_PPE_ENTRY_MASK GENMASK(15, 0) diff --git a/target/linux/airoha/patches-6.18/920-12-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch b/target/linux/airoha/patches-6.18/920-12-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch index 68560bff8ef..96a89a5bfba 100644 --- a/target/linux/airoha/patches-6.18/920-12-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch +++ b/target/linux/airoha/patches-6.18/920-12-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch @@ -19,35 +19,19 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -538,7 +538,7 @@ static bool airoha_fe_lro_is_enabled(str +@@ -2157,10 +2157,7 @@ static void airoha_update_netdev_feature + struct airoha_gdm_dev *iter_dev = port->devs[j]; + struct net_device *netdev; - static void airoha_dev_lro_enable(struct airoha_gdm_dev *dev) - { -- struct airoha_qdma *qdma = dev->qdma; -+ struct airoha_qdma *qdma = airoha_qdma_deref(dev); - struct airoha_eth *eth = qdma->eth; - int qdma_id = qdma - ð->qdma[0]; - int i, lro_queue_index = 0; -@@ -1164,7 +1164,7 @@ static void airoha_qdma_wake_netdev_txqs - if (!dev) - continue; - -- if (dev->qdma != qdma) -+ if (rcu_access_pointer(dev->qdma) != qdma) - continue; - - netdev = netdev_from_priv(dev); -@@ -2154,7 +2154,8 @@ static void airoha_update_netdev_feature - if (!iter_dev || iter_dev == dev) - continue; - -- if (iter_dev->qdma != dev->qdma) -+ if (rcu_access_pointer(iter_dev->qdma) != -+ rcu_access_pointer(dev->qdma)) +- if (!iter_dev || iter_dev == dev) +- continue; +- if (rcu_access_pointer(iter_dev->qdma) != +- rcu_access_pointer(dev->qdma)) ++ if (!iter_dev) continue; netdev = netdev_from_priv(iter_dev); -@@ -2166,14 +2167,27 @@ static void airoha_update_netdev_feature +@@ -2172,6 +2169,16 @@ static void airoha_update_netdev_feature } } @@ -64,21 +48,7 @@ Signed-off-by: Lorenzo Bianconi static int airoha_dev_open(struct net_device *netdev) { struct airoha_gdm_dev *dev = netdev_priv(netdev); - struct airoha_gdm_port *port = dev->port; -- struct airoha_qdma *qdma = dev->qdma; -- struct airoha_eth *eth = qdma->eth; -+ struct airoha_eth *eth = dev->eth; -+ struct airoha_qdma *qdma; - u32 pse_port = FE_PSE_PORT_PPE1; -- int err, qdma_id = qdma - ð->qdma[0]; -+ int err, qdma_id; -+ -+ qdma = airoha_qdma_deref(dev); -+ qdma_id = qdma - ð->qdma[0]; - - /* HW LRO is shared by all netdevs using the same QDMA. */ - if (qdma->users && airoha_fe_lro_is_enabled(eth, qdma_id)) { -@@ -2205,7 +2219,7 @@ static int airoha_dev_open(struct net_de +@@ -2215,7 +2222,7 @@ static int airoha_dev_open(struct net_de airoha_dev_set_xmit_frame_size(netdev); port->users++; @@ -87,495 +57,55 @@ Signed-off-by: Lorenzo Bianconi if (!airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1)) -@@ -2225,18 +2239,19 @@ static int airoha_dev_stop(struct net_de - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); - struct airoha_gdm_port *port = dev->port; -- struct airoha_qdma *qdma = dev->qdma; -+ struct airoha_qdma *qdma; - - netif_tx_disable(netdev); - airoha_set_vip_for_gdm_port(dev, false); - -+ qdma = airoha_qdma_deref(dev); - if (--port->users) - airoha_ppe_set_xmit_frame_size(dev); - else - airoha_set_gdm_port_fwd_cfg(qdma->eth, - REG_GDM_FWD_CFG(port->id), +@@ -2248,7 +2255,7 @@ static int airoha_dev_stop(struct net_de FE_PSE_PORT_DROP); + + qdma = airoha_qdma_deref(dev); - qdma->users--; + airoha_qdma_user_put(qdma); airoha_update_netdev_features(dev); phylink_stop(dev->phylink); -@@ -2322,6 +2337,53 @@ static int airoha_enable_gdm2_loopback(s - return 0; - } - -+static int airoha_disable_gdm2_loopback(struct airoha_gdm_dev *dev) -+{ -+ struct airoha_gdm_port *port = dev->port; -+ struct airoha_eth *eth = dev->eth; -+ int i, src_port; -+ u32 pse_port; -+ -+ src_port = eth->soc->ops.get_sport(dev->port, dev->nbq); -+ if (src_port < 0) -+ return src_port; -+ -+ airoha_fe_clear(eth, -+ REG_SP_DFT_CPORT(src_port >> fls(SP_CPORT_DFT_MASK)), -+ SP_CPORT_MASK(src_port & SP_CPORT_DFT_MASK)); -+ -+ airoha_fe_set(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), -+ GDM_STRIP_CRC_MASK); -+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), -+ FE_PSE_PORT_DROP); -+ airoha_fe_clear(eth, REG_GDM_LPBK_CFG(AIROHA_GDM2_IDX), -+ LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK); -+ pse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2 -+ : FE_PSE_PORT_PPE1; -+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), -+ pse_port); -+ -+ airoha_fe_rmw(eth, REG_FE_WAN_PORT, WAN0_MASK, -+ FIELD_PREP(WAN0_MASK, AIROHA_GDM2_IDX)); -+ -+ for (i = 0; i < eth->soc->num_ppe; i++) -+ airoha_fe_clear(eth, REG_PPE_DFT_CPORT(i, AIROHA_GDM2_IDX), -+ DFT_CPORT_MASK(AIROHA_GDM2_IDX)); -+ -+ /* Enable VIP and IFC for GDM2 */ -+ airoha_fe_set(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX)); -+ airoha_fe_set(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX)); -+ -+ if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) { -+ u32 mask = FC_ID_OF_SRC_PORT_MASK(dev->nbq); -+ -+ airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, mask, -+ FC_MAP6_DEF_VALUE & mask); -+ } -+ -+ return 0; -+} -+ - static struct airoha_gdm_dev * - airoha_get_wan_gdm_dev(struct airoha_eth *eth) - { -@@ -2348,15 +2410,30 @@ airoha_get_wan_gdm_dev(struct airoha_eth - static void airoha_dev_set_qdma(struct airoha_gdm_dev *dev) - { +@@ -2409,17 +2416,28 @@ static void airoha_dev_set_qdma(struct a struct net_device *netdev = netdev_from_priv(dev); -+ struct airoha_qdma *cur_qdma, *qdma; + struct airoha_qdma *cur_qdma, *qdma; struct airoha_eth *eth = dev->eth; - int ppe_id; ++ bool running = netif_running(netdev); + int i, ppe_id; /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ -- dev->qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; -- netdev->irq = dev->qdma->irq_banks[0].irq; -+ qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; -+ cur_qdma = airoha_qdma_deref(dev); -+ if (netif_running(netdev)) -+ airoha_qdma_user_get(qdma); + qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; + cur_qdma = airoha_qdma_deref(dev); + +- if (cur_qdma) ++ if (cur_qdma) { + netif_tx_stop_all_queues(netdev); ++ if (running && cur_qdma != qdma) { ++ int id = cur_qdma - ð->qdma[0]; + -+ rcu_assign_pointer(dev->qdma, qdma); -+ netdev->irq = qdma->irq_banks[0].irq; ++ if (netdev->features & NETIF_F_GRO_HW) ++ airoha_fe_lro_disable(eth, id); ++ airoha_qdma_user_put(cur_qdma); ++ } ++ } + + rcu_assign_pointer(dev->qdma, qdma); + netdev->irq = qdma->irq_banks[0].irq; ++ if (running && cur_qdma != qdma) ++ airoha_qdma_user_get(qdma); + synchronize_rcu(); ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1); - airoha_ppe_set_cpu_port(dev, ppe_id, airoha_get_fe_port(dev)); +@@ -2438,6 +2456,12 @@ static void airoha_dev_set_qdma(struct a + + if (cur_qdma) + netif_tx_wake_all_queues(netdev); + -+ if (!cur_qdma) -+ return; -+ -+ synchronize_rcu(); -+ netif_tx_wake_all_queues(netdev); -+ -+ if (netif_running(netdev)) -+ airoha_qdma_user_put(cur_qdma); ++ if (cur_qdma != qdma) { ++ airoha_update_netdev_features(dev); ++ if (running && (netdev->features & NETIF_F_GRO_HW)) ++ airoha_dev_lro_enable(dev); ++ } } static int airoha_dev_init(struct net_device *netdev) -@@ -2511,8 +2588,10 @@ static netdev_features_t airoha_dev_fix_ - netdev_features_t features) - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_qdma *qdma; - -- if (dev->qdma->users > 1) -+ qdma = airoha_qdma_deref(dev); -+ if (qdma->users > 1) - features &= ~NETIF_F_GRO_HW; - - return features; -@@ -2523,7 +2602,7 @@ static int airoha_dev_set_features(struc - { - netdev_features_t diff = netdev->features ^ features; - struct airoha_gdm_dev *dev = netdev_priv(netdev); -- struct airoha_qdma *qdma = dev->qdma; -+ struct airoha_qdma *qdma = airoha_qdma_deref(dev); - int qdma_id = qdma - &dev->eth->qdma[0]; - - if (!(diff & NETIF_F_GRO_HW)) -@@ -2541,9 +2620,9 @@ static netdev_tx_t airoha_dev_xmit(struc - struct net_device *netdev) - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); -- struct airoha_qdma *qdma = dev->qdma; - u32 nr_frags, tag, msg0, msg1, len; - struct airoha_queue_entry *e; -+ struct airoha_qdma *qdma; - struct netdev_queue *txq; - struct airoha_queue *q; - LIST_HEAD(tx_list); -@@ -2552,6 +2631,8 @@ static netdev_tx_t airoha_dev_xmit(struc - u16 index; - u8 fport; - -+ rcu_read_lock(); -+ qdma = rcu_dereference(dev->qdma); - qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb)); - tag = airoha_get_dsa_tag(skb, netdev); - -@@ -2601,6 +2682,8 @@ static netdev_tx_t airoha_dev_xmit(struc - netif_tx_stop_queue(txq); - q->txq_stopped = true; - spin_unlock_bh(&q->lock); -+ rcu_read_unlock(); -+ - return NETDEV_TX_BUSY; - } - -@@ -2666,6 +2749,7 @@ static netdev_tx_t airoha_dev_xmit(struc - FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); - - spin_unlock_bh(&q->lock); -+ rcu_read_unlock(); - - return NETDEV_TX_OK; - -@@ -2678,6 +2762,7 @@ error_unlock: - error: - dev_kfree_skb_any(skb); - netdev->stats.tx_dropped++; -+ rcu_read_unlock(); - - return NETDEV_TX_OK; - } -@@ -2775,17 +2860,19 @@ static int airoha_qdma_set_chan_tx_sched - const u16 *weights, u8 n_weights) - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_qdma *qdma; - int i; - -+ qdma = airoha_qdma_deref(dev); - for (i = 0; i < AIROHA_NUM_QOS_QUEUES; i++) -- airoha_qdma_clear(dev->qdma, REG_QUEUE_CLOSE_CFG(channel), -+ airoha_qdma_clear(qdma, REG_QUEUE_CLOSE_CFG(channel), - TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i)); - - for (i = 0; i < n_weights; i++) { - u32 status; - int err; - -- airoha_qdma_wr(dev->qdma, REG_TXWRR_WEIGHT_CFG, -+ airoha_qdma_wr(qdma, REG_TXWRR_WEIGHT_CFG, - TWRR_RW_CMD_MASK | - FIELD_PREP(TWRR_CHAN_IDX_MASK, channel) | - FIELD_PREP(TWRR_QUEUE_IDX_MASK, i) | -@@ -2793,12 +2880,12 @@ static int airoha_qdma_set_chan_tx_sched - err = read_poll_timeout(airoha_qdma_rr, status, - status & TWRR_RW_CMD_DONE, - USEC_PER_MSEC, 10 * USEC_PER_MSEC, -- true, dev->qdma, REG_TXWRR_WEIGHT_CFG); -+ true, qdma, REG_TXWRR_WEIGHT_CFG); - if (err) - return err; - } - -- airoha_qdma_rmw(dev->qdma, REG_CHAN_QOS_MODE(channel >> 3), -+ airoha_qdma_rmw(qdma, REG_CHAN_QOS_MODE(channel >> 3), - CHAN_QOS_MODE_MASK(channel), - __field_prep(CHAN_QOS_MODE_MASK(channel), mode)); - -@@ -2862,7 +2949,7 @@ static int airoha_qdma_get_tx_ets_stats( - struct tc_ets_qopt_offload *opt) - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); -- struct airoha_qdma *qdma = dev->qdma; -+ struct airoha_qdma *qdma = airoha_qdma_deref(dev); - - u64 cpu_tx_packets = airoha_qdma_rr(qdma, REG_CNTR_VAL(channel << 1)); - u64 fwd_tx_packets = airoha_qdma_rr(qdma, -@@ -3147,16 +3234,18 @@ static int airoha_qdma_set_tx_rate_limit - u32 bucket_size) - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_qdma *qdma; - int i, err; - -+ qdma = airoha_qdma_deref(dev); - for (i = 0; i <= TRTCM_PEAK_MODE; i++) { -- err = airoha_qdma_set_trtcm_config(dev->qdma, channel, -+ err = airoha_qdma_set_trtcm_config(qdma, channel, - REG_EGRESS_TRTCM_CFG, i, - !!rate, TRTCM_METER_MODE); - if (err) - return err; - -- err = airoha_qdma_set_trtcm_token_bucket(dev->qdma, channel, -+ err = airoha_qdma_set_trtcm_token_bucket(qdma, channel, - REG_EGRESS_TRTCM_CFG, - i, rate, bucket_size); - if (err) -@@ -3192,11 +3281,12 @@ static int airoha_tc_htb_alloc_leaf_queu - u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; - int err, num_tx_queues = AIROHA_NUM_TX_RING + channel + 1; - struct airoha_gdm_dev *dev = netdev_priv(netdev); -- struct airoha_qdma *qdma = dev->qdma; -+ struct airoha_qdma *qdma; - - /* Here we need to check the requested QDMA channel is not already - * in use by another net_device running on the same QDMA block. - */ -+ qdma = airoha_qdma_deref(dev); - if (test_and_set_bit(channel, qdma->qos_channel_map)) { - NL_SET_ERR_MSG_MOD(opt->extack, - "qdma qos channel already in use"); -@@ -3232,7 +3322,7 @@ static int airoha_qdma_set_rx_meter(stru - u32 rate, u32 bucket_size, - enum trtcm_unit_type unit_type) - { -- struct airoha_qdma *qdma = dev->qdma; -+ struct airoha_qdma *qdma = airoha_qdma_deref(dev); - int i; - - for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { -@@ -3407,10 +3497,11 @@ static void airoha_tc_remove_htb_queue(s - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); - int num_tx_queues = AIROHA_NUM_TX_RING; -- struct airoha_qdma *qdma = dev->qdma; -+ struct airoha_qdma *qdma; - - airoha_qdma_set_tx_rate_limit(netdev, queue, 0, 0); - -+ qdma = airoha_qdma_deref(dev); - clear_bit(queue, qdma->qos_channel_map); - clear_bit(queue, dev->qos_sq_bmap); - -@@ -3436,6 +3527,95 @@ static int airoha_tc_htb_delete_leaf_que - return 0; - } - -+static void airoha_disable_qos_for_gdm34(struct net_device *netdev) -+{ -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; -+ int err; -+ -+ if (port->id != AIROHA_GDM3_IDX && -+ port->id != AIROHA_GDM4_IDX) -+ return; -+ -+ err = airoha_disable_gdm2_loopback(dev); -+ if (err) -+ netdev_warn(netdev, -+ "failed disabling GDM2 loopback: %d\n", err); -+ -+ dev->flags &= ~AIROHA_PRIV_F_WAN; -+ airoha_dev_set_qdma(dev); -+ -+ airoha_set_macaddr(dev, netdev->dev_addr); -+ if (netif_running(netdev)) -+ airoha_set_gdm_port_fwd_cfg(dev->eth, -+ REG_GDM_FWD_CFG(port->id), -+ FE_PSE_PORT_PPE1); -+} -+ -+static int airoha_enable_qos_for_gdm34(struct net_device *netdev, -+ struct netlink_ext_ack *extack) -+{ -+ struct airoha_gdm_dev *wan_dev, *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; -+ struct airoha_eth *eth = dev->eth; -+ int err = -EBUSY; -+ -+ if (port->id != AIROHA_GDM3_IDX && -+ port->id != AIROHA_GDM4_IDX) { -+ /* HW QoS is always supported by GDM1 and GDM2 */ -+ return 0; -+ } -+ -+ if (!airoha_is_lan_gdm_dev(dev)) /* Already enabled */ -+ return 0; -+ -+ mutex_lock(&flow_offload_mutex); -+ -+ wan_dev = airoha_get_wan_gdm_dev(eth); -+ if (wan_dev) { -+ if ((wan_dev->flags & AIROHA_PRIV_F_QOS) || -+ wan_dev->port->id == AIROHA_GDM2_IDX) { -+ NL_SET_ERR_MSG_MOD(extack, -+ "QoS configured for WAN device"); -+ goto error_unlock; -+ } -+ airoha_disable_qos_for_gdm34(netdev_from_priv(wan_dev)); -+ } -+ -+ dev->flags |= AIROHA_PRIV_F_WAN; -+ airoha_dev_set_qdma(dev); -+ err = airoha_enable_gdm2_loopback(dev); -+ if (err) -+ goto error_disable_wan; -+ -+ err = airoha_set_macaddr(dev, netdev->dev_addr); -+ if (err) -+ goto error_disable_loopback; -+ -+ if (netif_running(netdev)) { -+ u32 pse_port; -+ -+ pse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2 -+ : FE_PSE_PORT_PPE1; -+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id), -+ pse_port); -+ } -+ -+ mutex_unlock(&flow_offload_mutex); -+ -+ return 0; -+ -+error_disable_loopback: -+ airoha_disable_gdm2_loopback(dev); -+error_disable_wan: -+ dev->flags &= ~AIROHA_PRIV_F_WAN; -+ airoha_dev_set_qdma(dev); -+error_unlock: -+ mutex_unlock(&flow_offload_mutex); -+ -+ return err; -+} -+ - static int airoha_tc_htb_destroy(struct net_device *netdev) - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); -@@ -3444,6 +3624,8 @@ static int airoha_tc_htb_destroy(struct - for_each_set_bit(q, dev->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS) - airoha_tc_remove_htb_queue(netdev, q); - -+ dev->flags &= ~AIROHA_PRIV_F_QOS; -+ - return 0; - } - -@@ -3463,24 +3645,33 @@ static int airoha_tc_get_htb_get_leaf_qu - return 0; - } - --static int airoha_tc_setup_qdisc_htb(struct net_device *dev, -+static int airoha_tc_setup_qdisc_htb(struct net_device *netdev, - struct tc_htb_qopt_offload *opt) - { - switch (opt->command) { -- case TC_HTB_CREATE: -+ case TC_HTB_CREATE: { -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ int err; -+ -+ err = airoha_enable_qos_for_gdm34(netdev, opt->extack); -+ if (err) -+ return err; -+ -+ dev->flags |= AIROHA_PRIV_F_QOS; - break; -+ } - case TC_HTB_DESTROY: -- return airoha_tc_htb_destroy(dev); -+ return airoha_tc_htb_destroy(netdev); - case TC_HTB_NODE_MODIFY: -- return airoha_tc_htb_modify_queue(dev, opt); -+ return airoha_tc_htb_modify_queue(netdev, opt); - case TC_HTB_LEAF_ALLOC_QUEUE: -- return airoha_tc_htb_alloc_leaf_queue(dev, opt); -+ return airoha_tc_htb_alloc_leaf_queue(netdev, opt); - case TC_HTB_LEAF_DEL: - case TC_HTB_LEAF_DEL_LAST: - case TC_HTB_LEAF_DEL_LAST_FORCE: -- return airoha_tc_htb_delete_leaf_queue(dev, opt); -+ return airoha_tc_htb_delete_leaf_queue(netdev, opt); - case TC_HTB_LEAF_QUERY_QUEUE: -- return airoha_tc_get_htb_get_leaf_queue(dev, opt); -+ return airoha_tc_get_htb_get_leaf_queue(netdev, opt); - default: - return -EOPNOTSUPP; - } ---- a/drivers/net/ethernet/airoha/airoha_regs.h -+++ b/drivers/net/ethernet/airoha/airoha_regs.h -@@ -401,6 +401,7 @@ - - #define REG_SRC_PORT_FC_MAP6 0x2298 - #define FC_ID_OF_SRC_PORT_MASK(_n) GENMASK(4 + ((_n) << 3), ((_n) << 3)) -+#define FC_MAP6_DEF_VALUE 0x1b1a1918 - - #define REG_WAN_MTU0 0x2300 - #define WAN_MTU1_MASK GENMASK(29, 16) ---- a/drivers/net/ethernet/airoha/airoha_eth.h -+++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -589,11 +589,12 @@ struct airoha_qdma { - - enum airoha_priv_flags { - AIROHA_PRIV_F_WAN = BIT(0), -+ AIROHA_PRIV_F_QOS = BIT(1), - }; - - struct airoha_gdm_dev { -+ struct airoha_qdma __rcu *qdma; - struct airoha_gdm_port *port; -- struct airoha_qdma *qdma; - struct airoha_eth *eth; - - DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); -@@ -743,6 +744,16 @@ int airoha_get_fe_port(struct airoha_gdm - bool airoha_is_valid_gdm_dev(struct airoha_eth *eth, - struct airoha_gdm_dev *dev); - -+extern struct mutex flow_offload_mutex; -+ -+static inline struct airoha_qdma * -+airoha_qdma_deref(struct airoha_gdm_dev *dev) -+{ -+ return rcu_dereference_protected(dev->qdma, -+ lockdep_rtnl_is_held() || -+ lockdep_is_held(&flow_offload_mutex)); -+} -+ - void airoha_ppe_set_xmit_frame_size(struct airoha_gdm_dev *dev); - void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport); - bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index); ---- a/drivers/net/ethernet/airoha/airoha_ppe.c -+++ b/drivers/net/ethernet/airoha/airoha_ppe.c -@@ -16,7 +16,10 @@ - #include "airoha_regs.h" - #include "airoha_eth.h" - --static DEFINE_MUTEX(flow_offload_mutex); -+/* Serialize airoha_gdm_dev flags, QDMA pointer and PPE CPU port -+ * configuration. -+ */ -+DEFINE_MUTEX(flow_offload_mutex); - static DEFINE_SPINLOCK(ppe_lock); - - static const struct rhashtable_params airoha_flow_table_params = { -@@ -87,8 +90,8 @@ static u32 airoha_ppe_get_timestamp(stru - - void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport) - { -- struct airoha_qdma *qdma = dev->qdma; -- struct airoha_eth *eth = qdma->eth; -+ struct airoha_qdma *qdma = airoha_qdma_deref(dev); -+ struct airoha_eth *eth = dev->eth; - u8 qdma_id = qdma - ð->qdma[0]; - u32 fe_cpu_port; - diff --git a/target/linux/airoha/patches-6.18/920-13-net-airoha-Rework-MTU-configuration.patch b/target/linux/airoha/patches-6.18/920-13-net-airoha-Rework-MTU-configuration.patch index 9cd234b4b1a..4f2652387ad 100644 --- a/target/linux/airoha/patches-6.18/920-13-net-airoha-Rework-MTU-configuration.patch +++ b/target/linux/airoha/patches-6.18/920-13-net-airoha-Rework-MTU-configuration.patch @@ -16,22 +16,17 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -3544,6 +3544,7 @@ static void airoha_disable_qos_for_gdm34 +@@ -3577,9 +3577,9 @@ static void airoha_disable_qos_for_gdm34 - dev->flags &= ~AIROHA_PRIV_F_WAN; + clear_bit(AIROHA_DEV_F_WAN, &dev->flags); airoha_dev_set_qdma(dev); + airoha_dev_set_xmit_frame_size(netdev); airoha_set_macaddr(dev, netdev->dev_addr); +- airoha_ppe_set_xmit_frame_size(dev); + if (netif_running(netdev)) -@@ -3592,6 +3593,7 @@ static int airoha_enable_qos_for_gdm34(s - if (err) - goto error_disable_loopback; - -+ airoha_dev_set_xmit_frame_size(netdev); - if (netif_running(netdev)) { - u32 pse_port; - + airoha_set_gdm_port_fwd_cfg(dev->eth, --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -105,16 +105,23 @@ void airoha_ppe_set_xmit_frame_size(stru diff --git a/target/linux/airoha/patches-6.18/920-15-net-airoha-fix-wrong-airoha_get_fe_port.patch b/target/linux/airoha/patches-6.18/920-15-net-airoha-fix-wrong-airoha_get_fe_port.patch index 7f496670e6f..e9cb44d35a6 100644 --- a/target/linux/airoha/patches-6.18/920-15-net-airoha-fix-wrong-airoha_get_fe_port.patch +++ b/target/linux/airoha/patches-6.18/920-15-net-airoha-fix-wrong-airoha_get_fe_port.patch @@ -18,7 +18,7 @@ Signed-off-by: Christian Marangi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -2571,17 +2571,9 @@ static u32 airoha_get_dsa_tag(struct sk_ +@@ -2599,17 +2599,9 @@ static u32 airoha_get_dsa_tag(struct sk_ int airoha_get_fe_port(struct airoha_gdm_dev *dev) { struct airoha_gdm_port *port = dev->port;