Merge branch 'net-mvpp2-fix-xdp-rx-buffer-handling'

Til Kaiser says:

====================
net: mvpp2: fix XDP RX buffer handling

This is v5 of the earlier XDP_PASS fix. The XDP_PASS change is
retained, and the series also fixes related RX/XDP buffer handling
issues found during review.

Tested with tools/testing/selftests/drivers/net/xdp.py on mvpp2
hardware.
====================

Link: https://patch.msgid.link/20260607134943.21996-1-mail@tk154.de
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-06-11 09:57:33 +02:00
commit b59873c9c4

View File

@ -3917,10 +3917,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
struct mvpp2_bm_pool *bm_pool;
struct page_pool *pp = NULL;
struct sk_buff *skb;
unsigned int frag_size;
unsigned int frag_size, rx_sync_size;
dma_addr_t dma_addr;
phys_addr_t phys_addr;
int pool, rx_bytes, err, ret;
int pool, rx_bytes, rx_offset, err, ret;
struct page *page;
void *data;
@ -3933,6 +3933,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
rx_status = mvpp2_rxdesc_status_get(port, rx_desc);
rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc);
rx_bytes -= MVPP2_MH_SIZE;
rx_sync_size = rx_bytes + MVPP2_MH_SIZE;
rx_offset = MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM;
dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc);
pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >>
@ -3946,9 +3948,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
dma_dir = DMA_FROM_DEVICE;
}
dma_sync_single_for_cpu(dev->dev.parent, dma_addr,
rx_bytes + MVPP2_MH_SIZE,
dma_dir);
dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr,
MVPP2_SKB_HEADROOM,
rx_sync_size,
dma_dir);
/* Buffer header not supported */
if (rx_status & MVPP2_RXD_BUF_HDR)
@ -3970,6 +3973,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
else
frag_size = bm_pool->frag_size;
err = mvpp2_rx_refill(port, bm_pool, pp, pool);
if (err) {
netdev_err(port->dev, "failed to refill BM pools\n");
goto err_drop_frame;
}
if (xdp_prog) {
struct xdp_rxq_info *xdp_rxq;
@ -3978,7 +3987,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
else
xdp_rxq = &rxq->xdp_rxq_long;
xdp_init_buff(&xdp, PAGE_SIZE, xdp_rxq);
xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq);
xdp_prepare_buff(&xdp, data,
MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM,
rx_bytes, true);
@ -3987,17 +3996,19 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
if (ret) {
xdp_ret |= ret;
err = mvpp2_rx_refill(port, bm_pool, pp, pool);
if (err) {
netdev_err(port->dev, "failed to refill BM pools\n");
goto err_drop_frame;
}
ps.rx_packets++;
ps.rx_bytes += rx_bytes;
continue;
}
rx_sync_size = max_t(unsigned int, rx_sync_size,
xdp.data_end - xdp.data_hard_start -
MVPP2_SKB_HEADROOM);
/* Update offset and length to reflect any XDP adjustments. */
rx_offset = xdp.data - data;
rx_bytes = xdp.data_end - xdp.data;
metasize = xdp.data - xdp.data_meta;
}
@ -4007,8 +4018,20 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
skb = slab_build_skb(data);
if (!skb) {
netdev_warn(port->dev, "skb build failed\n");
goto err_drop_frame;
if (pp) {
page_pool_put_page(pp, virt_to_head_page(data),
rx_sync_size, true);
} else {
dma_unmap_single_attrs(dev->dev.parent, dma_addr,
bm_pool->buf_size,
DMA_FROM_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
mvpp2_frag_free(bm_pool, pp, data);
}
goto err_drop_frame_retired;
}
if (pp)
skb_mark_for_recycle(skb);
/* If we have RX hardware timestamping enabled, grab the
* timestamp from the queue and convert.
@ -4019,16 +4042,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
skb_hwtstamps(skb));
}
err = mvpp2_rx_refill(port, bm_pool, pp, pool);
if (err) {
netdev_err(port->dev, "failed to refill BM pools\n");
dev_kfree_skb_any(skb);
goto err_drop_frame;
}
if (pp)
skb_mark_for_recycle(skb);
else
if (!pp)
dma_unmap_single_attrs(dev->dev.parent, dma_addr,
bm_pool->buf_size, DMA_FROM_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
@ -4036,7 +4050,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
ps.rx_packets++;
ps.rx_bytes += rx_bytes;
skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM);
skb_reserve(skb, rx_offset);
skb_put(skb, rx_bytes);
if (metasize)
skb_metadata_set(skb, metasize);
@ -4047,13 +4061,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
continue;
err_drop_frame:
dev->stats.rx_errors++;
mvpp2_rx_error(port, rx_desc);
/* Return the buffer to the pool */
if (rx_status & MVPP2_RXD_BUF_HDR)
mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status);
else
mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
err_drop_frame_retired:
dev->stats.rx_errors++;
mvpp2_rx_error(port, rx_desc);
}
if (xdp_ret & MVPP2_XDP_REDIR)