[PATCH net-next v5 11/19] net: stmmac: complete DMA configuration allocation unwind

From: James Hilliard

Date: Sun Sep 27 2026 - 18:03:41 EST


Build on Ding Hui's per-queue allocation cleanup. The combined RX/TX
allocator still needs to release the successful RX allocation if TX
allocation fails. Guard coherent frees after the per-queue unwind has
already emptied a queue.

Propagate RXQ memory-model registration errors instead of continuing
with an unusable RXQ. Clear XSK RXQ bindings before the RXQ goes away and
release any saved partial packet. The MTU transaction added later relies
on preparation failures being fully unwound without touching the active
configuration.

Take ownership of saved partial RX state at poll entry by clearing the
saved flag and skb pointer immediately. Preserve incomplete state if the
next descriptor is still DMA-owned. A budget-one completion must not
leave an already delivered or freed skb reachable by the new teardown
cleanup.

Fixes: 71fedb0198cb ("net: stmmac: break some functions into RX and TX scopes")
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 54 ++++++++++++++++-------
1 file changed, 37 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 258de45d122c..bc19f8c19bb8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1931,17 +1931,19 @@ static int __init_dma_rx_desc_rings(struct stmmac_priv *priv,
rx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue);

if (rx_q->xsk_pool) {
- WARN_ON(xdp_rxq_info_reg_mem_model(&rx_q->xdp_rxq,
- MEM_TYPE_XSK_BUFF_POOL,
- NULL));
+ ret = xdp_rxq_info_reg_mem_model(&rx_q->xdp_rxq,
+ MEM_TYPE_XSK_BUFF_POOL, NULL);
+ if (ret)
+ return ret;
netdev_info(priv->dev,
"Register MEM_TYPE_XSK_BUFF_POOL RxQ-%d\n",
queue);
xsk_pool_set_rxq_info(rx_q->xsk_pool, &rx_q->xdp_rxq);
} else {
- WARN_ON(xdp_rxq_info_reg_mem_model(&rx_q->xdp_rxq,
- MEM_TYPE_PAGE_POOL,
- rx_q->page_pool));
+ ret = xdp_rxq_info_reg_mem_model(&rx_q->xdp_rxq,
+ MEM_TYPE_PAGE_POOL, rx_q->page_pool);
+ if (ret)
+ return ret;
netdev_info(priv->dev,
"Register MEM_TYPE_PAGE_POOL RxQ-%d\n",
queue);
@@ -2003,6 +2005,8 @@ static int init_dma_rx_desc_rings(struct net_device *dev,
dma_free_rx_skbufs(priv, dma_conf, queue);

rx_q->buf_alloc_num = 0;
+ if (rx_q->xsk_pool)
+ xsk_pool_set_rxq_info(rx_q->xsk_pool, NULL);
rx_q->xsk_pool = NULL;

queue--;
@@ -2188,10 +2192,16 @@ static void __free_dma_rx_desc_resources(struct stmmac_priv *priv,
void *addr;

/* Release the DMA RX socket buffers */
- if (rx_q->xsk_pool)
+ if (rx_q->xsk_pool) {
dma_free_rx_xskbufs(priv, dma_conf, queue);
- else
+ xsk_pool_set_rxq_info(rx_q->xsk_pool, NULL);
+ } else {
dma_free_rx_skbufs(priv, dma_conf, queue);
+ }
+ if (rx_q->state_saved)
+ dev_kfree_skb_any(rx_q->state.skb);
+ rx_q->state.skb = NULL;
+ rx_q->state_saved = 0;

rx_q->buf_alloc_num = 0;
rx_q->xsk_pool = NULL;
@@ -2204,7 +2214,8 @@ static void __free_dma_rx_desc_resources(struct stmmac_priv *priv,

size = stmmac_get_rx_desc_size(priv) * dma_conf->dma_rx_size;

- dma_free_coherent(priv->device, size, addr, rx_q->dma_rx_phy);
+ if (addr)
+ dma_free_coherent(priv->device, size, addr, rx_q->dma_rx_phy);
rx_q->dma_erx = NULL;
rx_q->dma_rx = NULL;
rx_q->dma_rx_phy = 0;
@@ -2259,7 +2270,8 @@ static void __free_dma_tx_desc_resources(struct stmmac_priv *priv,

size = stmmac_get_tx_desc_size(priv, tx_q) * dma_conf->dma_tx_size;

- dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy);
+ if (addr)
+ dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy);
tx_q->dma_etx = NULL;
tx_q->dma_entx = NULL;
tx_q->dma_tx = NULL;
@@ -2500,6 +2512,8 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv,
return ret;

ret = alloc_dma_tx_desc_resources(priv, dma_conf);
+ if (ret)
+ free_dma_rx_desc_resources(priv, dma_conf);

return ret;
}
@@ -5822,6 +5836,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
struct sk_buff *skb = NULL;
struct stmmac_xdp_buff ctx;
int xdp_status = 0;
+ bool in_progress = rx_q->state_saved;
int bufsz;

dma_dir = page_pool_get_dma_dir(rx_q->page_pool);
@@ -5836,6 +5851,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true,
rx_q->dma_rx_phy, desc_size);
}
+ if (in_progress) {
+ skb = rx_q->state.skb;
+ error = rx_q->state.error;
+ len = rx_q->state.len;
+ rx_q->state.skb = NULL;
+ rx_q->state_saved = false;
+ }
+
while (count < limit) {
unsigned int buf1_len = 0, buf2_len = 0;
enum pkt_hash_types hash_type;
@@ -5844,12 +5867,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
int entry;
u32 hash;

- if (!count && rx_q->state_saved) {
- skb = rx_q->state.skb;
- error = rx_q->state.error;
- len = rx_q->state.len;
- } else {
- rx_q->state_saved = false;
+ if (!in_progress) {
skb = NULL;
error = 0;
len = 0;
@@ -5883,6 +5901,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)

prefetch(np);

+ in_progress = status & rx_not_ls;
+
if (priv->extend_desc)
stmmac_rx_extended_status(priv, &priv->xstats, rx_q->dma_erx + entry);
if (unlikely(status == discard_frame)) {
@@ -6057,7 +6077,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
count++;
}

- if (status & rx_not_ls || skb) {
+ if (in_progress || skb) {
rx_q->state_saved = true;
rx_q->state.skb = skb;
rx_q->state.error = error;

--
2.53.0