/* skb_dma_map.c: DMA mapping helpers for socket buffers. * * Copyright (C) David S. Miller <davem@davemloft.net> */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/skbuff.h> int skb_dma_map(struct device *dev, struct sk_buff *skb, enum dma_data_direction dir) { struct skb_shared_info *sp = skb_shinfo(skb); dma_addr_t map; int i; map = dma_map_single(dev, skb->data, skb_headlen(skb), dir); if (dma_mapping_error(dev, map)) goto out_err; sp->dma_maps[0] = map; for (i = 0; i < sp->nr_frags; i++) { skb_frag_t *fp = &sp->frags[i]; map = dma_map_page(dev, fp->page, fp->page_offset, fp->size, dir); if (dma_mapping_error(dev, map)) goto unwind; sp->dma_maps[i + 1] = map; } sp->num_dma_maps = i + 1; return 0; unwind: while (--i >= 0) { skb_frag_t *fp = &sp->frags[i]; dma_unmap_page(dev, sp->dma_maps[i + 1], fp->size, dir); } dma_unmap_single(dev, sp->dma_maps[0], skb_headlen(skb), dir); out_err: return -ENOMEM; } EXPORT_SYMBOL(skb_dma_map); void skb_dma_unmap(struct device *dev, struct sk_buff *skb, enum dma_data_direction dir) { struct skb_shared_info *sp = skb_shinfo(skb); int i; dma_unmap_single(dev, sp->dma_maps[0], skb_headlen(skb), dir); for (i = 0; i < sp->nr_frags; i++) { skb_frag_t *fp = &sp->frags[i]; dma_unmap_page(dev, sp->dma_maps[i + 1], fp->size, dir); } } EXPORT_SYMBOL(skb_dma_unmap);