diff --git a/target/linux/airoha/patches-6.12/920-01-net-airoha-Add-airoha_gdm_dev-struct.patch b/target/linux/airoha/patches-6.12/920-01-net-airoha-Introduce-airoha_gdm_dev-struct.patch similarity index 68% rename from target/linux/airoha/patches-6.12/920-01-net-airoha-Add-airoha_gdm_dev-struct.patch rename to target/linux/airoha/patches-6.12/920-01-net-airoha-Introduce-airoha_gdm_dev-struct.patch index f56d26b103b6aa..71a2f725492800 100644 --- a/target/linux/airoha/patches-6.12/920-01-net-airoha-Add-airoha_gdm_dev-struct.patch +++ b/target/linux/airoha/patches-6.12/920-01-net-airoha-Introduce-airoha_gdm_dev-struct.patch @@ -1,40 +1,50 @@ -From 2cd15ef3379025ea1ae1f6c36c70621aa578c270 Mon Sep 17 00:00:00 2001 -Message-ID: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> +From e15783f7c987e199ecf80b3d858ed5a86d33c508 Mon Sep 17 00:00:00 2001 +Message-ID: From: Lorenzo Bianconi Date: Sat, 1 Nov 2025 11:25:52 +0100 -Subject: [bpf-next 01/16] net: airoha: Add airoha_gdm_dev struct +Subject: [PATCH 01/13] net: airoha: Introduce airoha_gdm_dev struct -Introduce airoha_gdm_dev stuct to collect net_device related info (e.g. -net_device and external phy pointer). This is a preliminary patch to -support multiple net_devices connected to the same Frame Engine GDM port -via an external arbiter/multiplexer. +EN7581 and AN7583 SoCs support connecting multiple external SerDes to GDM3 +or GDM4 ports via a hw arbiter that manages the traffic in a TDM manner. +As a result multiple net_devices can connect to the same GDM{3,4} port +and there is a theoretical "1:n" relation between GDM port and +net_devices. +Introduce airoha_gdm_dev struct to collect net_device related info (e.g. +net_device and external phy pointer). Please note this is just a +preliminary patch and we are still supporting a single net_device for +each GDM port. Subsequent patches will add support for multiple net_devices +connected to the same GDM port. +Tested-by: Xuegang Lu Signed-off-by: Lorenzo Bianconi --- - drivers/net/ethernet/airoha/airoha_eth.c | 266 ++++++++++++++--------- - drivers/net/ethernet/airoha/airoha_eth.h | 12 +- + drivers/net/ethernet/airoha/airoha_eth.c | 312 ++++++++++++++--------- + drivers/net/ethernet/airoha/airoha_eth.h | 13 +- drivers/net/ethernet/airoha/airoha_ppe.c | 17 +- - 3 files changed, 178 insertions(+), 117 deletions(-) + 3 files changed, 206 insertions(+), 136 deletions(-) --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -632,6 +632,7 @@ static int airoha_qdma_rx_process(struct - struct page *page = virt_to_head_page(e->buf); - u32 desc_ctrl = le32_to_cpu(desc->ctrl); +@@ -721,6 +721,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; + struct net_device *netdev; int data_len, len, p; + struct page *page; - if (!(desc_ctrl & QDMA_DESC_DONE_MASK)) -@@ -654,6 +655,7 @@ static int airoha_qdma_rx_process(struct +@@ -747,6 +748,10 @@ static int airoha_qdma_rx_process(struct goto free_frag; port = eth->ports[p]; ++ if (!port->dev) ++ goto free_frag; ++ + netdev = port->dev->dev; if (!q->skb) { /* first buffer */ - q->skb = napi_build_skb(e->buf, q->buf_size); - if (!q->skb) -@@ -661,15 +663,15 @@ static int airoha_qdma_rx_process(struct + q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM, + q->buf_size); +@@ -756,15 +761,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); @@ -53,7 +63,7 @@ Signed-off-by: Lorenzo Bianconi } else { /* scattered frame */ struct skb_shared_info *shinfo = skb_shinfo(q->skb); int nr_frags = shinfo->nr_frags; -@@ -680,7 +682,7 @@ static int airoha_qdma_rx_process(struct +@@ -780,7 +785,7 @@ static int airoha_qdma_rx_process(struct if (FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl)) continue; @@ -62,7 +72,7 @@ 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 -@@ -680,19 +682,21 @@ static int airoha_qdma_rx_process(struct +@@ -977,6 +982,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]; @@ -70,14 +80,12 @@ Signed-off-by: Lorenzo Bianconi int j; if (!port) - continue; - -- if (port->qdma != qdma) -+ dev = port->dev; -+ if (dev->qdma != qdma) +@@ -985,11 +991,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++) { if (airoha_qdma_get_txq(qdma, j) != qid) continue; @@ -87,7 +95,7 @@ Signed-off-by: Lorenzo Bianconi } } q->txq_stopped = false; -@@ -1626,10 +1628,11 @@ static void airoha_update_hw_stats(struc +@@ -1833,33 +1840,34 @@ static void airoha_update_hw_stats(struc spin_unlock(&port->stats.lock); } @@ -100,9 +108,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; - - #if defined(CONFIG_PCS_AIROHA) -@@ -1633,14 +1633,14 @@ static int airoha_dev_open(struct net_de + u32 pse_port = FE_PSE_PORT_PPE1; #if defined(CONFIG_PCS_AIROHA) if (airhoa_is_phy_external(port)) { @@ -120,10 +126,6 @@ Signed-off-by: Lorenzo Bianconi } #endif -@@ -1645,13 +1648,13 @@ static int airoha_dev_open(struct net_de - } - #endif - - netif_tx_start_all_queues(dev); + netif_tx_start_all_queues(netdev); err = airoha_set_vip_for_gdm_port(port, true); @@ -136,7 +138,7 @@ Signed-off-by: Lorenzo Bianconi airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id), GDM_STAG_EN_MASK); else -@@ -1671,16 +1674,17 @@ static int airoha_dev_open(struct net_de +@@ -1887,16 +1895,17 @@ static int airoha_dev_open(struct net_de return 0; } @@ -159,7 +161,7 @@ Signed-off-by: Lorenzo Bianconi airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), FE_PSE_PORT_DROP); -@@ -1700,8 +1700,8 @@ static int airoha_dev_stop(struct net_de +@@ -1916,24 +1925,25 @@ static int airoha_dev_stop(struct net_de #if defined(CONFIG_PCS_AIROHA) if (airhoa_is_phy_external(port)) { @@ -170,7 +172,6 @@ Signed-off-by: Lorenzo Bianconi } #endif -@@ -1708,16 +1712,17 @@ static int airoha_dev_stop(struct net_de return 0; } @@ -192,7 +193,7 @@ Signed-off-by: Lorenzo Bianconi return 0; } -@@ -1751,16 +1756,17 @@ static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) +@@ -1997,16 +2007,17 @@ static int airoha_set_gdm2_loopback(stru return 0; } @@ -215,7 +216,7 @@ Signed-off-by: Lorenzo Bianconi switch (port->id) { case AIROHA_GDM3_IDX: -@@ -1827,10 +1833,11 @@ static int airoha_dev_init(struct net_de +@@ -2031,10 +2042,11 @@ static int airoha_dev_init(struct net_de return 0; } @@ -229,7 +230,7 @@ Signed-off-by: Lorenzo Bianconi unsigned int start; airoha_update_hw_stats(port); -@@ -1849,36 +1856,39 @@ static void airoha_dev_get_stats64(struc +@@ -2053,36 +2065,39 @@ static void airoha_dev_get_stats64(struc } while (u64_stats_fetch_retry(&port->stats.syncp, start)); } @@ -276,8 +277,8 @@ Signed-off-by: Lorenzo Bianconi } static u32 airoha_get_dsa_tag(struct sk_buff *skb, struct net_device *dev) -@@ -1942,12 +1952,13 @@ static int airoha_get_fe_port(struct air - : port->id; +@@ -2145,12 +2160,13 @@ int airoha_get_fe_port(struct airoha_gdm + } } -static int airoha_dev_set_features(struct net_device *dev, @@ -293,7 +294,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_qdma *qdma = port->qdma; struct airoha_eth *eth = qdma->eth; int qdma_id = qdma - ð->qdma[0]; -@@ -1942,9 +1952,10 @@ static int airoha_get_fe_port(struct air +@@ -2185,9 +2201,10 @@ static int airoha_dev_set_features(struc } static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, @@ -306,7 +307,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_qdma *qdma = port->qdma; u32 nr_frags, tag, msg0, msg1, len; struct airoha_queue_entry *e; -@@ -1957,7 +1968,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2200,7 +2217,7 @@ static netdev_tx_t airoha_dev_xmit(struc u8 fport; qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb)); @@ -315,7 +316,7 @@ Signed-off-by: Lorenzo Bianconi msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK, qid / AIROHA_NUM_QOS_QUEUES) | -@@ -1993,7 +2004,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2236,7 +2253,7 @@ static netdev_tx_t airoha_dev_xmit(struc spin_lock_bh(&q->lock); @@ -324,7 +325,7 @@ Signed-off-by: Lorenzo Bianconi nr_frags = 1 + skb_shinfo(skb)->nr_frags; if (q->queued + nr_frags >= q->ndesc) { -@@ -2016,9 +2027,9 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2260,9 +2277,9 @@ static netdev_tx_t airoha_dev_xmit(struc dma_addr_t addr; u32 val; @@ -336,18 +337,16 @@ Signed-off-by: Lorenzo Bianconi goto error_unmap; list_move_tail(&e->list, &tx_list); -@@ -2065,8 +2076,8 @@ error_unmap: +@@ -2311,7 +2328,7 @@ static netdev_tx_t airoha_dev_xmit(struc error_unmap: list_for_each_entry(e, &tx_list, list) { - dma_unmap_single(dev->dev.parent, e->dma_addr, e->dma_len, -- DMA_TO_DEVICE); -+ dma_unmap_single(netdev->dev.parent, e->dma_addr, -+ e->dma_len, DMA_TO_DEVICE); ++ dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len, + DMA_TO_DEVICE); e->dma_addr = 0; } - list_splice(&tx_list, &q->tx_list); -@@ -2074,25 +2085,27 @@ error_unmap: +@@ -2320,25 +2337,27 @@ error_unmap: spin_unlock_bh(&q->lock); error: dev_kfree_skb_any(skb); @@ -380,7 +379,7 @@ Signed-off-by: Lorenzo Bianconi unsigned int start; airoha_update_hw_stats(port); -@@ -2120,11 +2133,12 @@ static const struct ethtool_rmon_hist_ra +@@ -2366,11 +2385,12 @@ static const struct ethtool_rmon_hist_ra }; static void @@ -395,7 +394,92 @@ Signed-off-by: Lorenzo Bianconi struct airoha_hw_stats *hw_stats = &port->stats; unsigned int start; -@@ -2642,11 +2656,12 @@ static int airoha_tc_matchall_act_valida +@@ -2395,11 +2415,12 @@ airoha_ethtool_get_rmon_stats(struct net + } while (u64_stats_fetch_retry(&port->stats.syncp, start)); + } + +-static int airoha_qdma_set_chan_tx_sched(struct net_device *dev, ++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) + { +- struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; + int i; + + for (i = 0; i < AIROHA_NUM_TX_RING; i++) +@@ -2484,10 +2505,12 @@ static int airoha_qdma_set_tx_ets_sched( + ARRAY_SIZE(w)); + } + +-static int airoha_qdma_get_tx_ets_stats(struct net_device *dev, int channel, ++static int airoha_qdma_get_tx_ets_stats(struct net_device *netdev, int channel, + struct tc_ets_qopt_offload *opt) + { +- struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; ++ + u64 cpu_tx_packets = airoha_qdma_rr(port->qdma, + REG_CNTR_VAL(channel << 1)); + u64 fwd_tx_packets = airoha_qdma_rr(port->qdma, +@@ -2749,11 +2772,12 @@ static int airoha_qdma_set_trtcm_token_b + mode, val); + } + +-static int airoha_qdma_set_tx_rate_limit(struct net_device *dev, ++static int airoha_qdma_set_tx_rate_limit(struct net_device *netdev, + int channel, u32 rate, + u32 bucket_size) + { +- struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; + int i, err; + + for (i = 0; i <= TRTCM_PEAK_MODE; i++) { +@@ -2773,20 +2797,22 @@ static int airoha_qdma_set_tx_rate_limit + return 0; + } + +-static int airoha_tc_htb_alloc_leaf_queue(struct net_device *dev, ++static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev, + struct tc_htb_qopt_offload *opt) + { + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; + u32 rate = div_u64(opt->rate, 1000) << 3; /* kbps */ +- int err, num_tx_queues = dev->real_num_tx_queues; +- struct airoha_gdm_port *port = netdev_priv(dev); ++ 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; + + if (opt->parent_classid != TC_HTB_CLASSID_ROOT) { + NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid"); + return -EINVAL; + } + +- err = airoha_qdma_set_tx_rate_limit(dev, channel, rate, opt->quantum); ++ err = airoha_qdma_set_tx_rate_limit(netdev, channel, rate, ++ opt->quantum); + if (err) { + NL_SET_ERR_MSG_MOD(opt->extack, + "failed configuring htb offload"); +@@ -2796,9 +2822,10 @@ static int airoha_tc_htb_alloc_leaf_queu + if (opt->command == TC_HTB_NODE_MODIFY) + return 0; + +- err = netif_set_real_num_tx_queues(dev, num_tx_queues + 1); ++ err = netif_set_real_num_tx_queues(netdev, num_tx_queues + 1); + if (err) { +- airoha_qdma_set_tx_rate_limit(dev, channel, 0, opt->quantum); ++ airoha_qdma_set_tx_rate_limit(netdev, channel, 0, ++ opt->quantum); + NL_SET_ERR_MSG_MOD(opt->extack, + "failed setting real_num_tx_queues"); + return err; +@@ -2888,11 +2915,12 @@ static int airoha_tc_matchall_act_valida return 0; } @@ -410,7 +494,7 @@ Signed-off-by: Lorenzo Bianconi u32 rate = 0, bucket_size = 0; switch (f->command) { -@@ -2681,18 +2696,19 @@ static int airoha_dev_tc_matchall(struct +@@ -2927,18 +2955,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) { @@ -434,7 +518,82 @@ Signed-off-by: Lorenzo Bianconi default: return -EOPNOTSUPP; } -@@ -2897,13 +2915,18 @@ static void airoha_metadata_dst_free(str +@@ -2985,47 +3014,51 @@ static int airoha_dev_setup_tc_block(str + } + } + +-static void airoha_tc_remove_htb_queue(struct net_device *dev, int queue) ++static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue) + { +- struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; + +- netif_set_real_num_tx_queues(dev, dev->real_num_tx_queues - 1); +- airoha_qdma_set_tx_rate_limit(dev, queue + 1, 0, 0); ++ netif_set_real_num_tx_queues(netdev, netdev->real_num_tx_queues - 1); ++ airoha_qdma_set_tx_rate_limit(netdev, queue + 1, 0, 0); + clear_bit(queue, port->qos_sq_bmap); + } + +-static int airoha_tc_htb_delete_leaf_queue(struct net_device *dev, ++static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev, + struct tc_htb_qopt_offload *opt) + { + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; +- struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; + + if (!test_bit(channel, port->qos_sq_bmap)) { + NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); + return -EINVAL; + } + +- airoha_tc_remove_htb_queue(dev, channel); ++ airoha_tc_remove_htb_queue(netdev, channel); + + return 0; + } + +-static int airoha_tc_htb_destroy(struct net_device *dev) ++static int airoha_tc_htb_destroy(struct net_device *netdev) + { +- struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; + int q; + + for_each_set_bit(q, port->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS) +- airoha_tc_remove_htb_queue(dev, q); ++ airoha_tc_remove_htb_queue(netdev, q); + + return 0; + } + +-static int airoha_tc_get_htb_get_leaf_queue(struct net_device *dev, ++static int airoha_tc_get_htb_get_leaf_queue(struct net_device *netdev, + struct tc_htb_qopt_offload *opt) + { + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; +- struct airoha_gdm_port *port = netdev_priv(dev); ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; + + if (!test_bit(channel, port->qos_sq_bmap)) { + NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); +@@ -3061,8 +3094,8 @@ static int airoha_tc_setup_qdisc_htb(str + return 0; + } + +-static int airoha_dev_tc_setup(struct net_device *dev, enum tc_setup_type type, +- void *type_data) ++static int airoha_dev_tc_setup(struct net_device *dev, ++ enum tc_setup_type type, void *type_data) + { + switch (type) { + case TC_SETUP_QDISC_ETS: +@@ -3134,13 +3167,18 @@ static void airoha_metadata_dst_free(str } } @@ -456,24 +615,21 @@ Signed-off-by: Lorenzo Bianconi return true; } -@@ -2950,10 +2950,10 @@ static void airoha_mac_link_up(struct ph +@@ -3152,8 +3190,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) { - struct airoha_gdm_port *port = container_of(config, struct airoha_gdm_port, - phylink_config); -- struct airoha_qdma *qdma = port->qdma; -- struct airoha_eth *eth = qdma->eth; + struct airoha_gdm_dev *dev = container_of(config, struct airoha_gdm_dev, + phylink_config); + struct airoha_gdm_port *port = dev->port; -+ struct airoha_eth *eth = dev->eth; + struct airoha_qdma *qdma = port->qdma; + struct airoha_eth *eth = qdma->eth; u32 frag_size_tx, frag_size_rx; - - switch (speed) { -@@ -3000,54 +3000,54 @@ static const struct phylink_mac_ops airo - .mac_link_up = airoha_mac_link_up, - }; +@@ -3209,65 +3248,122 @@ static int airoha_fill_available_pcs(str + &num_available_pcs); + } -static int airoha_setup_phylink(struct net_device *dev) +static int airoha_setup_phylink(struct net_device *netdev) @@ -496,11 +652,13 @@ Signed-off-by: Lorenzo Bianconi - port->phylink_config.dev = &dev->dev; - port->phylink_config.type = PHYLINK_NETDEV; - port->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | +- MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD | +- MAC_5000FD | MAC_10000FD; + dev->phylink_config.dev = &netdev->dev; + dev->phylink_config.type = PHYLINK_NETDEV; + dev->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD | - MAC_5000FD | MAC_10000FD; ++ MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD | ++ MAC_5000FD | MAC_10000FD; - err = fwnode_phylink_pcs_parse(dev_fwnode(&dev->dev), NULL, - &port->phylink_config.num_available_pcs); @@ -545,8 +703,6 @@ Signed-off-by: Lorenzo Bianconi return err; } -@@ -3005,12 +3028,69 @@ static int airoha_setup_phylink(struct n - } #endif +static int airoha_alloc_gdm_device(struct airoha_eth *eth, @@ -593,6 +749,7 @@ Signed-off-by: Lorenzo Bianconi + dev = netdev_priv(netdev); + dev->dev = netdev; + dev->port = port; ++ port->dev = dev; + dev->eth = eth; + +#if defined(CONFIG_PCS_AIROHA) @@ -602,7 +759,6 @@ Signed-off-by: Lorenzo Bianconi + return err; + } +#endif -+ port->dev = dev; + + return 0; +} @@ -616,7 +772,7 @@ Signed-off-by: Lorenzo Bianconi int err, p; u32 id; -@@ -3033,44 +3107,12 @@ static int airoha_alloc_gdm_port(struct +@@ -3289,58 +3385,22 @@ static int airoha_alloc_gdm_port(struct return -EINVAL; } @@ -644,12 +800,12 @@ Signed-off-by: Lorenzo Bianconi - err = netif_set_real_num_tx_queues(dev, AIROHA_NUM_TX_RING); - if (err) - return err; -- + - err = of_get_ethdev_address(np, dev); - if (err) { - if (err == -EPROBE_DEFER) - return err; - +- - eth_hw_addr_random(dev); - dev_info(eth->dev, "generated random MAC address %pM\n", - dev->dev_addr); @@ -661,10 +817,8 @@ Signed-off-by: Lorenzo Bianconi - port->eth = eth; - port->dev = dev; port->id = id; - eth->ports[p] = port; - -@@ -3050,15 +050,11 @@ static int airoha_alloc_gdm_port(struct - port->id = id; + /* XXX: Read nbq from DTS */ + port->nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0; eth->ports[p] = port; -#if defined(CONFIG_PCS_AIROHA) @@ -674,17 +828,16 @@ Signed-off-by: Lorenzo Bianconi - return err; - } -#endif -- -- return airoha_metadata_dst_alloc(port); + err = airoha_metadata_dst_alloc(port); + if (err) + return err; -+ + +- return airoha_metadata_dst_alloc(port); + return airoha_alloc_gdm_device(eth, port, np); } static int airoha_register_gdm_devices(struct airoha_eth *eth) -@@ -3104,7 +3143,7 @@ static int airoha_register_gdm_devices(s +@@ -3354,7 +3414,7 @@ static int airoha_register_gdm_devices(s if (!port) continue; @@ -693,7 +846,7 @@ Signed-off-by: Lorenzo Bianconi if (err) return err; } -@@ -3216,17 +3255,22 @@ error_hw_cleanup: +@@ -3463,16 +3523,18 @@ error_napi_stop: for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -703,27 +856,19 @@ Signed-off-by: Lorenzo Bianconi continue; - if (port->dev->reg_state == NETREG_REGISTERED) { --#if defined(CONFIG_PCS_AIROHA) -- if (airhoa_is_phy_external(port)) -- phylink_destroy(port->phylink); --#endif -- unregister_netdev(port->dev); -- } -+ if (!port->dev) -+ continue; -+ + dev = port->dev; -+ if (dev->dev->reg_state == NETREG_REGISTERED) { -+#if defined(CONFIG_PCS_AIROHA) -+ if (airhoa_is_phy_external(port)) ++ if (dev && dev->dev->reg_state == NETREG_REGISTERED) { + #if defined(CONFIG_PCS_AIROHA) + if (airhoa_is_phy_external(port)) +- phylink_destroy(port->phylink); + phylink_destroy(dev->phylink); -+#endif + #endif +- unregister_netdev(port->dev); + unregister_netdev(dev->dev); -+ } + } airoha_metadata_dst_free(port); } - airoha_hw_cleanup(eth); -@@ -3248,16 +3293,21 @@ static void airoha_remove(struct platfor +@@ -3494,15 +3556,19 @@ static void airoha_remove(struct platfor for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -732,58 +877,50 @@ Signed-off-by: Lorenzo Bianconi if (!port) continue; --#if defined(CONFIG_PCS_AIROHA) -- if (airhoa_is_phy_external(port)) + #if defined(CONFIG_PCS_AIROHA) + if (airhoa_is_phy_external(port)) - phylink_destroy(port->phylink); --#endif ++ phylink_destroy(dev->phylink); + #endif - unregister_netdev(port->dev); -+ if (!port->dev) -+ continue; + + dev = port->dev; -+#if defined(CONFIG_PCS_AIROHA) -+ if (airhoa_is_phy_external(port)) -+ phylink_destroy(dev->phylink); -+#endif -+ unregister_netdev(dev->dev); ++ if (dev) ++ unregister_netdev(dev->dev); airoha_metadata_dst_free(port); } - free_netdev(eth->napi_dev); - + airoha_hw_cleanup(eth); --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -531,18 +531,23 @@ struct airoha_qdma { +@@ -546,17 +546,22 @@ 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 net_device *dev; +- int id; +- int nbq; + struct airoha_eth *eth; -+ -+#if defined(CONFIG_PCS_AIROHA) -+ struct phylink *phylink; -+ struct phylink_config phylink_config; -+#endif + + #if defined(CONFIG_PCS_AIROHA) + struct phylink *phylink; + struct phylink_config phylink_config; + #endif +}; + - struct airoha_gdm_port { - struct airoha_qdma *qdma; -- struct airoha_eth *eth; -- struct net_device *dev; ++struct airoha_gdm_port { ++ struct airoha_qdma *qdma; + struct airoha_gdm_dev *dev; - int id; - int nbq; ++ int id; ++ int nbq; --#if defined(CONFIG_PCS_AIROHA) -- struct phylink *phylink; -- struct phylink_config phylink_config; --#endif -- struct airoha_hw_stats stats; - DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); -@@ -651,8 +657,8 @@ static inline bool airoha_is_7583(struct +@@ -690,8 +695,8 @@ static inline bool airoha_qdma_is_lro_qu } int airoha_get_fe_port(struct airoha_gdm_port *port); @@ -792,11 +929,11 @@ Signed-off-by: Lorenzo Bianconi +bool airoha_is_valid_gdm_dev(struct airoha_eth *eth, + struct airoha_gdm_dev *dev); - 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, + void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id, + u8 fport); --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c -@@ -268,12 +268,12 @@ static void airoha_ppe_foe_set_bridge_ad +@@ -297,12 +297,12 @@ static void airoha_ppe_foe_set_bridge_ad static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth, struct airoha_foe_entry *hwe, @@ -811,7 +948,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_foe_mac_info_common *l2; u8 smac_id = 0xf; -@@ -289,10 +289,11 @@ static int airoha_ppe_foe_entry_prepare( +@@ -318,10 +318,11 @@ static int airoha_ppe_foe_entry_prepare( hwe->ib1 = val; val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f); @@ -825,14 +962,14 @@ Signed-off-by: Lorenzo Bianconi val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, info.idx) | FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, FE_PSE_PORT_CDM4); -@@ -302,12 +303,14 @@ static int airoha_ppe_foe_entry_prepare( +@@ -331,12 +332,14 @@ static int airoha_ppe_foe_entry_prepare( FIELD_PREP(AIROHA_FOE_MAC_WDMA_WCID, info.wcid); } else { - struct airoha_gdm_port *port = netdev_priv(dev); + struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port; u8 pse_port, channel, priority; ++ struct airoha_gdm_port *port; - if (!airoha_is_valid_gdm_port(eth, port)) + if (!airoha_is_valid_gdm_dev(eth, dev)) @@ -842,7 +979,7 @@ Signed-off-by: Lorenzo Bianconi if (dsa_port >= 0 || eth->ports[1]) pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id; -@@ -1400,7 +1403,7 @@ void airoha_ppe_check_skb(struct airoha_ +@@ -1483,7 +1486,7 @@ void airoha_ppe_check_skb(struct airoha_ void airoha_ppe_init_upd_mem(struct airoha_gdm_port *port) { struct airoha_eth *eth = port->qdma->eth; diff --git a/target/linux/airoha/patches-6.12/920-05-net-airoha-Move-airoha_qdma-porinter-in-airoha_gdm_d.patch b/target/linux/airoha/patches-6.12/920-02-net-airoha-Move-airoha_qdma-pointer-in-airoha_gdm_de.patch similarity index 71% rename from target/linux/airoha/patches-6.12/920-05-net-airoha-Move-airoha_qdma-porinter-in-airoha_gdm_d.patch rename to target/linux/airoha/patches-6.12/920-02-net-airoha-Move-airoha_qdma-pointer-in-airoha_gdm_de.patch index 4730c479865c3f..222d73cfcebb20 100644 --- a/target/linux/airoha/patches-6.12/920-05-net-airoha-Move-airoha_qdma-porinter-in-airoha_gdm_d.patch +++ b/target/linux/airoha/patches-6.12/920-02-net-airoha-Move-airoha_qdma-pointer-in-airoha_gdm_de.patch @@ -1,26 +1,30 @@ -From 8d44068d63072a3b3c840f86c328208fcf9ca517 Mon Sep 17 00:00:00 2001 -Message-ID: <8d44068d63072a3b3c840f86c328208fcf9ca517.1771966444.git.lorenzo@kernel.org> -In-Reply-To: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> -References: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> +From f62cea6483cc55360863d66300790a5fb9de5f7c Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: From: Lorenzo Bianconi Date: Tue, 24 Feb 2026 18:43:05 +0100 -Subject: [bpf-next 05/16] net: airoha: Move airoha_qdma porinter in - airoha_gdm_dev struct +Subject: [PATCH 02/13] net: airoha: Move airoha_qdma pointer in airoha_gdm_dev + struct -Move airoha_qdma porinter from airoha_gdm_port struct to airoha_gdm_dev -one. This is a preliminary patch to support multiple net_devices connected -to the same Frame Engine GDM port via an external arbiter. +Move airoha_qdma pointer from airoha_gdm_port struct to airoha_gdm_dev +one since the QDMA block used depends on the particular net_device +WAN/LAN configuration and in the current codebase net_device pointer is +associated to airoha_gdm_dev struct. +This is a preliminary patch to support multiple net_devices connected +to the same GDM{3,4} port via an external hw arbiter. +Tested-by: Xuegang Lu Signed-off-by: Lorenzo Bianconi --- - drivers/net/ethernet/airoha/airoha_eth.c | 101 +++++++++++------------ - drivers/net/ethernet/airoha/airoha_eth.h | 4 +- - drivers/net/ethernet/airoha/airoha_ppe.c | 9 +- - 3 files changed, 56 insertions(+), 58 deletions(-) + drivers/net/ethernet/airoha/airoha_eth.c | 105 +++++++++++------------ + drivers/net/ethernet/airoha/airoha_eth.h | 9 +- + drivers/net/ethernet/airoha/airoha_ppe.c | 17 ++-- + 3 files changed, 64 insertions(+), 67 deletions(-) --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -79,9 +79,10 @@ static bool airoha_is_phy_external(struc +@@ -80,9 +80,10 @@ static bool airhoa_is_phy_external(struc } #endif @@ -33,7 +37,7 @@ Signed-off-by: Lorenzo Bianconi u32 val, reg; reg = airoha_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H -@@ -93,7 +94,7 @@ static void airoha_set_macaddr(struct ai +@@ -94,7 +95,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); @@ -42,7 +46,7 @@ Signed-off-by: Lorenzo Bianconi } static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr, -@@ -109,10 +110,10 @@ static void airoha_set_gdm_port_fwd_cfg( +@@ -110,10 +111,10 @@ static void airoha_set_gdm_port_fwd_cfg( FIELD_PREP(GDM_UCFQ_MASK, val)); } @@ -55,8 +59,24 @@ Signed-off-by: Lorenzo Bianconi + struct airoha_eth *eth = dev->eth; u32 vip_port; - switch (port->id) { -@@ -1484,9 +1485,10 @@ static void airoha_qdma_stop_napi(struct + vip_port = eth->soc->ops.get_vip_port(port, port->nbq); +@@ -988,10 +989,13 @@ static void airoha_qdma_wake_netdev_txqs + if (!port) + continue; + +- if (port->qdma != qdma) ++ dev = port->dev; ++ if (!dev) ++ continue; ++ ++ 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; +@@ -1696,9 +1700,10 @@ static void airoha_qdma_stop_napi(struct } } @@ -69,16 +89,16 @@ Signed-off-by: Lorenzo Bianconi u32 val, i = 0; spin_lock(&port->stats.lock); -@@ -1633,7 +1635,7 @@ static int airoha_dev_open(struct net_de +@@ -1845,7 +1850,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; - u32 pse_port = FE_PSE_PORT_PPE1; + u32 pse_port = FE_PSE_PORT_PPE1; #if defined(CONFIG_PCS_AIROHA) -@@ -1649,7 +1651,7 @@ static int airoha_dev_open(struct net_de +@@ -1862,7 +1867,7 @@ static int airoha_dev_open(struct net_de #endif netif_tx_start_all_queues(netdev); @@ -87,7 +107,7 @@ Signed-off-by: Lorenzo Bianconi if (err) return err; -@@ -1677,11 +1679,11 @@ static int airoha_dev_open(struct net_de +@@ -1899,11 +1904,11 @@ static int airoha_dev_stop(struct net_de { struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; @@ -101,7 +121,7 @@ Signed-off-by: Lorenzo Bianconi for (i = 0; i < netdev->num_tx_queues; i++) netdev_tx_reset_subqueue(netdev, i); -@@ -1715,21 +1716,21 @@ static int airoha_dev_stop(struct net_de +@@ -1936,21 +1941,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); @@ -125,9 +145,9 @@ Signed-off-by: Lorenzo Bianconi + struct airoha_gdm_port *port = dev->port; + struct airoha_eth *eth = dev->eth; u32 val, pse_port, chan; - int src_port; + int i, src_port; -@@ -1715,7 +1716,7 @@ static int airoha_dev_stop(struct net_de +@@ -1995,7 +2000,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++) @@ -135,8 +155,8 @@ Signed-off-by: Lorenzo Bianconi + airoha_ppe_set_cpu_port(dev, i, AIROHA_GDM2_IDX); if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) { - u32 mask = FC_ID_OF_SRC_PORT_MASK(dev->nbq); -@@ -1764,9 +1766,9 @@ static int airoha_dev_init(struct net_device *netdev) + u32 mask = FC_ID_OF_SRC_PORT_MASK(port->nbq); +@@ -2015,9 +2020,9 @@ static int airoha_dev_init(struct net_de int i; /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ @@ -149,7 +169,7 @@ Signed-off-by: Lorenzo Bianconi switch (port->id) { case AIROHA_GDM3_IDX: -@@ -1801,7 +1802,7 @@ static int airoha_dev_init(struct net_de +@@ -2026,7 +2031,7 @@ static int airoha_dev_init(struct net_de if (!eth->ports[1]) { int err; @@ -158,17 +178,17 @@ Signed-off-by: Lorenzo Bianconi if (err) return err; } -@@ -1785,7 +1787,7 @@ static int airoha_dev_init(struct net_device *netdev) +@@ -2036,8 +2041,7 @@ static int airoha_dev_init(struct net_de } for (i = 0; i < eth->soc->num_ppe; i++) - airoha_ppe_set_cpu_port(port, i, - airoha_get_fe_port(port)); -+ airoha_ppe_set_cpu_port(dev, i, -+ airoha_get_fe_port(dev)); - ++ airoha_ppe_set_cpu_port(dev, i, airoha_get_fe_port(dev)); + return 0; -@@ -1840,7 +1841,7 @@ static void airoha_dev_get_stats64(struc + } +@@ -2049,7 +2053,7 @@ static void airoha_dev_get_stats64(struc struct airoha_gdm_port *port = dev->port; unsigned int start; @@ -177,7 +197,7 @@ Signed-off-by: Lorenzo Bianconi do { start = u64_stats_fetch_begin(&port->stats.syncp); storage->rx_packets = port->stats.rx_ok_pkts; -@@ -1860,8 +1861,8 @@ static int airoha_dev_change_mtu(struct +@@ -2069,8 +2073,8 @@ static int airoha_dev_change_mtu(struct { struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; @@ -187,7 +207,7 @@ Signed-off-by: Lorenzo Bianconi airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), GDM_LONG_LEN_MASK, -@@ -1935,10 +1936,10 @@ static u32 airoha_get_dsa_tag(struct sk_ +@@ -2144,10 +2148,10 @@ static u32 airoha_get_dsa_tag(struct sk_ #endif } @@ -201,7 +221,7 @@ Signed-off-by: Lorenzo Bianconi switch (eth->soc->version) { case 0x7583: -@@ -1955,8 +1956,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2166,8 +2170,7 @@ static int airoha_dev_set_features(struc netdev_features_t diff = netdev->features ^ features; struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -211,7 +231,7 @@ Signed-off-by: Lorenzo Bianconi struct airoha_eth *eth = qdma->eth; int qdma_id = qdma - ð->qdma[0]; -@@ -1955,8 +1956,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2204,8 +2207,7 @@ static netdev_tx_t airoha_dev_xmit(struc struct net_device *netdev) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -221,7 +241,7 @@ Signed-off-by: Lorenzo Bianconi u32 nr_frags, tag, msg0, msg1, len; struct airoha_queue_entry *e; struct netdev_queue *txq; -@@ -1994,7 +1994,7 @@ static netdev_tx_t airoha_dev_xmit(struc +@@ -2243,7 +2245,7 @@ static netdev_tx_t airoha_dev_xmit(struc } } @@ -230,7 +250,7 @@ Signed-off-by: Lorenzo Bianconi msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) | FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f); -@@ -2094,8 +2094,7 @@ static void airoha_ethtool_get_drvinfo(s +@@ -2346,8 +2348,7 @@ static void airoha_ethtool_get_drvinfo(s struct ethtool_drvinfo *info) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -240,7 +260,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)); -@@ -2108,7 +2107,7 @@ static void airoha_ethtool_get_mac_stats +@@ -2360,7 +2361,7 @@ static void airoha_ethtool_get_mac_stats struct airoha_gdm_port *port = dev->port; unsigned int start; @@ -249,7 +269,7 @@ Signed-off-by: Lorenzo Bianconi do { start = u64_stats_fetch_begin(&port->stats.syncp); stats->FramesTransmittedOK = port->stats.tx_ok_pkts; -@@ -2148,7 +2147,7 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2400,7 +2401,7 @@ airoha_ethtool_get_rmon_stats(struct net ARRAY_SIZE(hw_stats->rx_len) + 1); *ranges = airoha_ethtool_rmon_ranges; @@ -258,17 +278,11 @@ Signed-off-by: Lorenzo Bianconi do { int i; -@@ -2167,22 +2166,22 @@ static int airoha_qdma_set_chan_tx_sched - } while (u64_stats_fetch_retry(&port->stats.syncp, start)); - } - --static int airoha_qdma_set_chan_tx_sched(struct net_device *dev, -+static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev, - int channel, enum tx_sched_mode mode, +@@ -2420,18 +2421,17 @@ static int airoha_qdma_set_chan_tx_sched const u16 *weights, u8 n_weights) { -- struct airoha_gdm_port *port = netdev_priv(dev); -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_gdm_port *port = dev->port; int i; for (i = 0; i < AIROHA_NUM_TX_RING; i++) @@ -285,7 +299,7 @@ Signed-off-by: Lorenzo Bianconi TWRR_RW_CMD_MASK | FIELD_PREP(TWRR_CHAN_IDX_MASK, channel) | FIELD_PREP(TWRR_QUEUE_IDX_MASK, i) | -@@ -2186,13 +2184,12 @@ static int airoha_qdma_set_chan_tx_sched +@@ -2439,13 +2439,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, @@ -301,23 +315,11 @@ Signed-off-by: Lorenzo Bianconi CHAN_QOS_MODE_MASK(channel), __field_prep(CHAN_QOS_MODE_MASK(channel), mode)); -@@ -2260,7 +2257,7 @@ static int airoha_qdma_get_tx_ets_stats( - ARRAY_SIZE(w)); - } +@@ -2511,9 +2510,9 @@ static int airoha_qdma_get_tx_ets_stats( + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; --static int airoha_qdma_get_tx_ets_stats(struct net_device *dev, int channel, -+static int airoha_qdma_get_tx_ets_stats(struct net_device *netdev, int channel, - struct tc_ets_qopt_offload *opt) - { - struct airoha_gdm_port *port = netdev_priv(dev); -@@ -2260,10 +2257,11 @@ static int airoha_qdma_get_tx_ets_stats( - static int airoha_qdma_get_tx_ets_stats(struct net_device *netdev, int channel, - struct tc_ets_qopt_offload *opt) - { -- struct airoha_gdm_port *port = netdev_priv(dev); - u64 cpu_tx_packets = airoha_qdma_rr(port->qdma, -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; + u64 cpu_tx_packets = airoha_qdma_rr(dev->qdma, REG_CNTR_VAL(channel << 1)); - u64 fwd_tx_packets = airoha_qdma_rr(port->qdma, @@ -325,17 +327,11 @@ 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); -@@ -2525,21 +2522,21 @@ static int airoha_qdma_set_tx_rate_limit - mode, val); - } - --static int airoha_qdma_set_tx_rate_limit(struct net_device *dev, -+static int airoha_qdma_set_tx_rate_limit(struct net_device *netdev, - int channel, u32 rate, +@@ -2777,17 +2776,16 @@ static int airoha_qdma_set_tx_rate_limit u32 bucket_size) { -- struct airoha_gdm_port *port = netdev_priv(dev); -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_gdm_port *port = dev->port; int i, err; for (i = 0; i <= TRTCM_PEAK_MODE; i++) { @@ -351,7 +347,7 @@ Signed-off-by: Lorenzo Bianconi REG_EGRESS_TRTCM_CFG, i, rate, bucket_size); if (err) -@@ -2583,11 +2579,11 @@ static int airoha_tc_htb_alloc_leaf_queu +@@ -2837,11 +2835,11 @@ static int airoha_tc_htb_alloc_leaf_queu return 0; } @@ -365,7 +361,7 @@ Signed-off-by: Lorenzo Bianconi int i; for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { -@@ -2666,7 +2662,6 @@ static int airoha_dev_tc_matchall(struct +@@ -2920,7 +2918,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); @@ -373,7 +369,7 @@ Signed-off-by: Lorenzo Bianconi u32 rate = 0, bucket_size = 0; switch (f->command) { -@@ -2691,7 +2686,7 @@ static int airoha_dev_tc_matchall(struct +@@ -2945,7 +2942,7 @@ static int airoha_dev_tc_matchall(struct fallthrough; } case TC_CLSMATCHALL_DESTROY: @@ -382,7 +378,7 @@ Signed-off-by: Lorenzo Bianconi unit_type); default: return -EOPNOTSUPP; -@@ -2703,8 +2698,7 @@ static int airoha_dev_setup_tc_block_cb( +@@ -2957,8 +2954,7 @@ static int airoha_dev_setup_tc_block_cb( { struct net_device *netdev = cb_priv; struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -392,26 +388,35 @@ Signed-off-by: Lorenzo Bianconi if (!tc_can_offload(netdev)) return -EOPNOTSUPP; +@@ -3193,7 +3189,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; +- struct airoha_qdma *qdma = port->qdma; ++ 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_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -533,6 +533,7 @@ struct airoha_qdma { +@@ -548,6 +548,7 @@ struct airoha_qdma { struct airoha_gdm_dev { struct airoha_gdm_port *port; + struct airoha_qdma *qdma; struct net_device *dev; + struct airoha_eth *eth; - #if defined(CONFIG_PCS_AIROHA) -@@ -533,7 +533,6 @@ struct airoha_qdma { +@@ -558,7 +559,6 @@ struct airoha_gdm_dev { }; struct airoha_gdm_port { - struct airoha_qdma *qdma; struct airoha_gdm_dev *dev; int id; - int nbq; -@@ -651,19 +651,19 @@ static inline bool airoha_is_7583(struct airoha_eth *eth) - return eth->soc->version == 0x7583; + int nbq; +@@ -694,19 +694,18 @@ static inline bool airoha_qdma_is_lro_qu + return !!(AIROHA_RXQ_LRO_EN_MASK & BIT(qid)); } -int airoha_get_fe_port(struct airoha_gdm_port *port); @@ -420,8 +425,8 @@ Signed-off-by: Lorenzo Bianconi struct airoha_gdm_dev *dev); -void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id, -+void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, - u8 fport); +- u8 fport); ++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, u16 hash, bool rx_wlan); @@ -435,8 +440,8 @@ Signed-off-by: Lorenzo Bianconi u32 hash); --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c -@@ -85,9 +85,9 @@ static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe) - return FIELD_GET(AIROHA_FOE_IB1_BIND_TIMESTAMP, timestamp); +@@ -85,9 +85,9 @@ static u32 airoha_ppe_get_timestamp(stru + AIROHA_FOE_IB1_BIND_TIMESTAMP); } -void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id, u8 fport) @@ -447,18 +452,18 @@ Signed-off-by: Lorenzo Bianconi struct airoha_eth *eth = qdma->eth; u8 qdma_id = qdma - ð->qdma[0]; u32 fe_cpu_port; -@@ -174,8 +174,8 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) +@@ -181,8 +181,8 @@ static void airoha_ppe_hw_init(struct ai if (!port) continue; - airoha_ppe_set_cpu_port(port, i, - airoha_get_fe_port(port)); + airoha_ppe_set_cpu_port(port->dev, i, -+ airoha_get_fe_port(dev)); ++ airoha_get_fe_port(port->dev)); } } } -@@ -1421,11 +1421,12 @@ void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb, +@@ -1483,11 +1483,12 @@ void airoha_ppe_check_skb(struct airoha_ airoha_ppe_foe_insert_entry(ppe, skb, hash, rx_wlan); } diff --git a/target/linux/airoha/patches-6.12/920-06-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airhoa_.patch b/target/linux/airoha/patches-6.12/920-03-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airoha_.patch similarity index 63% rename from target/linux/airoha/patches-6.12/920-06-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airhoa_.patch rename to target/linux/airoha/patches-6.12/920-03-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airoha_.patch index 890a4a0862c661..ed1b7f5e609671 100644 --- a/target/linux/airoha/patches-6.12/920-06-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airhoa_.patch +++ b/target/linux/airoha/patches-6.12/920-03-net-airoha-Rely-on-airoha_gdm_dev-pointer-in-airoha_.patch @@ -1,26 +1,29 @@ -From fae16fa0bb1f4203181aff0c7496518c2c8a4b9c Mon Sep 17 00:00:00 2001 -Message-ID: -In-Reply-To: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> -References: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> +From 32bfd008c19f9ad55514181d8cd02e14bf384475 Mon Sep 17 00:00:00 2001 +Message-ID: <32bfd008c19f9ad55514181d8cd02e14bf384475.1779348625.git.lorenzo@kernel.org> +In-Reply-To: +References: From: Lorenzo Bianconi Date: Sat, 13 Dec 2025 10:06:45 +0100 -Subject: [bpf-next 10/16] net: airoha: Rely on airoha_gdm_dev pointer in - airhoa_is_lan_gdm_port() +Subject: [PATCH 03/13] net: airoha: Rely on airoha_gdm_dev pointer in + airoha_is_lan_gdm_port() -Rename airhoa_is_lan_gdm_port in airhoa_is_lan_gdm_dev. -This is a preliminary patch to properly support multiple external phys -connected to the same GDM port. +Rename airoha_is_lan_gdm_port in airoha_is_lan_gdm_dev. Moreover, rely +on airoha_gdm_dev pointer in airoha_is_lan_gdm_dev() instead of +airoha_gdm_port one. +This is a preliminary patch to support multiple net_devices connected to +the same GDM{3,4} port via an external hw arbiter. +Tested-by: Xuegang Lu Signed-off-by: Lorenzo Bianconi --- - drivers/net/ethernet/airoha/airoha_eth.c | 4 +--- + drivers/net/ethernet/airoha/airoha_eth.c | 6 ++---- drivers/net/ethernet/airoha/airoha_eth.h | 4 +++- drivers/net/ethernet/airoha/airoha_ppe.c | 2 +- - 3 files changed, 5 insertions(+), 5 deletions(-) + 3 files changed, 6 insertions(+), 6 deletions(-) --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -81,12 +81,10 @@ static bool airhoa_is_phy_external(struc +@@ -82,12 +82,10 @@ static bool airhoa_is_phy_external(struc static void airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr) { @@ -34,8 +37,8 @@ Signed-off-by: Lorenzo Bianconi val = (addr[0] << 16) | (addr[1] << 8) | addr[2]; airoha_fe_wr(eth, reg, val); -@@ -324,7 +324,7 @@ static int airoha_ppe_foe_entry_prepare( - u8 ppe_id; +@@ -2020,7 +2018,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)]; @@ -45,9 +48,9 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -643,8 +643,10 @@ u32 airoha_rmw(void __iomem *base, u32 o - #define airoha_qdma_clear(qdma, offset, val) \ - airoha_rmw((qdma)->regs, (offset), (val), 0) +@@ -663,8 +663,10 @@ static inline u16 airoha_qdma_get_txq(st + return qid % ARRAY_SIZE(qdma->q_tx); + } -static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port) +static inline bool airoha_is_lan_gdm_dev(struct airoha_gdm_dev *dev) @@ -59,7 +62,7 @@ Signed-off-by: Lorenzo Bianconi * phy module. --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c -@@ -324,7 +324,7 @@ static int airoha_ppe_foe_entry_prepare( +@@ -365,7 +365,7 @@ static int airoha_ppe_foe_entry_prepare( /* For downlink traffic consume SRAM memory for hw * forwarding descriptors queue. */ diff --git a/target/linux/airoha/patches-6.12/920-04-net-airoha-Move-qos_sq_bmap-in-airoha_gdm_dev-struct.patch b/target/linux/airoha/patches-6.12/920-04-net-airoha-Move-qos_sq_bmap-in-airoha_gdm_dev-struct.patch new file mode 100644 index 00000000000000..b9a6b6c5bc66b7 --- /dev/null +++ b/target/linux/airoha/patches-6.12/920-04-net-airoha-Move-qos_sq_bmap-in-airoha_gdm_dev-struct.patch @@ -0,0 +1,184 @@ +From 634d75285db77f3385aa85a1bf2b185396225100 Mon Sep 17 00:00:00 2001 +Message-ID: <634d75285db77f3385aa85a1bf2b185396225100.1779348625.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Fri, 10 Apr 2026 14:35:32 +0200 +Subject: [PATCH 04/13] net: airoha: Move qos_sq_bmap in airoha_gdm_dev struct + +Since now multiple net_devices connected to different QDMA blocks can +share the same GDM port, qos_sq_bmap field can be overwritten with the +configuration obtained from a net_device connected to a different QDMA +block. In order to fix the issue move qos_sq_bmap field from +airoha_gdm_port struct to airoha_gdm_dev one. +Add qos_channel_map bitmap in airoha_qdma struct to track if a shared +QDMA channel is already in use by another net_device. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 58 +++++++++++++++--------- + drivers/net/ethernet/airoha/airoha_eth.h | 6 ++- + 2 files changed, 40 insertions(+), 24 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2793,30 +2793,40 @@ static int airoha_qdma_set_tx_rate_limit + return 0; + } + +-static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev, +- struct tc_htb_qopt_offload *opt) ++static int airoha_tc_htb_modify_queue(struct net_device *dev, ++ struct tc_htb_qopt_offload *opt) + { + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; + u32 rate = div_u64(opt->rate, 1000) << 3; /* kbps */ +- 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; + + if (opt->parent_classid != TC_HTB_CLASSID_ROOT) { + NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid"); + return -EINVAL; + } + +- 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); ++} ++ ++static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev, ++ struct tc_htb_qopt_offload *opt) ++{ ++ 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; ++ ++ /* Here we need to check the requested QDMA channel is not already ++ * 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; ++ "qdma qos channel already in use"); ++ return -EBUSY; + } + +- if (opt->command == TC_HTB_NODE_MODIFY) +- return 0; ++ err = airoha_tc_htb_modify_queue(netdev, opt); ++ if (err) ++ goto error; + + err = netif_set_real_num_tx_queues(netdev, num_tx_queues + 1); + if (err) { +@@ -2824,13 +2834,17 @@ static int airoha_tc_htb_alloc_leaf_queu + opt->quantum); + NL_SET_ERR_MSG_MOD(opt->extack, + "failed setting real_num_tx_queues"); +- return err; ++ goto error; + } + +- set_bit(channel, port->qos_sq_bmap); ++ set_bit(channel, dev->qos_sq_bmap); + opt->qid = AIROHA_NUM_TX_RING + channel; + + return 0; ++error: ++ clear_bit(channel, qdma->qos_channel_map); ++ ++ return err; + } + + static int airoha_qdma_set_rx_meter(struct airoha_gdm_dev *dev, +@@ -3011,11 +3025,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); +- struct airoha_gdm_port *port = dev->port; ++ struct airoha_qdma *qdma = dev->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); +- clear_bit(queue, port->qos_sq_bmap); ++ ++ clear_bit(queue, qdma->qos_channel_map); ++ clear_bit(queue, dev->qos_sq_bmap); + } + + static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev, +@@ -3023,9 +3039,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); +- struct airoha_gdm_port *port = dev->port; + +- if (!test_bit(channel, port->qos_sq_bmap)) { ++ if (!test_bit(channel, dev->qos_sq_bmap)) { + NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); + return -EINVAL; + } +@@ -3038,10 +3053,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); +- struct airoha_gdm_port *port = dev->port; + int q; + +- for_each_set_bit(q, port->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS) ++ for_each_set_bit(q, dev->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS) + airoha_tc_remove_htb_queue(netdev, q); + + return 0; +@@ -3052,9 +3066,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); +- struct airoha_gdm_port *port = dev->port; + +- if (!test_bit(channel, port->qos_sq_bmap)) { ++ if (!test_bit(channel, dev->qos_sq_bmap)) { + NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); + return -EINVAL; + } +@@ -3073,6 +3086,7 @@ static int airoha_tc_setup_qdisc_htb(str + case TC_HTB_DESTROY: + return airoha_tc_htb_destroy(dev); + case TC_HTB_NODE_MODIFY: ++ return airoha_tc_htb_modify_queue(dev, opt); + case TC_HTB_LEAF_ALLOC_QUEUE: + return airoha_tc_htb_alloc_leaf_queue(dev, opt); + case TC_HTB_LEAF_DEL: +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -544,6 +544,8 @@ struct airoha_qdma { + + struct airoha_queue q_tx[AIROHA_NUM_TX_RING]; + struct airoha_queue q_rx[AIROHA_NUM_RX_RING]; ++ ++ DECLARE_BITMAP(qos_channel_map, AIROHA_NUM_QOS_CHANNELS); + }; + + struct airoha_gdm_dev { +@@ -556,6 +558,8 @@ struct airoha_gdm_dev { + struct phylink *phylink; + struct phylink_config phylink_config; + #endif ++ ++ DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); + }; + + struct airoha_gdm_port { +@@ -565,8 +569,6 @@ struct airoha_gdm_port { + + struct airoha_hw_stats stats; + +- DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); +- + /* qos stats counters */ + u64 cpu_tx_packets; + u64 fwd_tx_packets; diff --git a/target/linux/airoha/patches-6.12/920-05-net-airoha-Move-cpu-fwd-_tx_packets-in-airoha_gdm_de.patch b/target/linux/airoha/patches-6.12/920-05-net-airoha-Move-cpu-fwd-_tx_packets-in-airoha_gdm_de.patch new file mode 100644 index 00000000000000..08cbf6f4c44deb --- /dev/null +++ b/target/linux/airoha/patches-6.12/920-05-net-airoha-Move-cpu-fwd-_tx_packets-in-airoha_gdm_de.patch @@ -0,0 +1,73 @@ +From 00272dbf6a52241a21145631f22dc5f03891078b Mon Sep 17 00:00:00 2001 +Message-ID: <00272dbf6a52241a21145631f22dc5f03891078b.1779348625.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Fri, 10 Apr 2026 14:47:08 +0200 +Subject: [PATCH 05/13] net: airoha: Move {cpu,fwd}_tx_packets in + airoha_gdm_dev struct + +Since now multiple net_devices connected to different QDMA blocks can +share the same GDM port, cpu_tx_packets and fwd_tx_packets fields can +be overwritten with the value from a different QDMA block. In order to +fix the issue move cpu_tx_packets and fwd_tx_packets fields from +airoha_gdm_port struct to airoha_gdm_dev one. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 16 +++++++--------- + drivers/net/ethernet/airoha/airoha_eth.h | 7 +++---- + 2 files changed, 10 insertions(+), 13 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2506,19 +2506,17 @@ static int airoha_qdma_get_tx_ets_stats( + struct tc_ets_qopt_offload *opt) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +- struct airoha_gdm_port *port = dev->port; ++ struct airoha_qdma *qdma = dev->qdma; + +- u64 cpu_tx_packets = airoha_qdma_rr(dev->qdma, +- REG_CNTR_VAL(channel << 1)); +- u64 fwd_tx_packets = airoha_qdma_rr(dev->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 - port->cpu_tx_packets) + +- (fwd_tx_packets - port->fwd_tx_packets); ++ u64 tx_packets = (cpu_tx_packets - dev->cpu_tx_packets) + ++ (fwd_tx_packets - dev->fwd_tx_packets); + + _bstats_update(opt->stats.bstats, 0, tx_packets); +- +- port->cpu_tx_packets = cpu_tx_packets; +- port->fwd_tx_packets = fwd_tx_packets; ++ dev->cpu_tx_packets = cpu_tx_packets; ++ dev->fwd_tx_packets = fwd_tx_packets; + + return 0; + } +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -560,6 +560,9 @@ struct airoha_gdm_dev { + #endif + + DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); ++ /* qos stats counters */ ++ u64 cpu_tx_packets; ++ u64 fwd_tx_packets; + }; + + struct airoha_gdm_port { +@@ -569,10 +572,6 @@ struct airoha_gdm_port { + + struct airoha_hw_stats stats; + +- /* qos stats counters */ +- u64 cpu_tx_packets; +- u64 fwd_tx_packets; +- + struct metadata_dst *dsa_meta[AIROHA_MAX_DSA_PORTS]; + }; + diff --git a/target/linux/airoha/patches-6.12/920-08-net-airoha-Support-multiple-devs-for-a-single-FE-GDM.patch b/target/linux/airoha/patches-6.12/920-06-net-airoha-Support-multiple-net_devices-for-a-single.patch similarity index 55% rename from target/linux/airoha/patches-6.12/920-08-net-airoha-Support-multiple-devs-for-a-single-FE-GDM.patch rename to target/linux/airoha/patches-6.12/920-06-net-airoha-Support-multiple-net_devices-for-a-single.patch index 9dba2c6a2ea8c0..4e0e87eeb6d1f6 100644 --- a/target/linux/airoha/patches-6.12/920-08-net-airoha-Support-multiple-devs-for-a-single-FE-GDM.patch +++ b/target/linux/airoha/patches-6.12/920-06-net-airoha-Support-multiple-net_devices-for-a-single.patch @@ -1,27 +1,62 @@ -From d0a60691c8b279dc9a4e494d679952f4c32abcdb Mon Sep 17 00:00:00 2001 -Message-ID: -In-Reply-To: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> -References: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> +From 8eb0a71bfbe92b6fbc668c5d9ebdcbf6523a89ad Mon Sep 17 00:00:00 2001 +Message-ID: <8eb0a71bfbe92b6fbc668c5d9ebdcbf6523a89ad.1779348625.git.lorenzo@kernel.org> +In-Reply-To: +References: From: Lorenzo Bianconi Date: Sat, 1 Nov 2025 11:27:48 +0100 -Subject: [bpf-next 08/16] net: airoha: Support multiple devs for a single FE - GDM port +Subject: [PATCH 06/13] net: airoha: Support multiple net_devices for a single + FE GDM port +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +EN7581 or AN7583 SoCs support connecting multiple external SerDes (e.g. +Ethernet or USB SerDes) to GDM3 or GDM4 ports via a hw arbiter that +manages the traffic in a TDM manner. As a result multiple net_devices can +connect to the same GDM{3,4} port and there is a theoretical "1:n" +relation between GDM ports and net_devices. + + ┌─────────────────────────────────┐ + │ │ ┌──────┐ + │ P1 GDM1 ├────►MT7530│ + │ │ └──────┘ + │ │ ETH0 (DSA conduit) + │ │ + │ PSE/FE │ + │ │ + │ │ + │ │ ┌─────┐ + │ P0 CDM1 ├────►QDMA0│ + │ P4 P9 GDM4 │ └─────┘ + └──┬─────────────────────────┬────┘ + │ │ + ┌──▼──┐ ┌────▼────┐ + │ PPE │ │ ARB │ + └─────┘ └─┬─────┬─┘ + │ │ + ┌──▼──┐┌─▼───┐ + │ ETH ││ USB │ + └─────┘└─────┘ + ETH1 ETH2 Introduce support for multiple net_devices connected to the same Frame -Engine (FE) GDM port (GDM3 or GDM4) via an external arbiter connected -to the GDM port. +Engine (FE) GDM port (GDM3 or GDM4) via an external hw arbiter. +Please note GDM1 or GDM2 does not support the connection with the external +arbiter. Add get_dev_from_sport callback since EN7581 and AN7583 have different logics for the net_device type connected to GDM3 or GDM4. +Tested-by: Xuegang Lu Signed-off-by: Lorenzo Bianconi --- - drivers/net/ethernet/airoha/airoha_eth.c | 230 +++++++++++++++++------ - drivers/net/ethernet/airoha/airoha_eth.h | 9 +- - 2 files changed, 183 insertions(+), 56 deletions(-) + drivers/net/ethernet/airoha/airoha_eth.c | 274 +++++++++++++++++------ + drivers/net/ethernet/airoha/airoha_eth.h | 10 +- + drivers/net/ethernet/airoha/airoha_ppe.c | 13 +- + 3 files changed, 228 insertions(+), 69 deletions(-) --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -111,7 +111,7 @@ static int airoha_qdma_fill_rx_queue(str +@@ -115,7 +115,7 @@ static int airoha_set_vip_for_gdm_port(s struct airoha_eth *eth = dev->eth; u32 vip_port; @@ -30,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); -@@ -592,30 +592,26 @@ static int airoha_qdma_fill_rx_queue(str +@@ -612,30 +612,26 @@ static int airoha_qdma_fill_rx_queue(str return nframes; } @@ -69,16 +104,16 @@ Signed-off-by: Lorenzo Bianconi + 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; ++ if (d >= ARRAY_SIZE(port->devs)) ++ return ERR_PTR(-ENODEV); ++ + return port->devs[d] ? port->devs[d] : ERR_PTR(-ENODEV); } - static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) -@@ -632,9 +628,8 @@ static int airoha_qdma_rx_process(struct + static int airoha_qdma_lro_rx_process(struct airoha_queue *q, +@@ -719,9 +715,8 @@ 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; @@ -87,25 +122,28 @@ Signed-off-by: Lorenzo Bianconi - int data_len, len, p; + struct airoha_gdm_dev *dev; + int data_len, len; - struct page *page; + struct page *page; desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); -@@ -651,12 +646,10 @@ static int airoha_qdma_rx_process(struct +@@ -742,15 +737,10 @@ 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; -- port = eth->ports[p]; - netdev = port->dev->dev; if (!q->skb) { /* first buffer */ - q->skb = napi_build_skb(e->buf, q->buf_size); - if (!q->skb) -@@ -664,15 +657,15 @@ static int airoha_qdma_rx_process(struct + q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM, + q->buf_size); +@@ -760,15 +750,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); @@ -124,7 +162,7 @@ Signed-off-by: Lorenzo Bianconi } else { /* scattered frame */ struct skb_shared_info *shinfo = skb_shinfo(q->skb); int nr_frags = shinfo->nr_frags; -@@ -683,7 +676,9 @@ static int airoha_qdma_rx_process(struct +@@ -784,7 +774,9 @@ static int airoha_qdma_rx_process(struct if (FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl)) continue; @@ -135,47 +173,45 @@ 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 -@@ -683,7 +676,6 @@ static int airoha_qdma_rx_process(struct +@@ -981,24 +973,27 @@ 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; - int j; +- int j; ++ int d; if (!port) -@@ -683,15 +676,22 @@ static int airoha_qdma_rx_process(struct - if (!port) continue; - + - dev = port->dev; +- if (!dev) +- continue; ++ for (d = 0; d < ARRAY_SIZE(port->devs); d++) { ++ struct airoha_gdm_dev *dev = port->devs[d]; ++ int j; + - if (dev->qdma != qdma) - continue; -- ++ if (!dev) ++ continue; + - for (j = 0; j < dev->dev->num_tx_queues; j++) { - if (airoha_qdma_get_txq(qdma, j) != qid) -- continue; -- ++ if (dev->qdma != qdma) + continue; + - netif_wake_subqueue(dev->dev, j); -+ for (j = 0; j < ARRAY_SIZE(port->devs); j++) { -+ struct airoha_gdm_dev *dev = port->devs[j]; -+ int k; -+ -+ if (!dev) -+ continue; -+ -+ if (dev->qdma != qdma) -+ continue; -+ -+ for (k = 0; k < dev->dev->num_tx_queues; k++) { -+ if (airoha_qdma_get_txq(qdma, j) != qid) -+ continue; ++ for (j = 0; j < dev->dev->num_tx_queues; j++) { ++ if (airoha_qdma_get_txq(qdma, j) != qid) ++ continue; + -+ netif_wake_subqueue(dev->dev, k); -+ } - } ++ netif_wake_subqueue(dev->dev, j); ++ } + } } q->txq_stopped = false; -@@ -1761,7 +1756,7 @@ static int airhoha_set_gdm2_loopback(str +@@ -1984,7 +1979,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)); @@ -184,16 +220,16 @@ Signed-off-by: Lorenzo Bianconi if (src_port < 0) return src_port; -@@ -1777,7 +1770,7 @@ static int airhoha_set_gdm2_loopback(str - FE_PSE_PORT_CDM2 << __ffs(SP_CPORT_MASK(val))); +@@ -2001,7 +1996,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)) { - u32 mask = FC_ID_OF_SRC_PORT_MASK(port->nbq); + u32 mask = FC_ID_OF_SRC_PORT_MASK(dev->nbq); airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, mask, - AIROHA_GDM2_IDX << __ffs(mask)); -@@ -1997,7 +1990,8 @@ static netdev_tx_t airoha_dev_xmit(struc + __field_prep(mask, AIROHA_GDM2_IDX)); +@@ -2244,7 +2239,8 @@ static netdev_tx_t airoha_dev_xmit(struc } fport = airoha_get_fe_port(dev); @@ -203,127 +239,7 @@ Signed-off-by: Lorenzo Bianconi FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f); q = &qdma->q_tx[qid]; -@@ -2926,7 +2920,7 @@ bool airoha_is_valid_gdm_dev(struct airo - return 0; - } - --static int airoha_tc_htb_alloc_leaf_queue(struct net_device *dev, -+static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev, - struct tc_htb_qopt_offload *opt) - { - u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; -@@ -2926,7 +2920,8 @@ bool airoha_is_valid_gdm_dev(struct airo - u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; - u32 rate = div_u64(opt->rate, 1000) << 3; /* kbps */ -- int err, num_tx_queues = dev->real_num_tx_queues; -- struct airoha_gdm_port *port = netdev_priv(dev); -+ 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; - - if (opt->parent_classid != TC_HTB_CLASSID_ROOT) { - NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid"); -@@ -2926,7 +2920,7 @@ bool airoha_is_valid_gdm_dev(struct airo - return -EINVAL; - } - -- err = airoha_qdma_set_tx_rate_limit(dev, channel, rate, opt->quantum); -+ err = airoha_qdma_set_tx_rate_limit(netdev, channel, rate, opt->quantum); - if (err) { - NL_SET_ERR_MSG_MOD(opt->extack, - "failed configuring htb offload"); -@@ -2926,9 +2920,9 @@ bool airoha_is_valid_gdm_dev(struct airo - if (opt->command == TC_HTB_NODE_MODIFY) - return 0; - -- err = netif_set_real_num_tx_queues(dev, num_tx_queues + 1); -+ err = netif_set_real_num_tx_queues(netdev, num_tx_queues + 1); - if (err) { -- airoha_qdma_set_tx_rate_limit(dev, channel, 0, opt->quantum); -+ airoha_qdma_set_tx_rate_limit(netdev, channel, 0, opt->quantum); - NL_SET_ERR_MSG_MOD(opt->extack, - "failed setting real_num_tx_queues"); - return err; -@@ -2926,12 +2926,13 @@ static int airoha_setup_phylink(struct n - } - } - --static void airoha_tc_remove_htb_queue(struct net_device *dev, int queue) -+static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue) - { -- struct airoha_gdm_port *port = netdev_priv(dev); -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; - -- netif_set_real_num_tx_queues(dev, dev->real_num_tx_queues - 1); -- airoha_qdma_set_tx_rate_limit(dev, queue + 1, 0, 0); -+ netif_set_real_num_tx_queues(netdev, netdev->real_num_tx_queues - 1); -+ airoha_qdma_set_tx_rate_limit(netdev, queue + 1, 0, 0); - clear_bit(queue, port->qos_sq_bmap); - } - -@@ -2926,11 +2926,12 @@ static int airoha_setup_phylink(struct n - clear_bit(queue, port->qos_sq_bmap); - } - --static int airoha_tc_htb_delete_leaf_queue(struct net_device *dev, -+static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev, - struct tc_htb_qopt_offload *opt) - { - u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; -- struct airoha_gdm_port *port = netdev_priv(dev); -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; - - if (!test_bit(channel, port->qos_sq_bmap)) { - NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); -@@ -2926,7 +2926,7 @@ static int airoha_setup_phylink(struct n - return -EINVAL; - } - -- airoha_tc_remove_htb_queue(dev, channel); -+ airoha_tc_remove_htb_queue(netdev, channel); - - return 0; - } -@@ -2926,9 +2926,10 @@ static int airoha_setup_phylink(struct n - return 0; - } - --static int airoha_tc_htb_destroy(struct net_device *dev) -+static int airoha_tc_htb_destroy(struct net_device *netdev) - { -- struct airoha_gdm_port *port = netdev_priv(dev); -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; - int q; - - for_each_set_bit(q, port->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS) -@@ -2926,7 +2926,7 @@ static int airoha_setup_phylink(struct n - int q; - - for_each_set_bit(q, port->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS) -- airoha_tc_remove_htb_queue(dev, q); -+ airoha_tc_remove_htb_queue(netdev, q); - - return 0; - } -@@ -2926,11 +2926,12 @@ static int airoha_setup_phylink(struct n - return 0; - } - --static int airoha_tc_get_htb_get_leaf_queue(struct net_device *dev, -+static int airoha_tc_get_htb_get_leaf_queue(struct net_device *netdev, - struct tc_htb_qopt_offload *opt) - { - u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; -- struct airoha_gdm_port *port = netdev_priv(dev); -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; - - if (!test_bit(channel, port->qos_sq_bmap)) { - NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); -@@ -2926,12 +2920,15 @@ bool airoha_is_valid_gdm_dev(struct airo +@@ -3180,12 +3176,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]; @@ -341,9 +257,9 @@ Signed-off-by: Lorenzo Bianconi } return false; -@@ -3035,10 +3032,11 @@ static int airoha_setup_phylink(struct n +@@ -3309,10 +3308,11 @@ static int airoha_setup_phylink(struct n + static int airoha_alloc_gdm_device(struct airoha_eth *eth, - struct airoha_qdma *qdma, struct airoha_gdm_port *port, - struct device_node *np) + int nbq, struct device_node *np) @@ -355,7 +271,15 @@ Signed-off-by: Lorenzo Bianconi int err; netdev = devm_alloc_etherdev_mqs(eth->dev, sizeof(*dev), -@@ -3077,10 +3075,23 @@ static int airoha_alloc_gdm_device(struc +@@ -3330,7 +3330,6 @@ static int airoha_alloc_gdm_device(struc + netdev->hw_features = AIROHA_HW_FEATURES | NETIF_F_LRO; + 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 */ +@@ -3348,11 +3347,25 @@ static int airoha_alloc_gdm_device(struc netdev->dev_addr); } @@ -363,7 +287,7 @@ Signed-off-by: Lorenzo Bianconi + * and PCIE1 respectively. + */ + index = nbq; -+ if (airoha_is_7581(eth) && port->id == AIROHA_GDM3_IDX) ++ if (index && airoha_is_7581(eth) && port->id == AIROHA_GDM3_IDX) + index -= 4; + + if (index >= ARRAY_SIZE(port->devs) || port->devs[index]) { @@ -371,47 +295,43 @@ Signed-off-by: Lorenzo Bianconi + return -EINVAL; + } + ++ netdev->dev.of_node = of_node_get(np); dev = netdev_priv(netdev); dev->dev = netdev; dev->port = port; +- port->dev = dev; dev->eth = eth; + dev->nbq = nbq; ++ port->devs[index] = dev; #if defined(CONFIG_PCS_AIROHA) if (airhoa_is_phy_external(port)) { -@@ -3077,7 +3075,7 @@ static int airoha_alloc_gdm_device(struc - return err; - } - #endif -- port->dev = dev; -+ port->devs[index] = dev; - - return 0; - } -@@ -3093,7 +3104,8 @@ static int airoha_alloc_gdm_port(struct +@@ -3370,7 +3383,8 @@ static int airoha_alloc_gdm_port(struct { const __be32 *id_ptr = of_get_property(np, "reg", NULL); struct airoha_gdm_port *port; - int err, p; + struct device_node *node; -+ int err, p, d = 0; ++ int err, nbq, p, d = 0; u32 id; if (!id_ptr) { -@@ -3136,8 +3148,6 @@ static int airoha_alloc_gdm_port(struct - return -ENOMEM; - +@@ -3398,15 +3412,51 @@ static int airoha_alloc_gdm_port(struct + u64_stats_init(&port->stats.syncp); + spin_lock_init(&port->stats.lock); port->id = id; - /* XXX: Read nbq from DTS */ - port->nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0; eth->ports[p] = port; err = airoha_metadata_dst_alloc(port); -@@ -3136,7 +3148,36 @@ static int airoha_alloc_gdm_port(struct - } - #endif + if (err) + return err; - return airoha_alloc_gdm_device(eth, port, np); ++ /* Default nbq value to ensure backward compatibility */ ++ nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0; ++ + for_each_child_of_node(np, node) { + /* Multiple external serdes connected to the FE GDM port via an + * external arbiter. @@ -428,24 +348,30 @@ Signed-off-by: Lorenzo Bianconi + nbq_ptr = of_get_property(node, "reg", NULL); + if (!nbq_ptr) { + dev_err(eth->dev, "missing nbq id\n"); -+ err = -EINVAL; + of_node_put(node); -+ break; ++ return -EINVAL; + } + -+ err = airoha_alloc_gdm_device(eth, port, -+ be32_to_cpup(nbq_ptr), node); ++ /* Verify the provided nbq parameter is valid */ ++ nbq = be32_to_cpup(nbq_ptr); ++ err = eth->soc->ops.get_sport(port, nbq); ++ if (err < 0) { ++ of_node_put(node); ++ return err; ++ } ++ ++ err = airoha_alloc_gdm_device(eth, port, nbq, node); + if (err) { + of_node_put(node); + return err; + } + } + -+ return !d ? airoha_alloc_gdm_device(eth, port, 0, np) : 0; ++ return !d ? airoha_alloc_gdm_device(eth, port, nbq, np) : 0; } static int airoha_register_gdm_devices(struct airoha_eth *eth) -@@ -3145,14 +3186,22 @@ static int airoha_register_gdm_devices(s +@@ -3415,14 +3465,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]; @@ -471,8 +397,8 @@ Signed-off-by: Lorenzo Bianconi + } } - return 0; -@@ -3262,7 +3311,7 @@ error_hw_cleanup: + set_bit(DEV_STATE_REGISTERED, ð->state); +@@ -3529,18 +3587,27 @@ error_napi_stop: for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -481,37 +407,32 @@ Signed-off-by: Lorenzo Bianconi if (!port) continue; -@@ -3278,16 +3324,19 @@ error_hw_cleanup: - if (!port) - continue; -- if (!port->dev) -- continue; -- - dev = port->dev; -- if (dev->dev->reg_state == NETREG_REGISTERED) { --#if defined(CONFIG_PCS_AIROHA) -- if (airhoa_is_phy_external(port)) -- phylink_destroy(dev->phylink); --#endif -- unregister_netdev(dev->dev); +- if (dev && dev->dev->reg_state == NETREG_REGISTERED) { + for (j = 0; j < ARRAY_SIZE(port->devs); j++) { + struct airoha_gdm_dev *dev = port->devs[j]; ++ struct net_device *netdev; + + if (!dev) + continue; + -+ if (dev->dev->reg_state == NETREG_REGISTERED) { -+#if defined(CONFIG_PCS_AIROHA) ++ netdev = dev->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); -+#endif -+ unregister_netdev(dev->dev); + #endif +- unregister_netdev(dev->dev); ++ unregister_netdev(netdev); + } ++ of_node_put(netdev->dev.of_node); } airoha_metadata_dst_free(port); } -@@ -3300,7 +3352,7 @@ static void airoha_remove(struct platfor +@@ -3562,19 +3629,26 @@ static void airoha_remove(struct platfor for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -520,35 +441,31 @@ Signed-off-by: Lorenzo Bianconi if (!port) continue; -@@ -3315,15 +3365,18 @@ static void airoha_remove(struct platfor - if (!port) - continue; -- if (!port->dev) -- continue; + for (j = 0; j < ARRAY_SIZE(port->devs); j++) { + struct airoha_gdm_dev *dev = port->devs[j]; - -- dev = port->dev; --#if defined(CONFIG_PCS_AIROHA) -- if (airhoa_is_phy_external(port)) -- phylink_destroy(dev->phylink); --#endif -- unregister_netdev(dev->dev); ++ struct net_device *netdev; ++ + if (!dev) + continue; + -+#if defined(CONFIG_PCS_AIROHA) -+ if (airhoa_is_phy_external(port)) -+ phylink_destroy(dev->phylink); -+#endif -+ unregister_netdev(dev->dev); + #if defined(CONFIG_PCS_AIROHA) + 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); ++ of_node_put(netdev->dev.of_node); + } airoha_metadata_dst_free(port); } airoha_hw_cleanup(eth); -@@ -3357,6 +3412,39 @@ static int airoha_en7581_get_src_port_id - return -EINVAL; +@@ -3636,6 +3710,39 @@ static u32 airoha_en7581_get_vip_port(st + return 0; } +static int airoha_en7581_get_dev_from_sport(struct airoha_qdma_desc *desc, @@ -562,8 +479,8 @@ Signed-off-by: Lorenzo Bianconi + case 0x10 ... 0x14: + *port = 0; /* GDM1 */ + break; -+ case 0x2: -+ *port = 1; /* GDM2 */ ++ case 0x2 ... 0x4: ++ *port = sport - 1; + break; + case HSGMII_LAN_7581_PCIE1_SRCPORT: + *dev = 1; @@ -587,8 +504,8 @@ Signed-off-by: Lorenzo Bianconi static const char * const an7583_xsi_rsts_names[] = { "hsi0-mac", "hsi1-mac", -@@ -3385,6 +3471,36 @@ static int airoha_an7583_get_src_port_id - return -EINVAL; +@@ -3684,6 +3791,36 @@ static u32 airoha_an7583_get_vip_port(st + return 0; } +static int airoha_an7583_get_dev_from_sport(struct airoha_qdma_desc *desc, @@ -602,8 +519,8 @@ Signed-off-by: Lorenzo Bianconi + case 0x10 ... 0x14: + *port = 0; /* GDM1 */ + break; -+ case 0x2: -+ *port = 1; /* GDM2 */ ++ case 0x2 ... 0x4: ++ *port = sport - 1; + break; + case HSGMII_LAN_7583_ETH_SRCPORT: + *port = 2; /* GDM3 */ @@ -624,17 +541,17 @@ Signed-off-by: Lorenzo Bianconi static const struct airoha_eth_soc_data en7581_soc_data = { .version = 0x7581, .xsi_rsts_names = en7581_xsi_rsts_names, -@@ -3392,6 +3506,7 @@ static const struct airoha_eth_soc_data +@@ -3692,6 +3829,7 @@ static const struct airoha_eth_soc_data .ops = { - .get_src_port_id = airoha_en7581_get_src_port_id, + .get_sport = airoha_en7581_get_sport, .get_vip_port = airoha_en7581_get_vip_port, + .get_dev_from_sport = airoha_en7581_get_dev_from_sport, }, }; -@@ -3402,6 +3517,7 @@ static const struct airoha_eth_soc_data +@@ -3703,6 +3841,7 @@ static const struct airoha_eth_soc_data .ops = { - .get_src_port_id = airoha_an7583_get_src_port_id, + .get_sport = airoha_an7583_get_sport, .get_vip_port = airoha_an7583_get_vip_port, + .get_dev_from_sport = airoha_an7583_get_dev_from_sport, }, @@ -650,16 +567,22 @@ Signed-off-by: Lorenzo Bianconi #define AIROHA_MAX_NUM_QDMA 2 #define AIROHA_MAX_NUM_IRQ_BANKS 4 #define AIROHA_MAX_DSA_PORTS 7 -@@ -534,6 +535,8 @@ struct airoha_qdma { +@@ -551,8 +552,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; ++ struct net_device *dev; -+ int nbq; -+ #if defined(CONFIG_PCS_AIROHA) struct phylink *phylink; - struct phylink_config phylink_config; -@@ -534,9 +535,8 @@ struct airoha_qdma { +@@ -563,12 +564,13 @@ struct airoha_gdm_dev { + /* qos stats counters */ + u64 cpu_tx_packets; + u64 fwd_tx_packets; ++ ++ int nbq; }; struct airoha_gdm_port { @@ -670,9 +593,9 @@ Signed-off-by: Lorenzo Bianconi struct airoha_hw_stats stats; -@@ -587,6 +590,8 @@ struct airoha_eth_soc_data { +@@ -604,6 +606,8 @@ struct airoha_eth_soc_data { struct { - int (*get_src_port_id)(struct airoha_gdm_port *port, int nbq); + int (*get_sport)(struct airoha_gdm_port *port, int nbq); u32 (*get_vip_port)(struct airoha_gdm_port *port, int nbq); + int (*get_dev_from_sport)(struct airoha_qdma_desc *desc, + u16 *port, u16 *dev); @@ -681,7 +604,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c -@@ -163,6 +163,7 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) +@@ -170,6 +170,7 @@ static void airoha_ppe_hw_init(struct ai for (p = 0; p < ARRAY_SIZE(eth->ports); p++) { struct airoha_gdm_port *port = eth->ports[p]; @@ -689,20 +612,21 @@ Signed-off-by: Lorenzo Bianconi airoha_fe_rmw(eth, REG_PPE_MTU(i, p), FP0_EGRESS_MTU_MASK | -@@ -174,8 +175,15 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) +@@ -181,8 +182,16 @@ static void airoha_ppe_hw_init(struct ai if (!port) continue; - airoha_ppe_set_cpu_port(port->dev, i, -- airoha_get_fe_port(dev)); +- airoha_get_fe_port(port->dev)); + for (j = 0; j < ARRAY_SIZE(port->devs); j++) { + struct airoha_gdm_dev *dev = port->devs[j]; ++ u8 fport; + + if (!dev) + continue; + -+ airoha_ppe_set_cpu_port(dev, i, -+ airoha_get_fe_port(dev)); ++ fport = airoha_get_fe_port(dev); ++ airoha_ppe_set_cpu_port(dev, i, fport); + } } } diff --git a/target/linux/airoha/patches-6.12/920-07-net-airoha-Add-addr-pointer-to-airoha_ppe_init_upd_m.patch b/target/linux/airoha/patches-6.12/920-07-net-airoha-Add-addr-pointer-to-airoha_ppe_init_upd_m.patch deleted file mode 100644 index e678c83fc1133e..00000000000000 --- a/target/linux/airoha/patches-6.12/920-07-net-airoha-Add-addr-pointer-to-airoha_ppe_init_upd_m.patch +++ /dev/null @@ -1,57 +0,0 @@ -From d9052fd98149a180a5caa5f220f9c498a3db5df6 Mon Sep 17 00:00:00 2001 -Message-ID: -In-Reply-To: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> -References: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> -From: Lorenzo Bianconi -Date: Sat, 1 Nov 2025 11:52:06 +0100 -Subject: [bpf-next 06/16] net: airoha: Add addr pointer to - airoha_ppe_init_upd_mem signature - -This is a preliminary patch to support multiple net_devices connected -to the same Frame Engine GDM port via an external arbiter. - -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/airoha/airoha_eth.c | 2 +- - drivers/net/ethernet/airoha/airoha_eth.h | 2 +- - drivers/net/ethernet/airoha/airoha_ppe.c | 4 +--- - 3 files changed, 3 insertions(+), 5 deletions(-) - ---- a/drivers/net/ethernet/airoha/airoha_eth.c -+++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -94,7 +94,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); - -- airoha_ppe_init_upd_mem(dev); -+ airoha_ppe_init_upd_mem(dev, addr); - } - - static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr, ---- a/drivers/net/ethernet/airoha/airoha_eth.h -+++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -666,7 +666,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); --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); - u32 airoha_ppe_get_total_num_entries(struct airoha_ppe *ppe); - struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe, - u32 hash); ---- a/drivers/net/ethernet/airoha/airoha_ppe.c -+++ b/drivers/net/ethernet/airoha/airoha_ppe.c -@@ -1400,12 +1400,10 @@ void airoha_ppe_check_skb(struct airoha_ - airoha_ppe_foe_insert_entry(ppe, skb, hash, rx_wlan); - } - --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 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; - - val = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5]; diff --git a/target/linux/airoha/patches-6.12/920-07-net-airoha-Do-not-stop-GDM-port-if-it-is-shared.patch b/target/linux/airoha/patches-6.12/920-07-net-airoha-Do-not-stop-GDM-port-if-it-is-shared.patch new file mode 100644 index 00000000000000..bb2140cad662ef --- /dev/null +++ b/target/linux/airoha/patches-6.12/920-07-net-airoha-Do-not-stop-GDM-port-if-it-is-shared.patch @@ -0,0 +1,132 @@ +From de856a5b802cf030c8e242e98df3bc88446a4ea1 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Fri, 20 Mar 2026 11:09:40 +0100 +Subject: [PATCH 07/13] net: airoha: Do not stop GDM port if it is shared + +Theoretically, in the current codebase, two independent net_devices can +be connected to the same GDM port so we need to check the GDM port is not +used by any other running net_device before setting the forward +configuration to FE_PSE_PORT_DROP. +Moreover, always set in GDM_LONG_LEN_MASK field of REG_GDM_LEN_CFG +register the maximum MTU of all running net_devices connected to the same +GDM port. + +Tested-by: Xuegang Lu +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 59 +++++++++++++++++++----- + drivers/net/ethernet/airoha/airoha_eth.h | 1 + + 2 files changed, 48 insertions(+), 12 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1843,8 +1843,8 @@ 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; +- u32 pse_port = FE_PSE_PORT_PPE1; + + #if defined(CONFIG_PCS_AIROHA) + if (airhoa_is_phy_external(port)) { +@@ -1872,10 +1872,20 @@ static int airoha_dev_open(struct net_de + airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id), + GDM_STAG_EN_MASK); + +- airoha_fe_rmw(qdma->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), ++ GDM_LONG_LEN_MASK); ++ if (!port->users || len > cur_len) { ++ /* Opening a sibling net_device with a larger MTU updates the ++ * MTU of already running devices. This is required to allow ++ * multiple net_devices with different MTUs to share the same ++ * GDM port. ++ */ ++ airoha_fe_rmw(qdma->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)); ++ } ++ port->users++; + + airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, + GLOBAL_CFG_TX_DMA_EN_MASK | +@@ -1893,6 +1903,30 @@ static int airoha_dev_open(struct net_de + return 0; + } + ++static void airoha_set_port_mtu(struct airoha_eth *eth, ++ struct airoha_gdm_port *port) ++{ ++ u32 len = 0; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(port->devs); i++) { ++ struct airoha_gdm_dev *dev = port->devs[i]; ++ struct net_device *netdev; ++ ++ if (!dev) ++ continue; ++ ++ netdev = dev->dev; ++ if (netif_running(netdev)) ++ len = max_t(u32, len, netdev->mtu); ++ } ++ len += ETH_HLEN + ETH_FCS_LEN; ++ ++ airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), ++ GDM_LONG_LEN_MASK, ++ FIELD_PREP(GDM_LONG_LEN_MASK, len)); ++} ++ + static int airoha_dev_stop(struct net_device *netdev) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +@@ -1905,8 +1939,12 @@ 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), +- FE_PSE_PORT_DROP); ++ if (--port->users) ++ airoha_set_port_mtu(dev->eth, port); ++ else ++ 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)) { + airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, +@@ -2066,13 +2104,10 @@ static int airoha_dev_change_mtu(struct + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; +- u32 len = ETH_HLEN + mtu + ETH_FCS_LEN; +- struct airoha_eth *eth = dev->eth; + +- airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), +- GDM_LONG_LEN_MASK, +- FIELD_PREP(GDM_LONG_LEN_MASK, len)); + WRITE_ONCE(netdev->mtu, mtu); ++ if (port->users) ++ airoha_set_port_mtu(dev->eth, port); + + return 0; + } +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -571,6 +571,7 @@ struct airoha_gdm_dev { + struct airoha_gdm_port { + struct airoha_gdm_dev *devs[AIROHA_MAX_NUM_GDM_DEVS]; + int id; ++ int users; + + struct airoha_hw_stats stats; + diff --git a/target/linux/airoha/patches-6.12/920-08-net-airoha-Introduce-WAN-device-flag.patch b/target/linux/airoha/patches-6.12/920-08-net-airoha-Introduce-WAN-device-flag.patch new file mode 100644 index 00000000000000..5f8ec4407b8e79 --- /dev/null +++ b/target/linux/airoha/patches-6.12/920-08-net-airoha-Introduce-WAN-device-flag.patch @@ -0,0 +1,174 @@ +From c4f3077948eda05a6b9d1a11304d82c3e0300151 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Fri, 3 Apr 2026 12:07:27 +0200 +Subject: [PATCH 08/13] net: airoha: Introduce WAN device flag + +Introduce WAN flag to specify if a given device is used to transmit/receive +WAN or LAN traffic. Current codebase supports specifying LAN/WAN device +configuration in ndo_init() callback during device bootstrap. +In order to consider setups where LAN configuration is used even for +GDM3/GDM4 devices, check airoha_is_lan_gdm_dev() to select pse_port in +airoha_ppe_foe_entry_prepare(). +Please note after this patch, it will be possible to specify multiple LAN +devices but just a single WAN one. Please note this change is not visible +to the user since airoha_eth driver currently supports just the internal +phy available via the MT7530 DSA switch and there are no WAN interfaces +officially supported since PCS/external phy is not merged mainline yet +(it will be posted with following patches). + +Tested-by: Xuegang Lu +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 72 +++++++++++++++++++----- + drivers/net/ethernet/airoha/airoha_eth.h | 13 ++--- + drivers/net/ethernet/airoha/airoha_ppe.c | 2 +- + 3 files changed, 65 insertions(+), 22 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2043,36 +2043,80 @@ 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) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { ++ struct airoha_gdm_port *port = eth->ports[i]; ++ int j; ++ ++ if (!port) ++ continue; ++ ++ for (j = 0; j < ARRAY_SIZE(port->devs); j++) { ++ struct airoha_gdm_dev *dev = port->devs[j]; ++ ++ if (dev && !airoha_is_lan_gdm_dev(dev)) ++ return dev; ++ } ++ } ++ ++ return NULL; ++} ++ ++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 airoha_eth *eth = dev->eth; + int i; + + /* 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; +- airoha_set_macaddr(dev, netdev->dev_addr); ++ ++ for (i = 0; i < eth->soc->num_ppe; i++) ++ airoha_ppe_set_cpu_port(dev, i, airoha_get_fe_port(dev)); ++} ++ ++static int airoha_dev_init(struct net_device *netdev) ++{ ++ struct airoha_gdm_dev *dev = netdev_priv(netdev); ++ struct airoha_gdm_port *port = dev->port; + + switch (port->id) { + case AIROHA_GDM3_IDX: +- case AIROHA_GDM4_IDX: +- /* If GDM2 is active we can't enable loopback */ +- if (!eth->ports[1]) { +- int err; +- +- err = airoha_set_gdm2_loopback(dev); +- if (err) +- return err; +- } ++ 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)) ++ break; ++ ++ fallthrough; ++ } ++ case AIROHA_GDM2_IDX: ++ /* GDM2 is always used as wan */ ++ dev->flags |= AIROHA_PRIV_F_WAN; + break; + default: + break; + } + +- for (i = 0; i < eth->soc->num_ppe; i++) +- airoha_ppe_set_cpu_port(dev, i, airoha_get_fe_port(dev)); ++ airoha_dev_set_qdma(dev); ++ airoha_set_macaddr(dev, netdev->dev_addr); ++ ++ if (!airoha_is_lan_gdm_dev(dev) && ++ (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)) { ++ int err; ++ ++ err = airoha_set_gdm2_loopback(dev); ++ if (err) ++ return err; ++ } + + return 0; + } +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -549,6 +549,10 @@ struct airoha_qdma { + DECLARE_BITMAP(qos_channel_map, AIROHA_NUM_QOS_CHANNELS); + }; + ++enum airoha_priv_flags { ++ AIROHA_PRIV_F_WAN = BIT(0), ++}; ++ + struct airoha_gdm_dev { + struct airoha_gdm_port *port; + struct airoha_qdma *qdma; +@@ -565,6 +569,7 @@ struct airoha_gdm_dev { + u64 cpu_tx_packets; + u64 fwd_tx_packets; + ++ u32 flags; + int nbq; + }; + +@@ -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) + { +- struct airoha_gdm_port *port = dev->port; +- +- /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. +- * GDM{2,3,4} can be used as wan port connected to an external +- * phy module. +- */ +- return port->id == 1; ++ return !(dev->flags & AIROHA_PRIV_F_WAN); + } + + static inline bool airoha_is_7581(struct airoha_eth *eth) +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -349,7 +349,7 @@ static int airoha_ppe_foe_entry_prepare( + return -EINVAL; + + port = dev->port; +- if (dsa_port >= 0 || eth->ports[1]) ++ if (dsa_port >= 0 || airoha_is_lan_gdm_dev(dev)) + pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 + : port->id; + else diff --git a/target/linux/airoha/patches-6.12/920-09-net-airoha-Support-multiple-LAN-WAN-interfaces-for-h.patch b/target/linux/airoha/patches-6.12/920-09-net-airoha-Support-multiple-LAN-WAN-interfaces-for-h.patch new file mode 100644 index 00000000000000..b9675417f685a8 --- /dev/null +++ b/target/linux/airoha/patches-6.12/920-09-net-airoha-Support-multiple-LAN-WAN-interfaces-for-h.patch @@ -0,0 +1,180 @@ +From 144f0e6e55896625e3411aad02399a5ebb48d8f9 Mon Sep 17 00:00:00 2001 +Message-ID: <144f0e6e55896625e3411aad02399a5ebb48d8f9.1779348625.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Mon, 13 Apr 2026 17:38:51 +0200 +Subject: [PATCH 09/13] net: airoha: Support multiple LAN/WAN interfaces for hw + MAC address configuration + +The EN7581 and AN7583 SoCs provide registers to configure hardware LAN/WAN +MAC addresses, used to determine whether received traffic is destined for +this host or should be forwarded to another device. +The SoC hardware design assumes all interfaces configured as LAN (or WAN) +share a common upper MAC address, which is programmed into the +REG_FE_{LAN,WAN}_MAC_H register. The lower bytes of 'local' addresses can +be expressed as a range via the REG_FE_MAC_LMIN and REG_FE_MAC_LMAX +registers. +Previously, only a single interface was considered when programming these +registers. Extend the logic to derive the correct minimum and maximum +values for REG_FE_MAC_LMIN/REG_FE_MAC_LMAX when two or more interfaces are +configured as LAN or WAN. + +Tested-by: Madhur Agrawal +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 77 ++++++++++++++++++++---- + drivers/net/ethernet/airoha/airoha_eth.h | 2 +- + drivers/net/ethernet/airoha/airoha_ppe.c | 4 +- + 3 files changed, 68 insertions(+), 15 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -80,20 +80,69 @@ static bool airhoa_is_phy_external(struc + } + #endif + +-static void airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr) ++static int airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr) + { ++ u8 ref_addr[ETH_ALEN] __aligned(2); + struct airoha_eth *eth = dev->eth; +- u32 val, reg; ++ u32 reg, val, lmin, lmax; ++ int i; ++ ++ eth_zero_addr(ref_addr); ++ lmin = (addr[3] << 16) | (addr[4] << 8) | addr[5]; ++ lmax = lmin; ++ ++ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { ++ struct airoha_gdm_port *port = eth->ports[i]; ++ int j; ++ ++ if (!port) ++ continue; ++ ++ for (j = 0; j < ARRAY_SIZE(port->devs); j++) { ++ struct airoha_gdm_dev *iter_dev; ++ struct net_device *netdev; ++ ++ iter_dev = port->devs[j]; ++ if (!iter_dev || iter_dev == dev) ++ continue; ++ ++ if (airoha_is_lan_gdm_dev(iter_dev) != ++ airoha_is_lan_gdm_dev(dev)) ++ continue; ++ ++ netdev = iter_dev->dev; ++ if (netdev->reg_state != NETREG_REGISTERED) ++ continue; ++ ++ ether_addr_copy(ref_addr, netdev->dev_addr); ++ val = (netdev->dev_addr[3] << 16) | ++ (netdev->dev_addr[4] << 8) | netdev->dev_addr[5]; ++ if (val < lmin) ++ lmin = val; ++ if (val > lmax) ++ lmax = val; ++ } ++ } ++ ++ if (!is_zero_ether_addr(ref_addr) && memcmp(ref_addr, addr, 3)) { ++ /* According to the HW design, hw mac address MS bits ++ * must be the same for each net_device with the same ++ * LAN/WAN configuration. ++ */ ++ netdev_err(dev->dev, "wrong mac addr for shared GDM port\n"); ++ return -EINVAL; ++ } + + reg = airoha_is_lan_gdm_dev(dev) ? REG_FE_LAN_MAC_H : REG_FE_WAN_MAC_H; + val = (addr[0] << 16) | (addr[1] << 8) | addr[2]; + airoha_fe_wr(eth, reg, val); + +- val = (addr[3] << 16) | (addr[4] << 8) | addr[5]; +- airoha_fe_wr(eth, REG_FE_MAC_LMIN(reg), val); +- 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); ++ airoha_ppe_init_upd_mem(dev, addr); ++ ++ return 0; + } + + static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr, +@@ -1972,13 +2021,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); ++ struct sockaddr *addr = p; + int err; + +- err = eth_mac_addr(netdev, p); ++ err = eth_prepare_mac_addr_change(netdev, p); + if (err) + return err; + +- airoha_set_macaddr(dev, netdev->dev_addr); ++ err = airoha_set_macaddr(dev, addr->sa_data); ++ if (err) ++ return err; ++ ++ eth_commit_mac_addr_change(netdev, p); + + return 0; + } +@@ -2083,6 +2137,7 @@ static int airoha_dev_init(struct net_de + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; ++ int err; + + switch (port->id) { + case AIROHA_GDM3_IDX: +@@ -2107,12 +2162,12 @@ static int airoha_dev_init(struct net_de + } + + airoha_dev_set_qdma(dev); +- airoha_set_macaddr(dev, netdev->dev_addr); ++ err = airoha_set_macaddr(dev, netdev->dev_addr); ++ if (err) ++ return err; + + if (!airoha_is_lan_gdm_dev(dev) && + (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)) { +- int err; +- + err = airoha_set_gdm2_loopback(dev); + if (err) + return err; +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -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); +-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); + u32 airoha_ppe_get_total_num_entries(struct airoha_ppe *ppe); + struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe, + u32 hash); +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -1492,12 +1492,10 @@ void airoha_ppe_check_skb(struct airoha_ + airoha_ppe_foe_insert_entry(ppe, skb, hash, rx_wlan); + } + +-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 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; + + val = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5]; diff --git a/target/linux/airoha/patches-6.12/920-10-net-airoha-Rename-airoha_set_gdm2_loopback-in-airoha.patch b/target/linux/airoha/patches-6.12/920-10-net-airoha-Rename-airoha_set_gdm2_loopback-in-airoha.patch new file mode 100644 index 00000000000000..0f3f85ce732600 --- /dev/null +++ b/target/linux/airoha/patches-6.12/920-10-net-airoha-Rename-airoha_set_gdm2_loopback-in-airoha.patch @@ -0,0 +1,37 @@ +From 917f959d54efd09719bd5047aa4b9543615e131e Mon Sep 17 00:00:00 2001 +Message-ID: <917f959d54efd09719bd5047aa4b9543615e131e.1779348625.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Fri, 19 Dec 2025 23:12:32 +0100 +Subject: [PATCH 10/13] net: airoha: Rename airoha_set_gdm2_loopback in + airoha_enable_gdm2_loopback + +This is a preliminary patch in order to allow the user to select if the +configured device will be used as hw lan or wan. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2037,7 +2037,7 @@ static int airoha_dev_set_macaddr(struct + return 0; + } + +-static int airoha_set_gdm2_loopback(struct airoha_gdm_dev *dev) ++static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev) + { + struct airoha_gdm_port *port = dev->port; + struct airoha_eth *eth = dev->eth; +@@ -2168,7 +2168,7 @@ static int airoha_dev_init(struct net_de + + if (!airoha_is_lan_gdm_dev(dev) && + (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)) { +- err = airoha_set_gdm2_loopback(dev); ++ err = airoha_enable_gdm2_loopback(dev); + if (err) + return err; + } diff --git a/target/linux/airoha/patches-6.12/920-11-net-airoha-Disable-GDM2-forwarding-before-configurin.patch b/target/linux/airoha/patches-6.12/920-11-net-airoha-Disable-GDM2-forwarding-before-configurin.patch index 008020fbe05a13..ed4b174deccb65 100644 --- a/target/linux/airoha/patches-6.12/920-11-net-airoha-Disable-GDM2-forwarding-before-configurin.patch +++ b/target/linux/airoha/patches-6.12/920-11-net-airoha-Disable-GDM2-forwarding-before-configurin.patch @@ -1,14 +1,15 @@ -From 20cc439daa9e54044788da82671abe2654ae0bca Mon Sep 17 00:00:00 2001 -Message-ID: <20cc439daa9e54044788da82671abe2654ae0bca.1771966444.git.lorenzo@kernel.org> -In-Reply-To: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> -References: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> +From fb79a8a3e8d1e4d729590bb01eb24cc57ef67155 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: From: Lorenzo Bianconi Date: Sat, 27 Dec 2025 08:47:38 +0100 -Subject: [bpf-next 15/16] net: airoha: Disable GDM2 forwarding before - configuring GDM2 loopback +Subject: [PATCH 11/13] net: airoha: Disable GDM2 forwarding before configuring + GDM2 loopback Hw requires to disable GDM2 forwarding before enabling GDM2 loopback. +Tested-by: Madhur Agrawal Signed-off-by: Lorenzo Bianconi --- drivers/net/ethernet/airoha/airoha_eth.c | 10 ++++++---- @@ -16,9 +17,9 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -1740,11 +1740,8 @@ static int airhoha_enable_gdm2_loopback( +@@ -2044,11 +2044,8 @@ static int airoha_enable_gdm2_loopback(s u32 val, pse_port, chan; - int src_port; + int i, src_port; - /* Forward the traffic to the proper GDM port */ - pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3 @@ -29,7 +30,7 @@ Signed-off-by: Lorenzo Bianconi airoha_fe_clear(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX), GDM_STRIP_CRC_MASK); -@@ -1762,6 +1759,11 @@ static int airhoha_enable_gdm2_loopback( +@@ -2066,6 +2063,11 @@ static int airoha_enable_gdm2_loopback(s GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU)); diff --git a/target/linux/airoha/patches-6.12/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch b/target/linux/airoha/patches-6.12/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch index 484bd66c509131..a65b39a43312c7 100644 --- a/target/linux/airoha/patches-6.12/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch +++ b/target/linux/airoha/patches-6.12/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch @@ -1,47 +1,45 @@ -From b80426c1ecc6df524442d2d9132a180d966fee90 Mon Sep 17 00:00:00 2001 -Message-ID: -In-Reply-To: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> -References: <2cd15ef3379025ea1ae1f6c36c70621aa578c270.1771966444.git.lorenzo@kernel.org> +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: [bpf-next 16/16] net: airoha: Add ethtool priv_flags callbacks +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 | 191 +++++++++++++++++++++- - drivers/net/ethernet/airoha/airoha_eth.h | 13 +- - drivers/net/ethernet/airoha/airoha_ppe.c | 2 +- + drivers/net/ethernet/airoha/airoha_eth.c | 173 ++++++++++++++++++++++ drivers/net/ethernet/airoha/airoha_regs.h | 1 + - 4 files changed, 195 insertions(+), 12 deletions(-) + 2 files changed, 174 insertions(+) --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -1644,6 +1644,11 @@ static int airoha_dev_open(struct net_de - } - #endif +@@ -1895,6 +1895,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 cab be used just as wan */ + return -EBUSY; + } + - netif_tx_start_all_queues(netdev); - err = airoha_set_vip_for_gdm_port(dev, true); - if (err) -@@ -1757,37 +1762,115 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev) + #if defined(CONFIG_PCS_AIROHA) + if (airhoa_is_phy_external(port)) { + err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0); +@@ -2099,6 +2104,45 @@ static int airoha_enable_gdm2_loopback(s return 0; } --static int airoha_dev_init(struct net_device *netdev) -+static int airoha_disable_gdm2_loopback(struct airoha_gdm_dev *dev) ++static int airhoa_disable_gdm2_loopback(struct airoha_gdm_dev *dev) +{ + struct airoha_eth *eth = dev->eth; ++ int i, src_port; + u32 pse_port; -+ int src_port; + + src_port = eth->soc->ops.get_sport(dev->port, dev->nbq); + if (src_port < 0) @@ -63,6 +61,10 @@ Signed-off-by: Lorenzo Bianconi + 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)); @@ -72,93 +74,10 @@ Signed-off-by: Lorenzo Bianconi + return 0; +} + -+static struct airoha_gdm_dev * -+airoha_get_wan_gdm_dev(struct airoha_eth *eth) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { -+ struct airoha_gdm_port *port = eth->ports[i]; -+ int j; -+ -+ if (!port) -+ continue; -+ -+ for (j = 0; j < ARRAY_SIZE(port->devs); j++) { -+ struct airoha_gdm_dev *dev = port->devs[j]; -+ -+ if (!dev) -+ continue; -+ -+ if (airoha_is_lan_gdm_dev(dev)) -+ continue; -+ -+ return dev; -+ } -+ } -+ -+ return NULL; -+} -+ -+static void airoha_dev_set_qdma(struct airoha_gdm_dev *dev) + 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; - struct airoha_eth *eth = dev->eth; - int i; - - /* 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; -- airoha_set_macaddr(dev, netdev->dev_addr); -+ -+ for (i = 0; i < eth->soc->num_ppe; i++) -+ airoha_ppe_set_cpu_port(dev, i, -+ airoha_get_fe_port(dev)); -+} -+ -+static int airoha_dev_init(struct net_device *netdev) -+{ -+ struct airoha_gdm_dev *dev = netdev_priv(netdev); -+ struct airoha_gdm_port *port = dev->port; - -+ airoha_dev_set_qdma(dev); -+ - switch (port->id) { -+ case AIROHA_GDM2_IDX: -+ /* GDM2 is always used as wan */ -+ dev->flags |= PRIV_FLAG_WAN; -+ break; - case AIROHA_GDM3_IDX: -- case AIROHA_GDM4_IDX: -- /* If GDM2 is active we can't enable loopback */ -- if (!eth->ports[1]) { -+ case AIROHA_GDM4_IDX: { -+ struct airoha_eth *eth = dev->eth; -+ -+ if (!eth->ports[1] && !airoha_get_wan_gdm_dev(eth)) { - int err; - - err = airoha_set_gdm2_loopback(dev); - if (err) - return err; -+ -+ dev->flags |= PRIV_FLAG_WAN; - } - break; -+ } - default: - break; - } - -- for (i = 0; i < eth->soc->num_ppe; i++) -- airoha_ppe_set_cpu_port(dev, i, -- airoha_get_fe_port(dev)); -+ airoha_set_macaddr(dev, netdev->dev_addr); - - return 0; - } -@@ -2083,6 +2165,76 @@ error: +@@ -2474,6 +2518,80 @@ error: return NETDEV_TX_OK; } @@ -173,13 +92,13 @@ Signed-off-by: Lorenzo Bianconi + struct airoha_gdm_port *port = dev->port; + struct airoha_eth *eth = dev->eth; + -+ if (!((dev->flags ^ flags) & PRIV_FLAG_WAN)) ++ if (!((dev->flags ^ flags) & AIROHA_PRIV_F_WAN)) + return 0; + + if (netif_running(netdev)) + return -EBUSY; + -+ if (flags & PRIV_FLAG_WAN) { ++ if (flags & AIROHA_PRIV_F_WAN) { + struct airoha_gdm_dev *wan_dev; + + /* Verify the wan device is not already configured */ @@ -189,29 +108,33 @@ Signed-off-by: Lorenzo Bianconi + + 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; + -+ err = airoha_set_gdm2_loopback(dev); -+ if (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; + } -+ -+ dev->flags |= PRIV_FLAG_WAN; -+ airoha_set_macaddr(dev, netdev->dev_addr); + } else { + switch (port->id) { + case AIROHA_GDM3_IDX: + case AIROHA_GDM4_IDX: { + int err; + -+ err = airoha_disable_gdm2_loopback(dev); ++ err = airhoa_disable_gdm2_loopback(dev); + if (err) + return err; + break; @@ -219,12 +142,12 @@ Signed-off-by: Lorenzo Bianconi + default: + break; + } -+ dev->flags &= ~PRIV_FLAG_WAN; -+ } + -+ airoha_dev_set_qdma(dev); ++ dev->flags &= ~AIROHA_PRIV_F_WAN; ++ airoha_dev_set_qdma(dev); ++ } + -+ return 0; ++ return airoha_set_macaddr(dev, netdev->dev_addr);; +} + +static const struct airoha_ethool_priv_flags airoha_eth_priv_flags[] = { @@ -235,7 +158,7 @@ Signed-off-by: Lorenzo Bianconi static void airoha_ethtool_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) { -@@ -2091,6 +2243,7 @@ static void airoha_ethtool_get_drvinfo(s +@@ -2482,6 +2600,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)); @@ -243,7 +166,7 @@ Signed-off-by: Lorenzo Bianconi } static void airoha_ethtool_get_mac_stats(struct net_device *netdev, -@@ -2155,6 +2308,56 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2546,6 +2665,56 @@ airoha_ethtool_get_rmon_stats(struct net } while (u64_stats_fetch_retry(&port->stats.syncp, start)); } @@ -300,9 +223,9 @@ Signed-off-by: Lorenzo Bianconi 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) -@@ -2860,6 +3063,10 @@ static const struct ethtool_ops airoha_e - .get_eth_mac_stats = airoha_ethtool_get_mac_stats, +@@ -3267,6 +3436,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, @@ -310,56 +233,10 @@ Signed-off-by: Lorenzo Bianconi + .get_strings = airoha_ethtool_get_strings, }; - #if defined(CONFIG_PCS_AIROHA) ---- a/drivers/net/ethernet/airoha/airoha_eth.h -+++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -532,12 +532,17 @@ struct airoha_qdma { - struct airoha_queue q_rx[AIROHA_NUM_RX_RING]; - }; - -+enum airoha_priv_flags { -+ PRIV_FLAG_WAN = BIT(0), -+}; -+ - struct airoha_gdm_dev { - struct airoha_gdm_port *port; - struct airoha_qdma *qdma; - struct net_device *dev; - struct airoha_eth *eth; - -+ u32 flags; - int nbq; - - #if defined(CONFIG_PCS_AIROHA) -@@ -645,13 +650,7 @@ u32 airoha_rmw(void __iomem *base, u32 o - - static inline bool airoha_is_lan_gdm_dev(struct airoha_gdm_dev *dev) - { -- struct airoha_gdm_port *port = dev->port; -- -- /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. -- * GDM{2,3,4} can be used as wan port connected to an external -- * phy module. -- */ -- return port->id == 1; -+ return !(dev->flags & PRIV_FLAG_WAN); - } - - static inline bool airoha_is_7581(struct airoha_eth *eth) ---- a/drivers/net/ethernet/airoha/airoha_ppe.c -+++ b/drivers/net/ethernet/airoha/airoha_ppe.c -@@ -340,7 +340,7 @@ static int airoha_ppe_foe_entry_prepare( - return -EINVAL; - - port = dev->port; -- if (dsa_port >= 0 || eth->ports[1]) -+ if (dsa_port >= 0 || airoha_is_lan_gdm_dev(dev)) - pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 - : port->id; - else + 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 -@@ -388,6 +388,7 @@ +@@ -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)) diff --git a/target/linux/airoha/patches-6.12/920-13-net-airoha-Rework-MTU-configuration.patch b/target/linux/airoha/patches-6.12/920-13-net-airoha-Rework-MTU-configuration.patch new file mode 100644 index 00000000000000..10fd885a4d758c --- /dev/null +++ b/target/linux/airoha/patches-6.12/920-13-net-airoha-Rework-MTU-configuration.patch @@ -0,0 +1,208 @@ +From 99e204d255c9b47a188dd79762b9406d9c5fed9b Mon Sep 17 00:00:00 2001 +Message-ID: <99e204d255c9b47a188dd79762b9406d9c5fed9b.1779348625.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Wed, 20 May 2026 17:16:39 +0200 +Subject: [PATCH 13/13] net: airoha: Rework MTU configuration + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_eth.c | 85 +++++++++++------------ + drivers/net/ethernet/airoha/airoha_eth.h | 1 + + drivers/net/ethernet/airoha/airoha_ppe.c | 8 +-- + drivers/net/ethernet/airoha/airoha_regs.h | 9 ++- + 4 files changed, 49 insertions(+), 54 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -180,10 +180,15 @@ static void airoha_fe_maccr_init(struct + { + int p; + +- for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) ++ for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) { + airoha_fe_set(eth, REG_GDM_FWD_CFG(p), + GDM_TCP_CKSUM_MASK | GDM_UDP_CKSUM_MASK | + GDM_IP4_CKSUM_MASK | GDM_DROP_CRC_ERR_MASK); ++ airoha_fe_rmw(eth, REG_GDM_LEN_CFG(p), ++ GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, ++ FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | ++ FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU)); ++ } + + airoha_fe_rmw(eth, REG_CDM_VLAN_CTRL(1), CDM_VLAN_MASK, + FIELD_PREP(CDM_VLAN_MASK, 0x8100)); +@@ -1887,13 +1892,37 @@ static void airoha_update_hw_stats(struc + spin_unlock(&port->stats.lock); + } + ++void airoha_set_port_mtu(struct airoha_eth *eth, struct airoha_gdm_port *port) ++{ ++ u32 mtu = 0, index; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(port->devs); i++) { ++ struct airoha_gdm_dev *dev = port->devs[i]; ++ struct net_device *netdev; ++ ++ if (!dev) ++ continue; ++ ++ netdev = dev->dev; ++ if (netif_running(netdev)) ++ mtu = max_t(u32, mtu, netdev->mtu); ++ } ++ ++ index = port->id == AIROHA_GDM4_IDX ? 7 : port->id; ++ for (i = 0; i < eth->soc->num_ppe; i++) ++ airoha_fe_rmw(eth, REG_PPE_MTU(i, index), ++ FP_EGRESS_MTU_MASK(index), ++ __field_prep(FP_EGRESS_MTU_MASK(index), mtu)); ++} ++ + 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; ++ u32 pse_port = FE_PSE_PORT_PPE1; ++ int err; + + if (port->id == AIROHA_GDM2_IDX && airoha_is_lan_gdm_dev(dev)) { + /* GDM2 cab be used just as wan */ +@@ -1926,19 +1955,12 @@ static int airoha_dev_open(struct net_de + airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id), + GDM_STAG_EN_MASK); + +- cur_len = airoha_fe_get(qdma->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 +- * MTU of already running devices. This is required to allow +- * multiple net_devices with different MTUs to share the same +- * GDM port. +- */ +- airoha_fe_rmw(qdma->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)); +- } ++ airoha_set_port_mtu(qdma->eth, port); ++ if (airoha_is_lan_gdm_dev(dev)) ++ airoha_fe_rmw(qdma->eth, REG_WAN_MTU0, ++ WAN_MTU0_MASK, ++ FIELD_PREP(WAN_MTU0_MASK, netdev->mtu)); ++ + port->users++; + + airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, +@@ -1957,30 +1979,6 @@ static int airoha_dev_open(struct net_de + return 0; + } + +-static void airoha_set_port_mtu(struct airoha_eth *eth, +- struct airoha_gdm_port *port) +-{ +- u32 len = 0; +- int i; +- +- for (i = 0; i < ARRAY_SIZE(port->devs); i++) { +- struct airoha_gdm_dev *dev = port->devs[i]; +- struct net_device *netdev; +- +- if (!dev) +- continue; +- +- netdev = dev->dev; +- if (netif_running(netdev)) +- len = max_t(u32, len, netdev->mtu); +- } +- len += ETH_HLEN + ETH_FCS_LEN; +- +- airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), +- GDM_LONG_LEN_MASK, +- FIELD_PREP(GDM_LONG_LEN_MASK, len)); +-} +- + static int airoha_dev_stop(struct net_device *netdev) + { + struct airoha_gdm_dev *dev = netdev_priv(netdev); +@@ -2064,10 +2062,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); +- airoha_fe_rmw(eth, REG_GDM_LEN_CFG(AIROHA_GDM2_IDX), +- GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, +- FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | +- FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU)); + /* Forward the traffic to the proper GDM port */ + pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3 + : FE_PSE_PORT_GDM4; +@@ -2565,6 +2559,9 @@ static int airoha_dev_set_wan_flag(struc + default: + return -EOPNOTSUPP; + } ++ airoha_fe_rmw(eth, REG_WAN_MTU0, ++ WAN_MTU0_MASK, ++ FIELD_PREP(WAN_MTU0_MASK, netdev->mtu)); + } else { + switch (port->id) { + case AIROHA_GDM3_IDX: +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -705,6 +705,7 @@ int airoha_get_fe_port(struct airoha_gdm + bool airoha_is_valid_gdm_dev(struct airoha_eth *eth, + struct airoha_gdm_dev *dev); + ++void airoha_set_port_mtu(struct airoha_eth *eth, struct airoha_gdm_port *port); + 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 +@@ -172,16 +172,10 @@ static void airoha_ppe_hw_init(struct ai + struct airoha_gdm_port *port = eth->ports[p]; + int j; + +- airoha_fe_rmw(eth, REG_PPE_MTU(i, p), +- FP0_EGRESS_MTU_MASK | +- FP1_EGRESS_MTU_MASK, +- FIELD_PREP(FP0_EGRESS_MTU_MASK, +- AIROHA_MAX_MTU) | +- FIELD_PREP(FP1_EGRESS_MTU_MASK, +- AIROHA_MAX_MTU)); + if (!port) + continue; + ++ airoha_set_port_mtu(eth, port); + for (j = 0; j < ARRAY_SIZE(port->devs); j++) { + struct airoha_gdm_dev *dev = port->devs[j]; + u8 fport; +--- a/drivers/net/ethernet/airoha/airoha_regs.h ++++ b/drivers/net/ethernet/airoha/airoha_regs.h +@@ -341,9 +341,8 @@ + #define PPE_SRAM_TABLE_EN_MASK BIT(0) + + #define REG_PPE_MTU_BASE(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x304) +-#define REG_PPE_MTU(_m, _n) (REG_PPE_MTU_BASE(_m) + ((_n) << 2)) +-#define FP1_EGRESS_MTU_MASK GENMASK(29, 16) +-#define FP0_EGRESS_MTU_MASK GENMASK(13, 0) ++#define REG_PPE_MTU(_m, _n) (REG_PPE_MTU_BASE(_m) + (((_n) / 2) << 2)) ++#define FP_EGRESS_MTU_MASK(_n) GENMASK(13 + (((_n) % 2) << 4), ((_n) % 2) << 4) + + #define REG_PPE_RAM_CTRL(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x31c) + #define PPE_SRAM_CTRL_ACK_MASK BIT(31) +@@ -404,6 +403,10 @@ + #define FC_ID_OF_SRC_PORT_MASK(_n) GENMASK(4 + ((_n) << 3), ((_n) << 3)) + #define FC_MAP6_DEF_VALUE 0x1b1a1918 + ++#define REG_WAN_MTU0 0x2300 ++#define WAN_MTU1_MASK GENMASK(29, 16) ++#define WAN_MTU0_MASK GENMASK(13, 0) ++ + #define REG_CDM5_RX_OQ1_DROP_CNT 0x29d4 + + /* QDMA */ diff --git a/target/linux/airoha/patches-6.12/923-net-airoha-better-handle-MIB-for-GDM-with-multiple-p.patch b/target/linux/airoha/patches-6.12/920-14-net-airoha-Better-handle-MIB-for-GDM-with-multiple-p.patch similarity index 80% rename from target/linux/airoha/patches-6.12/923-net-airoha-better-handle-MIB-for-GDM-with-multiple-p.patch rename to target/linux/airoha/patches-6.12/920-14-net-airoha-Better-handle-MIB-for-GDM-with-multiple-p.patch index 8ec30146805b95..ec0f7cbb510d2d 100644 --- a/target/linux/airoha/patches-6.12/923-net-airoha-better-handle-MIB-for-GDM-with-multiple-p.patch +++ b/target/linux/airoha/patches-6.12/920-14-net-airoha-Better-handle-MIB-for-GDM-with-multiple-p.patch @@ -1,7 +1,8 @@ -From 4f79671ba98d10628665f8cd9dca8ff81da17f03 Mon Sep 17 00:00:00 2001 +From 9652322e0b47eacfef497828f6476a2a3169fd13 Mon Sep 17 00:00:00 2001 +Message-ID: <9652322e0b47eacfef497828f6476a2a3169fd13.1779351672.git.lorenzo@kernel.org> From: Christian Marangi Date: Sat, 17 Jan 2026 14:46:12 +0100 -Subject: [PATCH] net: airoha: better handle MIB for GDM with multiple port +Subject: [PATCH] net: airoha: Better handle MIB for GDM with multiple port attached In the context of a GDM that can have multiple port attached (GDM3/4) @@ -20,26 +21,48 @@ kernel for the related interface. Also move the stats struct from port to dev since HW counter are now specific to the network interface instead of the GDM port. +Co-developed-by: Brown Huang +Signed-off-by: Brown Huang Signed-off-by: Christian Marangi --- - drivers/net/ethernet/airoha/airoha_eth.c | 179 ++++++++++++----------- - drivers/net/ethernet/airoha/airoha_eth.h | 3 +- - 2 files changed, 97 insertions(+), 85 deletions(-) + drivers/net/ethernet/airoha/airoha_eth.c | 191 +++++++++++++---------- + drivers/net/ethernet/airoha/airoha_eth.h | 7 +- + 2 files changed, 112 insertions(+), 86 deletions(-) --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -1484,143 +1484,151 @@ static void airoha_update_hw_stats(struc +@@ -600,6 +600,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); + ++ /* Enable split for MIB counters for GDM3 and GDM4 */ ++ airoha_fe_set(eth, REG_FE_GDM_MIB_CFG(AIROHA_GDM3_IDX), ++ FE_GDM_TX_MIB_SPLIT_EN_MASK | ++ FE_GDM_RX_MIB_SPLIT_EN_MASK); ++ airoha_fe_set(eth, REG_FE_GDM_MIB_CFG(AIROHA_GDM4_IDX), ++ FE_GDM_TX_MIB_SPLIT_EN_MASK | ++ FE_GDM_RX_MIB_SPLIT_EN_MASK); ++ + airoha_fe_crsn_qsel_init(eth); + + airoha_fe_clear(eth, REG_FE_CPORT_CFG, FE_CPORT_QUEUE_XFC_MASK); +@@ -1747,149 +1755,169 @@ static void airoha_qdma_stop_napi(struct + } + } + +-static void airoha_update_hw_stats(struct airoha_gdm_dev *dev) ++static void airoha_dev_get_hw_stats(struct airoha_gdm_dev *dev) + { + struct airoha_gdm_port *port = dev->port; struct airoha_eth *eth = dev->eth; u32 val, i = 0; - spin_lock(&port->stats.lock); - u64_stats_update_begin(&port->stats.syncp); -+ spin_lock(&dev->stats.lock); + u64_stats_update_begin(&dev->stats.syncp); + + /* Read relevant MIB for GDM with multiple port attached */ -+ if (port->id == AIROHA_GDM3_IDX || -+ port->id == AIROHA_GDM4_IDX) ++ if (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX) + airoha_fe_rmw(eth, REG_FE_GDM_MIB_CFG(port->id), + FE_TX_MIB_ID_MASK | FE_RX_MIB_ID_MASK, + FIELD_PREP(FE_TX_MIB_ID_MASK, dev->nbq) | @@ -219,30 +242,35 @@ Signed-off-by: Christian Marangi val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_LONG_CNT(port->id)); - port->stats.rx_len[i++] += val; + dev->stats.rx_len[i++] += val; - - /* reset mib counters */ - airoha_fe_set(eth, REG_FE_GDM_MIB_CLEAR(port->id), ++ ++ u64_stats_update_end(&dev->stats.syncp); ++} + +- /* reset mib counters */ +- airoha_fe_set(eth, REG_FE_GDM_MIB_CLEAR(port->id), ++static void airoha_update_hw_stats(struct airoha_gdm_dev *dev) ++{ ++ struct airoha_gdm_port *port = dev->port; ++ int i; ++ ++ spin_lock(&port->stats_lock); ++ ++ for (i = 0; i < ARRAY_SIZE(port->devs); i++) { ++ if (port->devs[i]) ++ airoha_dev_get_hw_stats(port->devs[i]); ++ } ++ ++ /* Reset MIB counters */ ++ airoha_fe_set(dev->eth, REG_FE_GDM_MIB_CLEAR(port->id), FE_GDM_MIB_RX_CLEAR_MASK | FE_GDM_MIB_TX_CLEAR_MASK); - u64_stats_update_end(&port->stats.syncp); - spin_unlock(&port->stats.lock); -+ u64_stats_update_end(&dev->stats.syncp); -+ spin_unlock(&dev->stats.lock); ++ spin_unlock(&port->stats_lock); } - static int airoha_dev_open(struct net_device *netdev) -@@ -1896,6 +1904,10 @@ static int airoha_dev_init(struct net_de - - dev->flags |= PRIV_FLAG_WAN; - } -+ /* Enable split MIB for GDM with multiple port attached */ -+ airoha_fe_set(eth, REG_FE_GDM_MIB_CFG(port->id), -+ FE_GDM_TX_MIB_SPLIT_EN_MASK | -+ FE_GDM_RX_MIB_SPLIT_EN_MASK); - break; - } - default: -@@ -1912,23 +1924,22 @@ static void airoha_dev_get_stats64(struc + void airoha_set_port_mtu(struct airoha_eth *eth, struct airoha_gdm_port *port) +@@ -2220,23 +2248,22 @@ static void airoha_dev_get_stats64(struc struct rtnl_link_stats64 *storage) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -278,7 +306,7 @@ Signed-off-by: Christian Marangi } static int airoha_dev_change_mtu(struct net_device *netdev, int mtu) -@@ -2250,20 +2261,19 @@ static void airoha_ethtool_get_mac_stats +@@ -2604,20 +2631,19 @@ static void airoha_ethtool_get_mac_stats struct ethtool_eth_mac_stats *stats) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -308,7 +336,7 @@ Signed-off-by: Christian Marangi } static const struct ethtool_rmon_hist_range airoha_ethtool_rmon_ranges[] = { -@@ -2283,8 +2293,7 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2637,8 +2663,7 @@ airoha_ethtool_get_rmon_stats(struct net const struct ethtool_rmon_hist_range **ranges) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -318,7 +346,7 @@ Signed-off-by: Christian Marangi unsigned int start; BUILD_BUG_ON(ARRAY_SIZE(airoha_ethtool_rmon_ranges) != -@@ -2297,7 +2306,7 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2651,7 +2676,7 @@ airoha_ethtool_get_rmon_stats(struct net do { int i; @@ -327,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; -@@ -2305,7 +2314,7 @@ airoha_ethtool_get_rmon_stats(struct net +@@ -2659,7 +2684,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]; } @@ -336,40 +364,52 @@ Signed-off-by: Christian Marangi } static int airoha_ethtool_set_priv_flags(struct net_device *netdev, u32 flags) -@@ -3293,6 +3302,8 @@ static int airoha_alloc_gdm_device(struc +@@ -3667,6 +3692,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; - dev->nbq = nbq; -+ u64_stats_init(&dev->stats.syncp); -+ spin_lock_init(&dev->stats.lock); - - #if defined(CONFIG_PCS_AIROHA) - if (airhoa_is_phy_external(port)) { -@@ -3337,8 +3348,6 @@ static int airoha_alloc_gdm_port(struct +@@ -3715,9 +3741,8 @@ static int airoha_alloc_gdm_port(struct if (!port) return -ENOMEM; - u64_stats_init(&port->stats.syncp); - spin_lock_init(&port->stats.lock); port->id = id; ++ spin_lock_init(&port->stats_lock); eth->ports[p] = port; + err = airoha_metadata_dst_alloc(port); --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h -@@ -542,6 +542,8 @@ struct airoha_gdm_dev { - struct airoha_eth *eth; - struct net_device *dev; +@@ -226,8 +226,6 @@ struct airoha_tx_irq_queue { + }; -+ struct airoha_hw_stats stats; + struct airoha_hw_stats { +- /* protect concurrent hw_stats accesses */ +- spinlock_t lock; + struct u64_stats_sync syncp; + + /* get_stats64 */ +@@ -571,6 +569,8 @@ struct airoha_gdm_dev { + + u32 flags; + int nbq; + - #if defined(CONFIG_PCS_AIROHA) - struct phylink *phylink; - struct phylink_config phylink_config; -@@ -556,7 +558,6 @@ struct airoha_gdm_port { - struct airoha_gdm_dev *devs[AIROHA_MAX_NUM_GDM_DEVS]; ++ struct airoha_hw_stats stats; + }; + + struct airoha_gdm_port { +@@ -578,7 +578,8 @@ struct airoha_gdm_port { int id; + int users; - struct airoha_hw_stats stats; ++ /* protect concurrent hw_stats accesses */ ++ spinlock_t stats_lock; - DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); - + struct metadata_dst *dsa_meta[AIROHA_MAX_DSA_PORTS]; + }; diff --git a/target/linux/airoha/patches-6.12/930-airoha-ethtool-link.patch b/target/linux/airoha/patches-6.12/930-airoha-ethtool-link.patch index 59a81ac0c563f0..2ad7761df2560a 100644 --- a/target/linux/airoha/patches-6.12/930-airoha-ethtool-link.patch +++ b/target/linux/airoha/patches-6.12/930-airoha-ethtool-link.patch @@ -1,6 +1,6 @@ --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c -@@ -2342,6 +2342,30 @@ static u32 airoha_ethtool_get_priv_flags +@@ -2712,6 +2712,30 @@ static u32 airoha_ethtool_get_priv_flags return dev->flags; } @@ -31,9 +31,9 @@ static int airoha_ethtool_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { -@@ -3072,6 +3096,8 @@ static const struct ethtool_ops airoha_e - .get_eth_mac_stats = airoha_ethtool_get_mac_stats, +@@ -3458,6 +3482,8 @@ 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, + .get_link_ksettings = airoha_ethtool_get_link_ksettings, + .set_link_ksettings = airoha_ethtool_set_link_ksettings, diff --git a/target/linux/airoha/patches-6.12/931-net-airoha-fix-wrong-airoha_get_fe_port.patch b/target/linux/airoha/patches-6.12/931-net-airoha-fix-wrong-airoha_get_fe_port.patch index d69a7357c8e1a5..75a49306c2ca28 100644 --- a/target/linux/airoha/patches-6.12/931-net-airoha-fix-wrong-airoha_get_fe_port.patch +++ b/target/linux/airoha/patches-6.12/931-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 -@@ -2024,17 +2024,9 @@ static u32 airoha_get_dsa_tag(struct sk_ +@@ -2345,17 +2345,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 netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + static int airoha_dev_set_features(struct net_device *netdev, diff --git a/target/linux/airoha/patches-6.12/990-eip93-ahash-fix.patch b/target/linux/airoha/patches-6.12/990-eip93-ahash-fix.patch index c65d09fd664df0..0681f57c5fb1fd 100644 --- a/target/linux/airoha/patches-6.12/990-eip93-ahash-fix.patch +++ b/target/linux/airoha/patches-6.12/990-eip93-ahash-fix.patch @@ -71,11 +71,9 @@ Signed-off-by: Kenneth Kasilag drivers/crypto/inside-secure/eip93/eip93-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/drivers/crypto/inside-secure/eip93/eip93-common.c b/drivers/crypto/inside-secure/eip93/eip93-common.c -index f4ad6beff15e..259714a4ee4d 100644 --- a/drivers/crypto/inside-secure/eip93/eip93-common.c +++ b/drivers/crypto/inside-secure/eip93/eip93-common.c -@@ -731,7 +731,7 @@ int eip93_hmac_setkey(u32 ctx_flags, const u8 *key, unsigned int keylen, +@@ -731,7 +731,7 @@ int eip93_hmac_setkey(u32 ctx_flags, con return -EINVAL; } @@ -84,5 +82,3 @@ index f4ad6beff15e..259714a4ee4d 100644 if (IS_ERR(ahash_tfm)) return PTR_ERR(ahash_tfm); --- -2.51.0