diff options
Diffstat (limited to 'arch/arm/include/asm/dma-mapping.h')
| -rw-r--r-- | arch/arm/include/asm/dma-mapping.h | 79 | 
1 files changed, 60 insertions, 19 deletions
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index a96300bf83f..256ee1c9f51 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -57,18 +57,58 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)  #endif  /* - * DMA-consistent mapping functions.  These allocate/free a region of - * uncached, unwrite-buffered mapped memory space for use with DMA - * devices.  This is the "generic" version.  The PCI specific version - * is in pci.h + * The DMA API is built upon the notion of "buffer ownership".  A buffer + * is either exclusively owned by the CPU (and therefore may be accessed + * by it) or exclusively owned by the DMA device.  These helper functions + * represent the transitions between these two ownership states.   * - * 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_*) + * Note, however, that on later ARMs, this notion does not work due to + * speculative prefetches.  We model our approach on the assumption that + * the CPU does do speculative prefetches, which means we clean caches + * before transfers and delay cache invalidation until transfer completion. + * + * Private support functions: these are not part of the API and are + * liable to change.  Drivers must not use these.   */ -extern void dma_cache_maint(const void *kaddr, size_t size, int rw); -extern void dma_cache_maint_page(struct page *page, unsigned long offset, -				 size_t size, int rw); +static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size, +	enum dma_data_direction dir) +{ +	extern void ___dma_single_cpu_to_dev(const void *, size_t, +		enum dma_data_direction); + +	if (!arch_is_coherent()) +		___dma_single_cpu_to_dev(kaddr, size, dir); +} + +static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size, +	enum dma_data_direction dir) +{ +	extern void ___dma_single_dev_to_cpu(const void *, size_t, +		enum dma_data_direction); + +	if (!arch_is_coherent()) +		___dma_single_dev_to_cpu(kaddr, size, dir); +} + +static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off, +	size_t size, enum dma_data_direction dir) +{ +	extern void ___dma_page_cpu_to_dev(struct page *, unsigned long, +		size_t, enum dma_data_direction); + +	if (!arch_is_coherent()) +		___dma_page_cpu_to_dev(page, off, size, dir); +} + +static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, +	size_t size, enum dma_data_direction dir) +{ +	extern void ___dma_page_dev_to_cpu(struct page *, unsigned long, +		size_t, enum dma_data_direction); + +	if (!arch_is_coherent()) +		___dma_page_dev_to_cpu(page, off, size, dir); +}  /*   * Return whether the given device DMA address mask can be supported @@ -304,8 +344,7 @@ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,  {  	BUG_ON(!valid_dma_direction(dir)); -	if (!arch_is_coherent()) -		dma_cache_maint(cpu_addr, size, dir); +	__dma_single_cpu_to_dev(cpu_addr, size, dir);  	return virt_to_dma(dev, cpu_addr);  } @@ -329,8 +368,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,  {  	BUG_ON(!valid_dma_direction(dir)); -	if (!arch_is_coherent()) -		dma_cache_maint_page(page, offset, size, dir); +	__dma_page_cpu_to_dev(page, offset, size, dir);  	return page_to_dma(dev, page) + offset;  } @@ -352,7 +390,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,  static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,  		size_t size, enum dma_data_direction dir)  { -	/* nothing to do */ +	__dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir);  }  /** @@ -372,7 +410,8 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,  static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,  		size_t size, enum dma_data_direction dir)  { -	/* nothing to do */ +	__dma_page_dev_to_cpu(dma_to_page(dev, handle), handle & ~PAGE_MASK, +		size, dir);  }  #endif /* CONFIG_DMABOUNCE */ @@ -400,7 +439,10 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,  {  	BUG_ON(!valid_dma_direction(dir)); -	dmabounce_sync_for_cpu(dev, handle, offset, size, dir); +	if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir)) +		return; + +	__dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir);  }  static inline void dma_sync_single_range_for_device(struct device *dev, @@ -412,8 +454,7 @@ static inline void dma_sync_single_range_for_device(struct device *dev,  	if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))  		return; -	if (!arch_is_coherent()) -		dma_cache_maint(dma_to_virt(dev, handle) + offset, size, dir); +	__dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir);  }  static inline void dma_sync_single_for_cpu(struct device *dev,  |