From 2c122bdd74d4b8f0f1ea8f3dc8f95cf7d17af947 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Jun 2026 11:47:18 +0200 Subject: [PATCH] airoha: introduce HW-GRO support - Introduce HW-GRO support in order to allow bridging HW-GRO interfaces - Enable LRO for queues (7-0) - Rework LAN/WAN dynamic switching according to upstream requests: now in order to set GDM3/GDM4 as WAN it is necessary to enable Qdisc offloading without any dedicated ethool command. Signed-off-by: Lorenzo Bianconi Link: https://github.com/openwrt/openwrt/pull/23828 Signed-off-by: Christian Marangi --- ...nt-instead-of-atomic_t-for-qdma-user.patch | 49 ++ ...-airoha-Implement-HW-GRO-TCP-support.patch | 622 ++++++++++++++++ ...net-airoha-Implement-LRO-TCP-support.patch | 392 ---------- ...roha-Introduce-airoha_gdm_dev-struct.patch | 280 +++++--- ...airoha_qdma-pointer-in-airoha_gdm_de.patch | 126 ++-- ...on-airoha_gdm_dev-pointer-in-airoha_.patch | 8 +- ...qos_sq_bmap-in-airoha_gdm_dev-struct.patch | 31 +- ...cpu-fwd-_tx_packets-in-airoha_gdm_de.patch | 6 +- ...rt-multiple-net_devices-for-a-single.patch | 253 +++---- ...Do-not-stop-GDM-port-if-it-is-shared.patch | 37 +- ...net-airoha-Introduce-WAN-device-flag.patch | 17 +- ...rt-multiple-LAN-WAN-interfaces-for-h.patch | 18 +- ...e-airoha_set_gdm2_loopback-in-airoha.patch | 4 +- ...oha-Add-ethtool-priv_flags-callbacks.patch | 246 ------- ...-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch | 668 ++++++++++++++++++ ...-net-airoha-Rework-MTU-configuration.patch | 84 ++- ...r-handle-MIB-for-GDM-with-multiple-p.patch | 24 +- ...-airoha-fix-wrong-airoha_get_fe_port.patch | 4 +- ...get_sport-callback-at-the-beginning-.patch | 36 + ...ify-WAN-device-check-in-airoha_dev_i.patch | 42 ++ 20 files changed, 1901 insertions(+), 1046 deletions(-) create mode 100644 target/linux/airoha/patches-6.18/916-01-net-airoha-use-int-instead-of-atomic_t-for-qdma-user.patch create mode 100644 target/linux/airoha/patches-6.18/916-02-net-airoha-Implement-HW-GRO-TCP-support.patch delete mode 100644 target/linux/airoha/patches-6.18/916-net-airoha-Implement-LRO-TCP-support.patch delete mode 100644 target/linux/airoha/patches-6.18/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch create mode 100644 target/linux/airoha/patches-6.18/920-12-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch create mode 100644 target/linux/airoha/patches-6.18/921-net-airoha-move-get_sport-callback-at-the-beginning-.patch create mode 100644 target/linux/airoha/patches-6.18/922-net-airoha-simplify-WAN-device-check-in-airoha_dev_i.patch diff --git a/target/linux/airoha/patches-6.18/916-01-net-airoha-use-int-instead-of-atomic_t-for-qdma-user.patch b/target/linux/airoha/patches-6.18/916-01-net-airoha-use-int-instead-of-atomic_t-for-qdma-user.patch new file mode 100644 index 00000000000..5d4ecf66069 --- /dev/null +++ b/target/linux/airoha/patches-6.18/916-01-net-airoha-use-int-instead-of-atomic_t-for-qdma-user.patch @@ -0,0 +1,49 @@ +From a459b560e58be327689e9bd8c0a6be9a4f163366 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Lorenzo Bianconi +Date: Thu, 11 Jun 2026 23:55:51 +0200 +Subject: [PATCH] net: airoha: use int instead of atomic_t for qdma users + counter + +QDMA users counter is always accessed holding RTNL lock so we do not +require atomic_t for it. + +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/airoha/airoha_eth.c | 4 ++-- + drivers/net/ethernet/airoha/airoha_eth.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1761,7 +1761,7 @@ static int airoha_dev_open(struct net_de + airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, + GLOBAL_CFG_TX_DMA_EN_MASK | + GLOBAL_CFG_RX_DMA_EN_MASK); +- atomic_inc(&qdma->users); ++ qdma->users++; + + if (port->id == AIROHA_GDM2_IDX && + airoha_ppe_is_enabled(qdma->eth, 1)) { +@@ -1788,7 +1788,7 @@ static int airoha_dev_stop(struct net_de + airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), + FE_PSE_PORT_DROP); + +- if (atomic_dec_and_test(&qdma->users)) { ++ if (!--qdma->users) { + airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, + GLOBAL_CFG_TX_DMA_EN_MASK | + GLOBAL_CFG_RX_DMA_EN_MASK); +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -525,7 +525,7 @@ struct airoha_qdma { + struct airoha_eth *eth; + void __iomem *regs; + +- atomic_t users; ++ int users; + + struct airoha_irq_bank irq_banks[AIROHA_MAX_NUM_IRQ_BANKS]; + 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 new file mode 100644 index 00000000000..7598a22199c --- /dev/null +++ b/target/linux/airoha/patches-6.18/916-02-net-airoha-Implement-HW-GRO-TCP-support.patch @@ -0,0 +1,622 @@ +From 598e1ddfe85ad0f4778eeadd5d878209dd931280 Mon Sep 17 00:00:00 2001 +Message-ID: <598e1ddfe85ad0f4778eeadd5d878209dd931280.1779112628.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Thu, 14 May 2026 20:25:19 +0200 +Subject: [PATCH] net: airoha: Implement LRO TCP support + +Signed-off-by: Lorenzo Bianconi +--- + 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(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -11,8 +11,10 @@ + #include + #include + #include ++#include + #include + #include ++#include + #include + + #include "airoha_regs.h" +@@ -439,6 +441,73 @@ static void airoha_fe_crsn_qsel_init(str + CDM_CRSN_QSEL_Q1)); + } + ++static void airoha_fe_lro_rxq_enable(struct airoha_eth *eth, int qdma_id, ++ int lro_queue_index, int qid, ++ int buf_size) ++{ ++ int id = qdma_id + 1; ++ ++ airoha_fe_rmw(eth, REG_CDM_LRO_LIMIT(id), ++ CDM_LRO_AGG_NUM_MASK | CDM_LRO_AGG_SIZE_MASK, ++ FIELD_PREP(CDM_LRO_AGG_SIZE_MASK, buf_size) | ++ FIELD_PREP(CDM_LRO_AGG_NUM_MASK, ++ AIROHA_RXQ_LRO_MAX_AGG_COUNT)); ++ airoha_fe_rmw(eth, REG_CDM_LRO_AGE_TIME(id), ++ CDM_LRO_AGE_TIME_MASK | CDM_LRO_AGG_TIME_MASK, ++ FIELD_PREP(CDM_LRO_AGE_TIME_MASK, ++ AIROHA_RXQ_LRO_MAX_AGE_TIME) | ++ FIELD_PREP(CDM_LRO_AGG_TIME_MASK, ++ AIROHA_RXQ_LRO_MAX_AGG_TIME)); ++ airoha_fe_rmw(eth, REG_CDM_LRO_RXQ(id, lro_queue_index), ++ LRO_RXQ_MASK(lro_queue_index), ++ __field_prep(LRO_RXQ_MASK(lro_queue_index), qid)); ++ airoha_fe_set(eth, REG_CDM_LRO_EN(id), BIT(lro_queue_index)); ++} ++ ++static void airoha_fe_lro_disable(struct airoha_eth *eth, int qdma_id) ++{ ++ int i, id = qdma_id + 1; ++ ++ airoha_fe_clear(eth, REG_CDM_LRO_EN(id), LRO_RXQ_EN_MASK); ++ airoha_fe_clear(eth, REG_CDM_LRO_LIMIT(id), ++ CDM_LRO_AGG_NUM_MASK | CDM_LRO_AGG_SIZE_MASK); ++ airoha_fe_clear(eth, REG_CDM_LRO_AGE_TIME(id), ++ CDM_LRO_AGE_TIME_MASK | CDM_LRO_AGG_TIME_MASK); ++ for (i = 0; i < AIROHA_MAX_NUM_LRO_QUEUES; i++) ++ airoha_fe_clear(eth, REG_CDM_LRO_RXQ(id, i), LRO_RXQ_MASK(i)); ++} ++ ++static bool airoha_fe_lro_is_enabled(struct airoha_eth *eth, int qdma_id) ++{ ++ return airoha_fe_get(eth, REG_CDM_LRO_EN(qdma_id + 1), ++ LRO_RXQ_EN_MASK); ++} ++ ++static void airoha_dev_lro_enable(struct airoha_gdm_port *port) ++{ ++ struct airoha_qdma *qdma = port->qdma; ++ struct airoha_eth *eth = qdma->eth; ++ int qdma_id = qdma - ð->qdma[0]; ++ int i, lro_queue_index = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { ++ struct airoha_queue *q = &qdma->q_rx[i]; ++ u32 size; ++ ++ if (!q->ndesc) ++ continue; ++ ++ if (!airoha_qdma_is_lro_queue(q)) ++ continue; ++ ++ size = SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size)); ++ size = min_t(u32, size, CDM_LRO_AGG_SIZE_MASK); ++ airoha_fe_lro_rxq_enable(eth, qdma_id, lro_queue_index, i, ++ size); ++ lro_queue_index++; ++ } ++} ++ + static int airoha_fe_init(struct airoha_eth *eth) + { + airoha_fe_maccr_init(eth); +@@ -558,6 +627,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)); + ++ WRITE_ONCE(desc->tcp_ts_reply, 0); + 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)); +@@ -603,12 +673,169 @@ static int airoha_qdma_get_gdm_port(stru + return port >= ARRAY_SIZE(eth->ports) ? -EINVAL : port; + } + ++static struct sk_buff *airoha_qdma_lro_rx_skb(struct airoha_queue *q, ++ struct airoha_qdma_desc *desc, ++ struct airoha_queue_entry *e) ++{ ++ 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 msg2 = le32_to_cpu(READ_ONCE(desc->msg2)); ++ u32 msg3 = le32_to_cpu(READ_ONCE(desc->msg3)); ++ struct skb_shared_info *shinfo; ++ u16 tcp_win, l2_len; ++ struct sk_buff *skb; ++ struct tcphdr *th; ++ struct page *page; ++ bool ipv4, ipv6; ++ ++ ipv4 = FIELD_GET(QDMA_ETH_RXMSG_IP4_MASK, msg1); ++ ipv6 = FIELD_GET(QDMA_ETH_RXMSG_IP6_MASK, msg1); ++ if (!ipv4 && !ipv6) ++ return NULL; ++ ++ 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; ++ ++ if (len < l2_len + sizeof(*iph)) ++ return NULL; ++ ++ iph = (struct iphdr *)(e->buf + l2_len); ++ if (iph->protocol != IPPROTO_TCP) ++ return NULL; ++ ++ if (iph->ihl < 5) ++ return NULL; ++ ++ th_off = l2_len + (iph->ihl << 2); ++ if (len < th_off) ++ return NULL; ++ ++ iph->tot_len = cpu_to_be16(len - l2_len); ++ iph->check = 0; ++ iph->check = ip_fast_csum((void *)iph, iph->ihl); ++ } else { ++ struct ipv6hdr *ip6h; ++ ++ th_off = l2_len + sizeof(*ip6h); ++ if (len < th_off) ++ return NULL; ++ ++ ip6h = (struct ipv6hdr *)(e->buf + l2_len); ++ if (ip6h->nexthdr != NEXTHDR_TCP) ++ return NULL; ++ ++ ip6h->payload_len = cpu_to_be16(len - th_off); ++ } ++ ++ if (len < th_off + sizeof(*th)) ++ return NULL; ++ ++ th = (struct tcphdr *)(e->buf + th_off); ++ if (th->doff < 5) ++ return NULL; ++ ++ data_off = th_off + (th->doff << 2); ++ if (len < data_off) ++ return NULL; ++ ++ tcp_win = FIELD_GET(QDMA_ETH_RXMSG_TCP_WIN_MASK, 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); ++ ++ 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); ++ } ++ } ++ ++ if (ipv4) { ++ struct iphdr *iph = (struct iphdr *)(e->buf + 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); ++ ++ 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_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; ++} ++ + static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) + { + enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool); +- struct airoha_qdma *qdma = q->qdma; +- struct airoha_eth *eth = qdma->eth; +- int qid = q - &qdma->q_rx[0]; ++ struct airoha_eth *eth = q->qdma->eth; + int done = 0; + + while (done < budget) { +@@ -643,18 +870,9 @@ static int airoha_qdma_rx_process(struct + + port = eth->ports[p]; + 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, port->dev); + 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 = port->dev; +- q->skb->protocol = eth_type_trans(q->skb, port->dev); +- q->skb->ip_summed = CHECKSUM_UNNECESSARY; +- skb_record_rx_queue(q->skb, qid); + } else { /* scattered frame */ + struct skb_shared_info *shinfo = skb_shinfo(q->skb); + int nr_frags = shinfo->nr_frags; +@@ -743,12 +961,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) + { +- const struct page_pool_params pp_params = { +- .order = 0, ++ struct page_pool_params pp_params = { + .pool_size = 256, + .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, + .dma_dir = DMA_FROM_DEVICE, +- .max_len = PAGE_SIZE, + .nid = NUMA_NO_NODE, + .dev = qdma->eth->dev, + .napi = &q->napi, +@@ -756,9 +972,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; ++ bool lro_q; + +- q->buf_size = PAGE_SIZE / 2; + q->qdma = qdma; ++ lro_q = airoha_qdma_is_lro_queue(q); + + q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry), + GFP_KERNEL); +@@ -770,6 +987,9 @@ static int airoha_qdma_init_rx_queue(str + if (!q->desc) + return -ENOMEM; + ++ pp_params.order = lro_q ? AIROHA_LRO_PAGE_ORDER : 0; ++ pp_params.max_len = PAGE_SIZE << pp_params.order; ++ + q->page_pool = page_pool_create(&pp_params); + if (IS_ERR(q->page_pool)) { + int err = PTR_ERR(q->page_pool); +@@ -778,6 +998,7 @@ static int airoha_qdma_init_rx_queue(str + return err; + } + ++ q->buf_size = lro_q ? pp_params.max_len : pp_params.max_len / 2; + q->ndesc = ndesc; + netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll); + +@@ -791,7 +1012,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)); +- airoha_qdma_set(qdma, REG_RX_SCATTER_CFG(qid), RX_RING_SG_EN_MASK); ++ if (lro_q) ++ airoha_qdma_clear(qdma, REG_RX_SCATTER_CFG(qid), ++ RX_RING_SG_EN_MASK); ++ else ++ airoha_qdma_set(qdma, REG_RX_SCATTER_CFG(qid), ++ RX_RING_SG_EN_MASK); + + airoha_qdma_fill_rx_queue(q); + +@@ -813,6 +1039,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 */ ++ WRITE_ONCE(desc->tcp_ts_reply, 0); + WRITE_ONCE(desc->ctrl, 0); + WRITE_ONCE(desc->addr, 0); + WRITE_ONCE(desc->data, 0); +@@ -1720,13 +1947,45 @@ static void airoha_update_hw_stats(struc + spin_unlock(&port->stats.lock); + } + ++static void airoha_update_netdev_features(struct airoha_gdm_port *port) ++{ ++ struct airoha_eth *eth = port->eth; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { ++ struct airoha_gdm_port *p = eth->ports[i]; ++ struct net_device *netdev; ++ ++ if (!p) ++ continue; ++ ++ netdev = p->dev; ++ if (netdev->reg_state != NETREG_REGISTERED) ++ continue; ++ ++ netdev_update_features(netdev); ++ } ++} ++ + static int airoha_dev_open(struct net_device *dev) + { + int err, len = ETH_HLEN + dev->mtu + ETH_FCS_LEN; + struct airoha_gdm_port *port = netdev_priv(dev); + struct airoha_qdma *qdma = port->qdma; ++ struct airoha_eth *eth = qdma->eth; ++ int qdma_id = qdma - ð->qdma[0]; + u32 pse_port = FE_PSE_PORT_PPE1; + ++ /* HW 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. ++ */ ++ if (qdma->users && airoha_fe_lro_is_enabled(eth, qdma_id)) { ++ netdev_warn(dev, "required to disable HW GRO on QDMA%d\n", ++ qdma_id); ++ return -EBUSY; ++ } ++ + #if defined(CONFIG_PCS_AIROHA) + if (airhoa_is_phy_external(port)) { + err = phylink_of_phy_connect(port->phylink, dev->dev.of_node, 0); +@@ -1747,13 +2006,13 @@ static int airoha_dev_open(struct net_de + + /* It seems GDM3 and GDM4 needs SPORT enabled to correctly work */ + if (netdev_uses_dsa(dev) || port->id > 2) +- airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id), ++ airoha_fe_set(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_fe_rmw(qdma->eth, REG_GDM_LEN_CFG(port->id), ++ airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), + GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, + FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | + FIELD_PREP(GDM_LONG_LEN_MASK, len)); +@@ -1763,14 +2022,18 @@ static int airoha_dev_open(struct net_de + GLOBAL_CFG_RX_DMA_EN_MASK); + qdma->users++; + +- if (port->id == AIROHA_GDM2_IDX && +- airoha_ppe_is_enabled(qdma->eth, 1)) { ++ if (port->id == AIROHA_GDM2_IDX && airoha_ppe_is_enabled(eth, 1)) { + /* For PPE2 always use secondary cpu port. */ + 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), + pse_port); + ++ if (dev->features & NETIF_F_GRO_HW) ++ airoha_dev_lro_enable(port); ++ ++ airoha_update_netdev_features(port); ++ + return 0; + } + +@@ -1778,6 +2041,7 @@ static int airoha_dev_stop(struct net_de + { + struct airoha_gdm_port *port = netdev_priv(dev); + struct airoha_qdma *qdma = port->qdma; ++ struct airoha_eth *eth = qdma->eth; + int i; + + netif_tx_disable(dev); +@@ -1785,7 +2049,7 @@ static int airoha_dev_stop(struct net_de + for (i = 0; i < dev->num_tx_queues; i++) + netdev_tx_reset_subqueue(dev, i); + +- 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), + FE_PSE_PORT_DROP); + + if (!--qdma->users) { +@@ -1801,6 +2065,8 @@ static int airoha_dev_stop(struct net_de + } + } + ++ airoha_update_netdev_features(port); ++ + #if defined(CONFIG_PCS_AIROHA) + if (airhoa_is_phy_external(port)) { + phylink_stop(port->phylink); +@@ -2034,6 +2300,38 @@ int airoha_get_fe_port(struct airoha_gdm + } + } + ++static netdev_features_t airoha_dev_fix_features(struct net_device *dev, ++ netdev_features_t features) ++{ ++ struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_qdma *qdma = port->qdma; ++ ++ if (qdma->users > 1) ++ features &= ~NETIF_F_GRO_HW; ++ ++ return features; ++} ++ ++static int airoha_dev_set_features(struct net_device *dev, ++ netdev_features_t features) ++{ ++ netdev_features_t diff = dev->features ^ features; ++ struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_qdma *qdma = port->qdma; ++ struct airoha_eth *eth = qdma->eth; ++ int qdma_id = qdma - ð->qdma[0]; ++ ++ if (!(diff & NETIF_F_GRO_HW)) ++ return 0; ++ ++ if (features & NETIF_F_GRO_HW) ++ airoha_dev_lro_enable(port); ++ else ++ airoha_fe_lro_disable(eth, qdma_id); ++ ++ return 0; ++} ++ + static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + struct net_device *dev) + { +@@ -2933,6 +3231,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, ++ .ndo_fix_features = airoha_dev_fix_features, ++ .ndo_set_features = airoha_dev_set_features, + .ndo_start_xmit = airoha_dev_xmit, + .ndo_get_stats64 = airoha_dev_get_stats64, + .ndo_set_mac_address = airoha_dev_set_macaddr, +@@ -3150,12 +3450,9 @@ static int airoha_alloc_gdm_port(struct + dev->ethtool_ops = &airoha_ethtool_ops; + dev->max_mtu = AIROHA_MAX_MTU; + dev->watchdog_timeo = 5 * HZ; +- dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | +- NETIF_F_TSO6 | NETIF_F_IPV6_CSUM | +- NETIF_F_SG | NETIF_F_TSO | +- NETIF_F_HW_TC; +- dev->features |= dev->hw_features; +- dev->vlan_features = dev->hw_features; ++ dev->hw_features = AIROHA_HW_FEATURES | NETIF_F_GRO_HW; ++ dev->features |= AIROHA_HW_FEATURES; ++ dev->vlan_features = AIROHA_HW_FEATURES; + dev->dev.of_node = np; + SET_NETDEV_DEV(dev, eth->dev); + +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -43,6 +43,18 @@ + (_n) == 15 ? 128 : \ + (_n) == 0 ? 1024 : 16) + ++#define AIROHA_LRO_PAGE_ORDER order_base_2(SZ_16K / PAGE_SIZE) ++#define AIROHA_MAX_NUM_LRO_QUEUES 8 ++#define AIROHA_RXQ_LRO_EN_MASK GENMASK(7, 0) ++#define AIROHA_RXQ_LRO_MAX_AGG_COUNT 64 ++#define AIROHA_RXQ_LRO_MAX_AGG_TIME 100 ++#define AIROHA_RXQ_LRO_MAX_AGE_TIME 2000 ++ ++#define AIROHA_HW_FEATURES \ ++ (NETIF_F_IP_CSUM | NETIF_F_RXCSUM | \ ++ NETIF_F_TSO6 | NETIF_F_IPV6_CSUM | \ ++ NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_TC) ++ + #define PSE_RSV_PAGES 128 + #define PSE_QUEUE_RSV_PAGES 64 + +@@ -666,6 +678,18 @@ static inline bool airoha_is_7583(struct + return eth->soc->version == 0x7583; + } + ++static inline bool airoha_qdma_is_lro_queue(struct airoha_queue *q) ++{ ++ struct airoha_qdma *qdma = q->qdma; ++ int qid = q - &qdma->q_rx[0]; ++ ++ /* EN7581 SoC supports at most 8 LRO rx queues */ ++ BUILD_BUG_ON(hweight32(AIROHA_RXQ_LRO_EN_MASK) > ++ AIROHA_MAX_NUM_LRO_QUEUES); ++ ++ return !!(AIROHA_RXQ_LRO_EN_MASK & BIT(qid)); ++} ++ + int airoha_get_fe_port(struct airoha_gdm_port *port); + bool airoha_is_valid_gdm_port(struct airoha_eth *eth, + struct airoha_gdm_port *port); +--- a/drivers/net/ethernet/airoha/airoha_regs.h ++++ b/drivers/net/ethernet/airoha/airoha_regs.h +@@ -122,6 +122,20 @@ + #define CDM_CRSN_QSEL_REASON_MASK(_n) \ + GENMASK(4 + (((_n) % 4) << 3), (((_n) % 4) << 3)) + ++#define REG_CDM_LRO_RXQ(_n, _m) (CDM_BASE(_n) + 0x78 + ((_m) & 0x4)) ++#define LRO_RXQ_MASK(_n) GENMASK(4 + (((_n) & 0x3) << 3), ((_n) & 0x3) << 3) ++ ++#define REG_CDM_LRO_EN(_n) (CDM_BASE(_n) + 0x80) ++#define LRO_RXQ_EN_MASK GENMASK(7, 0) ++ ++#define REG_CDM_LRO_LIMIT(_n) (CDM_BASE(_n) + 0x84) ++#define CDM_LRO_AGG_NUM_MASK GENMASK(23, 16) ++#define CDM_LRO_AGG_SIZE_MASK GENMASK(15, 0) ++ ++#define REG_CDM_LRO_AGE_TIME(_n) (CDM_BASE(_n) + 0x88) ++#define CDM_LRO_AGE_TIME_MASK GENMASK(31, 16) ++#define CDM_LRO_AGG_TIME_MASK GENMASK(15, 0) ++ + #define REG_GDM_FWD_CFG(_n) GDM_BASE(_n) + #define GDM_PAD_EN_MASK BIT(28) + #define GDM_DROP_CRC_ERR_MASK BIT(23) +@@ -895,9 +909,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) ++/* RX MSG2 */ ++#define QDMA_ETH_RXMSG_AGG_COUNT_MASK GENMASK(31, 24) ++#define QDMA_ETH_RXMSG_L2_LEN_MASK GENMASK(6, 0) ++/* RX MSG3 */ ++#define QDMA_ETH_RXMSG_AGG_LEN_MASK GENMASK(31, 16) ++#define QDMA_ETH_RXMSG_TCP_WIN_MASK GENMASK(15, 0) + + struct airoha_qdma_desc { +- __le32 rsv; ++ __le32 tcp_ts_reply; + __le32 ctrl; + __le32 addr; + __le32 data; diff --git a/target/linux/airoha/patches-6.18/916-net-airoha-Implement-LRO-TCP-support.patch b/target/linux/airoha/patches-6.18/916-net-airoha-Implement-LRO-TCP-support.patch deleted file mode 100644 index 7636ecbbc82..00000000000 --- a/target/linux/airoha/patches-6.18/916-net-airoha-Implement-LRO-TCP-support.patch +++ /dev/null @@ -1,392 +0,0 @@ -From 598e1ddfe85ad0f4778eeadd5d878209dd931280 Mon Sep 17 00:00:00 2001 -Message-ID: <598e1ddfe85ad0f4778eeadd5d878209dd931280.1779112628.git.lorenzo@kernel.org> -From: Lorenzo Bianconi -Date: Thu, 14 May 2026 20:25:19 +0200 -Subject: [PATCH] net: airoha: Implement LRO TCP support - -Signed-off-by: Lorenzo Bianconi ---- - 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(-) - ---- a/drivers/net/ethernet/airoha/airoha_eth.c -+++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - #include - - #include "airoha_regs.h" -@@ -439,6 +440,48 @@ static void airoha_fe_crsn_qsel_init(str - CDM_CRSN_QSEL_Q1)); - } - -+static void airoha_fe_lro_init_rx_queue(struct airoha_eth *eth, int qdma_id, -+ int lro_queue_index, int qid, -+ int buf_size) -+{ -+ int id = qdma_id + 1; -+ -+ airoha_fe_rmw(eth, REG_CDM_LRO_LIMIT(id), -+ CDM_LRO_AGG_NUM_MASK | CDM_LRO_AGG_SIZE_MASK, -+ FIELD_PREP(CDM_LRO_AGG_SIZE_MASK, buf_size) | -+ FIELD_PREP(CDM_LRO_AGG_NUM_MASK, -+ AIROHA_RXQ_LRO_MAX_AGG_COUNT)); -+ airoha_fe_rmw(eth, REG_CDM_LRO_AGE_TIME(id), -+ CDM_LRO_AGE_TIME_MASK | CDM_LRO_AGG_TIME_MASK, -+ FIELD_PREP(CDM_LRO_AGE_TIME_MASK, -+ AIROHA_RXQ_LRO_MAX_AGE_TIME) | -+ FIELD_PREP(CDM_LRO_AGG_TIME_MASK, -+ AIROHA_RXQ_LRO_MAX_AGG_TIME)); -+ airoha_fe_rmw(eth, REG_CDM_LRO_RXQ(id, lro_queue_index), -+ LRO_RXQ_MASK(lro_queue_index), -+ __field_prep(LRO_RXQ_MASK(lro_queue_index), qid)); -+ airoha_fe_set(eth, REG_CDM_LRO_EN(id), BIT(lro_queue_index)); -+} -+ -+static void airoha_fe_lro_disable(struct airoha_eth *eth, int qdma_id) -+{ -+ int i, id = qdma_id + 1; -+ -+ airoha_fe_clear(eth, REG_CDM_LRO_EN(id), LRO_RXQ_EN_MASK); -+ airoha_fe_clear(eth, REG_CDM_LRO_LIMIT(id), -+ CDM_LRO_AGG_NUM_MASK | CDM_LRO_AGG_SIZE_MASK); -+ airoha_fe_clear(eth, REG_CDM_LRO_AGE_TIME(id), -+ CDM_LRO_AGE_TIME_MASK | CDM_LRO_AGG_TIME_MASK); -+ for (i = 0; i < AIROHA_MAX_NUM_LRO_QUEUES; i++) -+ airoha_fe_clear(eth, REG_CDM_LRO_RXQ(id, i), LRO_RXQ_MASK(i)); -+} -+ -+static bool airoha_fe_lro_is_enabled(struct airoha_eth *eth, int qdma_id) -+{ -+ return airoha_fe_get(eth, REG_CDM_LRO_EN(qdma_id + 1), -+ LRO_RXQ_EN_MASK); -+} -+ - static int airoha_fe_init(struct airoha_eth *eth) - { - airoha_fe_maccr_init(eth); -@@ -603,6 +646,85 @@ static int airoha_qdma_get_gdm_port(stru - return port >= ARRAY_SIZE(eth->ports) ? -EINVAL : port; - } - -+static int airoha_qdma_lro_rx_process(struct airoha_queue *q, -+ struct airoha_qdma_desc *desc) -+{ -+ u32 desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); -+ u32 msg1 = le32_to_cpu(READ_ONCE(desc->msg1)); -+ u32 msg2 = le32_to_cpu(READ_ONCE(desc->msg2)); -+ u32 msg3 = le32_to_cpu(READ_ONCE(desc->msg3)); -+ struct sk_buff *skb = q->skb; -+ u32 len, th_off, tcp_ack_seq; -+ u16 tcp_win, l2_len; -+ struct tcphdr *th; -+ bool ipv4, ipv6; -+ -+ if (FIELD_GET(QDMA_ETH_RXMSG_AGG_COUNT_MASK, msg2) <= 1) -+ return 0; -+ -+ ipv4 = FIELD_GET(QDMA_ETH_RXMSG_IP4_MASK, msg1); -+ ipv6 = FIELD_GET(QDMA_ETH_RXMSG_IP6_MASK, msg1); -+ if (!ipv4 && !ipv6) -+ return -EOPNOTSUPP; -+ -+ 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; -+ -+ if (!pskb_may_pull(skb, l2_len + sizeof(*iph))) -+ return -EINVAL; -+ -+ iph = (struct iphdr *)(skb->data + l2_len); -+ if (iph->protocol != IPPROTO_TCP) -+ return -EOPNOTSUPP; -+ -+ iph->tot_len = cpu_to_be16(len - l2_len); -+ iph->check = 0; -+ iph->check = ip_fast_csum((void *)iph, iph->ihl); -+ th_off = l2_len + (iph->ihl << 2); -+ } else { -+ struct ipv6hdr *ip6h; -+ -+ if (!pskb_may_pull(skb, l2_len + sizeof(*ip6h))) -+ return -EINVAL; -+ -+ ip6h = (struct ipv6hdr *)(skb->data + l2_len); -+ if (ip6h->nexthdr != NEXTHDR_TCP) -+ return -EOPNOTSUPP; -+ -+ ip6h->payload_len = cpu_to_be16(len - l2_len - sizeof(*ip6h)); -+ th_off = l2_len + sizeof(*ip6h); -+ } -+ -+ tcp_win = FIELD_GET(QDMA_ETH_RXMSG_TCP_WIN_MASK, msg3); -+ tcp_ack_seq = le32_to_cpu(READ_ONCE(desc->data)); -+ -+ if (!pskb_may_pull(skb, th_off + sizeof(*th))) -+ return -EINVAL; -+ -+ th = (struct tcphdr *)(skb->data + th_off); -+ 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) { -+ __be32 *topt = (__be32 *)(th + 1); -+ -+ if (*topt == cpu_to_be32((TCPOPT_NOP << 24) | -+ (TCPOPT_NOP << 16) | -+ (TCPOPT_TIMESTAMP << 8) | -+ TCPOLEN_TIMESTAMP)) { -+ __le32 tcp_ts_reply = READ_ONCE(desc->tcp_ts_reply); -+ -+ put_unaligned_be32(le32_to_cpu(tcp_ts_reply), -+ topt + 2); -+ } -+ } -+ -+ return 0; -+} -+ - static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) - { - enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool); -@@ -650,11 +772,15 @@ static int airoha_qdma_rx_process(struct - - skb_reserve(q->skb, AIROHA_RX_HEADROOM); - __skb_put(q->skb, len); -- skb_mark_for_recycle(q->skb); - q->skb->dev = port->dev; -- q->skb->protocol = eth_type_trans(q->skb, port->dev); - q->skb->ip_summed = CHECKSUM_UNNECESSARY; - skb_record_rx_queue(q->skb, qid); -+ -+ if (airoha_qdma_lro_rx_process(q, desc) < 0) -+ goto free_frag; -+ -+ q->skb->protocol = eth_type_trans(q->skb, port->dev); -+ skb_mark_for_recycle(q->skb); - } else { /* scattered frame */ - struct skb_shared_info *shinfo = skb_shinfo(q->skb); - int nr_frags = shinfo->nr_frags; -@@ -743,12 +869,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) - { -- const struct page_pool_params pp_params = { -- .order = 0, -+ struct page_pool_params pp_params = { - .pool_size = 256, - .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, - .dma_dir = DMA_FROM_DEVICE, -- .max_len = PAGE_SIZE, - .nid = NUMA_NO_NODE, - .dev = qdma->eth->dev, - .napi = &q->napi, -@@ -756,9 +880,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; -+ bool lro_q; - -- q->buf_size = PAGE_SIZE / 2; - q->qdma = qdma; -+ lro_q = airoha_qdma_is_lro_queue(q); - - q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry), - GFP_KERNEL); -@@ -770,6 +895,9 @@ static int airoha_qdma_init_rx_queue(str - if (!q->desc) - return -ENOMEM; - -+ pp_params.order = lro_q ? AIROHA_LRO_PAGE_ORDER : 0; -+ pp_params.max_len = PAGE_SIZE << pp_params.order; -+ - q->page_pool = page_pool_create(&pp_params); - if (IS_ERR(q->page_pool)) { - int err = PTR_ERR(q->page_pool); -@@ -778,6 +906,7 @@ static int airoha_qdma_init_rx_queue(str - return err; - } - -+ q->buf_size = lro_q ? pp_params.max_len : pp_params.max_len / 2; - q->ndesc = ndesc; - netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll); - -@@ -2034,6 +2163,67 @@ int airoha_get_fe_port(struct airoha_gdm - } - } - -+static int airoha_dev_set_features(struct net_device *dev, -+ netdev_features_t features) -+{ -+ netdev_features_t diff = dev->features ^ features; -+ struct airoha_gdm_port *port = netdev_priv(dev); -+ struct airoha_qdma *qdma = port->qdma; -+ struct airoha_eth *eth = qdma->eth; -+ int qdma_id = qdma - ð->qdma[0]; -+ int i; -+ -+ if (!(diff & NETIF_F_LRO)) -+ return 0; -+ -+ if (netif_running(dev)) -+ return -EBUSY; -+ -+ /* reset LRO configuration */ -+ if (features & NETIF_F_LRO) { -+ int lro_queue_index = 0; -+ -+ if (airoha_fe_lro_is_enabled(eth, qdma_id)) -+ return 0; -+ -+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { -+ struct airoha_queue *q = &qdma->q_rx[i]; -+ u32 size; -+ -+ if (!q->ndesc) -+ continue; -+ -+ if (!airoha_qdma_is_lro_queue(q)) -+ continue; -+ -+ size = SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size)); -+ size = min_t(u32, size, CDM_LRO_AGG_SIZE_MASK); -+ airoha_fe_lro_init_rx_queue(eth, qdma_id, -+ lro_queue_index, i, size); -+ lro_queue_index++; -+ } -+ } else { -+ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { -+ struct airoha_gdm_port *p = eth->ports[i]; -+ -+ if (!p) -+ continue; -+ -+ if (p->qdma != qdma) -+ continue; -+ -+ if (p->dev == dev) -+ continue; -+ -+ if (p->dev->features & NETIF_F_LRO) -+ return 0; -+ } -+ airoha_fe_lro_disable(eth, qdma_id); -+ } -+ -+ return 0; -+} -+ - static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, - struct net_device *dev) - { -@@ -2933,6 +3123,7 @@ 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, -+ .ndo_set_features = airoha_dev_set_features, - .ndo_start_xmit = airoha_dev_xmit, - .ndo_get_stats64 = airoha_dev_get_stats64, - .ndo_set_mac_address = airoha_dev_set_macaddr, -@@ -3150,12 +3341,9 @@ static int airoha_alloc_gdm_port(struct - dev->ethtool_ops = &airoha_ethtool_ops; - dev->max_mtu = AIROHA_MAX_MTU; - dev->watchdog_timeo = 5 * HZ; -- dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | -- NETIF_F_TSO6 | NETIF_F_IPV6_CSUM | -- NETIF_F_SG | NETIF_F_TSO | -- NETIF_F_HW_TC; -- dev->features |= dev->hw_features; -- dev->vlan_features = dev->hw_features; -+ dev->hw_features = AIROHA_HW_FEATURES | NETIF_F_LRO; -+ dev->features |= AIROHA_HW_FEATURES; -+ dev->vlan_features = AIROHA_HW_FEATURES; - dev->dev.of_node = np; - SET_NETDEV_DEV(dev, eth->dev); - ---- a/drivers/net/ethernet/airoha/airoha_eth.h -+++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -43,6 +43,18 @@ - (_n) == 15 ? 128 : \ - (_n) == 0 ? 1024 : 16) - -+#define AIROHA_LRO_PAGE_ORDER 2 -+#define AIROHA_MAX_NUM_LRO_QUEUES 8 -+#define AIROHA_RXQ_LRO_EN_MASK 0xff000000 -+#define AIROHA_RXQ_LRO_MAX_AGG_COUNT 64 -+#define AIROHA_RXQ_LRO_MAX_AGG_TIME 100 -+#define AIROHA_RXQ_LRO_MAX_AGE_TIME 2000 /* 1ms */ -+ -+#define AIROHA_HW_FEATURES \ -+ (NETIF_F_IP_CSUM | NETIF_F_RXCSUM | \ -+ NETIF_F_TSO6 | NETIF_F_IPV6_CSUM | \ -+ NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_TC) -+ - #define PSE_RSV_PAGES 128 - #define PSE_QUEUE_RSV_PAGES 64 - -@@ -666,6 +678,18 @@ static inline bool airoha_is_7583(struct - return eth->soc->version == 0x7583; - } - -+static inline bool airoha_qdma_is_lro_queue(struct airoha_queue *q) -+{ -+ struct airoha_qdma *qdma = q->qdma; -+ int qid = q - &qdma->q_rx[0]; -+ -+ /* EN7581 SoC supports at most 8 LRO rx queues */ -+ BUILD_BUG_ON(hweight32(AIROHA_RXQ_LRO_EN_MASK) > -+ AIROHA_MAX_NUM_LRO_QUEUES); -+ -+ return !!(AIROHA_RXQ_LRO_EN_MASK & BIT(qid)); -+} -+ - int airoha_get_fe_port(struct airoha_gdm_port *port); - bool airoha_is_valid_gdm_port(struct airoha_eth *eth, - struct airoha_gdm_port *port); ---- a/drivers/net/ethernet/airoha/airoha_regs.h -+++ b/drivers/net/ethernet/airoha/airoha_regs.h -@@ -122,6 +122,20 @@ - #define CDM_CRSN_QSEL_REASON_MASK(_n) \ - GENMASK(4 + (((_n) % 4) << 3), (((_n) % 4) << 3)) - -+#define REG_CDM_LRO_RXQ(_n, _m) (CDM_BASE(_n) + 0x78 + ((_m) & 0x4)) -+#define LRO_RXQ_MASK(_n) GENMASK(4 + (((_n) & 0x3) << 3), ((_n) & 0x3) << 3) -+ -+#define REG_CDM_LRO_EN(_n) (CDM_BASE(_n) + 0x80) -+#define LRO_RXQ_EN_MASK GENMASK(7, 0) -+ -+#define REG_CDM_LRO_LIMIT(_n) (CDM_BASE(_n) + 0x84) -+#define CDM_LRO_AGG_NUM_MASK GENMASK(23, 16) -+#define CDM_LRO_AGG_SIZE_MASK GENMASK(15, 0) -+ -+#define REG_CDM_LRO_AGE_TIME(_n) (CDM_BASE(_n) + 0x88) -+#define CDM_LRO_AGE_TIME_MASK GENMASK(31, 16) -+#define CDM_LRO_AGG_TIME_MASK GENMASK(15, 0) -+ - #define REG_GDM_FWD_CFG(_n) GDM_BASE(_n) - #define GDM_PAD_EN_MASK BIT(28) - #define GDM_DROP_CRC_ERR_MASK BIT(23) -@@ -895,9 +909,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) -+/* RX MSG2 */ -+#define QDMA_ETH_RXMSG_AGG_COUNT_MASK GENMASK(31, 24) -+#define QDMA_ETH_RXMSG_L2_LEN_MASK GENMASK(6, 0) -+/* RX MSG3 */ -+#define QDMA_ETH_RXMSG_AGG_LEN_MASK GENMASK(31, 16) -+#define QDMA_ETH_RXMSG_TCP_WIN_MASK GENMASK(15, 0) - - struct airoha_qdma_desc { -- __le32 rsv; -+ __le32 tcp_ts_reply; - __le32 ctrl; - __le32 addr; - __le32 data; diff --git a/target/linux/airoha/patches-6.18/920-01-net-airoha-Introduce-airoha_gdm_dev-struct.patch b/target/linux/airoha/patches-6.18/920-01-net-airoha-Introduce-airoha_gdm_dev-struct.patch index 6d2eee04462..f92593c504a 100644 --- a/target/linux/airoha/patches-6.18/920-01-net-airoha-Introduce-airoha_gdm_dev-struct.patch +++ b/target/linux/airoha/patches-6.18/920-01-net-airoha-Introduce-airoha_gdm_dev-struct.patch @@ -25,7 +25,18 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -738,6 +738,7 @@ static int airoha_qdma_rx_process(struct +@@ -483,8 +483,9 @@ static bool airoha_fe_lro_is_enabled(str + LRO_RXQ_EN_MASK); + } + +-static void airoha_dev_lro_enable(struct airoha_gdm_port *port) ++static void airoha_dev_lro_enable(struct airoha_gdm_dev *dev) + { ++ struct airoha_gdm_port *port = dev->port; + struct airoha_qdma *qdma = port->qdma; + struct airoha_eth *eth = qdma->eth; + int qdma_id = qdma - ð->qdma[0]; +@@ -843,6 +844,7 @@ static int airoha_qdma_rx_process(struct struct airoha_qdma_desc *desc = &q->desc[q->tail]; u32 hash, reason, msg1, desc_ctrl; struct airoha_gdm_port *port; @@ -33,35 +44,21 @@ Signed-off-by: Lorenzo Bianconi int data_len, len, p; struct page *page; -@@ -764,6 +765,10 @@ static int airoha_qdma_rx_process(struct +@@ -869,8 +871,12 @@ static int airoha_qdma_rx_process(struct goto free_frag; port = eth->ports[p]; + if (!port->dev) + goto free_frag; + -+ netdev = port->dev->dev; ++ netdev = netdev_from_priv(port->dev); if (!q->skb) { /* first buffer */ - q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM, - q->buf_size); -@@ -772,14 +777,14 @@ static int airoha_qdma_rx_process(struct - - skb_reserve(q->skb, AIROHA_RX_HEADROOM); - __skb_put(q->skb, len); -- q->skb->dev = port->dev; -+ q->skb->dev = netdev; - q->skb->ip_summed = CHECKSUM_UNNECESSARY; - skb_record_rx_queue(q->skb, qid); - - if (airoha_qdma_lro_rx_process(q, desc) < 0) +- q->skb = airoha_qdma_build_rx_skb(q, desc, e, port->dev); ++ q->skb = airoha_qdma_build_rx_skb(q, desc, e, netdev); + if (!q->skb) goto free_frag; - -- q->skb->protocol = eth_type_trans(q->skb, port->dev); -+ q->skb->protocol = eth_type_trans(q->skb, netdev); - skb_mark_for_recycle(q->skb); } else { /* scattered frame */ - struct skb_shared_info *shinfo = skb_shinfo(q->skb); -@@ -796,7 +801,7 @@ static int airoha_qdma_rx_process(struct +@@ -888,7 +894,7 @@ static int airoha_qdma_rx_process(struct if (FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl)) continue; @@ -70,33 +67,55 @@ Signed-off-by: Lorenzo Bianconi /* PPE module requires untagged packets to work * properly and it provides DSA port index via the * DMA descriptor. Report DSA tag to the DSA stack -@@ -993,6 +998,7 @@ static void airoha_qdma_wake_netdev_txqs +@@ -1091,6 +1097,7 @@ static void airoha_qdma_wake_netdev_txqs for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; -+ struct airoha_gdm_dev *dev; ++ struct net_device *netdev; int j; if (!port) -@@ -1001,11 +1007,12 @@ static void airoha_qdma_wake_netdev_txqs +@@ -1099,11 +1106,12 @@ static void airoha_qdma_wake_netdev_txqs if (port->qdma != qdma) continue; - for (j = 0; j < port->dev->num_tx_queues; j++) { -+ dev = port->dev; -+ for (j = 0; j < dev->dev->num_tx_queues; j++) { ++ netdev = netdev_from_priv(port->dev); ++ for (j = 0; j < netdev->num_tx_queues; j++) { if (airoha_qdma_get_txq(qdma, j) != qid) continue; - netif_wake_subqueue(port->dev, j); -+ netif_wake_subqueue(dev->dev, j); ++ netif_wake_subqueue(netdev, j); } } q->txq_stopped = false; -@@ -1849,33 +1856,34 @@ static void airoha_update_hw_stats(struc +@@ -1947,9 +1955,10 @@ static void airoha_update_hw_stats(struc spin_unlock(&port->stats.lock); } +-static void airoha_update_netdev_features(struct airoha_gdm_port *port) ++static void airoha_update_netdev_features(struct airoha_gdm_dev *dev) + { +- struct airoha_eth *eth = port->eth; ++ struct airoha_gdm_port *port = dev->port; ++ struct airoha_eth *eth = dev->eth; + int i; + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { +@@ -1959,7 +1968,7 @@ static void airoha_update_netdev_feature + if (!p) + continue; + +- netdev = p->dev; ++ netdev = netdev_from_priv(p->dev); + if (netdev->reg_state != NETREG_REGISTERED) + continue; + +@@ -1967,10 +1976,11 @@ static void airoha_update_netdev_feature + } + } + -static int airoha_dev_open(struct net_device *dev) +static int airoha_dev_open(struct net_device *netdev) { @@ -106,16 +125,28 @@ Signed-off-by: Lorenzo Bianconi + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; struct airoha_qdma *qdma = port->qdma; - u32 pse_port = FE_PSE_PORT_PPE1; + struct airoha_eth *eth = qdma->eth; + int qdma_id = qdma - ð->qdma[0]; +@@ -1981,31 +1991,32 @@ static int airoha_dev_open(struct net_de + * the same QDMA if LRO is enabled on any device sharing it. + */ + if (qdma->users && airoha_fe_lro_is_enabled(eth, qdma_id)) { +- netdev_warn(dev, "required to disable HW GRO on QDMA%d\n", ++ netdev_warn(netdev, "required to disable HW GRO on QDMA%d\n", + qdma_id); + return -EBUSY; + } #if defined(CONFIG_PCS_AIROHA) if (airhoa_is_phy_external(port)) { - err = phylink_of_phy_connect(port->phylink, dev->dev.of_node, 0); -+ err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0); ++ err = phylink_of_phy_connect(dev->phylink, ++ netdev->dev.of_node, 0); if (err) { - netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, -+ netdev_err(netdev, "%s: could not attach PHY: %d\n", __func__, - err); +- err); ++ netdev_err(netdev, "%s: could not attach PHY: %d\n", ++ __func__, err); return err; } @@ -133,10 +164,21 @@ Signed-off-by: Lorenzo Bianconi /* It seems GDM3 and GDM4 needs SPORT enabled to correctly work */ - if (netdev_uses_dsa(dev) || port->id > 2) + 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), GDM_STAG_EN_MASK); else -@@ -1903,16 +1911,17 @@ static int airoha_dev_open(struct net_de +@@ -2029,25 +2040,26 @@ static int airoha_dev_open(struct net_de + airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id), + pse_port); + +- if (dev->features & NETIF_F_GRO_HW) +- airoha_dev_lro_enable(port); ++ if (netdev->features & NETIF_F_GRO_HW) ++ airoha_dev_lro_enable(dev); + +- airoha_update_netdev_features(port); ++ airoha_update_netdev_features(dev); + return 0; } @@ -147,6 +189,7 @@ Signed-off-by: Lorenzo Bianconi + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; struct airoha_qdma *qdma = port->qdma; + struct airoha_eth *eth = qdma->eth; int i; - netif_tx_disable(dev); @@ -157,9 +200,14 @@ Signed-off-by: Lorenzo Bianconi + for (i = 0; i < netdev->num_tx_queues; i++) + netdev_tx_reset_subqueue(netdev, i); - 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), FE_PSE_PORT_DROP); -@@ -1932,24 +1941,25 @@ static int airoha_dev_stop(struct net_de +@@ -2065,28 +2077,29 @@ static int airoha_dev_stop(struct net_de + } + } + +- airoha_update_netdev_features(port); ++ airoha_update_netdev_features(dev); #if defined(CONFIG_PCS_AIROHA) if (airhoa_is_phy_external(port)) { @@ -191,7 +239,7 @@ Signed-off-by: Lorenzo Bianconi return 0; } -@@ -2015,16 +2025,17 @@ static int airoha_set_gdm2_loopback(stru +@@ -2152,16 +2165,17 @@ static int airoha_set_gdm2_loopback(stru return 0; } @@ -209,12 +257,12 @@ Signed-off-by: Lorenzo Bianconi port->qdma = ð->qdma[!airoha_is_lan_gdm_port(port)]; - port->dev->irq = port->qdma->irq_banks[0].irq; - airoha_set_macaddr(port, dev->dev_addr); -+ dev->dev->irq = port->qdma->irq_banks[0].irq; ++ netdev->irq = port->qdma->irq_banks[0].irq; + airoha_set_macaddr(port, netdev->dev_addr); switch (port->id) { case AIROHA_GDM3_IDX: -@@ -2049,10 +2060,11 @@ static int airoha_dev_init(struct net_de +@@ -2186,10 +2200,11 @@ static int airoha_dev_init(struct net_de return 0; } @@ -228,7 +276,7 @@ Signed-off-by: Lorenzo Bianconi unsigned int start; airoha_update_hw_stats(port); -@@ -2071,36 +2083,39 @@ static void airoha_dev_get_stats64(struc +@@ -2208,36 +2223,39 @@ static void airoha_dev_get_stats64(struc } while (u64_stats_fetch_retry(&port->stats.syncp, start)); } @@ -275,10 +323,24 @@ Signed-off-by: Lorenzo Bianconi } static u32 airoha_get_dsa_tag(struct sk_buff *skb, struct net_device *dev) -@@ -2163,11 +2178,12 @@ int airoha_get_fe_port(struct airoha_gdm +@@ -2300,10 +2318,11 @@ int airoha_get_fe_port(struct airoha_gdm } } +-static netdev_features_t airoha_dev_fix_features(struct net_device *dev, ++static netdev_features_t airoha_dev_fix_features(struct net_device *netdev, + netdev_features_t features) + { +- struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; + struct airoha_qdma *qdma = port->qdma; + + if (qdma->users > 1) +@@ -2312,11 +2331,12 @@ static netdev_features_t airoha_dev_fix_ + return features; + } + -static int airoha_dev_set_features(struct net_device *dev, +static int airoha_dev_set_features(struct net_device *netdev, netdev_features_t features) @@ -291,38 +353,16 @@ Signed-off-by: Lorenzo Bianconi struct airoha_qdma *qdma = port->qdma; struct airoha_eth *eth = qdma->eth; int qdma_id = qdma - ð->qdma[0]; -@@ -2176,7 +2192,7 @@ static int airoha_dev_set_features(struc - if (!(diff & NETIF_F_LRO)) +@@ -2325,7 +2345,7 @@ static int airoha_dev_set_features(struc return 0; -- if (netif_running(dev)) -+ if (netif_running(netdev)) - return -EBUSY; - - /* reset LRO configuration */ -@@ -2205,6 +2221,7 @@ static int airoha_dev_set_features(struc - } else { - for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { - struct airoha_gdm_port *p = eth->ports[i]; -+ struct airoha_gdm_dev *d; - - if (!p) - continue; -@@ -2212,10 +2229,11 @@ static int airoha_dev_set_features(struc - if (p->qdma != qdma) - continue; - -- if (p->dev == dev) -+ d = p->dev; -+ if (d->dev == netdev) - continue; - -- if (p->dev->features & NETIF_F_LRO) -+ if (d->dev->features & NETIF_F_LRO) - return 0; - } + if (features & NETIF_F_GRO_HW) +- airoha_dev_lro_enable(port); ++ airoha_dev_lro_enable(dev); + else airoha_fe_lro_disable(eth, qdma_id); -@@ -2225,9 +2243,10 @@ static int airoha_dev_set_features(struc + +@@ -2333,9 +2353,10 @@ static int airoha_dev_set_features(struc } static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, @@ -335,7 +375,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_qdma *qdma = port->qdma; u32 nr_frags, tag, msg0, msg1, len; struct airoha_queue_entry *e; -@@ -2240,7 +2259,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2348,7 +2369,7 @@ static netdev_tx_t airoha_dev_xmit(struc u8 fport; qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb)); @@ -344,7 +384,7 @@ Signed-off-by: Lorenzo Bianconi msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK, qid / AIROHA_NUM_QOS_QUEUES) | -@@ -2276,7 +2295,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2384,7 +2405,7 @@ static netdev_tx_t airoha_dev_xmit(struc spin_lock_bh(&q->lock); @@ -353,7 +393,7 @@ Signed-off-by: Lorenzo Bianconi nr_frags = 1 + skb_shinfo(skb)->nr_frags; if (q->queued + nr_frags >= q->ndesc) { -@@ -2300,9 +2319,9 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2408,9 +2429,9 @@ static netdev_tx_t airoha_dev_xmit(struc dma_addr_t addr; u32 val; @@ -365,7 +405,7 @@ Signed-off-by: Lorenzo Bianconi goto error_unmap; list_move_tail(&e->list, &tx_list); -@@ -2351,7 +2370,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2459,7 +2480,7 @@ static netdev_tx_t airoha_dev_xmit(struc error_unmap: list_for_each_entry(e, &tx_list, list) { @@ -374,7 +414,7 @@ Signed-off-by: Lorenzo Bianconi DMA_TO_DEVICE); e->dma_addr = 0; } -@@ -2360,25 +2379,27 @@ error_unmap: +@@ -2468,25 +2489,27 @@ error_unmap: spin_unlock_bh(&q->lock); error: dev_kfree_skb_any(skb); @@ -407,7 +447,7 @@ Signed-off-by: Lorenzo Bianconi unsigned int start; airoha_update_hw_stats(port); -@@ -2406,11 +2427,12 @@ static const struct ethtool_rmon_hist_ra +@@ -2514,11 +2537,12 @@ static const struct ethtool_rmon_hist_ra }; static void @@ -422,7 +462,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_hw_stats *hw_stats = &port->stats; unsigned int start; -@@ -2435,11 +2457,12 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2543,11 +2567,12 @@ airoha_ethtool_get_rmon_stats(struct net } while (u64_stats_fetch_retry(&port->stats.syncp, start)); } @@ -437,7 +477,7 @@ Signed-off-by: Lorenzo Bianconi int i; for (i = 0; i < AIROHA_NUM_TX_RING; i++) -@@ -2524,10 +2547,12 @@ static int airoha_qdma_set_tx_ets_sched( +@@ -2632,10 +2657,12 @@ static int airoha_qdma_set_tx_ets_sched( ARRAY_SIZE(w)); } @@ -452,7 +492,7 @@ Signed-off-by: Lorenzo Bianconi u64 cpu_tx_packets = airoha_qdma_rr(port->qdma, REG_CNTR_VAL(channel << 1)); u64 fwd_tx_packets = airoha_qdma_rr(port->qdma, -@@ -2789,11 +2814,12 @@ static int airoha_qdma_set_trtcm_token_b +@@ -2897,11 +2924,12 @@ static int airoha_qdma_set_trtcm_token_b mode, val); } @@ -467,7 +507,7 @@ Signed-off-by: Lorenzo Bianconi int i, err; for (i = 0; i <= TRTCM_PEAK_MODE; i++) { -@@ -2813,20 +2839,22 @@ static int airoha_qdma_set_tx_rate_limit +@@ -2921,20 +2949,22 @@ static int airoha_qdma_set_tx_rate_limit return 0; } @@ -494,7 +534,7 @@ Signed-off-by: Lorenzo Bianconi if (err) { NL_SET_ERR_MSG_MOD(opt->extack, "failed configuring htb offload"); -@@ -2836,9 +2864,10 @@ static int airoha_tc_htb_alloc_leaf_queu +@@ -2944,9 +2974,10 @@ static int airoha_tc_htb_alloc_leaf_queu if (opt->command == TC_HTB_NODE_MODIFY) return 0; @@ -507,7 +547,7 @@ Signed-off-by: Lorenzo Bianconi NL_SET_ERR_MSG_MOD(opt->extack, "failed setting real_num_tx_queues"); return err; -@@ -2928,11 +2957,12 @@ static int airoha_tc_matchall_act_valida +@@ -3036,11 +3067,12 @@ static int airoha_tc_matchall_act_valida return 0; } @@ -522,7 +562,7 @@ Signed-off-by: Lorenzo Bianconi u32 rate = 0, bucket_size = 0; switch (f->command) { -@@ -2967,18 +2997,19 @@ static int airoha_dev_tc_matchall(struct +@@ -3075,18 +3107,19 @@ static int airoha_dev_tc_matchall(struct static int airoha_dev_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) { @@ -546,7 +586,7 @@ Signed-off-by: Lorenzo Bianconi default: return -EOPNOTSUPP; } -@@ -3025,47 +3056,51 @@ static int airoha_dev_setup_tc_block(str +@@ -3133,47 +3166,51 @@ static int airoha_dev_setup_tc_block(str } } @@ -610,7 +650,7 @@ Signed-off-by: Lorenzo Bianconi if (!test_bit(channel, port->qos_sq_bmap)) { NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); -@@ -3101,8 +3136,8 @@ static int airoha_tc_setup_qdisc_htb(str +@@ -3209,8 +3246,8 @@ static int airoha_tc_setup_qdisc_htb(str return 0; } @@ -621,7 +661,7 @@ Signed-off-by: Lorenzo Bianconi { switch (type) { case TC_SETUP_QDISC_ETS: -@@ -3174,13 +3209,18 @@ static void airoha_metadata_dst_free(str +@@ -3283,13 +3320,18 @@ static void airoha_metadata_dst_free(str } } @@ -643,7 +683,7 @@ Signed-off-by: Lorenzo Bianconi return true; } -@@ -3192,8 +3232,9 @@ static void airoha_mac_link_up(struct ph +@@ -3301,8 +3343,9 @@ static void airoha_mac_link_up(struct ph unsigned int mode, phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause) { @@ -655,7 +695,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_qdma *qdma = port->qdma; struct airoha_eth *eth = qdma->eth; u32 frag_size_tx, frag_size_rx; -@@ -3249,65 +3290,122 @@ static int airoha_fill_available_pcs(str +@@ -3358,65 +3401,121 @@ static int airoha_fill_available_pcs(str &num_available_pcs); } @@ -753,7 +793,7 @@ Signed-off-by: Lorenzo Bianconi + netdev->ethtool_ops = &airoha_ethtool_ops; + netdev->max_mtu = AIROHA_MAX_MTU; + netdev->watchdog_timeo = 5 * HZ; -+ netdev->hw_features = AIROHA_HW_FEATURES | NETIF_F_LRO; ++ netdev->hw_features = AIROHA_HW_FEATURES | NETIF_F_GRO_HW; + netdev->features |= AIROHA_HW_FEATURES; + netdev->vlan_features = AIROHA_HW_FEATURES; + netdev->dev.of_node = np; @@ -775,7 +815,6 @@ Signed-off-by: Lorenzo Bianconi + } + + dev = netdev_priv(netdev); -+ dev->dev = netdev; + dev->port = port; + port->dev = dev; + dev->eth = eth; @@ -800,7 +839,7 @@ Signed-off-by: Lorenzo Bianconi int err, p; u32 id; -@@ -3329,58 +3427,22 @@ static int airoha_alloc_gdm_port(struct +@@ -3438,58 +3537,22 @@ static int airoha_alloc_gdm_port(struct return -EINVAL; } @@ -818,7 +857,7 @@ Signed-off-by: Lorenzo Bianconi - dev->ethtool_ops = &airoha_ethtool_ops; - dev->max_mtu = AIROHA_MAX_MTU; - dev->watchdog_timeo = 5 * HZ; -- dev->hw_features = AIROHA_HW_FEATURES | NETIF_F_LRO; +- dev->hw_features = AIROHA_HW_FEATURES | NETIF_F_GRO_HW; - dev->features |= AIROHA_HW_FEATURES; - dev->vlan_features = AIROHA_HW_FEATURES; - dev->dev.of_node = np; @@ -865,16 +904,16 @@ Signed-off-by: Lorenzo Bianconi } static int airoha_register_gdm_devices(struct airoha_eth *eth) -@@ -3394,7 +3456,7 @@ static int airoha_register_gdm_devices(s +@@ -3503,7 +3566,7 @@ static int airoha_register_gdm_devices(s if (!port) continue; - err = register_netdev(port->dev); -+ err = register_netdev(port->dev->dev); ++ err = register_netdev(netdev_from_priv(port->dev)); if (err) return err; } -@@ -3503,16 +3565,18 @@ error_napi_stop: +@@ -3612,16 +3675,22 @@ error_napi_stop: for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -885,18 +924,23 @@ Signed-off-by: Lorenzo Bianconi - if (port->dev->reg_state == NETREG_REGISTERED) { + dev = port->dev; -+ if (dev && dev->dev->reg_state == NETREG_REGISTERED) { ++ if (dev) { ++ struct net_device *netdev = netdev_from_priv(dev); ++ ++ if (netdev->reg_state == NETREG_REGISTERED) { #if defined(CONFIG_PCS_AIROHA) - if (airhoa_is_phy_external(port)) +- if (airhoa_is_phy_external(port)) - phylink_destroy(port->phylink); -+ phylink_destroy(dev->phylink); ++ if (airhoa_is_phy_external(port)) ++ phylink_destroy(dev->phylink); #endif - unregister_netdev(port->dev); -+ unregister_netdev(dev->dev); ++ unregister_netdev(netdev); ++ } } airoha_metadata_dst_free(port); } -@@ -3534,15 +3598,19 @@ static void airoha_remove(struct platfor +@@ -3643,15 +3712,19 @@ static void airoha_remove(struct platfor for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -914,25 +958,24 @@ Signed-off-by: Lorenzo Bianconi + + dev = port->dev; + if (dev) -+ unregister_netdev(dev->dev); ++ unregister_netdev(netdev_from_priv(dev)); airoha_metadata_dst_free(port); } airoha_hw_cleanup(eth); --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -547,17 +547,22 @@ struct airoha_qdma { +@@ -547,17 +547,21 @@ struct airoha_qdma { struct airoha_queue q_rx[AIROHA_NUM_RX_RING]; }; -struct airoha_gdm_port { - struct airoha_qdma *qdma; -- struct airoha_eth *eth; +struct airoha_gdm_dev { + struct airoha_gdm_port *port; - struct net_device *dev; + struct airoha_eth *eth; +- struct net_device *dev; - int id; - int nbq; -+ struct airoha_eth *eth; #if defined(CONFIG_PCS_AIROHA) struct phylink *phylink; @@ -948,7 +991,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_hw_stats stats; -@@ -691,8 +696,8 @@ static inline bool airoha_qdma_is_lro_qu +@@ -691,8 +695,8 @@ static inline bool airoha_qdma_is_lro_qu } int airoha_get_fe_port(struct airoha_gdm_port *port); @@ -1007,12 +1050,33 @@ Signed-off-by: Lorenzo Bianconi if (dsa_port >= 0 || eth->ports[1]) pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id; -@@ -1485,7 +1488,7 @@ void airoha_ppe_check_skb(struct airoha_ +@@ -1484,8 +1487,8 @@ void airoha_ppe_check_skb(struct airoha_ + void airoha_ppe_init_upd_mem(struct airoha_gdm_port *port) { ++ struct net_device *dev = netdev_from_priv(port->dev); struct airoha_eth *eth = port->qdma->eth; - struct net_device *dev = port->dev; -+ struct net_device *dev = port->dev->dev; const u8 *addr = dev->dev_addr; u32 val; +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2760,6 +2760,17 @@ static inline void *netdev_priv(const st + return (void *)dev->priv; + } + ++/** ++ * netdev_from_priv() - get network device from priv ++ * @priv: network device private data ++ * ++ * Returns: net_device to which @priv belongs ++ */ ++static inline struct net_device *netdev_from_priv(const void *priv) ++{ ++ return container_of(priv, struct net_device, priv); ++} ++ + /* Set the sysfs physical device reference for the network logical device + * if set prior to registration will cause a symlink during initialization. + */ diff --git a/target/linux/airoha/patches-6.18/920-02-net-airoha-Move-airoha_qdma-pointer-in-airoha_gdm_de.patch b/target/linux/airoha/patches-6.18/920-02-net-airoha-Move-airoha_qdma-pointer-in-airoha_gdm_de.patch index 8f3dd2d1d1e..b95371056fc 100644 --- a/target/linux/airoha/patches-6.18/920-02-net-airoha-Move-airoha_qdma-pointer-in-airoha_gdm_de.patch +++ b/target/linux/airoha/patches-6.18/920-02-net-airoha-Move-airoha_qdma-pointer-in-airoha_gdm_de.patch @@ -24,7 +24,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -80,9 +80,10 @@ static bool airhoa_is_phy_external(struc +@@ -81,9 +81,10 @@ static bool airhoa_is_phy_external(struc } #endif @@ -37,7 +37,7 @@ Signed-off-by: Lorenzo Bianconi u32 val, reg; reg = airoha_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H -@@ -94,7 +95,7 @@ static void airoha_set_macaddr(struct ai +@@ -95,7 +96,7 @@ static void airoha_set_macaddr(struct ai airoha_fe_wr(eth, REG_FE_MAC_LMIN(reg), val); airoha_fe_wr(eth, REG_FE_MAC_LMAX(reg), val); @@ -46,7 +46,7 @@ Signed-off-by: Lorenzo Bianconi } static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr, -@@ -110,10 +111,10 @@ static void airoha_set_gdm_port_fwd_cfg( +@@ -111,10 +112,10 @@ static void airoha_set_gdm_port_fwd_cfg( FIELD_PREP(GDM_UCFQ_MASK, val)); } @@ -60,7 +60,24 @@ Signed-off-by: Lorenzo Bianconi u32 vip_port; vip_port = eth->soc->ops.get_vip_port(port, port->nbq); -@@ -1004,10 +1005,13 @@ static void airoha_qdma_wake_netdev_txqs +@@ -485,8 +486,7 @@ static bool airoha_fe_lro_is_enabled(str + + static void airoha_dev_lro_enable(struct airoha_gdm_dev *dev) + { +- struct airoha_gdm_port *port = dev->port; +- struct airoha_qdma *qdma = port->qdma; ++ struct airoha_qdma *qdma = dev->qdma; + struct airoha_eth *eth = qdma->eth; + int qdma_id = qdma - ð->qdma[0]; + int i, lro_queue_index = 0; +@@ -1097,13 +1097,18 @@ static void airoha_qdma_wake_netdev_txqs + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; ++ struct airoha_gdm_dev *dev; + struct net_device *netdev; + int j; + if (!port) continue; @@ -72,11 +89,8 @@ Signed-off-by: Lorenzo Bianconi + if (dev->qdma != qdma) continue; -- dev = port->dev; - for (j = 0; j < dev->dev->num_tx_queues; j++) { - if (airoha_qdma_get_txq(qdma, j) != qid) - continue; -@@ -1712,9 +1716,10 @@ static void airoha_qdma_stop_napi(struct + netdev = netdev_from_priv(port->dev); +@@ -1811,9 +1816,10 @@ static void airoha_qdma_stop_napi(struct } } @@ -89,16 +103,16 @@ Signed-off-by: Lorenzo Bianconi u32 val, i = 0; spin_lock(&port->stats.lock); -@@ -1861,7 +1866,7 @@ static int airoha_dev_open(struct net_de +@@ -1981,7 +1987,7 @@ static int airoha_dev_open(struct net_de int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN; struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; - struct airoha_qdma *qdma = port->qdma; + struct airoha_qdma *qdma = dev->qdma; + struct airoha_eth *eth = qdma->eth; + int qdma_id = qdma - ð->qdma[0]; u32 pse_port = FE_PSE_PORT_PPE1; - - #if defined(CONFIG_PCS_AIROHA) -@@ -1878,7 +1883,7 @@ static int airoha_dev_open(struct net_de +@@ -2011,7 +2017,7 @@ static int airoha_dev_open(struct net_de #endif netif_tx_start_all_queues(netdev); @@ -107,12 +121,13 @@ Signed-off-by: Lorenzo Bianconi if (err) return err; -@@ -1915,11 +1920,11 @@ static int airoha_dev_stop(struct net_de +@@ -2052,12 +2058,12 @@ 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 = port->qdma; + struct airoha_qdma *qdma = dev->qdma; + struct airoha_eth *eth = qdma->eth; int i; netif_tx_disable(netdev); @@ -121,7 +136,7 @@ Signed-off-by: Lorenzo Bianconi for (i = 0; i < netdev->num_tx_queues; i++) netdev_tx_reset_subqueue(netdev, i); -@@ -1952,21 +1957,21 @@ static int airoha_dev_stop(struct net_de +@@ -2092,21 +2098,21 @@ static int airoha_dev_stop(struct net_de static int airoha_dev_set_macaddr(struct net_device *netdev, void *p) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -147,7 +162,7 @@ Signed-off-by: Lorenzo Bianconi u32 val, pse_port, chan; int i, src_port; -@@ -2013,7 +2018,7 @@ static int airoha_set_gdm2_loopback(stru +@@ -2153,7 +2159,7 @@ static int airoha_set_gdm2_loopback(stru __field_prep(SP_CPORT_MASK(val), FE_PSE_PORT_CDM2)); for (i = 0; i < eth->soc->num_ppe; i++) @@ -156,20 +171,20 @@ Signed-off-by: Lorenzo Bianconi if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) { u32 mask = FC_ID_OF_SRC_PORT_MASK(nbq); -@@ -2033,9 +2038,9 @@ static int airoha_dev_init(struct net_de +@@ -2173,9 +2179,9 @@ static int airoha_dev_init(struct net_de int i; /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ - port->qdma = ð->qdma[!airoha_is_lan_gdm_port(port)]; -- dev->dev->irq = port->qdma->irq_banks[0].irq; +- netdev->irq = port->qdma->irq_banks[0].irq; - airoha_set_macaddr(port, netdev->dev_addr); + dev->qdma = ð->qdma[!airoha_is_lan_gdm_port(port)]; -+ dev->dev->irq = dev->qdma->irq_banks[0].irq; ++ netdev->irq = dev->qdma->irq_banks[0].irq; + airoha_set_macaddr(dev, netdev->dev_addr); switch (port->id) { case AIROHA_GDM3_IDX: -@@ -2044,7 +2049,7 @@ static int airoha_dev_init(struct net_de +@@ -2184,7 +2190,7 @@ static int airoha_dev_init(struct net_de if (!eth->ports[1]) { int err; @@ -178,7 +193,7 @@ Signed-off-by: Lorenzo Bianconi if (err) return err; } -@@ -2054,8 +2059,7 @@ static int airoha_dev_init(struct net_de +@@ -2194,8 +2200,7 @@ static int airoha_dev_init(struct net_de } for (i = 0; i < eth->soc->num_ppe; i++) @@ -188,7 +203,7 @@ Signed-off-by: Lorenzo Bianconi return 0; } -@@ -2067,7 +2071,7 @@ static void airoha_dev_get_stats64(struc +@@ -2207,7 +2212,7 @@ static void airoha_dev_get_stats64(struc struct airoha_gdm_port *port = dev->port; unsigned int start; @@ -197,7 +212,7 @@ Signed-off-by: Lorenzo Bianconi do { start = u64_stats_fetch_begin(&port->stats.syncp); storage->rx_packets = port->stats.rx_ok_pkts; -@@ -2087,8 +2091,8 @@ static int airoha_dev_change_mtu(struct +@@ -2227,8 +2232,8 @@ static int airoha_dev_change_mtu(struct { struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; @@ -207,7 +222,7 @@ Signed-off-by: Lorenzo Bianconi airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), GDM_LONG_LEN_MASK, -@@ -2162,10 +2166,10 @@ static u32 airoha_get_dsa_tag(struct sk_ +@@ -2302,10 +2307,10 @@ static u32 airoha_get_dsa_tag(struct sk_ #endif } @@ -221,7 +236,17 @@ Signed-off-by: Lorenzo Bianconi switch (eth->soc->version) { case 0x7583: -@@ -2183,8 +2187,7 @@ static int airoha_dev_set_features(struc +@@ -2322,8 +2327,7 @@ static netdev_features_t airoha_dev_fix_ + netdev_features_t features) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_gdm_port *port = dev->port; +- struct airoha_qdma *qdma = port->qdma; ++ struct airoha_qdma *qdma = dev->qdma; + + if (qdma->users > 1) + features &= ~NETIF_F_GRO_HW; +@@ -2336,8 +2340,7 @@ static int airoha_dev_set_features(struc { netdev_features_t diff = netdev->features ^ features; struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -230,21 +255,8 @@ Signed-off-by: Lorenzo Bianconi + struct airoha_qdma *qdma = dev->qdma; struct airoha_eth *eth = qdma->eth; int qdma_id = qdma - ð->qdma[0]; - int i; -@@ -2226,10 +2229,10 @@ static int airoha_dev_set_features(struc - if (!p) - continue; - -- if (p->qdma != qdma) -+ d = p->dev; -+ if (d->qdma != qdma) - continue; -- d = p->dev; - if (d->dev == netdev) - continue; - -@@ -2246,8 +2249,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2356,8 +2359,7 @@ static netdev_tx_t airoha_dev_xmit(struc struct net_device *netdev) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -254,7 +266,7 @@ Signed-off-by: Lorenzo Bianconi u32 nr_frags, tag, msg0, msg1, len; struct airoha_queue_entry *e; struct netdev_queue *txq; -@@ -2285,7 +2287,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2395,7 +2397,7 @@ static netdev_tx_t airoha_dev_xmit(struc } } @@ -263,7 +275,7 @@ Signed-off-by: Lorenzo Bianconi msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) | FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f); -@@ -2388,8 +2390,7 @@ static void airoha_ethtool_get_drvinfo(s +@@ -2498,8 +2500,7 @@ static void airoha_ethtool_get_drvinfo(s struct ethtool_drvinfo *info) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -273,7 +285,7 @@ Signed-off-by: Lorenzo Bianconi strscpy(info->driver, eth->dev->driver->name, sizeof(info->driver)); strscpy(info->bus_info, dev_name(eth->dev), sizeof(info->bus_info)); -@@ -2402,7 +2403,7 @@ static void airoha_ethtool_get_mac_stats +@@ -2512,7 +2513,7 @@ static void airoha_ethtool_get_mac_stats struct airoha_gdm_port *port = dev->port; unsigned int start; @@ -282,7 +294,7 @@ Signed-off-by: Lorenzo Bianconi do { start = u64_stats_fetch_begin(&port->stats.syncp); stats->FramesTransmittedOK = port->stats.tx_ok_pkts; -@@ -2442,7 +2443,7 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2552,7 +2553,7 @@ airoha_ethtool_get_rmon_stats(struct net ARRAY_SIZE(hw_stats->rx_len) + 1); *ranges = airoha_ethtool_rmon_ranges; @@ -291,7 +303,7 @@ Signed-off-by: Lorenzo Bianconi do { int i; -@@ -2462,18 +2463,17 @@ static int airoha_qdma_set_chan_tx_sched +@@ -2572,18 +2573,17 @@ static int airoha_qdma_set_chan_tx_sched const u16 *weights, u8 n_weights) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -312,7 +324,7 @@ Signed-off-by: Lorenzo Bianconi TWRR_RW_CMD_MASK | FIELD_PREP(TWRR_CHAN_IDX_MASK, channel) | FIELD_PREP(TWRR_QUEUE_IDX_MASK, i) | -@@ -2481,13 +2481,12 @@ static int airoha_qdma_set_chan_tx_sched +@@ -2591,13 +2591,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, @@ -328,7 +340,7 @@ Signed-off-by: Lorenzo Bianconi CHAN_QOS_MODE_MASK(channel), __field_prep(CHAN_QOS_MODE_MASK(channel), mode)); -@@ -2553,9 +2552,9 @@ static int airoha_qdma_get_tx_ets_stats( +@@ -2663,9 +2662,9 @@ static int airoha_qdma_get_tx_ets_stats( struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; @@ -340,7 +352,7 @@ Signed-off-by: Lorenzo Bianconi REG_CNTR_VAL((channel << 1) + 1)); u64 tx_packets = (cpu_tx_packets - port->cpu_tx_packets) + (fwd_tx_packets - port->fwd_tx_packets); -@@ -2819,17 +2818,16 @@ static int airoha_qdma_set_tx_rate_limit +@@ -2929,17 +2928,16 @@ static int airoha_qdma_set_tx_rate_limit u32 bucket_size) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -360,7 +372,7 @@ Signed-off-by: Lorenzo Bianconi REG_EGRESS_TRTCM_CFG, i, rate, bucket_size); if (err) -@@ -2879,11 +2877,11 @@ static int airoha_tc_htb_alloc_leaf_queu +@@ -2989,11 +2987,11 @@ static int airoha_tc_htb_alloc_leaf_queu return 0; } @@ -374,7 +386,7 @@ Signed-off-by: Lorenzo Bianconi int i; for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { -@@ -2962,7 +2960,6 @@ static int airoha_dev_tc_matchall(struct +@@ -3072,7 +3070,6 @@ static int airoha_dev_tc_matchall(struct { enum trtcm_unit_type unit_type = TRTCM_BYTE_UNIT; struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -382,7 +394,7 @@ Signed-off-by: Lorenzo Bianconi u32 rate = 0, bucket_size = 0; switch (f->command) { -@@ -2987,7 +2984,7 @@ static int airoha_dev_tc_matchall(struct +@@ -3097,7 +3094,7 @@ static int airoha_dev_tc_matchall(struct fallthrough; } case TC_CLSMATCHALL_DESTROY: @@ -391,7 +403,7 @@ Signed-off-by: Lorenzo Bianconi unit_type); default: return -EOPNOTSUPP; -@@ -2999,8 +2996,7 @@ static int airoha_dev_setup_tc_block_cb( +@@ -3109,8 +3106,7 @@ static int airoha_dev_setup_tc_block_cb( { struct net_device *netdev = cb_priv; struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -401,7 +413,7 @@ Signed-off-by: Lorenzo Bianconi if (!tc_can_offload(netdev)) return -EOPNOTSUPP; -@@ -3235,7 +3231,7 @@ static void airoha_mac_link_up(struct ph +@@ -3346,7 +3342,7 @@ static void airoha_mac_link_up(struct ph struct airoha_gdm_dev *dev = container_of(config, struct airoha_gdm_dev, phylink_config); struct airoha_gdm_port *port = dev->port; @@ -417,10 +429,10 @@ Signed-off-by: Lorenzo Bianconi struct airoha_gdm_dev { struct airoha_gdm_port *port; + struct airoha_qdma *qdma; - struct net_device *dev; struct airoha_eth *eth; -@@ -559,7 +560,6 @@ struct airoha_gdm_dev { + #if defined(CONFIG_PCS_AIROHA) +@@ -558,7 +559,6 @@ struct airoha_gdm_dev { }; struct airoha_gdm_port { @@ -428,7 +440,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_gdm_dev *dev; int id; int nbq; -@@ -695,19 +695,18 @@ static inline bool airoha_qdma_is_lro_qu +@@ -694,19 +694,18 @@ static inline bool airoha_qdma_is_lro_qu return !!(AIROHA_RXQ_LRO_EN_MASK & BIT(qid)); } @@ -483,11 +495,11 @@ Signed-off-by: Lorenzo Bianconi -void airoha_ppe_init_upd_mem(struct airoha_gdm_port *port) +void airoha_ppe_init_upd_mem(struct airoha_gdm_dev *dev) { +- struct net_device *dev = netdev_from_priv(port->dev); - struct airoha_eth *eth = port->qdma->eth; -- struct net_device *dev = port->dev->dev; - const u8 *addr = dev->dev_addr; ++ struct net_device *netdev = netdev_from_priv(dev); + struct airoha_gdm_port *port = dev->port; -+ struct net_device *netdev = dev->dev; + struct airoha_eth *eth = dev->eth; + const u8 *addr = netdev->dev_addr; u32 val; diff --git a/target/linux/airoha/patches-6.18/920-03-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airoha_.patch b/target/linux/airoha/patches-6.18/920-03-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airoha_.patch index 3ae068204bc..64ed102d3a6 100644 --- a/target/linux/airoha/patches-6.18/920-03-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airoha_.patch +++ b/target/linux/airoha/patches-6.18/920-03-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airoha_.patch @@ -23,7 +23,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -82,12 +82,10 @@ static bool airhoa_is_phy_external(struc +@@ -83,12 +83,10 @@ static bool airhoa_is_phy_external(struc static void airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr) { @@ -37,18 +37,18 @@ Signed-off-by: Lorenzo Bianconi val = (addr[0] << 16) | (addr[1] << 8) | addr[2]; airoha_fe_wr(eth, reg, val); -@@ -2038,7 +2036,7 @@ static int airoha_dev_init(struct net_de +@@ -2179,7 +2177,7 @@ static int airoha_dev_init(struct net_de int i; /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ - dev->qdma = ð->qdma[!airoha_is_lan_gdm_port(port)]; + dev->qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; - dev->dev->irq = dev->qdma->irq_banks[0].irq; + netdev->irq = dev->qdma->irq_banks[0].irq; airoha_set_macaddr(dev, netdev->dev_addr); --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -664,8 +664,10 @@ static inline u16 airoha_qdma_get_txq(st +@@ -663,8 +663,10 @@ static inline u16 airoha_qdma_get_txq(st return qid % ARRAY_SIZE(qdma->q_tx); } diff --git a/target/linux/airoha/patches-6.18/920-04-net-airoha-Move-qos_sq_bmap-in-airoha_gdm_dev-struct.patch b/target/linux/airoha/patches-6.18/920-04-net-airoha-Move-qos_sq_bmap-in-airoha_gdm_dev-struct.patch index 7e0077124ac..3bbcaab9366 100644 --- a/target/linux/airoha/patches-6.18/920-04-net-airoha-Move-qos_sq_bmap-in-airoha_gdm_dev-struct.patch +++ b/target/linux/airoha/patches-6.18/920-04-net-airoha-Move-qos_sq_bmap-in-airoha_gdm_dev-struct.patch @@ -22,7 +22,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -2835,30 +2835,40 @@ static int airoha_qdma_set_tx_rate_limit +@@ -2945,30 +2945,46 @@ static int airoha_qdma_set_tx_rate_limit return 0; } @@ -36,6 +36,7 @@ Signed-off-by: Lorenzo Bianconi - int err, num_tx_queues = netdev->real_num_tx_queues; - struct airoha_gdm_dev *dev = netdev_priv(netdev); - struct airoha_gdm_port *port = dev->port; ++ int err; if (opt->parent_classid != TC_HTB_CLASSID_ROOT) { NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid"); @@ -45,7 +46,13 @@ Signed-off-by: Lorenzo Bianconi - err = airoha_qdma_set_tx_rate_limit(netdev, channel, rate, - opt->quantum); - if (err) { -+ return airoha_qdma_set_tx_rate_limit(dev, channel, rate, opt->quantum); ++ err = airoha_qdma_set_tx_rate_limit(dev, channel, rate, opt->quantum); ++ if (err) + NL_SET_ERR_MSG_MOD(opt->extack, + "failed configuring htb offload"); +- return err; ++ ++ return err; +} + +static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev, @@ -60,9 +67,7 @@ Signed-off-by: Lorenzo Bianconi + * in use by another net_device running on the same QDMA block. + */ + if (test_and_set_bit(channel, qdma->qos_channel_map)) { - NL_SET_ERR_MSG_MOD(opt->extack, -- "failed configuring htb offload"); -- return err; ++ NL_SET_ERR_MSG_MOD(opt->extack, + "qdma qos channel already in use"); + return -EBUSY; } @@ -75,7 +80,7 @@ Signed-off-by: Lorenzo Bianconi err = netif_set_real_num_tx_queues(netdev, num_tx_queues + 1); if (err) { -@@ -2866,13 +2876,17 @@ static int airoha_tc_htb_alloc_leaf_queu +@@ -2976,13 +2992,17 @@ static int airoha_tc_htb_alloc_leaf_queu opt->quantum); NL_SET_ERR_MSG_MOD(opt->extack, "failed setting real_num_tx_queues"); @@ -95,7 +100,7 @@ Signed-off-by: Lorenzo Bianconi } static int airoha_qdma_set_rx_meter(struct airoha_gdm_dev *dev, -@@ -3053,11 +3067,13 @@ static int airoha_dev_setup_tc_block(str +@@ -3163,11 +3183,13 @@ static int airoha_dev_setup_tc_block(str static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -111,7 +116,7 @@ Signed-off-by: Lorenzo Bianconi } static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev, -@@ -3065,9 +3081,8 @@ static int airoha_tc_htb_delete_leaf_que +@@ -3175,9 +3197,8 @@ static int airoha_tc_htb_delete_leaf_que { u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -122,7 +127,7 @@ Signed-off-by: Lorenzo Bianconi NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); return -EINVAL; } -@@ -3080,10 +3095,9 @@ static int airoha_tc_htb_delete_leaf_que +@@ -3190,10 +3211,9 @@ static int airoha_tc_htb_delete_leaf_que static int airoha_tc_htb_destroy(struct net_device *netdev) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -134,7 +139,7 @@ Signed-off-by: Lorenzo Bianconi airoha_tc_remove_htb_queue(netdev, q); return 0; -@@ -3094,9 +3108,8 @@ static int airoha_tc_get_htb_get_leaf_qu +@@ -3204,9 +3224,8 @@ static int airoha_tc_get_htb_get_leaf_qu { u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -145,7 +150,7 @@ Signed-off-by: Lorenzo Bianconi NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); return -EINVAL; } -@@ -3115,6 +3128,7 @@ static int airoha_tc_setup_qdisc_htb(str +@@ -3225,6 +3244,7 @@ static int airoha_tc_setup_qdisc_htb(str case TC_HTB_DESTROY: return airoha_tc_htb_destroy(dev); case TC_HTB_NODE_MODIFY: @@ -164,7 +169,7 @@ Signed-off-by: Lorenzo Bianconi }; struct airoha_gdm_dev { -@@ -557,6 +559,8 @@ struct airoha_gdm_dev { +@@ -556,6 +558,8 @@ struct airoha_gdm_dev { struct phylink *phylink; struct phylink_config phylink_config; #endif @@ -173,7 +178,7 @@ Signed-off-by: Lorenzo Bianconi }; struct airoha_gdm_port { -@@ -566,8 +570,6 @@ struct airoha_gdm_port { +@@ -565,8 +569,6 @@ struct airoha_gdm_port { struct airoha_hw_stats stats; diff --git a/target/linux/airoha/patches-6.18/920-05-net-airoha-Move-cpu-fwd-_tx_packets-in-airoha_gdm_de.patch b/target/linux/airoha/patches-6.18/920-05-net-airoha-Move-cpu-fwd-_tx_packets-in-airoha_gdm_de.patch index 9522e36b71d..dfe8662b563 100644 --- a/target/linux/airoha/patches-6.18/920-05-net-airoha-Move-cpu-fwd-_tx_packets-in-airoha_gdm_de.patch +++ b/target/linux/airoha/patches-6.18/920-05-net-airoha-Move-cpu-fwd-_tx_packets-in-airoha_gdm_de.patch @@ -21,7 +21,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -2548,19 +2548,17 @@ static int airoha_qdma_get_tx_ets_stats( +@@ -2658,19 +2658,17 @@ static int airoha_qdma_get_tx_ets_stats( struct tc_ets_qopt_offload *opt) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -50,7 +50,7 @@ Signed-off-by: Lorenzo Bianconi } --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -561,6 +561,9 @@ struct airoha_gdm_dev { +@@ -560,6 +560,9 @@ struct airoha_gdm_dev { #endif DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); @@ -60,7 +60,7 @@ Signed-off-by: Lorenzo Bianconi }; struct airoha_gdm_port { -@@ -570,10 +573,6 @@ struct airoha_gdm_port { +@@ -569,10 +572,6 @@ struct airoha_gdm_port { struct airoha_hw_stats stats; diff --git a/target/linux/airoha/patches-6.18/920-06-net-airoha-Support-multiple-net_devices-for-a-single.patch b/target/linux/airoha/patches-6.18/920-06-net-airoha-Support-multiple-net_devices-for-a-single.patch index ad848a432a7..870b24371b5 100644 --- a/target/linux/airoha/patches-6.18/920-06-net-airoha-Support-multiple-net_devices-for-a-single.patch +++ b/target/linux/airoha/patches-6.18/920-06-net-airoha-Support-multiple-net_devices-for-a-single.patch @@ -56,7 +56,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -115,7 +115,7 @@ static int airoha_set_vip_for_gdm_port(s +@@ -116,7 +116,7 @@ static int airoha_set_vip_for_gdm_port(s struct airoha_eth *eth = dev->eth; u32 vip_port; @@ -65,7 +65,7 @@ Signed-off-by: Lorenzo Bianconi if (enable) { airoha_fe_set(eth, REG_FE_VIP_PORT_EN, vip_port); airoha_fe_set(eth, REG_FE_IFC_PORT_EN, vip_port); -@@ -619,30 +619,26 @@ static int airoha_qdma_fill_rx_queue(str +@@ -646,30 +646,26 @@ static int airoha_qdma_fill_rx_queue(str return nframes; } @@ -100,82 +100,65 @@ Signed-off-by: Lorenzo Bianconi + + if (p >= ARRAY_SIZE(eth->ports)) + return ERR_PTR(-ENODEV); -+ + +- return port >= ARRAY_SIZE(eth->ports) ? -EINVAL : port; + port = eth->ports[p]; + if (!port) + return ERR_PTR(-ENODEV); + + if (d >= ARRAY_SIZE(port->devs)) + return ERR_PTR(-ENODEV); - -- return port >= ARRAY_SIZE(eth->ports) ? -EINVAL : port; ++ + return port->devs[d] ? port->devs[d] : ERR_PTR(-ENODEV); } - static int airoha_qdma_lro_rx_process(struct airoha_queue *q, -@@ -736,9 +732,8 @@ static int airoha_qdma_rx_process(struct + static struct sk_buff *airoha_qdma_lro_rx_skb(struct airoha_queue *q, +@@ -841,9 +837,9 @@ static int airoha_qdma_rx_process(struct struct airoha_queue_entry *e = &q->entry[q->tail]; struct airoha_qdma_desc *desc = &q->desc[q->tail]; u32 hash, reason, msg1, desc_ctrl; - struct airoha_gdm_port *port; -- struct net_device *netdev; -- int data_len, len, p; + struct airoha_gdm_dev *dev; + struct net_device *netdev; +- int data_len, len, p; + int data_len, len; struct page *page; desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); -@@ -759,15 +754,10 @@ static int airoha_qdma_rx_process(struct +@@ -864,15 +860,11 @@ static int airoha_qdma_rx_process(struct if (!len || data_len < len) goto free_frag; - p = airoha_qdma_get_gdm_port(eth, desc); - if (p < 0 || !eth->ports[p]) -- goto free_frag; -- -- port = eth->ports[p]; -- if (!port->dev) + dev = airoha_qdma_get_gdm_dev(eth, desc); + if (IS_ERR(dev)) goto free_frag; -- netdev = port->dev->dev; +- port = eth->ports[p]; +- if (!port->dev) +- goto free_frag; +- +- netdev = netdev_from_priv(port->dev); ++ netdev = netdev_from_priv(dev); if (!q->skb) { /* first buffer */ - q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM, - q->buf_size); -@@ -776,14 +766,14 @@ static int airoha_qdma_rx_process(struct - - skb_reserve(q->skb, AIROHA_RX_HEADROOM); - __skb_put(q->skb, len); -- q->skb->dev = netdev; -+ q->skb->dev = dev->dev; - q->skb->ip_summed = CHECKSUM_UNNECESSARY; - skb_record_rx_queue(q->skb, qid); - - if (airoha_qdma_lro_rx_process(q, desc) < 0) - goto free_frag; - -- q->skb->protocol = eth_type_trans(q->skb, netdev); -+ q->skb->protocol = eth_type_trans(q->skb, dev->dev); - skb_mark_for_recycle(q->skb); - } else { /* scattered frame */ - struct skb_shared_info *shinfo = skb_shinfo(q->skb); -@@ -800,7 +790,9 @@ static int airoha_qdma_rx_process(struct - if (FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl)) + q->skb = airoha_qdma_build_rx_skb(q, desc, e, netdev); + if (!q->skb) +@@ -893,6 +885,8 @@ static int airoha_qdma_rx_process(struct continue; -- if (netdev_uses_dsa(netdev)) { -+ if (netdev_uses_dsa(dev->dev)) { + if (netdev_uses_dsa(netdev)) { + struct airoha_gdm_port *port = dev->port; + /* PPE module requires untagged packets to work * properly and it provides DSA port index via the * DMA descriptor. Report DSA tag to the DSA stack -@@ -997,24 +989,27 @@ static void airoha_qdma_wake_netdev_txqs +@@ -1095,26 +1089,29 @@ static void airoha_qdma_wake_netdev_txqs for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; - struct airoha_gdm_dev *dev; +- struct net_device *netdev; - int j; + int d; @@ -187,6 +170,7 @@ Signed-off-by: Lorenzo Bianconi - continue; + for (d = 0; d < ARRAY_SIZE(port->devs); d++) { + struct airoha_gdm_dev *dev = port->devs[d]; ++ struct net_device *netdev; + int j; - if (dev->qdma != qdma) @@ -194,36 +178,75 @@ Signed-off-by: Lorenzo Bianconi + if (!dev) + continue; -- for (j = 0; j < dev->dev->num_tx_queues; j++) { +- netdev = netdev_from_priv(port->dev); +- for (j = 0; j < netdev->num_tx_queues; j++) { - if (airoha_qdma_get_txq(qdma, j) != qid) + if (dev->qdma != qdma) continue; -- netif_wake_subqueue(dev->dev, j); -+ for (j = 0; j < dev->dev->num_tx_queues; j++) { +- netif_wake_subqueue(netdev, j); ++ netdev = netdev_from_priv(dev); ++ for (j = 0; j < netdev->num_tx_queues; j++) { + if (airoha_qdma_get_txq(qdma, j) != qid) + continue; + -+ netif_wake_subqueue(dev->dev, j); ++ netif_wake_subqueue(netdev, j); + } } } q->txq_stopped = false; -@@ -1903,11 +1898,9 @@ static int airoha_dev_open(struct net_de +@@ -1961,22 +1958,32 @@ static void airoha_update_hw_stats(struc + + static void airoha_update_netdev_features(struct airoha_gdm_dev *dev) + { +- struct airoha_gdm_port *port = dev->port; + struct airoha_eth *eth = dev->eth; + int i; + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { +- struct airoha_gdm_port *p = eth->ports[i]; +- struct net_device *netdev; ++ struct airoha_gdm_port *port = eth->ports[i]; ++ int j; + +- if (!p) ++ if (!port) + continue; + +- netdev = netdev_from_priv(p->dev); +- if (netdev->reg_state != NETREG_REGISTERED) +- continue; ++ for (j = 0; j < ARRAY_SIZE(port->devs); j++) { ++ struct airoha_gdm_dev *iter_dev = port->devs[j]; ++ struct net_device *netdev; ++ ++ if (!iter_dev || iter_dev == dev) ++ continue; ++ ++ if (iter_dev->qdma != dev->qdma) ++ continue; ++ ++ netdev = netdev_from_priv(iter_dev); ++ if (netdev->reg_state != NETREG_REGISTERED) ++ continue; + +- netdev_update_features(netdev); ++ netdev_update_features(netdev); ++ } + } + } + +@@ -2037,7 +2044,8 @@ static int airoha_dev_open(struct net_de GLOBAL_CFG_RX_DMA_EN_MASK); - atomic_inc(&qdma->users); + qdma->users++; -- if (port->id == AIROHA_GDM2_IDX && -- airoha_ppe_is_enabled(qdma->eth, 1)) { -- /* For PPE2 always use secondary cpu port. */ +- if (port->id == AIROHA_GDM2_IDX && airoha_ppe_is_enabled(eth, 1)) { + if (!airoha_is_lan_gdm_dev(dev) && -+ airoha_ppe_is_enabled(qdma->eth, 1)) ++ airoha_ppe_is_enabled(eth, 1)) { + /* For PPE2 always use secondary cpu port. */ pse_port = FE_PSE_PORT_PPE2; -- } - airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), - pse_port); - -@@ -2002,7 +1995,7 @@ static int airoha_set_gdm2_loopback(stru + } +@@ -2143,7 +2151,7 @@ static int airoha_set_gdm2_loopback(stru airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX)); airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX)); @@ -232,7 +255,7 @@ Signed-off-by: Lorenzo Bianconi if (src_port < 0) return src_port; -@@ -2019,7 +2012,7 @@ static int airoha_set_gdm2_loopback(stru +@@ -2160,7 +2168,7 @@ static int airoha_set_gdm2_loopback(stru airoha_ppe_set_cpu_port(dev, i, AIROHA_GDM2_IDX); if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) { @@ -241,7 +264,7 @@ Signed-off-by: Lorenzo Bianconi airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, mask, __field_prep(mask, AIROHA_GDM2_IDX)); -@@ -2033,7 +2026,7 @@ static int airoha_dev_init(struct net_de +@@ -2174,7 +2182,7 @@ static int airoha_dev_init(struct net_de struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; struct airoha_eth *eth = dev->eth; @@ -250,7 +273,7 @@ Signed-off-by: Lorenzo Bianconi /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ dev->qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; -@@ -2056,8 +2049,8 @@ static int airoha_dev_init(struct net_de +@@ -2197,8 +2205,8 @@ static int airoha_dev_init(struct net_de break; } @@ -261,42 +284,7 @@ Signed-off-by: Lorenzo Bianconi return 0; } -@@ -2222,20 +2215,26 @@ static int airoha_dev_set_features(struc - } else { - for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { - struct airoha_gdm_port *p = eth->ports[i]; -- struct airoha_gdm_dev *d; -+ int j; - - if (!p) - continue; - -- d = p->dev; -- if (d->qdma != qdma) -- continue; -+ for (j = 0; j < ARRAY_SIZE(p->devs); j++) { -+ struct airoha_gdm_dev *d = p->devs[j]; - -- if (d->dev == netdev) -- continue; -+ if (!d) -+ continue; - -- if (d->dev->features & NETIF_F_LRO) -- return 0; -+ if (d->qdma != qdma) -+ continue; -+ -+ if (d->dev == netdev) -+ continue; -+ -+ if (d->dev->features & NETIF_F_LRO) -+ return 0; -+ } - } - airoha_fe_lro_disable(eth, qdma_id); - } -@@ -2286,7 +2285,8 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2396,7 +2404,8 @@ static netdev_tx_t airoha_dev_xmit(struc } fport = airoha_get_fe_port(dev); @@ -306,7 +294,7 @@ Signed-off-by: Lorenzo Bianconi FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f); q = &qdma->q_tx[qid]; -@@ -3222,12 +3222,15 @@ bool airoha_is_valid_gdm_dev(struct airo +@@ -3339,12 +3348,15 @@ bool airoha_is_valid_gdm_dev(struct airo for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -324,7 +312,7 @@ Signed-off-by: Lorenzo Bianconi } return false; -@@ -3351,10 +3354,11 @@ static int airoha_setup_phylink(struct n +@@ -3468,10 +3480,11 @@ static int airoha_setup_phylink(struct n static int airoha_alloc_gdm_device(struct airoha_eth *eth, struct airoha_gdm_port *port, @@ -338,15 +326,15 @@ Signed-off-by: Lorenzo Bianconi int err; netdev = devm_alloc_etherdev_mqs(eth->dev, sizeof(*dev), -@@ -3372,7 +3376,6 @@ static int airoha_alloc_gdm_device(struc - netdev->hw_features = AIROHA_HW_FEATURES | NETIF_F_LRO; +@@ -3489,7 +3502,6 @@ static int airoha_alloc_gdm_device(struc + netdev->hw_features = AIROHA_HW_FEATURES | NETIF_F_GRO_HW; netdev->features |= AIROHA_HW_FEATURES; netdev->vlan_features = AIROHA_HW_FEATURES; - netdev->dev.of_node = np; SET_NETDEV_DEV(netdev, eth->dev); /* reserve hw queues for HTB offloading */ -@@ -3390,11 +3393,25 @@ static int airoha_alloc_gdm_device(struc +@@ -3507,10 +3519,24 @@ static int airoha_alloc_gdm_device(struc netdev->dev_addr); } @@ -364,7 +352,6 @@ Signed-off-by: Lorenzo Bianconi + + netdev->dev.of_node = of_node_get(np); dev = netdev_priv(netdev); - dev->dev = netdev; dev->port = port; - port->dev = dev; dev->eth = eth; @@ -373,7 +360,7 @@ Signed-off-by: Lorenzo Bianconi #if defined(CONFIG_PCS_AIROHA) if (airhoa_is_phy_external(port)) { -@@ -3412,7 +3429,8 @@ static int airoha_alloc_gdm_port(struct +@@ -3528,7 +3554,8 @@ static int airoha_alloc_gdm_port(struct { const __be32 *id_ptr = of_get_property(np, "reg", NULL); struct airoha_gdm_port *port; @@ -383,7 +370,7 @@ Signed-off-by: Lorenzo Bianconi u32 id; if (!id_ptr) { -@@ -3440,15 +3458,51 @@ static int airoha_alloc_gdm_port(struct +@@ -3556,15 +3583,51 @@ static int airoha_alloc_gdm_port(struct u64_stats_init(&port->stats.syncp); spin_lock_init(&port->stats.lock); port->id = id; @@ -438,7 +425,7 @@ Signed-off-by: Lorenzo Bianconi } static int airoha_register_gdm_devices(struct airoha_eth *eth) -@@ -3457,14 +3511,22 @@ static int airoha_register_gdm_devices(s +@@ -3573,14 +3636,22 @@ static int airoha_register_gdm_devices(s for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -448,7 +435,7 @@ Signed-off-by: Lorenzo Bianconi if (!port) continue; -- err = register_netdev(port->dev->dev); +- err = register_netdev(netdev_from_priv(port->dev)); - if (err) - return err; + for (j = 0; j < ARRAY_SIZE(port->devs); j++) { @@ -458,14 +445,14 @@ Signed-off-by: Lorenzo Bianconi + if (!dev) + continue; + -+ err = register_netdev(dev->dev); ++ err = register_netdev(netdev_from_priv(dev)); + if (err) + return err; + } } set_bit(DEV_STATE_REGISTERED, ð->state); -@@ -3571,18 +3633,27 @@ error_napi_stop: +@@ -3687,15 +3758,19 @@ error_napi_stop: for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -476,30 +463,28 @@ Signed-off-by: Lorenzo Bianconi continue; - dev = port->dev; -- if (dev && dev->dev->reg_state == NETREG_REGISTERED) { +- if (dev) { +- struct net_device *netdev = netdev_from_priv(dev); + for (j = 0; j < ARRAY_SIZE(port->devs); j++) { + struct airoha_gdm_dev *dev = port->devs[j]; + struct net_device *netdev; + + if (!dev) + continue; -+ -+ netdev = dev->dev; -+ if (netdev->reg_state == NETREG_REGISTERED) { + ++ netdev = netdev_from_priv(dev); + if (netdev->reg_state == NETREG_REGISTERED) { #if defined(CONFIG_PCS_AIROHA) -- if (airhoa_is_phy_external(port)) -- phylink_destroy(dev->phylink); -+ if (airhoa_is_phy_external(port)) -+ phylink_destroy(dev->phylink); + if (airhoa_is_phy_external(port)) +@@ -3703,6 +3778,7 @@ error_napi_stop: #endif -- unregister_netdev(dev->dev); -+ unregister_netdev(netdev); -+ } + unregister_netdev(netdev); + } + of_node_put(netdev->dev.of_node); } airoha_metadata_dst_free(port); } -@@ -3604,19 +3675,26 @@ static void airoha_remove(struct platfor +@@ -3724,19 +3800,27 @@ static void airoha_remove(struct platfor for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -517,21 +502,23 @@ Signed-off-by: Lorenzo Bianconi + continue; + #if defined(CONFIG_PCS_AIROHA) - if (airhoa_is_phy_external(port)) - phylink_destroy(dev->phylink); +- if (airhoa_is_phy_external(port)) +- phylink_destroy(dev->phylink); ++ if (airhoa_is_phy_external(port)) ++ phylink_destroy(dev->phylink); #endif -- + - dev = port->dev; - if (dev) -- unregister_netdev(dev->dev); -+ netdev = dev->dev; +- unregister_netdev(netdev_from_priv(dev)); ++ netdev = netdev_from_priv(dev); + unregister_netdev(netdev); + of_node_put(netdev->dev.of_node); + } airoha_metadata_dst_free(port); } airoha_hw_cleanup(eth); -@@ -3678,6 +3756,39 @@ static u32 airoha_en7581_get_vip_port(st +@@ -3798,6 +3882,39 @@ static u32 airoha_en7581_get_vip_port(st return 0; } @@ -571,7 +558,7 @@ Signed-off-by: Lorenzo Bianconi static const char * const an7583_xsi_rsts_names[] = { "hsi0-mac", "hsi1-mac", -@@ -3726,6 +3837,36 @@ static u32 airoha_an7583_get_vip_port(st +@@ -3846,6 +3963,36 @@ static u32 airoha_an7583_get_vip_port(st return 0; } @@ -608,7 +595,7 @@ Signed-off-by: Lorenzo Bianconi static const struct airoha_eth_soc_data en7581_soc_data = { .version = 0x7581, .xsi_rsts_names = en7581_xsi_rsts_names, -@@ -3734,6 +3875,7 @@ static const struct airoha_eth_soc_data +@@ -3854,6 +4001,7 @@ static const struct airoha_eth_soc_data .ops = { .get_sport = airoha_en7581_get_sport, .get_vip_port = airoha_en7581_get_vip_port, @@ -616,7 +603,7 @@ Signed-off-by: Lorenzo Bianconi }, }; -@@ -3745,6 +3887,7 @@ static const struct airoha_eth_soc_data +@@ -3865,6 +4013,7 @@ static const struct airoha_eth_soc_data .ops = { .get_sport = airoha_an7583_get_sport, .get_vip_port = airoha_an7583_get_vip_port, @@ -634,17 +621,7 @@ Signed-off-by: Lorenzo Bianconi #define AIROHA_MAX_NUM_QDMA 2 #define AIROHA_MAX_NUM_IRQ_BANKS 4 #define AIROHA_MAX_DSA_PORTS 7 -@@ -552,8 +553,8 @@ struct airoha_qdma { - struct airoha_gdm_dev { - struct airoha_gdm_port *port; - struct airoha_qdma *qdma; -- struct net_device *dev; - struct airoha_eth *eth; -+ struct net_device *dev; - - #if defined(CONFIG_PCS_AIROHA) - struct phylink *phylink; -@@ -564,12 +565,13 @@ struct airoha_gdm_dev { +@@ -563,12 +564,13 @@ struct airoha_gdm_dev { /* qos stats counters */ u64 cpu_tx_packets; u64 fwd_tx_packets; @@ -660,7 +637,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_hw_stats stats; -@@ -605,6 +607,8 @@ struct airoha_eth_soc_data { +@@ -604,6 +606,8 @@ struct airoha_eth_soc_data { struct { int (*get_sport)(struct airoha_gdm_port *port, int nbq); u32 (*get_vip_port)(struct airoha_gdm_port *port, int nbq); diff --git a/target/linux/airoha/patches-6.18/920-07-net-airoha-Do-not-stop-GDM-port-if-it-is-shared.patch b/target/linux/airoha/patches-6.18/920-07-net-airoha-Do-not-stop-GDM-port-if-it-is-shared.patch index eafefba314a..7dc33792bd8 100644 --- a/target/linux/airoha/patches-6.18/920-07-net-airoha-Do-not-stop-GDM-port-if-it-is-shared.patch +++ b/target/linux/airoha/patches-6.18/920-07-net-airoha-Do-not-stop-GDM-port-if-it-is-shared.patch @@ -23,25 +23,27 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -1859,8 +1859,8 @@ static int airoha_dev_open(struct net_de +@@ -1992,10 +1992,10 @@ static int airoha_dev_open(struct net_de int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN; struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; + u32 cur_len, pse_port = FE_PSE_PORT_PPE1; struct airoha_qdma *qdma = dev->qdma; + struct airoha_eth *eth = qdma->eth; + int qdma_id = qdma - ð->qdma[0]; - u32 pse_port = FE_PSE_PORT_PPE1; - #if defined(CONFIG_PCS_AIROHA) - if (airhoa_is_phy_external(port)) { -@@ -1888,10 +1888,20 @@ static int airoha_dev_open(struct net_de - airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id), + /* HW LRO is configured on the QDMA and it is shared between + * all the devices using it. Refuse to open a second device on +@@ -2034,10 +2034,20 @@ static int airoha_dev_open(struct net_de + airoha_fe_clear(eth, REG_GDM_INGRESS_CFG(port->id), GDM_STAG_EN_MASK); -- airoha_fe_rmw(qdma->eth, REG_GDM_LEN_CFG(port->id), +- airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), - GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, - FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | - FIELD_PREP(GDM_LONG_LEN_MASK, len)); -+ cur_len = airoha_fe_get(qdma->eth, REG_GDM_LEN_CFG(port->id), ++ cur_len = airoha_fe_get(eth, REG_GDM_LEN_CFG(port->id), + GDM_LONG_LEN_MASK); + if (!port->users || len > cur_len) { + /* Opening a sibling net_device with a larger MTU updates the @@ -49,7 +51,7 @@ Signed-off-by: Lorenzo Bianconi + * multiple net_devices with different MTUs to share the same + * GDM port. + */ -+ airoha_fe_rmw(qdma->eth, REG_GDM_LEN_CFG(port->id), ++ airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), + GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, + FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | + FIELD_PREP(GDM_LONG_LEN_MASK, len)); @@ -58,7 +60,7 @@ Signed-off-by: Lorenzo Bianconi airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_TX_DMA_EN_MASK | -@@ -1907,6 +1917,30 @@ static int airoha_dev_open(struct net_de +@@ -2060,6 +2070,30 @@ static int airoha_dev_open(struct net_de return 0; } @@ -75,7 +77,7 @@ Signed-off-by: Lorenzo Bianconi + if (!dev) + continue; + -+ netdev = dev->dev; ++ netdev = netdev_from_priv(dev); + if (netif_running(netdev)) + len = max_t(u32, len, netdev->mtu); + } @@ -89,22 +91,21 @@ Signed-off-by: Lorenzo Bianconi static int airoha_dev_stop(struct net_device *netdev) { struct airoha_gdm_dev *dev = netdev_priv(netdev); -@@ -1919,8 +1953,12 @@ static int airoha_dev_stop(struct net_de +@@ -2073,8 +2107,11 @@ static int airoha_dev_stop(struct net_de for (i = 0; i < netdev->num_tx_queues; i++) netdev_tx_reset_subqueue(netdev, i); -- 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), - FE_PSE_PORT_DROP); + if (--port->users) -+ airoha_set_port_mtu(dev->eth, port); ++ airoha_set_port_mtu(eth, port); + else -+ 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), + FE_PSE_PORT_DROP); - if (atomic_dec_and_test(&qdma->users)) { + if (!--qdma->users) { airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, -@@ -2082,13 +2120,10 @@ static int airoha_dev_change_mtu(struct +@@ -2238,13 +2275,10 @@ static int airoha_dev_change_mtu(struct { struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; @@ -122,7 +123,7 @@ Signed-off-by: Lorenzo Bianconi } --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -572,6 +572,7 @@ struct airoha_gdm_dev { +@@ -571,6 +571,7 @@ struct airoha_gdm_dev { struct airoha_gdm_port { struct airoha_gdm_dev *devs[AIROHA_MAX_NUM_GDM_DEVS]; int id; diff --git a/target/linux/airoha/patches-6.18/920-08-net-airoha-Introduce-WAN-device-flag.patch b/target/linux/airoha/patches-6.18/920-08-net-airoha-Introduce-WAN-device-flag.patch index 9451c6fcee6..a21fa3f05bd 100644 --- a/target/linux/airoha/patches-6.18/920-08-net-airoha-Introduce-WAN-device-flag.patch +++ b/target/linux/airoha/patches-6.18/920-08-net-airoha-Introduce-WAN-device-flag.patch @@ -29,14 +29,16 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -2059,36 +2059,80 @@ static int airoha_set_gdm2_loopback(stru +@@ -2214,36 +2214,81 @@ static int airoha_set_gdm2_loopback(stru return 0; } -static int airoha_dev_init(struct net_device *netdev) +static struct airoha_gdm_dev * +airoha_get_wan_gdm_dev(struct airoha_eth *eth) -+{ + { +- struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_gdm_port *port = dev->port; + int i; + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { @@ -58,15 +60,14 @@ Signed-off-by: Lorenzo Bianconi +} + +static void airoha_dev_set_qdma(struct airoha_gdm_dev *dev) - { -- struct airoha_gdm_dev *dev = netdev_priv(netdev); -- struct airoha_gdm_port *port = dev->port; ++{ ++ struct net_device *netdev = netdev_from_priv(dev); struct airoha_eth *eth = dev->eth; int ppe_id; /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ dev->qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; - dev->dev->irq = dev->qdma->irq_banks[0].irq; + netdev->irq = dev->qdma->irq_banks[0].irq; - airoha_set_macaddr(dev, netdev->dev_addr); + + ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1); @@ -138,7 +139,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_gdm_dev { struct airoha_gdm_port *port; struct airoha_qdma *qdma; -@@ -566,6 +570,7 @@ struct airoha_gdm_dev { +@@ -565,6 +569,7 @@ struct airoha_gdm_dev { u64 cpu_tx_packets; u64 fwd_tx_packets; @@ -146,7 +147,7 @@ Signed-off-by: Lorenzo Bianconi int nbq; }; -@@ -672,13 +677,7 @@ static inline u16 airoha_qdma_get_txq(st +@@ -671,13 +676,7 @@ static inline u16 airoha_qdma_get_txq(st static inline bool airoha_is_lan_gdm_dev(struct airoha_gdm_dev *dev) { diff --git a/target/linux/airoha/patches-6.18/920-09-net-airoha-Support-multiple-LAN-WAN-interfaces-for-h.patch b/target/linux/airoha/patches-6.18/920-09-net-airoha-Support-multiple-LAN-WAN-interfaces-for-h.patch index be9382c9eb8..553bd3cbf57 100644 --- a/target/linux/airoha/patches-6.18/920-09-net-airoha-Support-multiple-LAN-WAN-interfaces-for-h.patch +++ b/target/linux/airoha/patches-6.18/920-09-net-airoha-Support-multiple-LAN-WAN-interfaces-for-h.patch @@ -30,7 +30,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -80,20 +80,74 @@ static bool airhoa_is_phy_external(struc +@@ -81,20 +81,76 @@ static bool airhoa_is_phy_external(struc } #endif @@ -66,7 +66,7 @@ Signed-off-by: Lorenzo Bianconi + airoha_is_lan_gdm_dev(dev)) + continue; + -+ netdev = iter_dev->dev; ++ netdev = netdev_from_priv(iter_dev); + if (netdev->reg_state != NETREG_REGISTERED) + continue; + @@ -85,9 +85,11 @@ Signed-off-by: Lorenzo Bianconi + * the same for each net_device with the same LAN/WAN + * configuration. + */ ++ struct net_device *netdev = netdev_from_priv(dev); ++ + dev_warn(eth->dev, + "%s: wrong mac addr, MSBs must be %02x:%02x:%02x\n", -+ dev->dev->name, ref_addr[0], ref_addr[1], ++ netdev->name, ref_addr[0], ref_addr[1], + ref_addr[2]); + dev_warn(eth->dev, "FE hw forwarding won't work properly\n"); + @@ -103,15 +105,15 @@ Signed-off-by: Lorenzo Bianconi - airoha_fe_wr(eth, REG_FE_MAC_LMAX(reg), val); + airoha_fe_wr(eth, REG_FE_MAC_LMIN(reg), lmin); + airoha_fe_wr(eth, REG_FE_MAC_LMAX(reg), lmax); ++ ++ airoha_ppe_init_upd_mem(dev, addr); - airoha_ppe_init_upd_mem(dev); -+ airoha_ppe_init_upd_mem(dev, addr); -+ + return 0; } static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr, -@@ -1986,13 +2040,18 @@ static int airoha_dev_stop(struct net_de +@@ -2141,13 +2197,18 @@ static int airoha_dev_stop(struct net_de static int airoha_dev_set_macaddr(struct net_device *netdev, void *p) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -134,7 +136,7 @@ Signed-off-by: Lorenzo Bianconi } --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -713,7 +713,7 @@ void airoha_ppe_check_skb(struct airoha_ +@@ -712,7 +712,7 @@ void airoha_ppe_check_skb(struct airoha_ int airoha_ppe_setup_tc_block_cb(struct airoha_ppe_dev *dev, void *type_data); int airoha_ppe_init(struct airoha_eth *eth); void airoha_ppe_deinit(struct airoha_eth *eth); @@ -152,8 +154,8 @@ Signed-off-by: Lorenzo Bianconi -void airoha_ppe_init_upd_mem(struct airoha_gdm_dev *dev) +void airoha_ppe_init_upd_mem(struct airoha_gdm_dev *dev, const u8 *addr) { +- struct net_device *netdev = netdev_from_priv(dev); struct airoha_gdm_port *port = dev->port; -- struct net_device *netdev = dev->dev; struct airoha_eth *eth = dev->eth; - const u8 *addr = netdev->dev_addr; u32 val; diff --git a/target/linux/airoha/patches-6.18/920-10-net-airoha-Rename-airoha_set_gdm2_loopback-in-airoha.patch b/target/linux/airoha/patches-6.18/920-10-net-airoha-Rename-airoha_set_gdm2_loopback-in-airoha.patch index aca2ae25764..92ce90e7ca9 100644 --- a/target/linux/airoha/patches-6.18/920-10-net-airoha-Rename-airoha_set_gdm2_loopback-in-airoha.patch +++ b/target/linux/airoha/patches-6.18/920-10-net-airoha-Rename-airoha_set_gdm2_loopback-in-airoha.patch @@ -17,7 +17,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -2056,7 +2056,7 @@ static int airoha_dev_set_macaddr(struct +@@ -2213,7 +2213,7 @@ static int airoha_dev_set_macaddr(struct return 0; } @@ -26,7 +26,7 @@ Signed-off-by: Lorenzo Bianconi { struct airoha_gdm_port *port = dev->port; struct airoha_eth *eth = dev->eth; -@@ -2188,7 +2188,7 @@ static int airoha_dev_init(struct net_de +@@ -2346,7 +2346,7 @@ static int airoha_dev_init(struct net_de (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)) { int err; diff --git a/target/linux/airoha/patches-6.18/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch b/target/linux/airoha/patches-6.18/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch deleted file mode 100644 index f55b97253f3..00000000000 --- a/target/linux/airoha/patches-6.18/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch +++ /dev/null @@ -1,246 +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 -@@ -1916,6 +1916,11 @@ static int airoha_dev_open(struct net_de - u32 cur_len, pse_port = FE_PSE_PORT_PPE1; - struct airoha_qdma *qdma = dev->qdma; - -+ if (port->id == AIROHA_GDM2_IDX && airoha_is_lan_gdm_dev(dev)) { -+ /* GDM2 can be used just as wan */ -+ return -EBUSY; -+ } -+ - #if defined(CONFIG_PCS_AIROHA) - if (airhoa_is_phy_external(port)) { - err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0); -@@ -2118,6 +2123,45 @@ static int airoha_enable_gdm2_loopback(s - return 0; - } - -+static int airoha_disable_gdm2_loopback(struct airoha_gdm_dev *dev) -+{ -+ 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_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)); -+ -+ airoha_fe_wr(eth, REG_SRC_PORT_FC_MAP6, FC_MAP6_DEF_VALUE); -+ -+ return 0; -+} -+ - static struct airoha_gdm_dev * - airoha_get_wan_gdm_dev(struct airoha_eth *eth) - { -@@ -2522,6 +2566,80 @@ error: - return NETDEV_TX_OK; - } - -+struct airoha_ethool_priv_flags { -+ char name[ETH_GSTRING_LEN]; -+ int (*handler)(struct net_device *netdev, u32 flags); -+}; -+ -+static int airoha_dev_set_wan_flag(struct net_device *netdev, u32 flags) -+{ -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; -+ struct airoha_eth *eth = dev->eth; -+ -+ if (!((dev->flags ^ flags) & AIROHA_PRIV_F_WAN)) -+ return 0; -+ -+ if (netif_running(netdev)) -+ return -EBUSY; -+ -+ if (flags & AIROHA_PRIV_F_WAN) { -+ struct airoha_gdm_dev *wan_dev; -+ -+ /* Verify the wan device is not already configured */ -+ wan_dev = airoha_get_wan_gdm_dev(eth); -+ if (wan_dev && wan_dev != dev) -+ return -EBUSY; -+ -+ switch (port->id) { -+ case AIROHA_GDM2_IDX: -+ dev->flags |= AIROHA_PRIV_F_WAN; -+ airoha_dev_set_qdma(dev); -+ break; -+ case AIROHA_GDM3_IDX: -+ case AIROHA_GDM4_IDX: { -+ int err; -+ -+ dev->flags |= AIROHA_PRIV_F_WAN; -+ airoha_dev_set_qdma(dev); -+ -+ err = airoha_enable_gdm2_loopback(dev); -+ if (err) { -+ dev->flags &= ~AIROHA_PRIV_F_WAN; -+ return err; -+ } -+ break; -+ } -+ default: -+ return -EOPNOTSUPP; -+ } -+ } else { -+ switch (port->id) { -+ case AIROHA_GDM3_IDX: -+ case AIROHA_GDM4_IDX: { -+ int err; -+ -+ err = airoha_disable_gdm2_loopback(dev); -+ if (err) -+ return err; -+ break; -+ } -+ default: -+ break; -+ } -+ -+ dev->flags &= ~AIROHA_PRIV_F_WAN; -+ airoha_dev_set_qdma(dev); -+ } -+ -+ return airoha_set_macaddr(dev, netdev->dev_addr); -+} -+ -+static const struct airoha_ethool_priv_flags airoha_eth_priv_flags[] = { -+ { "wan", airoha_dev_set_wan_flag }, -+}; -+#define AIROHA_PRIV_FLAGS_STR_LEN ARRAY_SIZE(airoha_eth_priv_flags) -+ - static void airoha_ethtool_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *info) - { -@@ -2530,6 +2648,7 @@ static void airoha_ethtool_get_drvinfo(s - - strscpy(info->driver, eth->dev->driver->name, sizeof(info->driver)); - strscpy(info->bus_info, dev_name(eth->dev), sizeof(info->bus_info)); -+ info->n_priv_flags = AIROHA_PRIV_FLAGS_STR_LEN; - } - - static void airoha_ethtool_get_mac_stats(struct net_device *netdev, -@@ -2594,6 +2713,56 @@ airoha_ethtool_get_rmon_stats(struct net - } while (u64_stats_fetch_retry(&port->stats.syncp, start)); - } - -+static int airoha_ethtool_set_priv_flags(struct net_device *netdev, u32 flags) -+{ -+ int i; -+ -+ for (i = 0; i < AIROHA_PRIV_FLAGS_STR_LEN; i++) { -+ int err; -+ -+ if (!airoha_eth_priv_flags[i].handler) -+ continue; -+ -+ err = airoha_eth_priv_flags[i].handler(netdev, flags); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+static u32 airoha_ethtool_get_priv_flags(struct net_device *netdev) -+{ -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ -+ return dev->flags; -+} -+ -+static int airoha_ethtool_get_sset_count(struct net_device *netdev, int sset) -+{ -+ switch (sset) { -+ case ETH_SS_PRIV_FLAGS: -+ return AIROHA_PRIV_FLAGS_STR_LEN; -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static void airoha_ethtool_get_strings(struct net_device *netdev, -+ u32 stringset, u8 *data) -+{ -+ int i; -+ -+ switch (stringset) { -+ case ETH_SS_PRIV_FLAGS: -+ for (i = 0; i < AIROHA_PRIV_FLAGS_STR_LEN; i++) -+ ethtool_puts(&data, airoha_eth_priv_flags[i].name); -+ break; -+ default: -+ break; -+ } -+} -+ - 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) -@@ -3315,6 +3484,10 @@ static const struct ethtool_ops airoha_e - .get_rmon_stats = airoha_ethtool_get_rmon_stats, - .get_link_ksettings = phy_ethtool_get_link_ksettings, - .get_link = ethtool_op_get_link, -+ .set_priv_flags = airoha_ethtool_set_priv_flags, -+ .get_priv_flags = airoha_ethtool_get_priv_flags, -+ .get_sset_count = airoha_ethtool_get_sset_count, -+ .get_strings = airoha_ethtool_get_strings, - }; - - static void airoha_mac_config(struct phylink_config *config, unsigned int mode, ---- a/drivers/net/ethernet/airoha/airoha_regs.h -+++ b/drivers/net/ethernet/airoha/airoha_regs.h -@@ -402,6 +402,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_CDM5_RX_OQ1_DROP_CNT 0x29d4 - 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 new file mode 100644 index 00000000000..2c16f2ac02d --- /dev/null +++ b/target/linux/airoha/patches-6.18/920-12-net-airoha-defer-GDM3-GDM4-WAN-mode-and-GDM2-loopbac.patch @@ -0,0 +1,668 @@ +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 +@@ -540,7 +540,7 @@ static bool airoha_fe_lro_is_enabled(str + + 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; +@@ -1158,7 +1158,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); +@@ -2031,7 +2031,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)) + continue; + + netdev = netdev_from_priv(iter_dev); +@@ -2043,20 +2044,57 @@ static void airoha_update_netdev_feature + } + } + ++static void airoha_qdma_start(struct airoha_qdma *qdma) ++{ ++ airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, ++ GLOBAL_CFG_TX_DMA_EN_MASK | ++ GLOBAL_CFG_RX_DMA_EN_MASK); ++ qdma->users++; ++} ++ ++static void airoha_qdma_stop(struct airoha_qdma *qdma) ++{ ++ u32 status; ++ ++ if (--qdma->users) ++ return; ++ ++ airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, ++ GLOBAL_CFG_TX_DMA_EN_MASK | ++ GLOBAL_CFG_RX_DMA_EN_MASK); ++ ++ if (read_poll_timeout(airoha_qdma_rr, status, ++ !(status & (GLOBAL_CFG_TX_DMA_BUSY_MASK | ++ GLOBAL_CFG_RX_DMA_BUSY_MASK)), ++ USEC_PER_MSEC, 50 * USEC_PER_MSEC, true, ++ qdma, REG_QDMA_GLOBAL_CFG)) ++ dev_warn(qdma->eth->dev, "QDMA DMA engine busy timeout\n"); ++ ++ for (int i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { ++ if (!qdma->q_tx[i].ndesc) ++ continue; ++ ++ airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); ++ } ++} ++ + static int airoha_dev_open(struct net_device *netdev) + { + int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN; + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; + u32 cur_len, pse_port = FE_PSE_PORT_PPE1; +- struct airoha_qdma *qdma = dev->qdma; +- struct airoha_eth *eth = qdma->eth; +- int qdma_id = qdma - ð->qdma[0]; ++ struct airoha_eth *eth = dev->eth; ++ struct airoha_qdma *qdma; ++ int qdma_id; + + /* HW 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. + */ ++ qdma = airoha_qdma_deref(dev); ++ qdma_id = qdma - ð->qdma[0]; ++ + if (qdma->users && airoha_fe_lro_is_enabled(eth, qdma_id)) { + netdev_warn(netdev, "required to disable HW GRO on QDMA%d\n", + qdma_id); +@@ -2105,10 +2143,7 @@ static int airoha_dev_open(struct net_de + } + port->users++; + +- airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, +- GLOBAL_CFG_TX_DMA_EN_MASK | +- GLOBAL_CFG_RX_DMA_EN_MASK); +- qdma->users++; ++ airoha_qdma_start(qdma); + + if (!airoha_is_lan_gdm_dev(dev) && + airoha_ppe_is_enabled(eth, 1)) { +@@ -2154,8 +2189,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 = dev->qdma; +- struct airoha_eth *eth = qdma->eth; ++ struct airoha_qdma *qdma; + int i; + + netif_tx_disable(netdev); +@@ -2163,25 +2197,14 @@ static int airoha_dev_stop(struct net_de + for (i = 0; i < netdev->num_tx_queues; i++) + netdev_tx_reset_subqueue(netdev, i); + ++ qdma = airoha_qdma_deref(dev); + if (--port->users) +- airoha_set_port_mtu(eth, port); ++ airoha_set_port_mtu(dev->eth, port); + else +- airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id), ++ airoha_set_gdm_port_fwd_cfg(qdma->eth, ++ REG_GDM_FWD_CFG(port->id), + FE_PSE_PORT_DROP); +- +- if (!--qdma->users) { +- airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, +- GLOBAL_CFG_TX_DMA_EN_MASK | +- GLOBAL_CFG_RX_DMA_EN_MASK); +- +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { +- if (!qdma->q_tx[i].ndesc) +- continue; +- +- airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); +- } +- } +- ++ airoha_qdma_stop(qdma); + airoha_update_netdev_features(dev); + + #if defined(CONFIG_PCS_AIROHA) +@@ -2275,6 +2298,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) + { +@@ -2301,15 +2371,30 @@ 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; + + /* 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_start(qdma); ++ ++ rcu_assign_pointer(dev->qdma, qdma); ++ netdev->irq = qdma->irq_banks[0].irq; + + 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)); ++ ++ if (!cur_qdma) ++ return; ++ ++ synchronize_rcu(); ++ netif_tx_wake_all_queues(netdev); ++ ++ if (netif_running(netdev)) ++ airoha_qdma_stop(cur_qdma); + } + + static int airoha_dev_init(struct net_device *netdev) +@@ -2473,8 +2558,9 @@ static netdev_features_t airoha_dev_fix_ + netdev_features_t features) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_qdma *qdma = dev->qdma; ++ struct airoha_qdma *qdma; + ++ qdma = airoha_qdma_deref(dev); + if (qdma->users > 1) + features &= ~NETIF_F_GRO_HW; + +@@ -2486,9 +2572,8 @@ 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_eth *eth = qdma->eth; +- int qdma_id = qdma - ð->qdma[0]; ++ struct airoha_qdma *qdma = airoha_qdma_deref(dev); ++ int qdma_id = qdma - &dev->eth->qdma[0]; + + if (!(diff & NETIF_F_GRO_HW)) + return 0; +@@ -2496,7 +2581,7 @@ static int airoha_dev_set_features(struc + if (features & NETIF_F_GRO_HW) + airoha_dev_lro_enable(dev); + else +- airoha_fe_lro_disable(eth, qdma_id); ++ airoha_fe_lro_disable(dev->eth, qdma_id); + + return 0; + } +@@ -2505,9 +2590,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); +@@ -2516,6 +2601,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); + +@@ -2562,6 +2649,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; + } + +@@ -2624,6 +2713,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; + +@@ -2639,6 +2729,7 @@ error_unmap: + error: + dev_kfree_skb_any(skb); + netdev->stats.tx_dropped++; ++ rcu_read_unlock(); + + return NETDEV_TX_OK; + } +@@ -2720,17 +2811,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_TX_RING; 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) | +@@ -2738,12 +2831,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)); + +@@ -2807,13 +2900,15 @@ 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; ++ u64 cpu_tx_packets, fwd_tx_packets, tx_packets; ++ struct airoha_qdma *qdma; + +- 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); ++ 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)); ++ tx_packets = (cpu_tx_packets - dev->cpu_tx_packets) + ++ (fwd_tx_packets - dev->fwd_tx_packets); + + _bstats_update(opt->stats.bstats, 0, tx_packets); + dev->cpu_tx_packets = cpu_tx_packets; +@@ -3073,16 +3168,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) +@@ -3118,11 +3215,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 = netdev->real_num_tx_queues; + 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"); +@@ -3156,7 +3254,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++) { +@@ -3330,11 +3428,12 @@ static int airoha_dev_setup_tc_block(str + static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_qdma *qdma = dev->qdma; ++ struct airoha_qdma *qdma; + + netif_set_real_num_tx_queues(netdev, netdev->real_num_tx_queues - 1); + airoha_qdma_set_tx_rate_limit(netdev, queue + 1, 0, 0); + ++ qdma = airoha_qdma_deref(dev); + clear_bit(queue, qdma->qos_channel_map); + clear_bit(queue, dev->qos_sq_bmap); + } +@@ -3355,6 +3454,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); +@@ -3363,6 +3551,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; + } + +@@ -3382,24 +3572,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; + } +@@ -3509,8 +3708,8 @@ static void airoha_mac_link_up(struct ph + { + struct airoha_gdm_dev *dev = container_of(config, struct airoha_gdm_dev, + phylink_config); ++ struct airoha_qdma *qdma = airoha_qdma_deref(dev); + struct airoha_gdm_port *port = dev->port; +- struct airoha_qdma *qdma = dev->qdma; + struct airoha_eth *eth = qdma->eth; + u32 frag_size_tx, frag_size_rx; + +--- a/drivers/net/ethernet/airoha/airoha_regs.h ++++ b/drivers/net/ethernet/airoha/airoha_regs.h +@@ -402,6 +402,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_CDM5_RX_OQ1_DROP_CNT 0x29d4 + +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -552,11 +552,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; + + #if defined(CONFIG_PCS_AIROHA) +@@ -705,6 +706,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_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport); + bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index); + void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb, +--- 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 072b50fe35c..d17c537daa2 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 -@@ -185,10 +185,15 @@ static void airoha_fe_maccr_init(struct +@@ -188,10 +188,15 @@ static void airoha_fe_maccr_init(struct { int p; @@ -33,8 +33,8 @@ Signed-off-by: Lorenzo Bianconi airoha_fe_rmw(eth, REG_CDM_VLAN_CTRL(1), CDM_VLAN_MASK, FIELD_PREP(CDM_VLAN_MASK, 0x8100)); -@@ -1908,13 +1913,24 @@ static void airoha_update_hw_stats(struc - spin_unlock(&port->stats.lock); +@@ -2078,15 +2083,25 @@ static void airoha_qdma_stop(struct airo + } } +static void airoha_dev_set_mtu(struct net_device *netdev) @@ -54,17 +54,19 @@ Signed-off-by: Lorenzo Bianconi struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; - u32 cur_len, pse_port = FE_PSE_PORT_PPE1; - struct airoha_qdma *qdma = dev->qdma; + struct airoha_eth *eth = dev->eth; + struct airoha_qdma *qdma; +- int qdma_id; + u32 pse_port = FE_PSE_PORT_PPE1; -+ int err; ++ int err, qdma_id; - if (port->id == AIROHA_GDM2_IDX && airoha_is_lan_gdm_dev(dev)) { - /* GDM2 can be used just as wan */ -@@ -1947,19 +1963,7 @@ static int airoha_dev_open(struct net_de - airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id), + /* HW LRO is configured on the QDMA and it is shared between + * all the devices using it. Refuse to open a second device on +@@ -2128,19 +2143,7 @@ static int airoha_dev_open(struct net_de + airoha_fe_clear(eth, REG_GDM_INGRESS_CFG(port->id), GDM_STAG_EN_MASK); -- cur_len = airoha_fe_get(qdma->eth, REG_GDM_LEN_CFG(port->id), +- cur_len = airoha_fe_get(eth, REG_GDM_LEN_CFG(port->id), - GDM_LONG_LEN_MASK); - if (!port->users || len > cur_len) { - /* Opening a sibling net_device with a larger MTU updates the @@ -72,7 +74,7 @@ Signed-off-by: Lorenzo Bianconi - * multiple net_devices with different MTUs to share the same - * GDM port. - */ -- airoha_fe_rmw(qdma->eth, REG_GDM_LEN_CFG(port->id), +- airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), - GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, - FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | - FIELD_PREP(GDM_LONG_LEN_MASK, len)); @@ -80,8 +82,8 @@ Signed-off-by: Lorenzo Bianconi + airoha_dev_set_mtu(netdev); port->users++; - airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, -@@ -1976,30 +1980,6 @@ static int airoha_dev_open(struct net_de + airoha_qdma_start(qdma); +@@ -2161,30 +2164,6 @@ static int airoha_dev_open(struct net_de return 0; } @@ -98,7 +100,7 @@ Signed-off-by: Lorenzo Bianconi - if (!dev) - continue; - -- netdev = dev->dev; +- netdev = netdev_from_priv(dev); - if (netif_running(netdev)) - len = max_t(u32, len, netdev->mtu); - } @@ -112,16 +114,16 @@ Signed-off-by: Lorenzo Bianconi static int airoha_dev_stop(struct net_device *netdev) { struct airoha_gdm_dev *dev = netdev_priv(netdev); -@@ -2013,7 +1993,7 @@ static int airoha_dev_stop(struct net_de - netdev_tx_reset_subqueue(netdev, i); +@@ -2199,7 +2178,7 @@ static int airoha_dev_stop(struct net_de + qdma = airoha_qdma_deref(dev); if (--port->users) - airoha_set_port_mtu(dev->eth, port); + airoha_ppe_set_mtu(dev); else airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), -@@ -2083,10 +2063,6 @@ static int airoha_enable_gdm2_loopback(s +@@ -2258,10 +2237,6 @@ static int airoha_enable_gdm2_loopback(s FIELD_PREP(LPBK_CHAN_MASK, chan) | LBK_GAP_MODE_MASK | LBK_LEN_MODE_MASK | LBK_CHAN_MODE_MASK | LPBK_EN_MASK); @@ -132,7 +134,7 @@ Signed-off-by: Lorenzo Bianconi /* Forward the traffic to the proper GDM port */ pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3 : FE_PSE_PORT_GDM4; -@@ -2270,7 +2246,7 @@ static int airoha_dev_change_mtu(struct +@@ -2469,7 +2444,7 @@ static int airoha_dev_change_mtu(struct WRITE_ONCE(netdev->mtu, mtu); if (port->users) @@ -141,14 +143,22 @@ Signed-off-by: Lorenzo Bianconi return 0; } -@@ -2613,6 +2589,7 @@ static int airoha_dev_set_wan_flag(struc - default: - return -EOPNOTSUPP; - } -+ airoha_dev_set_mtu(netdev); - } else { - switch (port->id) { - case AIROHA_GDM3_IDX: +@@ -3471,6 +3446,7 @@ static void airoha_disable_qos_for_gdm34 + + dev->flags &= ~AIROHA_PRIV_F_WAN; + airoha_dev_set_qdma(dev); ++ airoha_dev_set_mtu(netdev); + + airoha_set_macaddr(dev, netdev->dev_addr); + if (netif_running(netdev)) +@@ -3519,6 +3495,7 @@ static int airoha_enable_qos_for_gdm34(s + if (err) + goto error_disable_loopback; + ++ airoha_dev_set_mtu(netdev); + if (netif_running(netdev)) { + u32 pse_port; + --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h @@ -23,6 +23,7 @@ @@ -159,9 +169,9 @@ Signed-off-by: Lorenzo Bianconi #define AIROHA_MAX_PACKET_SIZE 2048 #define AIROHA_NUM_QOS_CHANNELS 4 #define AIROHA_NUM_QOS_QUEUES 8 -@@ -706,6 +707,7 @@ int airoha_get_fe_port(struct airoha_gdm - bool airoha_is_valid_gdm_dev(struct airoha_eth *eth, - struct airoha_gdm_dev *dev); +@@ -716,6 +717,7 @@ airoha_qdma_deref(struct airoha_gdm_dev + lockdep_is_held(&flow_offload_mutex)); + } +void airoha_ppe_set_mtu(struct airoha_gdm_dev *dev); void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport); @@ -169,7 +179,7 @@ Signed-off-by: Lorenzo Bianconi void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb, --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c -@@ -98,6 +98,35 @@ void airoha_ppe_set_cpu_port(struct airo +@@ -101,6 +101,39 @@ void airoha_ppe_set_cpu_port(struct airo __field_prep(DFT_CPORT_MASK(fport), fe_cpu_port)); } @@ -177,20 +187,24 @@ Signed-off-by: Lorenzo Bianconi +{ + struct airoha_gdm_port *port = dev->port; + struct airoha_eth *eth = dev->eth; ++ struct airoha_qdma *qdma; + int i, ppe_id, index; + u32 mtu = 0; + ++ qdma = airoha_qdma_deref(dev); + for (i = 0; i < ARRAY_SIZE(port->devs); i++) { + struct airoha_gdm_dev *d = port->devs[i]; + struct net_device *netdev; ++ struct airoha_qdma *q; + + if (!d) + continue; + -+ if (d->qdma != dev->qdma) ++ q = airoha_qdma_deref(d); ++ if (q != qdma) + continue; + -+ netdev = d->dev; ++ netdev = netdev_from_priv(d); + if (netif_running(netdev)) + mtu = max_t(u32, mtu, netdev->mtu); + } @@ -205,7 +219,7 @@ Signed-off-by: Lorenzo Bianconi static void airoha_ppe_hw_init(struct airoha_ppe *ppe) { u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries; -@@ -116,8 +145,6 @@ static void airoha_ppe_hw_init(struct ai +@@ -119,8 +152,6 @@ static void airoha_ppe_hw_init(struct ai PPE_RAM_NUM_ENTRIES_SHIFT(sram_ppe_num_data_entries); for (i = 0; i < eth->soc->num_ppe; i++) { @@ -214,7 +228,7 @@ Signed-off-by: Lorenzo Bianconi airoha_fe_wr(eth, REG_PPE_TB_BASE(i), ppe->foe_dma + sram_tb_size); -@@ -167,15 +194,6 @@ static void airoha_ppe_hw_init(struct ai +@@ -170,15 +201,6 @@ static void airoha_ppe_hw_init(struct ai airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED); airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i), PPE_FLOW_CFG_IP6_6RD_MASK); @@ -230,7 +244,7 @@ Signed-off-by: Lorenzo Bianconi } for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { -@@ -197,6 +215,7 @@ static void airoha_ppe_hw_init(struct ai +@@ -200,6 +222,7 @@ static void airoha_ppe_hw_init(struct ai airoha_ppe_is_enabled(eth, 1); fport = airoha_get_fe_port(dev); airoha_ppe_set_cpu_port(dev, ppe_id, fport); diff --git a/target/linux/airoha/patches-6.18/920-14-net-airoha-Better-handle-MIB-for-GDM-with-multiple-p.patch b/target/linux/airoha/patches-6.18/920-14-net-airoha-Better-handle-MIB-for-GDM-with-multiple-p.patch index 25db5b6661e..1aec4e91fcf 100644 --- a/target/linux/airoha/patches-6.18/920-14-net-airoha-Better-handle-MIB-for-GDM-with-multiple-p.patch +++ b/target/linux/airoha/patches-6.18/920-14-net-airoha-Better-handle-MIB-for-GDM-with-multiple-p.patch @@ -31,7 +31,7 @@ Signed-off-by: Christian Marangi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -612,6 +612,14 @@ static int airoha_fe_init(struct airoha_ +@@ -640,6 +640,14 @@ static int airoha_fe_init(struct airoha_ airoha_fe_set(eth, REG_GDM_FWD_CFG(AIROHA_GDM4_IDX), GDM_PAD_EN_MASK | GDM_STRIP_CRC_MASK); @@ -46,7 +46,7 @@ Signed-off-by: Christian Marangi airoha_fe_crsn_qsel_init(eth); airoha_fe_clear(eth, REG_FE_CPORT_CFG, FE_CPORT_QUEUE_XFC_MASK); -@@ -1768,149 +1776,169 @@ static void airoha_qdma_stop_napi(struct +@@ -1872,149 +1880,169 @@ static void airoha_qdma_stop_napi(struct } } @@ -269,8 +269,8 @@ Signed-off-by: Christian Marangi + spin_unlock(&port->stats_lock); } - static void airoha_dev_set_mtu(struct net_device *netdev) -@@ -2220,23 +2248,22 @@ static void airoha_dev_get_stats64(struc + static void airoha_update_netdev_features(struct airoha_gdm_dev *dev) +@@ -2418,23 +2446,22 @@ static void airoha_dev_get_stats64(struc struct rtnl_link_stats64 *storage) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -306,7 +306,7 @@ Signed-off-by: Christian Marangi } static int airoha_dev_change_mtu(struct net_device *netdev, int mtu) -@@ -2632,20 +2659,19 @@ static void airoha_ethtool_get_mac_stats +@@ -2723,20 +2750,19 @@ static void airoha_ethtool_get_mac_stats struct ethtool_eth_mac_stats *stats) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -336,7 +336,7 @@ Signed-off-by: Christian Marangi } static const struct ethtool_rmon_hist_range airoha_ethtool_rmon_ranges[] = { -@@ -2665,8 +2691,7 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2756,8 +2782,7 @@ airoha_ethtool_get_rmon_stats(struct net const struct ethtool_rmon_hist_range **ranges) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -346,7 +346,7 @@ Signed-off-by: Christian Marangi unsigned int start; BUILD_BUG_ON(ARRAY_SIZE(airoha_ethtool_rmon_ranges) != -@@ -2679,7 +2704,7 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2770,7 +2795,7 @@ airoha_ethtool_get_rmon_stats(struct net do { int i; @@ -355,7 +355,7 @@ Signed-off-by: Christian Marangi stats->fragments = hw_stats->rx_fragment; stats->jabbers = hw_stats->rx_jabber; for (i = 0; i < ARRAY_SIZE(airoha_ethtool_rmon_ranges) - 1; -@@ -2687,7 +2712,7 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2778,7 +2803,7 @@ airoha_ethtool_get_rmon_stats(struct net stats->hist[i] = hw_stats->rx_len[i]; stats->hist_tx[i] = hw_stats->tx_len[i]; } @@ -363,16 +363,16 @@ Signed-off-by: Christian Marangi + } while (u64_stats_fetch_retry(&dev->stats.syncp, start)); } - static int airoha_ethtool_set_priv_flags(struct net_device *netdev, u32 flags) -@@ -3695,6 +3720,7 @@ static int airoha_alloc_gdm_device(struc + static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev, +@@ -3849,6 +3874,7 @@ 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); - dev->dev = netdev; dev->port = port; dev->eth = eth; -@@ -3743,9 +3769,8 @@ static int airoha_alloc_gdm_port(struct + dev->nbq = nbq; +@@ -3896,9 +3922,8 @@ static int airoha_alloc_gdm_port(struct if (!port) return -ENOMEM; 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 75a49306c2c..2df1996d19a 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 -@@ -2345,17 +2345,9 @@ static u32 airoha_get_dsa_tag(struct sk_ +@@ -2543,17 +2543,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; @@ -37,4 +37,4 @@ Signed-off-by: Christian Marangi + : port->id; } - static int airoha_dev_set_features(struct net_device *netdev, + static netdev_features_t airoha_dev_fix_features(struct net_device *netdev, diff --git a/target/linux/airoha/patches-6.18/921-net-airoha-move-get_sport-callback-at-the-beginning-.patch b/target/linux/airoha/patches-6.18/921-net-airoha-move-get_sport-callback-at-the-beginning-.patch new file mode 100644 index 00000000000..9cd99c759d7 --- /dev/null +++ b/target/linux/airoha/patches-6.18/921-net-airoha-move-get_sport-callback-at-the-beginning-.patch @@ -0,0 +1,36 @@ +From 18aa76cd820c412358dc36d115b8e02d24a78f39 Mon Sep 17 00:00:00 2001 +Message-ID: <18aa76cd820c412358dc36d115b8e02d24a78f39.1780942778.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Mon, 8 Jun 2026 20:10:35 +0200 +Subject: [PATCH] net: airoha: move get_sport() callback at the beginning of + airoha_enable_gdm2_loopback() + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2250,6 +2250,10 @@ static int airoha_enable_gdm2_loopback(s + u32 val, pse_port, chan; + int i, src_port; + ++ src_port = eth->soc->ops.get_sport(port, dev->nbq); ++ if (src_port < 0) ++ return src_port; ++ + airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), + FE_PSE_PORT_DROP); + airoha_fe_clear(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), +@@ -2275,10 +2279,6 @@ static int airoha_enable_gdm2_loopback(s + airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX)); + airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX)); + +- src_port = eth->soc->ops.get_sport(port, dev->nbq); +- if (src_port < 0) +- return src_port; +- + airoha_fe_rmw(eth, REG_FE_WAN_PORT, + WAN1_EN_MASK | WAN1_MASK | WAN0_MASK, + FIELD_PREP(WAN0_MASK, src_port)); diff --git a/target/linux/airoha/patches-6.18/922-net-airoha-simplify-WAN-device-check-in-airoha_dev_i.patch b/target/linux/airoha/patches-6.18/922-net-airoha-simplify-WAN-device-check-in-airoha_dev_i.patch new file mode 100644 index 00000000000..c9e788e3e15 --- /dev/null +++ b/target/linux/airoha/patches-6.18/922-net-airoha-simplify-WAN-device-check-in-airoha_dev_i.patch @@ -0,0 +1,42 @@ +From 3d67e4ba79bd4b40f520d26af098f133b5f551d4 Mon Sep 17 00:00:00 2001 +Message-ID: <3d67e4ba79bd4b40f520d26af098f133b5f551d4.1781097105.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Sat, 6 Jun 2026 08:53:03 +0200 +Subject: [PATCH] net: airoha: simplify WAN device check in airoha_dev_init() + +airoha_register_gdm_devices() iterates eth->ports[] in order, so GDM2's +netdev is always registered before GDM3/GDM4. This means the explicit +check for eth->ports[1] && eth->ports[1]->devs[0] is a redundant +special-case of what airoha_get_wan_gdm_dev() already covers, since +GDM2 is always marked as WAN during its own ndo_init. +Remove the redundant check and rely solely on airoha_get_wan_gdm_dev() +which handles both the GDM2-present and GDM2-absent cases. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2407,18 +2407,10 @@ static int airoha_dev_init(struct net_de + + switch (port->id) { + case AIROHA_GDM3_IDX: +- case AIROHA_GDM4_IDX: { +- struct airoha_eth *eth = dev->eth; +- +- /* GDM2 supports a single net_device */ +- if (eth->ports[1] && eth->ports[1]->devs[0]) +- break; +- +- if (airoha_get_wan_gdm_dev(eth)) ++ case AIROHA_GDM4_IDX: ++ if (airoha_get_wan_gdm_dev(dev->eth)) + break; +- + fallthrough; +- } + case AIROHA_GDM2_IDX: + /* GDM2 is always used as wan */ + dev->flags |= AIROHA_PRIV_F_WAN; -- 2.47.3