Message ID | 1339588218-24398-4-git-send-email-m.szyprowski@samsung.com |
---|---|
State | New |
Headers | show |
On Wed, Jun 13, 2012 at 01:50:15PM +0200, Marek Szyprowski wrote: > This patch adds dma_get_sgtable() function which is required to let > drivers to share the buffers allocated by DMA-mapping subsystem. Right > now the driver gets a dma address of the allocated buffer and the kernel > virtual mapping for it. If it wants to share it with other device (= map > into its dma address space) it usually hacks around kernel virtual > addresses to get pointers to pages or assumes that both devices share > the DMA address space. Both solutions are just hacks for the special > cases, which should be avoided in the final version of buffer sharing. > > To solve this issue in a generic way, a new call to DMA mapping has been > introduced - dma_get_sgtable(). It allocates a scatter-list which > describes the allocated buffer and lets the driver(s) to use it with > other device(s) by calling dma_map_sg() on it. > > This patch provides a generic implementation based on virt_to_page() > call. Architectures which require more sophisticated translation might > provide their own get_sgtable() methods. > > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 6f3676f..49785c1 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -217,4 +217,22 @@ void dmam_release_declared_memory(struct device *dev) } EXPORT_SYMBOL(dmam_release_declared_memory); +/* + * Create scatter-list for the already allocated DMA buffer. + */ +int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size) +{ + struct page *page = virt_to_page(cpu_addr); + int ret; + + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); + if (unlikely(ret)) + return ret; + + sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); + return 0; +} +EXPORT_SYMBOL(dma_common_get_sgtable); + #endif diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index 2e248d8..34841c6 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -176,4 +176,22 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL) #define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL) +int +dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, size_t size); + +static inline int +dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr, + dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + BUG_ON(!ops); + if (ops->get_sgtable) + return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, + attrs); + return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size); +} + +#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL) + #endif diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index dfc099e..94af418 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -18,6 +18,9 @@ struct dma_map_ops { int (*mmap)(struct device *, struct vm_area_struct *, void *, dma_addr_t, size_t, struct dma_attrs *attrs); + int (*get_sgtable)(struct device *dev, struct sg_table *sgt, void *, + dma_addr_t, size_t, struct dma_attrs *attrs); + dma_addr_t (*map_page)(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir,