mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
dpaa2-switch: fix the error path in dpaa2_switch_rx()
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>
This commit is contained in:
parent
efc1d92eac
commit
74c1c9f5c0
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user