/* 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)));
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;
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;
}
}
- skb = dpaa2_switch_build_linear_skb(ethsw, fd);
+ skb = dpaa2_switch_build_linear_skb(ethsw, fd, vaddr);
if (unlikely(!skb))
goto err_free_fd;
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;
}
}
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)