Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: airoha: Fix possible TX queue stall in airoha_qdma_tx_napi_poll()

Since multiple net_device TX queues can share the same hw QDMA TX queue,
there is no guarantee we have inflight packets queued in hw belonging to a
net_device TX queue stopped in the xmit path because hw QDMA TX queue
can be full. In this corner case the net_device TX queue will never be
re-activated. In order to avoid any potential net_device TX queue stall,
we need to wake all the net_device TX queues feeding the same hw QDMA TX
queue in airoha_qdma_tx_napi_poll routine.

Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260416-airoha-txq-potential-stall-v2-1-42c732074540@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Lorenzo Bianconi and committed by
Jakub Kicinski
b94769eb 2091c6aa

+33 -5
+32 -5
drivers/net/ethernet/airoha/airoha_eth.c
··· 843 843 return 0; 844 844 } 845 845 846 + static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) 847 + { 848 + struct airoha_qdma *qdma = q->qdma; 849 + struct airoha_eth *eth = qdma->eth; 850 + int i; 851 + 852 + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { 853 + struct airoha_gdm_port *port = eth->ports[i]; 854 + 855 + if (port && port->qdma == qdma) 856 + netif_tx_wake_all_queues(port->dev); 857 + } 858 + q->txq_stopped = false; 859 + } 860 + 846 861 static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) 847 862 { 848 863 struct airoha_tx_irq_queue *irq_q; ··· 934 919 935 920 txq = netdev_get_tx_queue(skb->dev, queue); 936 921 netdev_tx_completed_queue(txq, 1, skb->len); 937 - if (netif_tx_queue_stopped(txq) && 938 - q->ndesc - q->queued >= q->free_thr) 939 - netif_tx_wake_queue(txq); 940 - 941 922 dev_kfree_skb_any(skb); 942 923 } 924 + 925 + if (q->txq_stopped && q->ndesc - q->queued >= q->free_thr) { 926 + /* Since multiple net_device TX queues can share the 927 + * same hw QDMA TX queue, there is no guarantee we have 928 + * inflight packets queued in hw belonging to a 929 + * net_device TX queue stopped in the xmit path. 930 + * In order to avoid any potential net_device TX queue 931 + * stall, we need to wake all the net_device TX queues 932 + * feeding the same hw QDMA TX queue. 933 + */ 934 + airoha_qdma_wake_netdev_txqs(q); 935 + } 936 + 943 937 unlock: 944 938 spin_unlock_bh(&q->lock); 945 939 } ··· 2008 1984 if (q->queued + nr_frags >= q->ndesc) { 2009 1985 /* not enough space in the queue */ 2010 1986 netif_tx_stop_queue(txq); 1987 + q->txq_stopped = true; 2011 1988 spin_unlock_bh(&q->lock); 2012 1989 return NETDEV_TX_BUSY; 2013 1990 } ··· 2064 2039 TX_RING_CPU_IDX_MASK, 2065 2040 FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); 2066 2041 2067 - if (q->ndesc - q->queued < q->free_thr) 2042 + if (q->ndesc - q->queued < q->free_thr) { 2068 2043 netif_tx_stop_queue(txq); 2044 + q->txq_stopped = true; 2045 + } 2069 2046 2070 2047 spin_unlock_bh(&q->lock); 2071 2048
+1
drivers/net/ethernet/airoha/airoha_eth.h
··· 193 193 int ndesc; 194 194 int free_thr; 195 195 int buf_size; 196 + bool txq_stopped; 196 197 197 198 struct napi_struct napi; 198 199 struct page_pool *page_pool;