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 <[email protected]>
> Signed-off-by: Kyungmin Park <[email protected]>
> ---
>  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
> [email protected]
> https://lists.linuxfoundation.org/mailman/listinfo/iommu
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to