]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: eth: avoid TX buffer memory leak
authorMarkus Stockhausen <markus.stockhausen@gmx.de>
Sun, 24 May 2026 08:41:55 +0000 (10:41 +0200)
committerMarkus Stockhausen <markus.stockhausen@gmx.de>
Sat, 30 May 2026 06:50:00 +0000 (08:50 +0200)
Although never observed, a transmit timeout might happen.
In that case there is a resource leak inside rteth_tx_timeout().
This happens when rteth_setup_ring_buffer() reinitializes the
transmit buffers and overwrites all transmit slots. Any linked
SKB is lost and leaked at this point.

Be defensive and add a cleanup rteth_free_tx_buffers() function.
Call this alongside rteth_free_rx_buffers() where needed.

Link: https://github.com/openwrt/openwrt/pull/23483
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
target/linux/realtek/files-6.18/drivers/net/ethernet/rtl838x_eth.c

index 15f44b51532e6ba0873c6090b2825a42e1333dc4..23f397f6f70a1886db140af01fdf4b0b8d557278 100644 (file)
@@ -603,6 +603,24 @@ static void rteth_931x_hw_en_rxtx(struct rteth_ctrl *ctrl)
        regmap_write(ctrl->map, ctrl->r->mac_force_mode_ctrl, 0x2a1d);
 }
 
+static void rteth_free_tx_buffers(struct rteth_ctrl *ctrl)
+{
+       struct rteth_packet *packet;
+
+       for (int r = 0; r < RTETH_TX_RINGS; r++) {
+               for (int i = 0; i < RTETH_TX_RING_SIZE; i++) {
+                       packet = &ctrl->tx_data[r].packet[i];
+                       if (!packet->skb)
+                               continue;
+
+                       dma_unmap_single(&ctrl->pdev->dev, packet->dma,
+                                        packet->skb->len, DMA_TO_DEVICE);
+                       dev_kfree_skb_any(packet->skb);
+                       packet->skb = NULL;
+               }
+       }
+}
+
 static int rteth_setup_ring_buffer(struct rteth_ctrl *ctrl)
 {
        dma_addr_t rx_buf_dma = ctrl->rx_buf_dma;
@@ -817,6 +835,7 @@ static int rteth_stop(struct net_device *dev)
        for (int i = 0; i < RTETH_RX_RINGS; i++)
                napi_disable(&ctrl->rx_qs[i].napi);
 
+       rteth_free_tx_buffers(ctrl);
        netif_tx_stop_all_queues(dev);
 
        return 0;
@@ -916,6 +935,7 @@ static void rteth_tx_timeout(struct net_device *dev, unsigned int txqueue)
        pr_warn("%s\n", __func__);
        scoped_guard(spinlock_irqsave, &ctrl->lock) {
                rteth_hw_stop(ctrl);
+               rteth_free_tx_buffers(ctrl);
                rteth_hw_ring_setup(ctrl);
                ctrl->r->hw_en_rxtx(ctrl);
                netif_trans_update(dev);