From: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
To: Maxime Chevallier <maxime.chevallier@bootlin.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Maxime Coquelin <mcoquelin.stm32@gmail.com>,
"Alexandre Torgue" <alexandre.torgue@foss.st.com>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Jesper Dangaard Brouer <hawk@kernel.org>,
John Fastabend <john.fastabend@gmail.com>,
"Stanislav Fomichev" <sdf@fomichev.me>,
Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>,
Christophe Roullier <christophe.roullier@foss.st.com>
Cc: <netdev@vger.kernel.org>,
<linux-stm32@st-md-mailman.stormreply.com>,
<linux-arm-kernel@lists.infradead.org>,
<linux-kernel@vger.kernel.org>, <bpf@vger.kernel.org>,
Thomas Bourgoin <thomas.bourgoin@foss.st.com>
Subject: [PATCH 1/1] net: stmmac: rebuild RX descriptors before restarting DMA on resume
Date: Tue, 27 Oct 2026 16:05:56 +0100 [thread overview]
Message-ID: <20261027150556.51209-2-thomas.bourgoin@foss.st.com> (raw)
In-Reply-To: <20261027150556.51209-1-thomas.bourgoin@foss.st.com>
An RX descriptor can be written back by the DMA before suspend without
being processed by NAPI. Its buffer address fields then contain receive
status rather than DMA addresses.
On resume, stmmac_clear_descriptors() returns RX descriptors to the DMA
without restoring their buffer addresses. On DWMAC4, the DMA will
therefore consider a descriptor for the application as one for the DMA.
This can lead to illegal access from the DMA anywhere.
For example, on STM32MP21 the DMA address bus is 40 bits, thus the
extended status from the write-back descriptor is read as an high
address by the DMA. DMA will then try to write in the DDR at 0x100000000
whereas on STM32MP215f-dk DDR is only 2Gb from 0x8000 0000 to
0xffff ffff and nothing is mapped at 0x100000000.
To fix this, reconstruct the entire RX ring before rearming descriptors
and restarting the DMA. Reuse existing buffers, allocate missing ones,
and restore their DMA addresses independently of the saved RX producer
and consumer indices. Reset the queue indices only after descriptor
reconstruction succeeds.
Update stmmac_init_rx_buffers() to preserve an existing split-header
secondary page and restore its DMA address. Fold TX buffer cleanup into
the descriptor resume helper before clearing the TX descriptors.
Signed-off-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
---
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 86 +++++++++++++++----
1 file changed, 68 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 9ded31150fbe..198629265c90 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1700,8 +1700,10 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv,
buf->page_offset = stmmac_rx_offset(priv);
}
- if (stmmac_rx_check_buf2_cap(priv) && !buf->sec_page) {
- buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp);
+ if (stmmac_rx_check_buf2_cap(priv)) {
+ if (!buf->sec_page)
+ buf->sec_page = page_pool_alloc_pages(rx_q->page_pool,
+ gfp);
if (!buf->sec_page)
return -ENOMEM;
@@ -2149,19 +2151,6 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv,
}
}
-/**
- * stmmac_free_tx_skbufs - free TX skb buffers
- * @priv: private structure
- */
-static void stmmac_free_tx_skbufs(struct stmmac_priv *priv)
-{
- u8 tx_queue_cnt = priv->plat->tx_queues_to_use;
- u8 queue;
-
- for (queue = 0; queue < tx_queue_cnt; queue++)
- dma_free_tx_skbufs(priv, &priv->dma_conf, queue);
-}
-
/**
* __free_dma_rx_desc_resources - free RX dma desc resources (per queue)
* @priv: private structure
@@ -8425,6 +8414,63 @@ static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue)
rx_q->dirty_rx = 0;
}
+static int stmmac_resume_rx_descriptors(struct stmmac_priv *priv,
+ struct stmmac_dma_conf *dma_conf,
+ u32 queue)
+{
+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
+ int i;
+ int ret;
+
+ for (i = 0; i < dma_conf->dma_rx_size; i++) {
+ struct dma_desc *p = stmmac_get_rx_desc(priv, rx_q, i);
+ struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
+ dma_addr_t dma_addr;
+
+ if (rx_q->xsk_pool) {
+ if (!buf->xdp) {
+ buf->xdp = xsk_buff_alloc(rx_q->xsk_pool);
+ if (!buf->xdp)
+ return -ENOMEM;
+ }
+ dma_addr = xsk_buff_xdp_get_dma(buf->xdp);
+ stmmac_set_desc_addr(priv, p, dma_addr);
+ stmmac_set_desc_sec_addr(priv, p, 0, false);
+ } else {
+ ret = stmmac_init_rx_buffers(priv, dma_conf, p, i,
+ GFP_KERNEL, queue);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int stmmac_resume_descriptors(struct stmmac_priv *priv,
+ struct stmmac_dma_conf *dma_conf)
+{
+ u32 rx_queue_cnt = priv->plat->rx_queues_to_use;
+ u32 tx_queue_cnt = priv->plat->tx_queues_to_use;
+ u32 queue;
+ int ret;
+
+ for (queue = 0; queue < rx_queue_cnt; queue++) {
+ ret = stmmac_resume_rx_descriptors(priv, dma_conf, queue);
+ if (ret)
+ return ret;
+
+ stmmac_clear_rx_descriptors(priv, dma_conf, queue);
+ }
+
+ for (queue = 0; queue < tx_queue_cnt; queue++) {
+ dma_free_tx_skbufs(priv, &priv->dma_conf, queue);
+ stmmac_clear_tx_descriptors(priv, dma_conf, queue);
+ }
+
+ return 0;
+}
+
static void stmmac_reset_tx_queue(struct stmmac_priv *priv, u32 queue)
{
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
@@ -8507,10 +8553,14 @@ int stmmac_resume(struct device *dev)
mutex_lock(&priv->lock);
- stmmac_reset_queues_param(priv);
+ ret = stmmac_resume_descriptors(priv, &priv->dma_conf);
+ if (ret < 0) {
+ netdev_err(priv->dev, "%s: Resume descriptor failed\n",
+ __func__);
+ goto error_unlock;
+ }
- stmmac_free_tx_skbufs(priv);
- stmmac_clear_descriptors(priv, &priv->dma_conf);
+ stmmac_reset_queues_param(priv);
ret = stmmac_hw_setup(ndev);
if (ret < 0) {
--
2.43.0
next prev parent reply other threads:[~2026-10-27 15:07 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 15:05 [PATCH 0/1] net: stmmac: descriptor management issue during PM sequence Thomas Bourgoin
2026-10-27 15:05 ` Thomas Bourgoin [this message]
2026-10-27 15:18 ` Maxime Chevallier
2026-10-28 9:05 ` Thomas BOURGOIN
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261027150556.51209-2-thomas.bourgoin@foss.st.com \
--to=thomas.bourgoin@foss.st.com \
--cc=alexandre.torgue@foss.st.com \
--cc=andrew+netdev@lunn.ch \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=christophe.roullier@foss.st.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=hawk@kernel.org \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-stm32@st-md-mailman.stormreply.com \
--cc=lorenzo.bianconi@oss.qualcomm.com \
--cc=maxime.chevallier@bootlin.com \
--cc=mcoquelin.stm32@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®