diff options
Diffstat (limited to 'drivers/net/ethernet/airoha/airoha_eth.c')
| -rw-r--r-- | drivers/net/ethernet/airoha/airoha_eth.c | 16 | 
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 833dd911980b..433a646e9831 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -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);  | 
