* [PATCH net v4 1/4] net: mvpp2: sync RX data at the hardware packet offset
2026-06-05 15:44 [PATCH net v4 0/4] net: mvpp2: fix XDP RX buffer handling Til Kaiser
@ 2026-06-05 15:44 ` Til Kaiser
2026-06-05 15:44 ` [PATCH net v4 2/4] net: mvpp2: limit XDP frame size to the RX buffer Til Kaiser
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Til Kaiser @ 2026-06-05 15:44 UTC (permalink / raw)
To: netdev, bpf
Cc: marcin.s.wojtas, linux, andrew+netdev, davem, edumazet, kuba,
pabeni, ast, daniel, hawk, john.fastabend, sdf, mcroce,
sven.auhagen, lorenzo, Til Kaiser
mvpp2 programs the RX queue packet offset, so hardware writes received
data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at
dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the
unused headroom and misses the same number of bytes at the packet tail.
On non-coherent DMA systems this can leave the CPU reading stale cache
contents for the end of the received frame.
Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range
offset so the sync covers the Marvell header and packet data actually
written by hardware.
Fixes: e1921168bbd4 ("mvpp2: sync only the received frame")
Signed-off-by: Til Kaiser <mail@tk154.de>
---
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index f442b874bb59..92a701f4fe3f 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3946,9 +3946,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_bytes + MVPP2_MH_SIZE,
+ dma_dir);
/* Buffer header not supported */
if (rx_status & MVPP2_RXD_BUF_HDR)
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH net v4 2/4] net: mvpp2: limit XDP frame size to the RX buffer
2026-06-05 15:44 [PATCH net v4 0/4] net: mvpp2: fix XDP RX buffer handling Til Kaiser
2026-06-05 15:44 ` [PATCH net v4 1/4] net: mvpp2: sync RX data at the hardware packet offset Til Kaiser
@ 2026-06-05 15:44 ` Til Kaiser
2026-06-05 15:44 ` [PATCH net v4 3/4] net: mvpp2: refill RX buffers before XDP or skb use Til Kaiser
2026-06-05 15:44 ` [PATCH net v4 4/4] net: mvpp2: build skb from XDP-adjusted data on XDP_PASS Til Kaiser
3 siblings, 0 replies; 5+ messages in thread
From: Til Kaiser @ 2026-06-05 15:44 UTC (permalink / raw)
To: netdev, bpf
Cc: marcin.s.wojtas, linux, andrew+netdev, davem, edumazet, kuba,
pabeni, ast, daniel, hawk, john.fastabend, sdf, mcroce,
sven.auhagen, lorenzo, Til Kaiser
mvpp2 has short and long BM pools, and short pool buffers can be smaller
than PAGE_SIZE. The XDP path nevertheless initializes every xdp_buff with
PAGE_SIZE as frame size.
XDP helpers use frame_sz to validate tail growth and to derive the hard
end of the data area. Advertising PAGE_SIZE for short buffers can let
bpf_xdp_adjust_tail() grow a packet past the real allocation, corrupting
memory or later tripping skb tailroom checks.
Initialize the XDP buffer with bm_pool->frag_size so XDP tailroom matches
the actual buffer backing the packet.
Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support")
Signed-off-by: Til Kaiser <mail@tk154.de>
---
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 92a701f4fe3f..3372ed27cc8d 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3979,7 +3979,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);
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH net v4 3/4] net: mvpp2: refill RX buffers before XDP or skb use
2026-06-05 15:44 [PATCH net v4 0/4] net: mvpp2: fix XDP RX buffer handling Til Kaiser
2026-06-05 15:44 ` [PATCH net v4 1/4] net: mvpp2: sync RX data at the hardware packet offset Til Kaiser
2026-06-05 15:44 ` [PATCH net v4 2/4] net: mvpp2: limit XDP frame size to the RX buffer Til Kaiser
@ 2026-06-05 15:44 ` Til Kaiser
2026-06-05 15:44 ` [PATCH net v4 4/4] net: mvpp2: build skb from XDP-adjusted data on XDP_PASS Til Kaiser
3 siblings, 0 replies; 5+ messages in thread
From: Til Kaiser @ 2026-06-05 15:44 UTC (permalink / raw)
To: netdev, bpf
Cc: marcin.s.wojtas, linux, andrew+netdev, davem, edumazet, kuba,
pabeni, ast, daniel, hawk, john.fastabend, sdf, mcroce,
sven.auhagen, lorenzo, Til Kaiser
The RX error path returns the current descriptor buffer to the hardware
BM pool. That is only valid while the driver still owns the buffer.
mvpp2_rx_refill() can fail after the current buffer has been handed to
XDP or attached to an skb. In those cases mvpp2_run_xdp() may have
recycled, redirected, or queued the page for XDP_TX, and an skb free also
retires the data buffer. Returning such a buffer to BM lets hardware DMA
into memory that is no longer owned by the RX ring.
Refill the BM pool before handing the current buffer to XDP or to the
skb. If the allocation fails there, drop the packet and return the
still-owned current buffer to BM, preserving the pool depth. Once the
refill succeeds, later local drops retire/free the current buffer instead
of returning it to BM.
Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support")
Fixes: d6526926de73 ("net: mvpp2: fix memory leak in mvpp2_rx")
Signed-off-by: Til Kaiser <mail@tk154.de>
---
.../net/ethernet/marvell/mvpp2/mvpp2_main.c | 43 +++++++++++--------
1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 3372ed27cc8d..481daafdc1cb 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3971,6 +3971,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;
@@ -3988,12 +3994,6 @@ 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;
@@ -4008,8 +4008,21 @@ 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_bytes + MVPP2_MH_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.
@@ -4020,16 +4033,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);
@@ -4048,13 +4052,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)
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH net v4 4/4] net: mvpp2: build skb from XDP-adjusted data on XDP_PASS
2026-06-05 15:44 [PATCH net v4 0/4] net: mvpp2: fix XDP RX buffer handling Til Kaiser
` (2 preceding siblings ...)
2026-06-05 15:44 ` [PATCH net v4 3/4] net: mvpp2: refill RX buffers before XDP or skb use Til Kaiser
@ 2026-06-05 15:44 ` Til Kaiser
3 siblings, 0 replies; 5+ messages in thread
From: Til Kaiser @ 2026-06-05 15:44 UTC (permalink / raw)
To: netdev, bpf
Cc: marcin.s.wojtas, linux, andrew+netdev, davem, edumazet, kuba,
pabeni, ast, daniel, hawk, john.fastabend, sdf, mcroce,
sven.auhagen, lorenzo, Til Kaiser
When an XDP program uses bpf_xdp_adjust_head() or bpf_xdp_adjust_tail()
and then returns XDP_PASS, mvpp2 still builds the skb from fixed offsets
derived from the original RX descriptor. Packet geometry changes made by
the XDP program are therefore discarded before the skb reaches the stack.
Update rx_offset and rx_bytes from xdp.data and xdp.data_end for
XDP_PASS. This makes skb_reserve() and skb_put() reflect the packet seen
by XDP, and makes RX byte accounting for XDP_PASS follow the length of the
skb passed to the network stack.
Non-PASS verdicts continue to account the descriptor length because no skb
is passed up in those cases.
Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support")
Signed-off-by: Til Kaiser <mail@tk154.de>
---
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 481daafdc1cb..dd30674148aa 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3920,7 +3920,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
unsigned int frag_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,7 @@ 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_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) >>
@@ -3999,6 +4000,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
continue;
}
+ /* 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;
}
@@ -4041,7 +4046,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);
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread