mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-22 02:24:54 +04:00
airoha: backport LRO offload patch
Backport the upstream Airoha Ethernet LRO implementation for EN7581 and AN7583. Use the eight dedicated hardware LRO queues mapped to RX queues 24-31. Adjust the RX page pool configuration for LRO queues and provide the GSO metadata required to correctly re-segment forwarded aggregated packets. Since LRO is configured per QDMA block, expose NETIF_F_LRO only when a single device uses the QDMA, and update the feature during device registration and runtime QDMA migration. Link: https://patch.msgid.link/20260909-airoha-eth-lro-v7-1-e6317be79067@kernel.org Signed-off-by: Yalei Zang <yalei.zang@airoha.com> Link: https://github.com/openwrt/openwrt/pull/25901 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
1 parent
d4083ed9ee
commit
e1bd479ba8
8 files changed
+287
-333
No files matched your search
+258
-192
@@ -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 <lorenzo@kernel.org>
|
||||
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 <madhur.agrawal@airoha.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Reviewed-by: Simon Horman <horms@kernel.org>
|
||||
Link: https://patch.msgid.link/20260909-airoha-eth-lro-v7-1-e6317be79067@kernel.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
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 <linux/pcs/pcs.h>
|
||||
@@ -10,8 +10,10 @@
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
#include <net/dst_metadata.h>
|
||||
+#include <net/ip6_checksum.h>
|
||||
@@ -24,7 +61,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
#include <uapi/linux/ppp_defs.h>
|
||||
|
||||
#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 <lorenzo@kernel.org>
|
||||
+ 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 <lorenzo@kernel.org>
|
||||
+ 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 <lorenzo@kernel.org>
|
||||
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 <lorenzo@kernel.org>
|
||||
+ 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 <lorenzo@kernel.org>
|
||||
- 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 <lorenzo@kernel.org>
|
||||
.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 <lorenzo@kernel.org>
|
||||
|
||||
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 <lorenzo@kernel.org>
|
||||
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 <lorenzo@kernel.org>
|
||||
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 <lorenzo@kernel.org>
|
||||
|
||||
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 <lorenzo@kernel.org>
|
||||
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 <lorenzo@kernel.org>
|
||||
+ 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 <lorenzo@kernel.org>
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
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 <lorenzo@kernel.org>
|
||||
+
|
||||
+ 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 <lorenzo@kernel.org>
|
||||
+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 <lorenzo@kernel.org>
|
||||
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 <lorenzo@kernel.org>
|
||||
.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 <lorenzo@kernel.org>
|
||||
(_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 <lorenzo@kernel.org>
|
||||
#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 <lorenzo@kernel.org>
|
||||
#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 <lorenzo@kernel.org>
|
||||
+#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)
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
|
||||
--- 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;
|
||||
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
|
||||
--- 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 <ansuelsmth@gmail.com>
|
||||
|
||||
/* 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)
|
||||
|
||||
@@ -15,7 +15,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
|
||||
--- 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 <ansuelsmth@gmail.com>
|
||||
"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[] = {
|
||||
|
||||
@@ -41,8 +41,8 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
+#include <linux/pcs/pcs.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
#include <net/dst_metadata.h>
|
||||
#include <net/page_pool/helpers.h>
|
||||
@@ -1705,7 +1706,7 @@ static void airoha_update_hw_stats(struc
|
||||
#include <net/ip6_checksum.h>
|
||||
@@ -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 <ansuelsmth@gmail.com>
|
||||
|
||||
/* 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 <ansuelsmth@gmail.com>
|
||||
+ 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 <ansuelsmth@gmail.com>
|
||||
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 <ansuelsmth@gmail.com>
|
||||
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 <ansuelsmth@gmail.com>
|
||||
.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 <ansuelsmth@gmail.com>
|
||||
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 <ansuelsmth@gmail.com>
|
||||
}
|
||||
|
||||
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 <ansuelsmth@gmail.com>
|
||||
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 <ansuelsmth@gmail.com>
|
||||
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 <ansuelsmth@gmail.com>
|
||||
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 <ansuelsmth@gmail.com>
|
||||
};
|
||||
|
||||
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 <ansuelsmth@gmail.com>
|
||||
};
|
||||
--- 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)
|
||||
|
||||
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
From e928621a0bbd010b75624c77105ce31f2b8d2faf Mon Sep 17 00:00:00 2001
|
||||
Message-ID: <e928621a0bbd010b75624c77105ce31f2b8d2faf.1779348625.git.lorenzo@kernel.org>
|
||||
In-Reply-To: <e15783f7c987e199ecf80b3d858ed5a86d33c508.1779348625.git.lorenzo@kernel.org>
|
||||
References: <e15783f7c987e199ecf80b3d858ed5a86d33c508.1779348625.git.lorenzo@kernel.org>
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
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 <madhur.agrawal@airoha.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
---
|
||||
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)
|
||||
@@ -16,7 +16,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
|
||||
--- 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);
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
|
||||
--- 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;
|
||||
|
||||
Reference in new issue
Block a user