]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
dpaa2-switch: fix the error path in dpaa2_switch_rx()
authorIoana Ciornei <ioana.ciornei@nxp.com>
Thu, 28 May 2026 17:34:49 +0000 (20:34 +0300)
committerJakub Kicinski <kuba@kernel.org>
Wed, 3 Jun 2026 02:13:18 +0000 (19:13 -0700)
In case of an error in dpaa2_switch_rx(), the dpaa2_switch_free_fd()
function is called in order to free the FD. This is incorrect since the
dpaa2_switch_free_fd() is intended to be used on Tx frame descriptors,
meaning that it expects in the software annotation area of the FD data
to find a valid skb pointer on which to call dev_kfree_skb().

Fix this by extracting the dma_unmap_page() from
dpaa2_switch_build_linear_skb() directly into the dpaa2_switch_rx()
function. This allows us to directly use free_pages() in case of an
error before an SKB was created and kfree_skb() afterwards.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Link: https://patch.msgid.link/20260528173452.1953102-3-ioana.ciornei@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c

index 782fef26b78efb96fd43c7d6ae23de3485d5b6e6..53a32b21b95934bdb65e7394d8bceaabd615e80b 100644 (file)
@@ -2429,18 +2429,13 @@ static int dpaa2_switch_port_blocking_event(struct notifier_block *nb,
 
 /* Build a linear skb based on a single-buffer frame descriptor */
 static struct sk_buff *dpaa2_switch_build_linear_skb(struct ethsw_core *ethsw,
-                                                    const struct dpaa2_fd *fd)
+                                                    const struct dpaa2_fd *fd,
+                                                    void *fd_vaddr)
 {
        u16 fd_offset = dpaa2_fd_get_offset(fd);
-       dma_addr_t addr = dpaa2_fd_get_addr(fd);
        u32 fd_length = dpaa2_fd_get_len(fd);
        struct device *dev = ethsw->dev;
        struct sk_buff *skb = NULL;
-       void *fd_vaddr;
-
-       fd_vaddr = dpaa2_iova_to_virt(ethsw->iommu_domain, addr);
-       dma_unmap_page(dev, addr, DPAA2_SWITCH_RX_BUF_SIZE,
-                      DMA_FROM_DEVICE);
 
        skb = build_skb(fd_vaddr, DPAA2_SWITCH_RX_BUF_SIZE +
                        SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
@@ -2466,6 +2461,7 @@ static void dpaa2_switch_tx_conf(struct dpaa2_switch_fq *fq,
 static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
                            const struct dpaa2_fd *fd)
 {
+       dma_addr_t addr = dpaa2_fd_get_addr(fd);
        struct ethsw_core *ethsw = fq->ethsw;
        struct ethsw_port_priv *port_priv;
        struct net_device *netdev;
@@ -2473,10 +2469,14 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
        struct sk_buff *skb;
        u16 vlan_tci, vid;
        int if_id, err;
+       void *vaddr;
+
+       vaddr = dpaa2_iova_to_virt(ethsw->iommu_domain, addr);
+       dma_unmap_page(ethsw->dev, addr, DPAA2_SWITCH_RX_BUF_SIZE,
+                      DMA_FROM_DEVICE);
 
        /* get switch ingress interface ID */
        if_id = upper_32_bits(dpaa2_fd_get_flc(fd)) & 0x0000FFFF;
-
        if (if_id >= ethsw->sw_attr.num_ifs) {
                dev_err(ethsw->dev, "Frame received from unknown interface!\n");
                goto err_free_fd;
@@ -2492,7 +2492,7 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
                }
        }
 
-       skb = dpaa2_switch_build_linear_skb(ethsw, fd);
+       skb = dpaa2_switch_build_linear_skb(ethsw, fd, vaddr);
        if (unlikely(!skb))
                goto err_free_fd;
 
@@ -2510,7 +2510,8 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
                err = __skb_vlan_pop(skb, &vlan_tci);
                if (err) {
                        dev_info(ethsw->dev, "__skb_vlan_pop() returned %d", err);
-                       goto err_free_fd;
+                       kfree_skb(skb);
+                       return;
                }
        }
 
@@ -2525,7 +2526,7 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
        return;
 
 err_free_fd:
-       dpaa2_switch_free_fd(ethsw, fd);
+       free_pages((unsigned long)vaddr, 0);
 }
 
 static void dpaa2_switch_detect_features(struct ethsw_core *ethsw)