]> www.infradead.org Git - users/hch/misc.git/commitdiff
net: airoha: Take into account out-of-order tx completions in airoha_dev_xmit()
authorLorenzo Bianconi <lorenzo@kernel.org>
Sun, 12 Oct 2025 09:19:44 +0000 (11:19 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 14 Oct 2025 10:33:46 +0000 (12:33 +0200)
Completion napi can free out-of-order tx descriptors if hw QoS is
enabled and packets with different priority are queued to same DMA ring.
Take into account possible out-of-order reports checking if the tx queue
is full using circular buffer head/tail pointer instead of the number of
queued packets.

Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Suggested-by: Simon Horman <horms@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20251012-airoha-tx-busy-queue-v2-1-a600b08bab2d@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/airoha/airoha_eth.c

index 833dd911980b3f698bd7e5f9fd9e2ce131dd5222..433a646e9831773bf63600e7c3d3b2176c4d133e 100644 (file)
@@ -1873,6 +1873,20 @@ static u32 airoha_get_dsa_tag(struct sk_buff *skb, struct net_device *dev)
 #endif
 }
 
+static bool airoha_dev_tx_queue_busy(struct airoha_queue *q, u32 nr_frags)
+{
+       u32 tail = q->tail <= q->head ? q->tail + q->ndesc : q->tail;
+       u32 index = q->head + nr_frags;
+
+       /* completion napi can free out-of-order tx descriptors if hw QoS is
+        * enabled and packets with different priorities are queued to the same
+        * DMA ring. Take into account possible out-of-order reports checking
+        * if the tx queue is full using circular buffer head/tail pointers
+        * instead of the number of queued packets.
+        */
+       return index >= tail;
+}
+
 static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
                                   struct net_device *dev)
 {
@@ -1926,7 +1940,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
        txq = netdev_get_tx_queue(dev, qid);
        nr_frags = 1 + skb_shinfo(skb)->nr_frags;
 
-       if (q->queued + nr_frags > q->ndesc) {
+       if (airoha_dev_tx_queue_busy(q, nr_frags)) {
                /* not enough space in the queue */
                netif_tx_stop_queue(txq);
                spin_unlock_bh(&q->lock);