[PATCHv6 2/7] ARM: dma-mapping: use asm-generic/dma-mapping-common.h
Konrad Rzeszutek Wilk
konrad.wilk at oracle.com
Tue Feb 14 10:01:03 EST 2012
On Fri, Feb 10, 2012 at 07:58:39PM +0100, Marek Szyprowski wrote:
> This patch modifies dma-mapping implementation on ARM architecture to
> use common dma_map_ops structure and asm-generic/dma-mapping-common.h
> helpers.
The patch looks good, but I am not sure about the dma_debug API calls?
I am not seeing them being introduced back in the common/dmabounce.c which
is where the __dma_*_page calls are in, right?
>
> Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
> ---
> arch/arm/Kconfig | 1 +
> arch/arm/include/asm/device.h | 1 +
> arch/arm/include/asm/dma-mapping.h | 197 +++++-------------------------------
> arch/arm/mm/dma-mapping.c | 149 ++++++++++++++++-----------
> 4 files changed, 117 insertions(+), 231 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index a48aecc..59102fb 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -4,6 +4,7 @@ config ARM
> select HAVE_AOUT
> select HAVE_DMA_API_DEBUG
> select HAVE_IDE if PCI || ISA || PCMCIA
> + select HAVE_DMA_ATTRS
> select HAVE_MEMBLOCK
> select RTC_LIB
> select SYS_SUPPORTS_APM_EMULATION
> diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h
> index 7aa3680..6e2cb0e 100644
> --- a/arch/arm/include/asm/device.h
> +++ b/arch/arm/include/asm/device.h
> @@ -7,6 +7,7 @@
> #define ASMARM_DEVICE_H
>
> struct dev_archdata {
> + struct dma_map_ops *dma_ops;
> #ifdef CONFIG_DMABOUNCE
> struct dmabounce_device_info *dmabounce;
> #endif
> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
> index 6bc056c..cf7b77c 100644
> --- a/arch/arm/include/asm/dma-mapping.h
> +++ b/arch/arm/include/asm/dma-mapping.h
> @@ -10,6 +10,28 @@
> #include <asm-generic/dma-coherent.h>
> #include <asm/memory.h>
>
> +extern struct dma_map_ops arm_dma_ops;
> +
> +static inline struct dma_map_ops *get_dma_ops(struct device *dev)
> +{
> + if (dev && dev->archdata.dma_ops)
> + return dev->archdata.dma_ops;
> + return &arm_dma_ops;
> +}
> +
> +static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
> +{
> + BUG_ON(!dev);
> + dev->archdata.dma_ops = ops;
> +}
> +
> +#include <asm-generic/dma-mapping-common.h>
> +
> +static inline int dma_set_mask(struct device *dev, u64 mask)
> +{
> + return get_dma_ops(dev)->set_dma_mask(dev, mask);
> +}
> +
> #ifdef __arch_page_to_dma
> #error Please update to __arch_pfn_to_dma
> #endif
> @@ -117,7 +139,6 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
>
> extern int dma_supported(struct device *, u64);
> extern int dma_set_mask(struct device *, u64);
> -
> /*
> * DMA errors are defined by all-bits-set in the DMA address.
> */
> @@ -295,179 +316,17 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle,
> }
> #endif /* CONFIG_DMABOUNCE */
>
> -/**
> - * dma_map_single - map a single buffer for streaming DMA
> - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> - * @cpu_addr: CPU direct mapped address of buffer
> - * @size: size of buffer to map
> - * @dir: DMA transfer direction
> - *
> - * Ensure that any data held in the cache is appropriately discarded
> - * or written back.
> - *
> - * The device owns this memory once this call has completed. The CPU
> - * can regain ownership by calling dma_unmap_single() or
> - * dma_sync_single_for_cpu().
> - */
> -static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
> - size_t size, enum dma_data_direction dir)
> -{
> - unsigned long offset;
> - struct page *page;
> - dma_addr_t addr;
> -
> - BUG_ON(!virt_addr_valid(cpu_addr));
> - BUG_ON(!virt_addr_valid(cpu_addr + size - 1));
> - BUG_ON(!valid_dma_direction(dir));
> -
> - page = virt_to_page(cpu_addr);
> - offset = (unsigned long)cpu_addr & ~PAGE_MASK;
> - addr = __dma_map_page(dev, page, offset, size, dir);
> - debug_dma_map_page(dev, page, offset, size, dir, addr, true);
> -
> - return addr;
> -}
> -
> -/**
> - * dma_map_page - map a portion of a page for streaming DMA
> - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> - * @page: page that buffer resides in
> - * @offset: offset into page for start of buffer
> - * @size: size of buffer to map
> - * @dir: DMA transfer direction
> - *
> - * Ensure that any data held in the cache is appropriately discarded
> - * or written back.
> - *
> - * The device owns this memory once this call has completed. The CPU
> - * can regain ownership by calling dma_unmap_page().
> - */
> -static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
> - unsigned long offset, size_t size, enum dma_data_direction dir)
> -{
> - dma_addr_t addr;
> -
> - BUG_ON(!valid_dma_direction(dir));
> -
> - addr = __dma_map_page(dev, page, offset, size, dir);
> - debug_dma_map_page(dev, page, offset, size, dir, addr, false);
> -
> - return addr;
> -}
> -
> -/**
> - * dma_unmap_single - unmap a single buffer previously mapped
> - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> - * @handle: DMA address of buffer
> - * @size: size of buffer (same as passed to dma_map_single)
> - * @dir: DMA transfer direction (same as passed to dma_map_single)
> - *
> - * Unmap a single streaming mode DMA translation. The handle and size
> - * must match what was provided in the previous dma_map_single() call.
> - * All other usages are undefined.
> - *
> - * After this call, reads by the CPU to the buffer are guaranteed to see
> - * whatever the device wrote there.
> - */
> -static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
> - size_t size, enum dma_data_direction dir)
> -{
> - debug_dma_unmap_page(dev, handle, size, dir, true);
> - __dma_unmap_page(dev, handle, size, dir);
> -}
> -
> -/**
> - * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
> - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> - * @handle: DMA address of buffer
> - * @size: size of buffer (same as passed to dma_map_page)
> - * @dir: DMA transfer direction (same as passed to dma_map_page)
> - *
> - * Unmap a page streaming mode DMA translation. The handle and size
> - * must match what was provided in the previous dma_map_page() call.
> - * All other usages are undefined.
> - *
> - * After this call, reads by the CPU to the buffer are guaranteed to see
> - * whatever the device wrote there.
> - */
> -static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
> - size_t size, enum dma_data_direction dir)
> -{
> - debug_dma_unmap_page(dev, handle, size, dir, false);
> - __dma_unmap_page(dev, handle, size, dir);
> -}
> -
> -
> -static inline void dma_sync_single_for_cpu(struct device *dev,
> - dma_addr_t handle, size_t size, enum dma_data_direction dir)
> -{
> - BUG_ON(!valid_dma_direction(dir));
> -
> - debug_dma_sync_single_for_cpu(dev, handle, size, dir);
> -
> - if (!dmabounce_sync_for_cpu(dev, handle, size, dir))
> - return;
> -
> - __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir);
> -}
> -
> -static inline void dma_sync_single_for_device(struct device *dev,
> - dma_addr_t handle, size_t size, enum dma_data_direction dir)
> -{
> - BUG_ON(!valid_dma_direction(dir));
> -
> - debug_dma_sync_single_for_device(dev, handle, size, dir);
> -
> - if (!dmabounce_sync_for_device(dev, handle, size, dir))
> - return;
> -
> - __dma_single_cpu_to_dev(dma_to_virt(dev, handle), size, dir);
> -}
> -
> -/**
> - * dma_sync_single_range_for_cpu
> - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> - * @handle: DMA address of buffer
> - * @offset: offset of region to start sync
> - * @size: size of region to sync
> - * @dir: DMA transfer direction (same as passed to dma_map_single)
> - *
> - * Make physical memory consistent for a single streaming mode DMA
> - * translation after a transfer.
> - *
> - * If you perform a dma_map_single() but wish to interrogate the
> - * buffer using the cpu, yet do not wish to teardown the PCI dma
> - * mapping, you must call this function before doing so. At the
> - * next point you give the PCI dma address back to the card, you
> - * must first the perform a dma_sync_for_device, and then the
> - * device again owns the buffer.
> - */
> -static inline void dma_sync_single_range_for_cpu(struct device *dev,
> - dma_addr_t handle, unsigned long offset, size_t size,
> - enum dma_data_direction dir)
> -{
> - dma_sync_single_for_cpu(dev, handle + offset, size, dir);
> -}
> -
> -static inline void dma_sync_single_range_for_device(struct device *dev,
> - dma_addr_t handle, unsigned long offset, size_t size,
> - enum dma_data_direction dir)
> -{
> - dma_sync_single_for_device(dev, handle + offset, size, dir);
> -}
> -
> /*
> * The scatter list versions of the above methods.
> */
> -extern int dma_map_sg(struct device *, struct scatterlist *, int,
> - enum dma_data_direction);
> -extern void dma_unmap_sg(struct device *, struct scatterlist *, int,
> +extern int arm_dma_map_sg(struct device *, struct scatterlist *, int,
> + enum dma_data_direction, struct dma_attrs *attrs);
> +extern void arm_dma_unmap_sg(struct device *, struct scatterlist *, int,
> + enum dma_data_direction, struct dma_attrs *attrs);
> +extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
> enum dma_data_direction);
> -extern void dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
> +extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
> enum dma_data_direction);
> -extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
> - enum dma_data_direction);
> -
>
> #endif /* __KERNEL__ */
> #endif
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index a5ab8bf..91fe436 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -29,6 +29,86 @@
>
> #include "mm.h"
>
> +/**
> + * dma_map_page - map a portion of a page for streaming DMA
> + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> + * @page: page that buffer resides in
> + * @offset: offset into page for start of buffer
> + * @size: size of buffer to map
> + * @dir: DMA transfer direction
> + *
> + * Ensure that any data held in the cache is appropriately discarded
> + * or written back.
> + *
> + * The device owns this memory once this call has completed. The CPU
> + * can regain ownership by calling dma_unmap_page().
> + */
> +static inline dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
> + unsigned long offset, size_t size, enum dma_data_direction dir,
> + struct dma_attrs *attrs)
> +{
> + return __dma_map_page(dev, page, offset, size, dir);
> +}
> +
> +/**
> + * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
> + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> + * @handle: DMA address of buffer
> + * @size: size of buffer (same as passed to dma_map_page)
> + * @dir: DMA transfer direction (same as passed to dma_map_page)
> + *
> + * Unmap a page streaming mode DMA translation. The handle and size
> + * must match what was provided in the previous dma_map_page() call.
> + * All other usages are undefined.
> + *
> + * After this call, reads by the CPU to the buffer are guaranteed to see
> + * whatever the device wrote there.
> + */
> +
> +static inline void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
> + size_t size, enum dma_data_direction dir,
> + struct dma_attrs *attrs)
> +{
> + __dma_unmap_page(dev, handle, size, dir);
> +}
> +
> +static inline void arm_dma_sync_single_for_cpu(struct device *dev,
> + dma_addr_t handle, size_t size, enum dma_data_direction dir)
> +{
> + unsigned int offset = handle & (PAGE_SIZE - 1);
> + struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
> + if (!dmabounce_sync_for_cpu(dev, handle, size, dir))
> + return;
> +
> + __dma_page_dev_to_cpu(page, offset, size, dir);
> +}
> +
> +static inline void arm_dma_sync_single_for_device(struct device *dev,
> + dma_addr_t handle, size_t size, enum dma_data_direction dir)
> +{
> + unsigned int offset = handle & (PAGE_SIZE - 1);
> + struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
> + if (!dmabounce_sync_for_device(dev, handle, size, dir))
> + return;
> +
> + __dma_page_cpu_to_dev(page, offset, size, dir);
> +}
> +
> +static int arm_dma_set_mask(struct device *dev, u64 dma_mask);
> +
> +struct dma_map_ops arm_dma_ops = {
> + .map_page = arm_dma_map_page,
> + .unmap_page = arm_dma_unmap_page,
> + .map_sg = arm_dma_map_sg,
> + .unmap_sg = arm_dma_unmap_sg,
> + .sync_single_for_cpu = arm_dma_sync_single_for_cpu,
> + .sync_single_for_device = arm_dma_sync_single_for_device,
> + .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
> + .sync_sg_for_device = arm_dma_sync_sg_for_device,
> + .set_dma_mask = arm_dma_set_mask,
> +};
> +EXPORT_SYMBOL(arm_dma_ops);
> +
> static u64 get_coherent_dma_mask(struct device *dev)
> {
> u64 mask = (u64)arm_dma_limit;
> @@ -455,47 +535,6 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
> }
> EXPORT_SYMBOL(dma_free_coherent);
>
> -/*
> - * Make an area consistent for devices.
> - * Note: Drivers should NOT use this function directly, as it will break
> - * platforms with CONFIG_DMABOUNCE.
> - * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
> - */
> -void ___dma_single_cpu_to_dev(const void *kaddr, size_t size,
> - enum dma_data_direction dir)
> -{
> - unsigned long paddr;
> -
> - BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
> -
> - dmac_map_area(kaddr, size, dir);
> -
> - paddr = __pa(kaddr);
> - if (dir == DMA_FROM_DEVICE) {
> - outer_inv_range(paddr, paddr + size);
> - } else {
> - outer_clean_range(paddr, paddr + size);
> - }
> - /* FIXME: non-speculating: flush on bidirectional mappings? */
> -}
> -EXPORT_SYMBOL(___dma_single_cpu_to_dev);
> -
> -void ___dma_single_dev_to_cpu(const void *kaddr, size_t size,
> - enum dma_data_direction dir)
> -{
> - BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
> -
> - /* FIXME: non-speculating: not required */
> - /* don't bother invalidating if DMA to device */
> - if (dir != DMA_TO_DEVICE) {
> - unsigned long paddr = __pa(kaddr);
> - outer_inv_range(paddr, paddr + size);
> - }
> -
> - dmac_unmap_area(kaddr, size, dir);
> -}
> -EXPORT_SYMBOL(___dma_single_dev_to_cpu);
> -
> static void dma_cache_maint_page(struct page *page, unsigned long offset,
> size_t size, enum dma_data_direction dir,
> void (*op)(const void *, size_t, int))
> @@ -593,21 +632,18 @@ EXPORT_SYMBOL(___dma_page_dev_to_cpu);
> * Device ownership issues as mentioned for dma_map_single are the same
> * here.
> */
> -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
> - enum dma_data_direction dir)
> +int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
> + enum dma_data_direction dir, struct dma_attrs *attrs)
> {
> struct scatterlist *s;
> int i, j;
>
> - BUG_ON(!valid_dma_direction(dir));
> -
> for_each_sg(sg, s, nents, i) {
> s->dma_address = __dma_map_page(dev, sg_page(s), s->offset,
> s->length, dir);
> if (dma_mapping_error(dev, s->dma_address))
> goto bad_mapping;
> }
> - debug_dma_map_sg(dev, sg, nents, nents, dir);
> return nents;
>
> bad_mapping:
> @@ -615,7 +651,6 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
> __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
> return 0;
> }
> -EXPORT_SYMBOL(dma_map_sg);
>
> /**
> * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
> @@ -627,18 +662,15 @@ EXPORT_SYMBOL(dma_map_sg);
> * Unmap a set of streaming mode DMA translations. Again, CPU access
> * rules concerning calls here are the same as for dma_unmap_single().
> */
> -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
> - enum dma_data_direction dir)
> +void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
> + enum dma_data_direction dir, struct dma_attrs *attrs)
> {
> struct scatterlist *s;
> int i;
>
> - debug_dma_unmap_sg(dev, sg, nents, dir);
> -
> for_each_sg(sg, s, nents, i)
> __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
> }
> -EXPORT_SYMBOL(dma_unmap_sg);
>
> /**
> * dma_sync_sg_for_cpu
> @@ -647,7 +679,7 @@ EXPORT_SYMBOL(dma_unmap_sg);
> * @nents: number of buffers to map (returned from dma_map_sg)
> * @dir: DMA transfer direction (same as was passed to dma_map_sg)
> */
> -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
> +void arm_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
> int nents, enum dma_data_direction dir)
> {
> struct scatterlist *s;
> @@ -661,10 +693,7 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
> __dma_page_dev_to_cpu(sg_page(s), s->offset,
> s->length, dir);
> }
> -
> - debug_dma_sync_sg_for_cpu(dev, sg, nents, dir);
> }
> -EXPORT_SYMBOL(dma_sync_sg_for_cpu);
>
> /**
> * dma_sync_sg_for_device
> @@ -673,7 +702,7 @@ EXPORT_SYMBOL(dma_sync_sg_for_cpu);
> * @nents: number of buffers to map (returned from dma_map_sg)
> * @dir: DMA transfer direction (same as was passed to dma_map_sg)
> */
> -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
> +void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
> int nents, enum dma_data_direction dir)
> {
> struct scatterlist *s;
> @@ -687,10 +716,7 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
> __dma_page_cpu_to_dev(sg_page(s), s->offset,
> s->length, dir);
> }
> -
> - debug_dma_sync_sg_for_device(dev, sg, nents, dir);
> }
> -EXPORT_SYMBOL(dma_sync_sg_for_device);
>
> /*
> * Return whether the given device DMA address mask can be supported
> @@ -706,7 +732,7 @@ int dma_supported(struct device *dev, u64 mask)
> }
> EXPORT_SYMBOL(dma_supported);
>
> -int dma_set_mask(struct device *dev, u64 dma_mask)
> +static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
> {
> if (!dev->dma_mask || !dma_supported(dev, dma_mask))
> return -EIO;
> @@ -717,7 +743,6 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
>
> return 0;
> }
> -EXPORT_SYMBOL(dma_set_mask);
>
> #define PREALLOC_DMA_DEBUG_ENTRIES 4096
>
> --
> 1.7.1.569.g6f426
>
> _______________________________________________
> iommu mailing list
> iommu at lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu
More information about the linux-arm-kernel
mailing list