diff options
| author | Ruoyu Wang <ruoyuw560@gmail.com> | 2026-06-15 20:50:42 +0800 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-06-18 18:00:35 -0700 |
| commit | a0aa6bf985aa5f22f7d398ddfff3aa0754892aea (patch) | |
| tree | bacb1449a2ba0a4026c5bde14a305b7d935bb1b4 /drivers | |
| parent | d31deeab707b7945a7805d6406d0cd3118e640ef (diff) | |
net: pch_gbe: handle TX skb allocation failure
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>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 62f05f4569b1..48b94ce77490 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -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); } /** |
