]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: pch_gbe: handle TX skb allocation failure
authorRuoyu Wang <ruoyuw560@gmail.com>
Mon, 15 Jun 2026 12:50:42 +0000 (20:50 +0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 19 Jun 2026 01:00:35 +0000 (18:00 -0700)
pch_gbe_alloc_tx_buffers() allocates an skb for each TX descriptor and
then passes the returned pointer to skb_reserve(). If netdev_alloc_skb()
fails, skb_reserve() dereferences NULL.

Make pch_gbe_alloc_tx_buffers() return an error when an skb allocation
fails. On failure, let pch_gbe_alloc_tx_buffers() clean the partially
allocated TX ring before returning the error. While bringing the device
up, release the RX buffer pool through a shared cleanup helper before
unwinding the IRQ setup.

Cc: stable+noautosel@kernel.org # untested fix to unlikely error path
Fixes: 77555ee72282 ("net: Add Gigabit Ethernet driver of Topcliff PCH")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260615125043.3537046-1-ruoyuw560@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c

index 62f05f4569b1086678b8996d2f9fb6a01aa2fa94..48b94ce774906e35d4338c5a862460251c1f73e1 100644 (file)
@@ -1420,13 +1420,25 @@ pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter,
        return 0;
 }
 
+static void pch_gbe_free_rx_buffers_pool(struct pch_gbe_adapter *adapter,
+                                        struct pch_gbe_rx_ring *rx_ring)
+{
+       dma_free_coherent(&adapter->pdev->dev, rx_ring->rx_buff_pool_size,
+                         rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic);
+       rx_ring->rx_buff_pool_logic = 0;
+       rx_ring->rx_buff_pool_size = 0;
+       rx_ring->rx_buff_pool = NULL;
+}
+
 /**
  * pch_gbe_alloc_tx_buffers - Allocate transmit buffers
  * @adapter:   Board private structure
  * @tx_ring:   Tx descriptor ring
+ *
+ * Return: 0 on success, -ENOMEM if a TX skb allocation fails.
  */
-static void pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter,
-                                       struct pch_gbe_tx_ring *tx_ring)
+static int pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter,
+                                   struct pch_gbe_tx_ring *tx_ring)
 {
        struct pch_gbe_buffer *buffer_info;
        struct sk_buff *skb;
@@ -1440,12 +1452,17 @@ static void pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter,
        for (i = 0; i < tx_ring->count; i++) {
                buffer_info = &tx_ring->buffer_info[i];
                skb = netdev_alloc_skb(adapter->netdev, bufsz);
+               if (!skb) {
+                       pch_gbe_clean_tx_ring(adapter, tx_ring);
+                       return -ENOMEM;
+               }
                skb_reserve(skb, PCH_GBE_DMA_ALIGN);
                buffer_info->skb = skb;
                tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
                tx_desc->gbec_status = (DSC_INIT16);
        }
-       return;
+
+       return 0;
 }
 
 /**
@@ -1887,7 +1904,12 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
                           "Error: can't bring device up - alloc rx buffers pool failed\n");
                goto freeirq;
        }
-       pch_gbe_alloc_tx_buffers(adapter, tx_ring);
+       err = pch_gbe_alloc_tx_buffers(adapter, tx_ring);
+       if (err) {
+               netdev_err(netdev,
+                          "Error: can't bring device up - alloc tx buffers failed\n");
+               goto freebuf;
+       }
        pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count);
        adapter->tx_queue_len = netdev->tx_queue_len;
        pch_gbe_enable_dma_rx(&adapter->hw);
@@ -1901,6 +1923,8 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
 
        return 0;
 
+freebuf:
+       pch_gbe_free_rx_buffers_pool(adapter, rx_ring);
 freeirq:
        pch_gbe_free_irq(adapter);
 out:
@@ -1936,11 +1960,7 @@ void pch_gbe_down(struct pch_gbe_adapter *adapter)
        pch_gbe_clean_tx_ring(adapter, adapter->tx_ring);
        pch_gbe_clean_rx_ring(adapter, adapter->rx_ring);
 
-       dma_free_coherent(&adapter->pdev->dev, rx_ring->rx_buff_pool_size,
-                         rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic);
-       rx_ring->rx_buff_pool_logic = 0;
-       rx_ring->rx_buff_pool_size = 0;
-       rx_ring->rx_buff_pool = NULL;
+       pch_gbe_free_rx_buffers_pool(adapter, rx_ring);
 }
 
 /**