The SKB case of macb_tx_complete() must iterate over buffers taking into account frames might be multi-buffer. Following that, the code for XDP got integrated into the same loop. But in XDP cases, frames must be single buffer. Knowing that, we reverse operations: first we check the buffer type, then we iterate to consume all frame buffers if it is an SKB buffer. Side-effects: - Statistics tx_packets and tx_bytes are now incremented for XDP_TX and XDP_NDO frames as well. - Only increment statistics once per macb_tx_complete() call rather than once per frame. Signed-off-by: Théo Lebrun --- drivers/net/ethernet/cadence/macb_main.c | 71 +++++++++++------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 2c7644f2215a..6c33af667405 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1202,11 +1202,10 @@ static int macb_tx_complete(struct macb_queue *queue, int budget) spin_lock_irqsave(&queue->tx_ptr_lock, flags); head = queue->tx_head; for (tail = queue->tx_tail; tail != head && packets < budget; tail++) { - void *data = NULL; - struct macb_tx_buff *tx_buff; - struct sk_buff *skb; - struct macb_dma_desc *desc; - u32 ctrl; + struct macb_tx_buff *tx_buff; + struct macb_dma_desc *desc; + struct sk_buff *skb; + u32 ctrl; desc = macb_tx_desc(queue, tail); @@ -1221,48 +1220,44 @@ static int macb_tx_complete(struct macb_queue *queue, int budget) if (!(ctrl & MACB_BIT(TX_USED))) break; - /* Process all buffers of the current transmitted frame */ - for (;; tail++) { - tx_buff = macb_tx_buff(queue, tail); + tx_buff = macb_tx_buff(queue, tail); - if (tx_buff->type != MACB_TYPE_SKB) { - data = tx_buff->ptr; - goto unmap; + switch (tx_buff->type) { + case MACB_TYPE_SKB: + /* Process all buffers of the current transmitted frame */ + while (!tx_buff->ptr) { + macb_tx_unmap(bp, tx_buff, budget); + tail++; + tx_buff = macb_tx_buff(queue, tail); } - /* First, update TX stats if needed */ - if (tx_buff->type == MACB_TYPE_SKB && tx_buff->ptr) { - data = tx_buff->ptr; - skb = tx_buff->ptr; + skb = tx_buff->ptr; - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - !ptp_one_step_sync(skb)) - gem_ptp_do_txstamp(bp, skb, desc); + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + !ptp_one_step_sync(skb)) + gem_ptp_do_txstamp(bp, skb, desc); - netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", - macb_tx_ring_wrap(bp, tail), - skb->data); - bp->dev->stats.tx_packets++; - queue->stats.tx_packets++; - bp->dev->stats.tx_bytes += skb->len; - queue->stats.tx_bytes += skb->len; - packets++; - bytes += skb->len; - } + netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", + macb_tx_ring_wrap(bp, tail), + skb->data); + bytes += skb->len; + break; -unmap: - /* Now we can safely release resources */ - macb_tx_unmap(bp, tx_buff, budget); - - /* skb is set only for the last buffer of the frame. - * WARNING: at this point skb has been freed by - * macb_tx_unmap(). - */ - if (data) - break; + case MACB_TYPE_XDP_TX: + case MACB_TYPE_XDP_NDO: + bytes += tx_buff->size; + break; } + + packets++; + macb_tx_unmap(bp, tx_buff, budget); } + bp->dev->stats.tx_packets += packets; + queue->stats.tx_packets += packets; + bp->dev->stats.tx_bytes += bytes; + queue->stats.tx_bytes += bytes; + netdev_tx_completed_queue(netdev_get_tx_queue(bp->dev, queue_index), packets, bytes); -- 2.53.0