]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.10
authorSasha Levin <sashal@kernel.org>
Sat, 12 Jul 2025 14:54:13 +0000 (10:54 -0400)
committerSasha Levin <sashal@kernel.org>
Sat, 12 Jul 2025 14:56:31 +0000 (10:56 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.10/ethernet-atl1-add-missing-dma-mapping-error-checks-a.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/ethernet-atl1-add-missing-dma-mapping-error-checks-a.patch b/queue-5.10/ethernet-atl1-add-missing-dma-mapping-error-checks-a.patch
new file mode 100644 (file)
index 0000000..2e1ce91
--- /dev/null
@@ -0,0 +1,212 @@
+From 55fcc420956bf7b60afcfb84d51709cc8fc6bbd3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Jun 2025 16:16:24 +0200
+Subject: ethernet: atl1: Add missing DMA mapping error checks and count errors
+
+From: Thomas Fourier <fourier.thomas@gmail.com>
+
+[ Upstream commit d72411d20905180cdc452c553be17481b24463d2 ]
+
+The `dma_map_XXX()` functions can fail and must be checked using
+`dma_mapping_error()`.  This patch adds proper error handling for all
+DMA mapping calls.
+
+In `atl1_alloc_rx_buffers()`, if DMA mapping fails, the buffer is
+deallocated and marked accordingly.
+
+In `atl1_tx_map()`, previously mapped buffers are unmapped and the
+packet is dropped on failure.
+
+If `atl1_xmit_frame()` drops the packet, increment the tx_error counter.
+
+Fixes: f3cc28c79760 ("Add Attansic L1 ethernet driver.")
+Signed-off-by: Thomas Fourier <fourier.thomas@gmail.com>
+Link: https://patch.msgid.link/20250625141629.114984-2-fourier.thomas@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/atheros/atlx/atl1.c | 78 +++++++++++++++++-------
+ 1 file changed, 56 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
+index eaf96d002fa50..2e950313f427a 100644
+--- a/drivers/net/ethernet/atheros/atlx/atl1.c
++++ b/drivers/net/ethernet/atheros/atlx/atl1.c
+@@ -1861,14 +1861,21 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
+                       break;
+               }
+-              buffer_info->alloced = 1;
+-              buffer_info->skb = skb;
+-              buffer_info->length = (u16) adapter->rx_buffer_len;
+               page = virt_to_page(skb->data);
+               offset = offset_in_page(skb->data);
+               buffer_info->dma = dma_map_page(&pdev->dev, page, offset,
+                                               adapter->rx_buffer_len,
+                                               DMA_FROM_DEVICE);
++              if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
++                      kfree_skb(skb);
++                      adapter->soft_stats.rx_dropped++;
++                      break;
++              }
++
++              buffer_info->alloced = 1;
++              buffer_info->skb = skb;
++              buffer_info->length = (u16)adapter->rx_buffer_len;
++
+               rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+               rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
+               rfd_desc->coalese = 0;
+@@ -2180,8 +2187,8 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
+       return 0;
+ }
+-static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+-      struct tx_packet_desc *ptpd)
++static bool atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
++                      struct tx_packet_desc *ptpd)
+ {
+       struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+       struct atl1_buffer *buffer_info;
+@@ -2191,6 +2198,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+       unsigned int nr_frags;
+       unsigned int f;
+       int retval;
++      u16 first_mapped;
+       u16 next_to_use;
+       u16 data_len;
+       u8 hdr_len;
+@@ -2198,6 +2206,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+       buf_len -= skb->data_len;
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       next_to_use = atomic_read(&tpd_ring->next_to_use);
++      first_mapped = next_to_use;
+       buffer_info = &tpd_ring->buffer_info[next_to_use];
+       BUG_ON(buffer_info->skb);
+       /* put skb in last TPD */
+@@ -2213,6 +2222,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+               buffer_info->dma = dma_map_page(&adapter->pdev->dev, page,
+                                               offset, hdr_len,
+                                               DMA_TO_DEVICE);
++              if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma))
++                      goto dma_err;
+               if (++next_to_use == tpd_ring->count)
+                       next_to_use = 0;
+@@ -2239,6 +2250,9 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+                                                               page, offset,
+                                                               buffer_info->length,
+                                                               DMA_TO_DEVICE);
++                              if (dma_mapping_error(&adapter->pdev->dev,
++                                                    buffer_info->dma))
++                                      goto dma_err;
+                               if (++next_to_use == tpd_ring->count)
+                                       next_to_use = 0;
+                       }
+@@ -2251,6 +2265,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+               buffer_info->dma = dma_map_page(&adapter->pdev->dev, page,
+                                               offset, buf_len,
+                                               DMA_TO_DEVICE);
++              if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma))
++                      goto dma_err;
+               if (++next_to_use == tpd_ring->count)
+                       next_to_use = 0;
+       }
+@@ -2274,6 +2290,9 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+                       buffer_info->dma = skb_frag_dma_map(&adapter->pdev->dev,
+                               frag, i * ATL1_MAX_TX_BUF_LEN,
+                               buffer_info->length, DMA_TO_DEVICE);
++                      if (dma_mapping_error(&adapter->pdev->dev,
++                                            buffer_info->dma))
++                              goto dma_err;
+                       if (++next_to_use == tpd_ring->count)
+                               next_to_use = 0;
+@@ -2282,6 +2301,22 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+       /* last tpd's buffer-info */
+       buffer_info->skb = skb;
++
++      return true;
++
++ dma_err:
++      while (first_mapped != next_to_use) {
++              buffer_info = &tpd_ring->buffer_info[first_mapped];
++              dma_unmap_page(&adapter->pdev->dev,
++                             buffer_info->dma,
++                             buffer_info->length,
++                             DMA_TO_DEVICE);
++              buffer_info->dma = 0;
++
++              if (++first_mapped == tpd_ring->count)
++                      first_mapped = 0;
++      }
++      return false;
+ }
+ static void atl1_tx_queue(struct atl1_adapter *adapter, u16 count,
+@@ -2352,10 +2387,8 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
+       len = skb_headlen(skb);
+-      if (unlikely(skb->len <= 0)) {
+-              dev_kfree_skb_any(skb);
+-              return NETDEV_TX_OK;
+-      }
++      if (unlikely(skb->len <= 0))
++              goto drop_packet;
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       for (f = 0; f < nr_frags; f++) {
+@@ -2369,10 +2402,8 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
+               if (skb->protocol == htons(ETH_P_IP)) {
+                       proto_hdr_len = (skb_transport_offset(skb) +
+                                        tcp_hdrlen(skb));
+-                      if (unlikely(proto_hdr_len > len)) {
+-                              dev_kfree_skb_any(skb);
+-                              return NETDEV_TX_OK;
+-                      }
++                      if (unlikely(proto_hdr_len > len))
++                              goto drop_packet;
+                       /* need additional TPD ? */
+                       if (proto_hdr_len != len)
+                               count += (len - proto_hdr_len +
+@@ -2404,23 +2435,26 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
+       }
+       tso = atl1_tso(adapter, skb, ptpd);
+-      if (tso < 0) {
+-              dev_kfree_skb_any(skb);
+-              return NETDEV_TX_OK;
+-      }
++      if (tso < 0)
++              goto drop_packet;
+       if (!tso) {
+               ret_val = atl1_tx_csum(adapter, skb, ptpd);
+-              if (ret_val < 0) {
+-                      dev_kfree_skb_any(skb);
+-                      return NETDEV_TX_OK;
+-              }
++              if (ret_val < 0)
++                      goto drop_packet;
+       }
+-      atl1_tx_map(adapter, skb, ptpd);
++      if (!atl1_tx_map(adapter, skb, ptpd))
++              goto drop_packet;
++
+       atl1_tx_queue(adapter, count, ptpd);
+       atl1_update_mailbox(adapter);
+       return NETDEV_TX_OK;
++
++drop_packet:
++      adapter->soft_stats.tx_errors++;
++      dev_kfree_skb_any(skb);
++      return NETDEV_TX_OK;
+ }
+ static int atl1_rings_clean(struct napi_struct *napi, int budget)
+-- 
+2.39.5
+
index 5c1879677371f0e6bb92a75487587324066a7530..a87c8b5d051aa46e54b9561f25856da232582f6d 100644 (file)
@@ -184,3 +184,4 @@ pinctrl-qcom-msm-mark-certain-pins-as-invalid-for-interrupts.patch
 drm-sched-increment-job-count-before-swapping-tail-spsc-queue.patch
 usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch
 revert-acpi-battery-negate-current-when-discharging.patch
+ethernet-atl1-add-missing-dma-mapping-error-checks-a.patch