Re: [PATCH net-next 8/8] net: macb: add Tx zero-copy AF_XDP support
From: Maxime Chevallier
Date: Fri Mar 06 2026 - 07:55:43 EST
Hi Théo,
On 04/03/2026 19:24, Théo Lebrun wrote:
> Add a new buffer type (to `enum macb_tx_buff_type`). Near the end of
> macb_tx_complete(), we go and read the XSK buffers using
> xsk_tx_peek_release_desc_batch() and append those buffers to our Tx
> ring.
>
> Additionally, in macb_tx_complete(), we signal to the XSK subsystem
> number of bytes completed and conditionally mark the need_wakeup
> flag.
>
> Lastly, we update XSK wakeup by writing the TCOMP bit in the per-queue
> IMR register, to ensure NAPI scheduling will take place.
>
> Signed-off-by: Théo Lebrun <theo.lebrun@xxxxxxxxxxx>
> ---
[...]
> +static void macb_xdp_xmit_zc(struct macb *bp, unsigned int queue_index, int budget)
> +{
> + struct macb_queue *queue = &bp->queues[queue_index];
> + struct xsk_buff_pool *xsk = queue->xsk_pool;
> + dma_addr_t mapping;
> + u32 slot_available;
> + size_t bytes = 0;
> + u32 batch;
> +
> + guard(spinlock_irqsave)(&queue->tx_ptr_lock);
> +
> + /* This is a hard error, log it. */
> + slot_available = CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size);
> + if (slot_available < 1) {
> + netif_stop_subqueue(bp->dev, queue_index);
> + netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n",
> + queue->tx_head, queue->tx_tail);
> + return;
> + }
> +
> + batch = min_t(u32, slot_available, budget);
> + batch = xsk_tx_peek_release_desc_batch(xsk, batch);
> + if (!batch)
> + return;
> +
> + for (u32 i = 0; i < batch; i++) {
> + struct xdp_desc *desc = &xsk->tx_descs[i];
> +
> + mapping = xsk_buff_raw_get_dma(xsk, desc->addr);
> + xsk_buff_raw_dma_sync_for_device(xsk, mapping, desc->len);
> +
> + macb_xdp_submit_buff(bp, queue_index, (struct macb_tx_buff){
> + .ptr = NULL,
> + .mapping = mapping,
> + .size = desc->len,
> + .mapped_as_page = false,
> + .type = MACB_TYPE_XSK,
> + });
> +
> + bytes += desc->len;
> + }
> +
> + /* Make newly initialized descriptor visible to hardware */
> + wmb();
> + spin_lock(&bp->lock);
> + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
> + spin_unlock(&bp->lock);
this lock is also taken in interrupt context, this should probably use a
irqsave/restore variant. Now, there are a few other parts of this driver
that use a plain spin_lock() call and except for the paths that actually
run in interrupt context, they don't seem correct to me :(
Maxime