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/194-v7.2-net-airoha-add-LRO-offload-support.patch similarity index 57% rename from target/linux/airoha/patches-6.18/916-02-net-airoha-Implement-HW-GRO-TCP-support.patch rename to target/linux/airoha/patches-6.18/194-v7.2-net-airoha-add-LRO-offload-support.patch index 04b73b708ce..be55dbca124 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/194-v7.2-net-airoha-add-LRO-offload-support.patch @@ -1,20 +1,57 @@ -From 598e1ddfe85ad0f4778eeadd5d878209dd931280 Mon Sep 17 00:00:00 2001 -Message-ID: <598e1ddfe85ad0f4778eeadd5d878209dd931280.1779112628.git.lorenzo@kernel.org> +From a952507ca094d4e77bea78b462a0482d3c546c9e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi -Date: Thu, 14 May 2026 20:25:19 +0200 -Subject: [PATCH] net: airoha: Implement LRO TCP support +Date: Wed, 9 Sep 2026 21:06:05 +0200 +Subject: [PATCH 48/50] net: airoha: add LRO offload support +Introduce LRO offload support to the airoha_eth driver, leveraging +the EN7581/AN7583 SoC's 8 dedicated LRO hardware queues mapped to RX +queues 24-31. LRO offloading does not support Scatter-Gather (SG) so +it is required to increase the page_pool allocation order to 2 for RX +queues 24-31 (LRO queues). + +Since LRO is configured per-QDMA and shared across all devices using +it, LRO is mutually exclusive with multiple devices bound to the +same QDMA block. NETIF_F_LRO availability is re-evaluated whenever the +QDMA user count changes (device registration and runtime QDMA +migration): airoha_update_netdev_features() drops the feature when the +QDMA has more than one user, while airoha_dev_set_qdma() re-enables LRO +on the destination QDMA after a migration so that a running device +keeps it active on the new QDMA block. + +Set the GSO metadata (gso_type/gso_size/gso_segs) on aggregated packets, +together with CHECKSUM_PARTIAL and the pseudo-header checksum, so that +L3-forwarded traffic is correctly re-segmented by the GSO/TSO path on +the egress device. + +The HW does not report the per-segment MSS (msg3[31:16] only reports +the max aggregated size), so the gso_size of an aggregated packet is +approximated as DIV_ROUND_UP(data_len, agg_count), i.e. the mean +segment size. Since this can never exceed the largest merged segment, +re-segmentation only produces smaller packets, which is safe. +Aggregated skbs are marked SKB_GSO_DODGY so that the stack recomputes +gso_segs from gso_size and does not merge the aggregate into the GRO +engine. + +Performance comparison between sw GRO and LRO has been carried out using +a 10Gbps NIC: +GRO: ~2.7 Gbps +LRO: ~8.2 Gbps + +Tested-by: Madhur Agrawal Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260909-airoha-eth-lro-v7-1-e6317be79067@kernel.org +Signed-off-by: Jakub Kicinski --- - drivers/net/ethernet/airoha/airoha_eth.c | 178 ++++++++++++++++++++-- - drivers/net/ethernet/airoha/airoha_eth.h | 23 +++ - drivers/net/ethernet/airoha/airoha_regs.h | 22 ++- - 3 files changed, 208 insertions(+), 15 deletions(-) + drivers/net/ethernet/airoha/airoha_eth.c | 363 ++++++++++++++++++++-- + drivers/net/ethernet/airoha/airoha_eth.h | 26 ++ + drivers/net/ethernet/airoha/airoha_regs.h | 23 +- + 3 files changed, 390 insertions(+), 22 deletions(-) --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -11,8 +11,10 @@ - #include +@@ -10,8 +10,10 @@ + #include #include #include +#include @@ -24,7 +61,7 @@ Signed-off-by: Lorenzo Bianconi #include #include "airoha_regs.h" -@@ -492,6 +494,73 @@ static void airoha_fe_crsn_qsel_init(str +@@ -491,6 +493,88 @@ static void airoha_fe_crsn_qsel_init(str CDM_CRSN_QSEL_Q1)); } @@ -77,6 +114,9 @@ Signed-off-by: Lorenzo Bianconi + int qdma_id = qdma - ð->qdma[0]; + int i, lro_queue_index = 0; + ++ if (airoha_fe_lro_is_enabled(eth, qdma_id)) ++ return; ++ + for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { + struct airoha_queue *q = &qdma->q_rx[i]; + u32 size; @@ -88,17 +128,29 @@ Signed-off-by: Lorenzo Bianconi + continue; + + size = SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size)); -+ size = min_t(u32, size, CDM_LRO_AGG_SIZE_MASK); ++ size = min_t(u32, size, AIROHA_MAX_RX_SIZE); + airoha_fe_lro_rxq_enable(eth, qdma_id, lro_queue_index, i, + size); + lro_queue_index++; + } +} ++ ++static void airoha_dev_lro_disable(struct airoha_gdm_dev *dev) ++{ ++ struct airoha_qdma *qdma = airoha_qdma_deref(dev); ++ struct airoha_eth *eth = qdma->eth; ++ int qdma_id = qdma - ð->qdma[0]; ++ ++ if (!airoha_fe_lro_is_enabled(eth, qdma_id)) ++ return; ++ ++ airoha_fe_lro_disable(eth, qdma_id); ++} + static int airoha_fe_init(struct airoha_eth *eth) { airoha_fe_maccr_init(eth); -@@ -619,6 +688,7 @@ static int airoha_qdma_fill_rx_queue(str +@@ -616,6 +700,7 @@ static int airoha_qdma_fill_rx_queue(str e->dma_addr = page_pool_get_dma_addr(page) + offset; e->dma_len = SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size)); @@ -106,51 +158,56 @@ Signed-off-by: Lorenzo Bianconi val = FIELD_PREP(QDMA_DESC_LEN_MASK, e->dma_len); WRITE_ONCE(desc->ctrl, cpu_to_le32(val)); WRITE_ONCE(desc->addr, cpu_to_le32(e->dma_addr)); -@@ -660,12 +730,169 @@ airoha_qdma_get_gdm_dev(struct airoha_et +@@ -657,13 +742,146 @@ airoha_qdma_get_gdm_dev(struct airoha_et return port->devs[d] ? port->devs[d] : ERR_PTR(-ENODEV); } -+static struct sk_buff *airoha_qdma_lro_rx_skb(struct airoha_queue *q, -+ struct airoha_qdma_desc *desc, -+ struct airoha_queue_entry *e) ++static int airoha_qdma_lro_rx_skb(struct airoha_queue *q, ++ struct airoha_qdma_desc *desc, ++ u32 msg1, u32 len) +{ -+ u32 len, th_off, tcp_ack_seq, agg_count, data_off, data_len; -+ u32 desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); -+ u32 msg1 = le32_to_cpu(READ_ONCE(desc->msg1)); ++ u32 th_off, tcp_ack_seq, data_off, agg_count = 1; + u32 msg2 = le32_to_cpu(READ_ONCE(desc->msg2)); -+ u32 msg3 = le32_to_cpu(READ_ONCE(desc->msg3)); + struct skb_shared_info *shinfo; ++ struct sk_buff *skb = q->skb; + u16 tcp_win, l2_len; -+ struct sk_buff *skb; + struct tcphdr *th; -+ struct page *page; + bool ipv4, ipv6; + ++ if (airoha_qdma_is_lro_queue(q)) { ++ agg_count = FIELD_GET(QDMA_ETH_RXMSG_AGG_COUNT_MASK, msg2); ++ if (agg_count > AIROHA_RXQ_LRO_MAX_AGG_COUNT) ++ return -EINVAL; ++ } ++ ++ if (likely(agg_count <= 1)) /* not LRO */ ++ return 0; ++ + ipv4 = FIELD_GET(QDMA_ETH_RXMSG_IP4_MASK, msg1); + ipv6 = FIELD_GET(QDMA_ETH_RXMSG_IP6_MASK, msg1); + if (!ipv4 && !ipv6) -+ return NULL; ++ return 0; + + l2_len = FIELD_GET(QDMA_ETH_RXMSG_L2_LEN_MASK, msg2); -+ len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl); + + if (ipv4) { -+ struct iphdr *iph; ++ struct iphdr *iph, _iph; + -+ if (len < l2_len + sizeof(*iph)) -+ return NULL; ++ iph = skb_header_pointer(skb, l2_len, sizeof(*iph), &_iph); ++ if (!iph) ++ return -EINVAL; + -+ iph = (struct iphdr *)(e->buf + l2_len); + if (iph->protocol != IPPROTO_TCP) -+ return NULL; ++ return -EINVAL; + + if (iph->ihl < 5) -+ return NULL; ++ return -EINVAL; + + th_off = l2_len + (iph->ihl << 2); -+ if (len < th_off) -+ return NULL; ++ if (!pskb_may_pull(skb, th_off)) ++ return -EINVAL; + ++ iph = (struct iphdr *)(skb->data + l2_len); + iph->tot_len = cpu_to_be16(len - l2_len); + iph->check = 0; + iph->check = ip_fast_csum((void *)iph, iph->ihl); @@ -158,115 +215,86 @@ Signed-off-by: Lorenzo Bianconi + struct ipv6hdr *ip6h; + + th_off = l2_len + sizeof(*ip6h); -+ if (len < th_off) -+ return NULL; ++ if (!pskb_may_pull(skb, th_off)) ++ return -EINVAL; + -+ ip6h = (struct ipv6hdr *)(e->buf + l2_len); ++ ip6h = (struct ipv6hdr *)(skb->data + l2_len); + if (ip6h->nexthdr != NEXTHDR_TCP) -+ return NULL; ++ return -EINVAL; + + ip6h->payload_len = cpu_to_be16(len - th_off); + } + -+ if (len < th_off + sizeof(*th)) -+ return NULL; ++ data_off = th_off + sizeof(*th); ++ if (len < data_off) ++ return -EINVAL; + -+ th = (struct tcphdr *)(e->buf + th_off); ++ if (!pskb_may_pull(skb, data_off)) ++ return -EINVAL; ++ ++ th = (struct tcphdr *)(skb->data + th_off); + if (th->doff < 5) -+ return NULL; ++ return -EINVAL; + + data_off = th_off + (th->doff << 2); -+ if (len < data_off) -+ return NULL; ++ if (len <= data_off) ++ return -EINVAL; + -+ tcp_win = FIELD_GET(QDMA_ETH_RXMSG_TCP_WIN_MASK, msg3); ++ tcp_win = FIELD_GET(QDMA_ETH_RXMSG_TCP_WIN_MASK, ++ le32_to_cpu(READ_ONCE(desc->msg3))); + tcp_ack_seq = le32_to_cpu(READ_ONCE(desc->data)); + th->ack_seq = cpu_to_be32(tcp_ack_seq); + th->window = cpu_to_be16(tcp_win); + + /* Check tcp timestamp option */ + if (th->doff == (sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4) { -+ u32 topt = get_unaligned_be32(th + 1); ++ u32 topt; + ++ if (!pskb_may_pull(skb, data_off)) ++ return -EINVAL; ++ ++ th = (struct tcphdr *)(skb->data + th_off); ++ topt = get_unaligned_be32(th + 1); + if (topt == ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { + u8 *ptr = (u8 *)th + sizeof(*th) + 2 * sizeof(__be32); + __le32 tcp_ts_reply = READ_ONCE(desc->tcp_ts_reply); + -+ put_unaligned_be32(le32_to_cpu(tcp_ts_reply), ptr); ++ /* The field is pre-zeroed in the posted descriptor, ++ * so a non-zero value is the hardware confirming the ++ * timestamp echo reply is valid. Leave TSecr ++ * untouched otherwise, since the hardware may not ++ * populate it for every aggregate. ++ */ ++ if (tcp_ts_reply) ++ put_unaligned_be32(le32_to_cpu(tcp_ts_reply), ++ ptr); + } + } + + if (ipv4) { -+ struct iphdr *iph = (struct iphdr *)(e->buf + l2_len); ++ struct iphdr *iph = (struct iphdr *)(skb->data + l2_len); + + th->check = ~tcp_v4_check(len - th_off, iph->saddr, + iph->daddr, 0); + } else { -+ struct ipv6hdr *ip6h = (struct ipv6hdr *)(e->buf + l2_len); ++ struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + l2_len); + + th->check = ~tcp_v6_check(len - th_off, &ip6h->saddr, + &ip6h->daddr, 0); + } + -+ skb = napi_alloc_skb(&q->napi, data_off); -+ if (!skb) -+ return NULL; -+ -+ __skb_put(skb, data_off); -+ memcpy(skb->data, e->buf, data_off); -+ -+ page = virt_to_head_page(e->buf); -+ data_len = len - data_off; + shinfo = skb_shinfo(skb); -+ skb_add_rx_frag(skb, shinfo->nr_frags, page, -+ e->buf + data_off - page_address(page), data_len, -+ q->buf_size); -+ + shinfo->gso_type = ipv4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6; -+ agg_count = FIELD_GET(QDMA_ETH_RXMSG_AGG_COUNT_MASK, msg2); -+ shinfo->gso_size = DIV_ROUND_UP(data_len, agg_count); ++ shinfo->gso_type |= SKB_GSO_DODGY; ++ shinfo->gso_size = DIV_ROUND_UP(len - data_off, agg_count); + shinfo->gso_segs = agg_count; + + skb->csum_start = skb_headroom(skb) + th_off; + skb->csum_offset = offsetof(struct tcphdr, check); + skb->ip_summed = CHECKSUM_PARTIAL; + -+ return skb; -+} -+ -+static struct sk_buff *airoha_qdma_build_rx_skb(struct airoha_queue *q, -+ struct airoha_qdma_desc *desc, -+ struct airoha_queue_entry *e, -+ struct net_device *netdev) -+{ -+ u32 msg2 = le32_to_cpu(READ_ONCE(desc->msg2)); -+ int qid = q - &q->qdma->q_rx[0]; -+ struct sk_buff *skb; -+ -+ if (FIELD_GET(QDMA_ETH_RXMSG_AGG_COUNT_MASK, msg2) > 1) { /* LRO */ -+ skb = airoha_qdma_lro_rx_skb(q, desc, e); -+ if (!skb) -+ return NULL; -+ } else { -+ u32 desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); -+ u32 len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl); -+ -+ skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM, q->buf_size); -+ if (!skb) -+ return NULL; -+ -+ skb_reserve(skb, AIROHA_RX_HEADROOM); -+ __skb_put(skb, len); -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ } -+ -+ skb_mark_for_recycle(skb); -+ skb->dev = netdev; -+ skb_record_rx_queue(skb, qid); -+ skb->protocol = eth_type_trans(skb, netdev); -+ -+ return skb; ++ return 0; +} + static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) @@ -275,31 +303,50 @@ Signed-off-by: Lorenzo Bianconi - struct airoha_qdma *qdma = q->qdma; - struct airoha_eth *eth = qdma->eth; - int qid = q - &qdma->q_rx[0]; +- int done = 0; ++ int qid = q - &q->qdma->q_rx[0], done = 0; + struct airoha_eth *eth = q->qdma->eth; - int done = 0; while (done < budget) { -@@ -701,18 +928,9 @@ static int airoha_qdma_rx_process(struct + struct airoha_queue_entry *e = &q->entry[q->tail]; +@@ -696,7 +914,9 @@ static int airoha_qdma_rx_process(struct + if (IS_ERR(dev)) + goto free_frag; ++ msg1 = le32_to_cpu(READ_ONCE(desc->msg1)); netdev = netdev_from_priv(dev); ++ if (!q->skb) { /* first buffer */ -- q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM, -- q->buf_size); -+ q->skb = airoha_qdma_build_rx_skb(q, desc, e, netdev); - if (!q->skb) - goto free_frag; -- -- skb_reserve(q->skb, AIROHA_RX_HEADROOM); -- __skb_put(q->skb, len); -- skb_mark_for_recycle(q->skb); -- q->skb->dev = netdev; + q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM, + q->buf_size); +@@ -707,9 +927,17 @@ static int airoha_qdma_rx_process(struct + __skb_put(q->skb, len); + skb_mark_for_recycle(q->skb); + q->skb->dev = netdev; - q->skb->protocol = eth_type_trans(q->skb, netdev); -- q->skb->ip_summed = CHECKSUM_UNNECESSARY; -- skb_record_rx_queue(q->skb, qid); + q->skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_record_rx_queue(q->skb, qid); ++ ++ if (airoha_qdma_lro_rx_skb(q, desc, msg1, len)) { ++ dev_core_stats_rx_dropped_inc(netdev); ++ dev_kfree_skb(q->skb); ++ q->skb = NULL; ++ continue; ++ } ++ ++ q->skb->protocol = eth_type_trans(q->skb, netdev); } else { /* scattered frame */ struct skb_shared_info *shinfo = skb_shinfo(q->skb); int nr_frags = shinfo->nr_frags; -@@ -803,12 +1021,10 @@ static int airoha_qdma_rx_napi_poll(stru +@@ -742,7 +970,6 @@ static int airoha_qdma_rx_process(struct + &port->dsa_meta[sptag]->dst); + } + +- msg1 = le32_to_cpu(READ_ONCE(desc->msg1)); + hash = FIELD_GET(AIROHA_RXD4_FOE_ENTRY, msg1); + if (hash != AIROHA_RXD4_FOE_ENTRY) + skb_set_hash(q->skb, jhash_1word(hash, 0), +@@ -800,12 +1027,10 @@ static int airoha_qdma_rx_napi_poll(stru static int airoha_qdma_init_rx_queue(struct airoha_queue *q, struct airoha_qdma *qdma, int ndesc) { @@ -313,7 +360,7 @@ Signed-off-by: Lorenzo Bianconi .nid = NUMA_NO_NODE, .dev = qdma->eth->dev, .napi = &q->napi, -@@ -816,9 +1032,10 @@ static int airoha_qdma_init_rx_queue(str +@@ -813,9 +1038,10 @@ static int airoha_qdma_init_rx_queue(str struct airoha_eth *eth = qdma->eth; int qid = q - &qdma->q_rx[0], thr; dma_addr_t dma_addr; @@ -325,7 +372,7 @@ Signed-off-by: Lorenzo Bianconi q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry), GFP_KERNEL); -@@ -830,6 +1047,9 @@ static int airoha_qdma_init_rx_queue(str +@@ -827,6 +1053,9 @@ static int airoha_qdma_init_rx_queue(str if (!q->desc) return -ENOMEM; @@ -335,7 +382,7 @@ Signed-off-by: Lorenzo Bianconi q->page_pool = page_pool_create(&pp_params); if (IS_ERR(q->page_pool)) { int err = PTR_ERR(q->page_pool); -@@ -838,6 +1058,7 @@ static int airoha_qdma_init_rx_queue(str +@@ -835,6 +1064,7 @@ static int airoha_qdma_init_rx_queue(str return err; } @@ -343,7 +390,7 @@ Signed-off-by: Lorenzo Bianconi q->ndesc = ndesc; netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll); -@@ -851,7 +1072,12 @@ static int airoha_qdma_init_rx_queue(str +@@ -848,7 +1078,12 @@ static int airoha_qdma_init_rx_queue(str FIELD_PREP(RX_RING_THR_MASK, thr)); airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head)); @@ -357,7 +404,7 @@ Signed-off-by: Lorenzo Bianconi airoha_qdma_fill_rx_queue(q); -@@ -873,6 +1099,7 @@ static void airoha_qdma_cleanup_rx_queue +@@ -870,6 +1105,7 @@ static void airoha_qdma_cleanup_rx_queue page_pool_get_dma_dir(q->page_pool)); page_pool_put_full_page(q->page_pool, page, false); /* Reset DMA descriptor */ @@ -365,8 +412,8 @@ Signed-off-by: Lorenzo Bianconi WRITE_ONCE(desc->ctrl, 0); WRITE_ONCE(desc->addr, 0); WRITE_ONCE(desc->data, 0); -@@ -1914,13 +2141,56 @@ static void airoha_dev_set_xmit_frame_si - VLAN_ETH_HLEN + netdev->mtu)); +@@ -1896,6 +2132,34 @@ static void airoha_update_hw_stats(struc + spin_unlock(&port->stats_lock); } +static void airoha_update_netdev_features(struct airoha_gdm_dev *dev) @@ -385,10 +432,7 @@ Signed-off-by: Lorenzo Bianconi + struct airoha_gdm_dev *iter_dev = port->devs[j]; + struct net_device *netdev; + -+ 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); @@ -400,84 +444,94 @@ Signed-off-by: Lorenzo Bianconi + } +} + - static int airoha_dev_open(struct net_device *netdev) + static void airoha_dev_set_xmit_frame_size(struct net_device *netdev) { struct airoha_gdm_dev *dev = netdev_priv(netdev); +@@ -1913,14 +2177,28 @@ static int airoha_dev_open(struct net_de struct airoha_gdm_port *port = dev->port; u32 pse_port = FE_PSE_PORT_PPE1; struct airoha_qdma *qdma; - int err; -+ struct airoha_eth *eth; -+ int err, qdma_id; ++ int qdma_id, err; + ++ /* LRO is configured on the QDMA and it is shared between all ++ * the devices using it. Refuse to open a second device on the ++ * same QDMA if LRO is enabled on any device sharing it or if ++ * this device has LRO enabled in its feature set. ++ */ + qdma = airoha_qdma_deref(dev); -+ eth = qdma->eth; -+ qdma_id = qdma - ð->qdma[0]; ++ qdma_id = qdma - &qdma->eth->qdma[0]; + -+ /* HW LRO is shared by all netdevs using the same QDMA. */ -+ if (qdma->users && airoha_fe_lro_is_enabled(eth, qdma_id)) { -+ netdev_warn(netdev, "required to disable HW GRO on QDMA%d\n", ++ if (qdma->users > 1 && (airoha_fe_lro_is_enabled(qdma->eth, qdma_id) || ++ (netdev->features & NETIF_F_LRO))) { ++ netdev_warn(netdev, "required to disable LRO on QDMA%d\n", + qdma_id); + return -EBUSY; + } - err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0); - if (err) { -@@ -1935,24 +2205,29 @@ static int airoha_dev_open(struct net_de + netif_tx_start_all_queues(netdev); + err = airoha_set_vip_for_gdm_port(dev, true); 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), -+ airoha_fe_set(eth, REG_GDM_INGRESS_CFG(port->id), + if (netdev_uses_dsa(netdev)) + airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id), GDM_STAG_EN_MASK); - else -- airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id), -+ airoha_fe_clear(eth, REG_GDM_INGRESS_CFG(port->id), - GDM_STAG_EN_MASK); - - airoha_dev_set_xmit_frame_size(netdev); - port->users++; -+ qdma->users++; - - if (!airoha_is_lan_gdm_dev(dev) && -- airoha_ppe_is_enabled(qdma->eth, 1)) -+ airoha_ppe_is_enabled(eth, 1)) - pse_port = FE_PSE_PORT_PPE2; -- airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), -+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id), +@@ -1937,6 +2215,9 @@ static int airoha_dev_open(struct net_de + airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), pse_port); -+ if (netdev->features & NETIF_F_GRO_HW) ++ if (netdev->features & NETIF_F_LRO) + airoha_dev_lro_enable(dev); -+ -+ airoha_update_netdev_features(dev); + return 0; } -@@ -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 +@@ -1954,6 +2235,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); - -+ qdma = airoha_qdma_deref(dev); -+ qdma->users--; -+ airoha_update_netdev_features(dev); + - phylink_stop(dev->phylink); - phylink_disconnect_phy(dev->phylink); ++ if (netdev->features & NETIF_F_LRO) ++ airoha_dev_lro_disable(dev); ++ + return 0; + } -@@ -2308,6 +2588,38 @@ int airoha_get_fe_port(struct airoha_gdm +@@ -2115,11 +2400,14 @@ static void airoha_dev_set_qdma(struct a + 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); ++ airoha_dev_lro_disable(dev); ++ } + + rcu_assign_pointer(dev->qdma, qdma); + netdev->irq = qdma->irq_banks[0].irq; ++ qdma->users++; + synchronize_rcu(); + + ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1); +@@ -2136,8 +2424,14 @@ static void airoha_dev_set_qdma(struct a + airoha_qdma_rr(qdma, REG_CNTR_VAL((i << 1) + 1)); + } + +- if (cur_qdma) ++ if (cur_qdma) { ++ cur_qdma->users--; + netif_tx_wake_all_queues(netdev); ++ } ++ ++ airoha_update_netdev_features(dev); ++ if (netdev->features & NETIF_F_LRO) ++ airoha_dev_lro_enable(dev); + } + + static int airoha_dev_init(struct net_device *netdev) +@@ -2288,6 +2582,32 @@ int airoha_get_fe_port(struct airoha_gdm } } @@ -489,7 +543,7 @@ Signed-off-by: Lorenzo Bianconi + + qdma = airoha_qdma_deref(dev); + if (qdma->users > 1) -+ features &= ~NETIF_F_GRO_HW; ++ features &= ~NETIF_F_LRO; + + return features; +} @@ -497,18 +551,12 @@ Signed-off-by: Lorenzo Bianconi +static int airoha_dev_set_features(struct net_device *netdev, + netdev_features_t features) +{ -+ netdev_features_t diff = netdev->features ^ features; + struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_qdma *qdma = airoha_qdma_deref(dev); -+ int qdma_id = qdma - &dev->eth->qdma[0]; + -+ if (!(diff & NETIF_F_GRO_HW)) -+ return 0; -+ -+ if (features & NETIF_F_GRO_HW) ++ if (features & NETIF_F_LRO) + airoha_dev_lro_enable(dev); + else -+ airoha_fe_lro_disable(dev->eth, qdma_id); ++ airoha_dev_lro_disable(dev); + + return 0; +} @@ -516,7 +564,24 @@ Signed-off-by: Lorenzo Bianconi static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, struct net_device *netdev) { -@@ -3401,6 +3713,8 @@ static const struct net_device_ops airoh +@@ -3219,7 +3539,7 @@ static int airoha_enable_qos_for_gdm34(s + 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; ++ int err; + + if (port->id != AIROHA_GDM3_IDX && + port->id != AIROHA_GDM4_IDX) { +@@ -3238,6 +3558,7 @@ static int airoha_enable_qos_for_gdm34(s + wan_dev->port->id == AIROHA_GDM2_IDX) { + NL_SET_ERR_MSG_MOD(extack, + "QoS configured for WAN device"); ++ err = -EBUSY; + goto error_unlock; + } + airoha_disable_qos_for_gdm34(netdev_from_priv(wan_dev)); +@@ -3363,6 +3684,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, @@ -525,7 +590,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, -@@ -3638,11 +3952,9 @@ static int airoha_alloc_gdm_device(struc +@@ -3450,11 +3773,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; @@ -546,9 +611,9 @@ Signed-off-by: Lorenzo Bianconi (_n) == 15 ? 128 : \ (_n) == 0 ? 1024 : 32) -+#define AIROHA_LRO_PAGE_ORDER order_base_2(SZ_16K / PAGE_SIZE) ++#define AIROHA_LRO_PAGE_ORDER get_order(SZ_16K) +#define AIROHA_MAX_NUM_LRO_QUEUES 8 -+#define AIROHA_RXQ_LRO_EN_MASK GENMASK(7, 0) ++#define AIROHA_RXQ_LRO_EN_MASK GENMASK(31, 24) +#define AIROHA_RXQ_LRO_MAX_AGG_COUNT 64 +#define AIROHA_RXQ_LRO_MAX_AGG_TIME 100 +#define AIROHA_RXQ_LRO_MAX_AGE_TIME 2000 @@ -561,16 +626,16 @@ Signed-off-by: Lorenzo Bianconi #define PSE_RSV_PAGES 128 #define PSE_QUEUE_RSV_PAGES 64 -@@ -562,6 +574,8 @@ struct airoha_irq_bank { - struct airoha_qdma { +@@ -563,6 +575,8 @@ struct airoha_qdma { struct airoha_eth *eth; void __iomem *regs; -+ /* Number of running netdevs; DMA lifetime is managed at probe/remove. */ -+ int users; ++ int users; ++ struct airoha_irq_bank irq_banks[AIROHA_MAX_NUM_IRQ_BANKS]; -@@ -720,6 +734,18 @@ static inline bool airoha_is_7583(struct + struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ]; +@@ -717,6 +731,18 @@ static inline bool airoha_is_7583(struct return eth->soc->version == 0x7583; } @@ -612,7 +677,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) -@@ -899,9 +913,15 @@ +@@ -887,9 +901,16 @@ #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) @@ -620,6 +685,7 @@ Signed-off-by: Lorenzo Bianconi +#define QDMA_ETH_RXMSG_AGG_COUNT_MASK GENMASK(31, 24) +#define QDMA_ETH_RXMSG_L2_LEN_MASK GENMASK(6, 0) +/* RX MSG3 */ ++/* max aggregated size in bytes */ +#define QDMA_ETH_RXMSG_AGG_LEN_MASK GENMASK(31, 16) +#define QDMA_ETH_RXMSG_TCP_WIN_MASK GENMASK(15, 0) 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 e3c362cd969..10eb450dda5 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 -@@ -1623,6 +1623,10 @@ static int airoha_hw_init(struct platfor +@@ -1859,6 +1859,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 bc836f6f725..4dcb6eebeb9 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 @@ -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 -@@ -558,8 +558,10 @@ static int airoha_fe_init(struct airoha_ +@@ -642,8 +642,10 @@ static int airoha_fe_init(struct airoha_ FIELD_PREP(IP_ASSEMBLE_PORT_MASK, 0) | FIELD_PREP(IP_ASSEMBLE_NBQ_MASK, 22)); @@ -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), -@@ -1925,7 +1927,8 @@ static int airoha_dev_open(struct net_de +@@ -2203,7 +2205,8 @@ static int airoha_dev_open(struct net_de + if (err) 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 e1546bf14df..9a74ab5b657 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 -@@ -3782,7 +3782,6 @@ static void airoha_remove(struct platfor +@@ -4103,7 +4103,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", -@@ -3869,7 +3868,6 @@ static int airoha_en7581_get_dev_from_sp +@@ -4190,7 +4189,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 96bb580558b..a595e692f72 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 @@ -41,8 +41,8 @@ Signed-off-by: Christian Marangi +#include #include #include - #include -@@ -1705,7 +1706,7 @@ static void airoha_update_hw_stats(struc + #include +@@ -1941,7 +1942,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) -@@ -1899,7 +1900,7 @@ static void airoha_update_hw_stats(struc +@@ -2135,7 +2136,7 @@ static void airoha_update_hw_stats(struc u64_stats_update_end(&dev->stats.syncp); @@ -59,10 +59,10 @@ Signed-off-by: Christian Marangi + spin_unlock(&port->lock); } - static void airoha_dev_set_xmit_frame_size(struct net_device *netdev) -@@ -1921,6 +1922,14 @@ static int airoha_dev_open(struct net_de - struct airoha_qdma *qdma; - int err; + static void airoha_update_netdev_features(struct airoha_gdm_dev *dev) +@@ -2200,6 +2201,14 @@ static int airoha_dev_open(struct net_de + return -EBUSY; + } + err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0); + if (err) { @@ -75,18 +75,17 @@ Signed-off-by: Christian Marangi netif_tx_start_all_queues(netdev); err = airoha_set_vip_for_gdm_port(dev, true); if (err) -@@ -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); -+ +@@ -2246,6 +2255,9 @@ static int airoha_dev_stop(struct net_de + if (netdev->features & NETIF_F_LRO) + airoha_dev_lro_disable(dev); + + phylink_stop(dev->phylink); + phylink_disconnect_phy(dev->phylink); + return 0; } -@@ -2516,6 +2529,24 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2836,6 +2848,24 @@ airoha_ethtool_get_rmon_stats(struct net } while (u64_stats_fetch_retry(&dev->stats.syncp, start)); } @@ -111,7 +110,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) -@@ -3380,7 +3411,8 @@ static const struct ethtool_ops airoha_e +@@ -3703,7 +3733,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, @@ -121,7 +120,7 @@ Signed-off-by: Christian Marangi .get_link = ethtool_op_get_link, }; -@@ -3436,6 +3468,155 @@ bool airoha_is_valid_gdm_dev(struct airo +@@ -3759,6 +3790,155 @@ bool airoha_is_valid_gdm_dev(struct airo return false; } @@ -277,7 +276,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) -@@ -3501,7 +3682,7 @@ static int airoha_alloc_gdm_device(struc +@@ -3822,7 +4002,7 @@ static int airoha_alloc_gdm_device(struc dev->nbq = nbq; port->devs[index] = dev; @@ -286,7 +285,7 @@ Signed-off-by: Christian Marangi } static int airoha_alloc_gdm_port(struct airoha_eth *eth, -@@ -3536,7 +3717,7 @@ static int airoha_alloc_gdm_port(struct +@@ -3857,7 +4037,7 @@ static int airoha_alloc_gdm_port(struct return -ENOMEM; port->id = id; @@ -295,7 +294,7 @@ Signed-off-by: Christian Marangi eth->ports[p] = port; err = airoha_metadata_dst_alloc(port); -@@ -3733,6 +3914,8 @@ error_napi_stop: +@@ -4054,6 +4234,8 @@ error_napi_stop: netdev = netdev_from_priv(dev); if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); @@ -304,7 +303,7 @@ Signed-off-by: Christian Marangi of_node_put(netdev->dev.of_node); } airoha_metadata_dst_free(port); -@@ -3771,6 +3954,7 @@ static void airoha_remove(struct platfor +@@ -4092,6 +4274,7 @@ static void airoha_remove(struct platfor netdev = netdev_from_priv(dev); unregister_netdev(netdev); @@ -314,7 +313,7 @@ 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 -@@ -598,6 +598,9 @@ struct airoha_gdm_dev { +@@ -612,6 +612,9 @@ struct airoha_gdm_dev { * QDMA migration. */ spinlock_t txq_lock[AIROHA_NUM_NETDEV_TX_RINGS]; @@ -324,7 +323,7 @@ Signed-off-by: Christian Marangi }; struct airoha_gdm_port { -@@ -605,8 +608,8 @@ struct airoha_gdm_port { +@@ -619,8 +622,8 @@ struct airoha_gdm_port { int id; int users; @@ -337,7 +336,7 @@ Signed-off-by: Christian Marangi }; --- a/drivers/net/ethernet/airoha/airoha_regs.h +++ b/drivers/net/ethernet/airoha/airoha_regs.h -@@ -357,6 +357,18 @@ +@@ -371,6 +371,18 @@ #define IP_FRAGMENT_PORT_MASK GENMASK(8, 5) #define IP_FRAGMENT_NBQ_MASK GENMASK(4, 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 deleted file mode 100644 index 96a89a5bfba..00000000000 --- a/target/linux/airoha/patches-6.18/920-12-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch +++ /dev/null @@ -1,111 +0,0 @@ -From e928621a0bbd010b75624c77105ce31f2b8d2faf Mon Sep 17 00:00:00 2001 -Message-ID: -In-Reply-To: -References: -From: Lorenzo Bianconi -Date: Sat, 13 Dec 2025 09:45:09 +0100 -Subject: [PATCH 12/13] net: airoha: Add ethtool priv_flags callbacks - -Introduce ethtool priv_flags callbacks in order to allow the user to -select if the configured device will be used as hw lan or wan and enable -or disable gdm2 loopback (used for hw QoS). - -Tested-by: Madhur Agrawal -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/airoha/airoha_eth.c | 173 ++++++++++++++++++++++ - drivers/net/ethernet/airoha/airoha_regs.h | 1 + - 2 files changed, 174 insertions(+) - ---- a/drivers/net/ethernet/airoha/airoha_eth.c -+++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -2157,10 +2157,7 @@ static void airoha_update_netdev_feature - struct airoha_gdm_dev *iter_dev = port->devs[j]; - struct net_device *netdev; - -- 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); -@@ -2172,6 +2169,16 @@ static void airoha_update_netdev_feature - } - } - -+static void airoha_qdma_user_get(struct airoha_qdma *qdma) -+{ -+ qdma->users++; -+} -+ -+static void airoha_qdma_user_put(struct airoha_qdma *qdma) -+{ -+ qdma->users--; -+} -+ - static int airoha_dev_open(struct net_device *netdev) - { - struct airoha_gdm_dev *dev = netdev_priv(netdev); -@@ -2215,7 +2222,7 @@ static int airoha_dev_open(struct net_de - - airoha_dev_set_xmit_frame_size(netdev); - port->users++; -- qdma->users++; -+ airoha_qdma_user_get(qdma); - - if (!airoha_is_lan_gdm_dev(dev) && - airoha_ppe_is_enabled(eth, 1)) -@@ -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); -@@ -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_eth *eth = dev->eth; -+ bool running = netif_running(netdev); - int i, ppe_id; - - /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ - 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]; -+ -+ 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); -@@ -2438,6 +2456,12 @@ static void airoha_dev_set_qdma(struct a - - if (cur_qdma) - netif_tx_wake_all_queues(netdev); -+ -+ 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) 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 4f2652387ad..859214a78ea 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,7 +16,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -3577,9 +3577,9 @@ static void airoha_disable_qos_for_gdm34 +@@ -3560,9 +3560,9 @@ static void airoha_disable_qos_for_gdm34 clear_bit(AIROHA_DEV_F_WAN, &dev->flags); airoha_dev_set_qdma(dev); 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 e9cb44d35a6..c6e8e9083f5 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 -@@ -2599,17 +2599,9 @@ static u32 airoha_get_dsa_tag(struct sk_ +@@ -2588,17 +2588,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;