* [PATCH net v3] net: axienet: free outstanding TX buffers in axienet_dma_bd_release()
@ 2026-10-04 8:37 Sagi Maimon
2026-10-05 23:41 ` Joe Damato
0 siblings, 1 reply; 3+ messages in thread
From: Sagi Maimon @ 2026-10-04 8:37 UTC (permalink / raw)
To: netdev
Cc: radhey.shyam.pandey, michal.simek, andrew+netdev, davem,
edumazet, kuba, pabeni, daniel, jacob.e.keller, joe,
suraj.gupta2, linux-arm-kernel, linux-kernel, Sagi Maimon
axienet_dma_bd_release() walks the RX ring to unmap and free every
receive buffer before releasing it, but frees the TX descriptor ring
with dma_free_coherent() alone. Any descriptor that
axienet_free_tx_chain() had not yet reclaimed still holds its skb and
its streaming DMA mapping, and both are lost.
axienet_stop() disables TX NAPI and stops the DMA engine before calling
it, so nothing reclaims those descriptors afterwards. Bringing the
interface down while frames are in flight therefore leaks up to
lp->tx_bd_num skbs and mappings each time.
Walk the TX ring the way axienet_dma_err_handler() already does: unmap
every descriptor whose cntrl is still set - axienet_free_tx_chain()
clears it on reclaim - and free any skb still attached, as a drop.
This relies on axienet_stop() having stopped the DMA engine first, as
the RX walk in the same function already does.
The walk must not run on a ring that is not there. axienet_open() does
not check the result of the reset that runs axienet_dma_bd_init(), so
when that reset fails tx_bd_v is either still NULL or, after an earlier
close, points at the ring that close freed. Clear tx_bd_v and rx_bd_v
once their rings are freed, and skip the walk when tx_bd_v is NULL.
That also ends the second dma_free_coherent() of a stale ring which the
same path already did. On the axienet_dma_bd_init() error path the TX
ring has just been allocated zeroed, so the walk does nothing.
This was reported by the Sashiko AI review bot.
Tested on the AXI Ethernet MAC of an ADVA TimeCard X2 (PCIe card, with
the built-in AXI DMA): traffic passes, and after each of ten down/up
cycles and five module reloads, all made with traffic running and each
running axienet_dma_bd_release(), traffic resumes and nothing is logged.
The leak itself was not measured, and the failed-reset paths were not
exercised.
Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Assisted-by: LLM sparse
Signed-off-by: Sagi Maimon <maimon.sagi@gmail.com>
---
Notes:
Changes in v3:
- Clear tx_bd_v and rx_bd_v after freeing the rings. v2 only caught a
NULL tx_bd_v from a first open; after a close followed by a failed
reset the walk would have read the freed ring (Sashiko).
- Reword the comment on the skb free: a descriptor can complete after
TX NAPI was disabled, so "never transmitted" was not always true
(Sashiko).
- Say in the commit message which hardware the test ran on.
- Kept Jacob's Reviewed-by, as the changes are small; please say if
that is not OK.
- The hardware test is v1's. The changes since only affect the
failed-reset paths, which it did not exercise, and how the freed skbs
are accounted.
- v2: https://lore.kernel.org/netdev/20260930133851.663023-1-maimon.sagi@gmail.com/
Changes in v2:
- Skip the TX walk when tx_bd_v is NULL (Sashiko).
- Free the skbs with dev_kfree_skb_any(), so they count as drops as in
axienet_dma_err_handler() (Sashiko).
- v1: https://lore.kernel.org/netdev/20260927081034.350422-1-maimon.sagi@gmail.com/
.../net/ethernet/xilinx/xilinx_axienet_main.c | 26 ++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 09443623a3e2..c88c671f8b2d 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -186,11 +186,34 @@ static void axienet_dma_bd_release(struct net_device *ndev)
int i;
struct axienet_local *lp = netdev_priv(ndev);
- /* If we end up here, tx_bd_v must have been DMA allocated. */
+ /* tx_bd_v is NULL if axienet_dma_bd_init() did not get as far as
+ * allocating it, and is cleared below once the ring is freed;
+ * dma_free_coherent() accepts NULL.
+ */
+ for (i = 0; lp->tx_bd_v && i < lp->tx_bd_num; i++) {
+ struct axidma_bd *cur_p = &lp->tx_bd_v[i];
+
+ /* axienet_free_tx_chain() clears cntrl when it reclaims a
+ * descriptor, so a non-zero value means the mapping is live.
+ */
+ if (cur_p->cntrl) {
+ dma_addr_t addr = desc_get_phys_addr(lp, cur_p);
+
+ dma_unmap_single(lp->dev, addr,
+ (cur_p->cntrl &
+ XAXIDMA_BD_CTRL_LENGTH_MASK),
+ DMA_TO_DEVICE);
+ }
+ /* not reclaimed by axienet_free_tx_chain(), so a drop */
+ if (cur_p->skb)
+ dev_kfree_skb_any(cur_p->skb);
+ }
+
dma_free_coherent(lp->dev,
sizeof(*lp->tx_bd_v) * lp->tx_bd_num,
lp->tx_bd_v,
lp->tx_bd_p);
+ lp->tx_bd_v = NULL;
if (!lp->rx_bd_v)
return;
@@ -221,6 +244,7 @@ static void axienet_dma_bd_release(struct net_device *ndev)
sizeof(*lp->rx_bd_v) * lp->rx_bd_num,
lp->rx_bd_v,
lp->rx_bd_p);
+ lp->rx_bd_v = NULL;
}
static u64 axienet_dma_rate(struct axienet_local *lp)
base-commit: 6dc989ea46b96ce170840174b4a38c4a387fb005
--
2.47.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v3] net: axienet: free outstanding TX buffers in axienet_dma_bd_release()
2026-10-04 8:37 [PATCH net v3] net: axienet: free outstanding TX buffers in axienet_dma_bd_release() Sagi Maimon
@ 2026-10-05 23:41 ` Joe Damato
2026-10-06 3:44 ` Sagi Maimon
0 siblings, 1 reply; 3+ messages in thread
From: Joe Damato @ 2026-10-05 23:41 UTC (permalink / raw)
To: Sagi Maimon
Cc: netdev, radhey.shyam.pandey, michal.simek, andrew+netdev, davem,
edumazet, kuba, pabeni, daniel, jacob.e.keller, suraj.gupta2,
linux-arm-kernel, linux-kernel
On Sun, Oct 04, 2026 at 11:37:59AM +0300, Sagi Maimon wrote:
> axienet_dma_bd_release() walks the RX ring to unmap and free every
> receive buffer before releasing it, but frees the TX descriptor ring
> with dma_free_coherent() alone. Any descriptor that
> axienet_free_tx_chain() had not yet reclaimed still holds its skb and
> its streaming DMA mapping, and both are lost.
>
> axienet_stop() disables TX NAPI and stops the DMA engine before calling
> it, so nothing reclaims those descriptors afterwards. Bringing the
> interface down while frames are in flight therefore leaks up to
> lp->tx_bd_num skbs and mappings each time.
>
> Walk the TX ring the way axienet_dma_err_handler() already does: unmap
> every descriptor whose cntrl is still set - axienet_free_tx_chain()
> clears it on reclaim - and free any skb still attached, as a drop.
> This relies on axienet_stop() having stopped the DMA engine first, as
> the RX walk in the same function already does.
[...]
> Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
> Assisted-by: LLM sparse
> Signed-off-by: Sagi Maimon <maimon.sagi@gmail.com>
> ---
>
> Notes:
> Changes in v3:
> - Clear tx_bd_v and rx_bd_v after freeing the rings. v2 only caught a
> NULL tx_bd_v from a first open; after a close followed by a failed
> reset the walk would have read the freed ring (Sashiko).
> - Reword the comment on the skb free: a descriptor can complete after
> TX NAPI was disabled, so "never transmitted" was not always true
> (Sashiko).
> - Say in the commit message which hardware the test ran on.
> - Kept Jacob's Reviewed-by, as the changes are small; please say if
> that is not OK.
> - The hardware test is v1's. The changes since only affect the
> failed-reset paths, which it did not exercise, and how the freed skbs
> are accounted.
> - v2: https://lore.kernel.org/netdev/20260930133851.663023-1-maimon.sagi@gmail.com/
[...]
>
> .../net/ethernet/xilinx/xilinx_axienet_main.c | 26 ++++++++++++++++++-
> 1 file changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> index 09443623a3e2..c88c671f8b2d 100644
> --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> @@ -186,11 +186,34 @@ static void axienet_dma_bd_release(struct net_device *ndev)
[...]
> + lp->tx_bd_v = NULL;
>
> if (!lp->rx_bd_v)
> return;
> @@ -221,6 +244,7 @@ static void axienet_dma_bd_release(struct net_device *ndev)
> sizeof(*lp->rx_bd_v) * lp->rx_bd_num,
> lp->rx_bd_v,
> lp->rx_bd_p);
> + lp->rx_bd_v = NULL;
> }
The added null writes makes me think that centralizing this code and using it
from both axienet_dma_err_handler and axienet_dma_bd_release (instead of
repeating it) is a good idea like I mentioned in the last post.
The code seems right tho even tho I don't like duplicating the logic.
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v3] net: axienet: free outstanding TX buffers in axienet_dma_bd_release()
2026-10-05 23:41 ` Joe Damato
@ 2026-10-06 3:44 ` Sagi Maimon
0 siblings, 0 replies; 3+ messages in thread
From: Sagi Maimon @ 2026-10-06 3:44 UTC (permalink / raw)
To: Joe Damato, Sagi Maimon, netdev, radhey.shyam.pandey,
michal.simek, andrew+netdev, davem, edumazet, kuba, pabeni,
daniel, jacob.e.keller, suraj.gupta2, linux-arm-kernel,
linux-kernel
On Tue, Oct 6, 2026 at 2:41 AM Joe Damato <joe@dama.to> wrote:
>
> On Sun, Oct 04, 2026 at 11:37:59AM +0300, Sagi Maimon wrote:
> > axienet_dma_bd_release() walks the RX ring to unmap and free every
> > receive buffer before releasing it, but frees the TX descriptor ring
> > with dma_free_coherent() alone. Any descriptor that
> > axienet_free_tx_chain() had not yet reclaimed still holds its skb and
> > its streaming DMA mapping, and both are lost.
> >
> > axienet_stop() disables TX NAPI and stops the DMA engine before calling
> > it, so nothing reclaims those descriptors afterwards. Bringing the
> > interface down while frames are in flight therefore leaks up to
> > lp->tx_bd_num skbs and mappings each time.
> >
> > Walk the TX ring the way axienet_dma_err_handler() already does: unmap
> > every descriptor whose cntrl is still set - axienet_free_tx_chain()
> > clears it on reclaim - and free any skb still attached, as a drop.
> > This relies on axienet_stop() having stopped the DMA engine first, as
> > the RX walk in the same function already does.
>
> [...]
>
> > Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
> > Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
> > Assisted-by: LLM sparse
> > Signed-off-by: Sagi Maimon <maimon.sagi@gmail.com>
> > ---
> >
> > Notes:
> > Changes in v3:
> > - Clear tx_bd_v and rx_bd_v after freeing the rings. v2 only caught a
> > NULL tx_bd_v from a first open; after a close followed by a failed
> > reset the walk would have read the freed ring (Sashiko).
> > - Reword the comment on the skb free: a descriptor can complete after
> > TX NAPI was disabled, so "never transmitted" was not always true
> > (Sashiko).
> > - Say in the commit message which hardware the test ran on.
> > - Kept Jacob's Reviewed-by, as the changes are small; please say if
> > that is not OK.
> > - The hardware test is v1's. The changes since only affect the
> > failed-reset paths, which it did not exercise, and how the freed skbs
> > are accounted.
> > - v2: https://lore.kernel.org/netdev/20260930133851.663023-1-maimon.sagi@gmail.com/
>
> [...]
>
> >
> > .../net/ethernet/xilinx/xilinx_axienet_main.c | 26 ++++++++++++++++++-
> > 1 file changed, 25 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> > index 09443623a3e2..c88c671f8b2d 100644
> > --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> > +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> > @@ -186,11 +186,34 @@ static void axienet_dma_bd_release(struct net_device *ndev)
>
> [...]
>
> > + lp->tx_bd_v = NULL;
> >
> > if (!lp->rx_bd_v)
> > return;
> > @@ -221,6 +244,7 @@ static void axienet_dma_bd_release(struct net_device *ndev)
> > sizeof(*lp->rx_bd_v) * lp->rx_bd_num,
> > lp->rx_bd_v,
> > lp->rx_bd_p);
> > + lp->rx_bd_v = NULL;
> > }
>
> The added null writes makes me think that centralizing this code and using it
> from both axienet_dma_err_handler and axienet_dma_bd_release (instead of
> repeating it) is a good idea like I mentioned in the last post.
>
> The code seems right tho even tho I don't like duplicating the logic.
>
> Reviewed-by: Joe Damato <joe@dama.to>
Thanks for the review, Joe.
Agreed on the helper. As on v2, I kept the fix minimal for net, and
will send the helper to net-next once this has reached it, with both
axienet_dma_bd_release() and axienet_dma_err_handler() using it.
Thanks,
Sagi
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-06 3:45 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-04 8:37 [PATCH net v3] net: axienet: free outstanding TX buffers in axienet_dma_bd_release() Sagi Maimon
2026-10-05 23:41 ` Joe Damato
2026-10-06 3:44 ` Sagi Maimon
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®