From: Suraj Gupta <suraj.gupta2@amd.com>
To: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: Michal Simek <michal.simek@amd.com>, <netdev@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<linux-kernel@vger.kernel.org>
Subject: [PATCH net] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop
Date: Thu, 10 Sep 2026 19:49:46 +0530 [thread overview]
Message-ID: <20260910141946.3017164-1-suraj.gupta2@amd.com> (raw)
In the dmaengine path the driver pre-submits RX buffers (and holds
in-flight TX buffers) whose SKBs are allocated and DMA-mapped by the
driver and reclaimed only in the completion callbacks. On ndo_stop()
the driver calls dmaengine_terminate_sync(), which aborts these
descriptors without running their callbacks, and then frees only the
skbuf_dma_descriptor ring shells with kfree().
As a result every SKB still owned by the DMA engine, together with its
DMA mapping, is leaked on each interface down. With RX_BUF_NUM_DEFAULT
(128) RX buffers pre-posted per channel, an ifup/ifdown cycle leaks up
to 128 SKBs and their DMA mappings; on systems with a limited IOMMU
aperture the mapping leak can eventually exhaust the address space.
Clear the ring slot's skb pointer in the TX and RX completion callbacks
so that a non-NULL skb reliably marks a slot that still owns a live,
DMA-mapped buffer. On stop, after terminating the channels, walk the
whole ring and unmap and free every such buffer before releasing the
rings, mirroring what the completion callbacks do.
Fixes: 6a91b846af85 ("net: axienet: Introduce dmaengine support")
Cc: stable@vger.kernel.org
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
.../net/ethernet/xilinx/xilinx_axienet_main.c | 34 ++++++++++++++++---
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 1722b7038f34..7828fbb09dc8 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -881,6 +881,7 @@ static void axienet_dma_tx_cb(void *data, const struct dmaengine_result *result)
u64_stats_update_end(&lp->tx_stat_sync);
dma_unmap_sg(lp->dev, skbuf_dma->sgl, skbuf_dma->sg_len, DMA_TO_DEVICE);
dev_consume_skb_any(skbuf_dma->skb);
+ skbuf_dma->skb = NULL;
netif_txq_completed_wake(txq, 1, len,
CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX),
2);
@@ -1171,6 +1172,7 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result)
&meta_max_len);
dma_unmap_single(lp->dev, skbuf_dma->dma_address, lp->max_frm_size,
DMA_FROM_DEVICE);
+ skbuf_dma->skb = NULL;
if (IS_ERR(app_metadata)) {
if (net_ratelimit())
@@ -1752,16 +1754,40 @@ static int axienet_stop(struct net_device *ndev)
free_irq(lp->rx_irq, ndev);
axienet_dma_bd_release(ndev);
} else {
+ struct skbuf_dma_descriptor *skbuf_dma;
+
dmaengine_terminate_sync(lp->tx_chan);
dmaengine_synchronize(lp->tx_chan);
dmaengine_terminate_sync(lp->rx_chan);
dmaengine_synchronize(lp->rx_chan);
- for (i = 0; i < TX_BD_NUM_MAX; i++)
- kfree(lp->tx_skb_ring[i]);
+ /* dmaengine_terminate_sync() aborts the descriptors still owned
+ * by the DMA engine without running their completion callbacks.
+ * A ring slot owns a live, DMA-mapped SKB iff its skb pointer is
+ * non-NULL (the callbacks clear it on completion), so unmap and
+ * free those here. Otherwise every outstanding TX/RX SKB and its
+ * DMA mapping is leaked on ifdown.
+ */
+ for (i = 0; i < TX_BD_NUM_MAX; i++) {
+ skbuf_dma = lp->tx_skb_ring[i];
+ if (skbuf_dma && skbuf_dma->skb) {
+ dma_unmap_sg(lp->dev, skbuf_dma->sgl,
+ skbuf_dma->sg_len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skbuf_dma->skb);
+ }
+ kfree(skbuf_dma);
+ }
kfree(lp->tx_skb_ring);
- for (i = 0; i < RX_BUF_NUM_DEFAULT; i++)
- kfree(lp->rx_skb_ring[i]);
+
+ for (i = 0; i < RX_BUF_NUM_DEFAULT; i++) {
+ skbuf_dma = lp->rx_skb_ring[i];
+ if (skbuf_dma && skbuf_dma->skb) {
+ dma_unmap_single(lp->dev, skbuf_dma->dma_address,
+ lp->max_frm_size, DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skbuf_dma->skb);
+ }
+ kfree(skbuf_dma);
+ }
kfree(lp->rx_skb_ring);
dma_release_channel(lp->rx_chan);
--
2.25.1
next reply other threads:[~2026-09-10 14:20 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-10 14:19 Suraj Gupta [this message]
2026-09-16 1:17 ` [PATCH net] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop Jakub Kicinski
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=20260910141946.3017164-1-suraj.gupta2@amd.com \
--to=suraj.gupta2@amd.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michal.simek@amd.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=radhey.shyam.pandey@amd.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.