diff options
Diffstat (limited to 'arch/arm/include/asm/dma-mapping.h')
-rw-r--r-- | arch/arm/include/asm/dma-mapping.h | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index a96300bf83f..69ce0727edb 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) | |||
57 | #endif | 57 | #endif |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * DMA-consistent mapping functions. These allocate/free a region of | 60 | * The DMA API is built upon the notion of "buffer ownership". A buffer |
61 | * uncached, unwrite-buffered mapped memory space for use with DMA | 61 | * is either exclusively owned by the CPU (and therefore may be accessed |
62 | * devices. This is the "generic" version. The PCI specific version | 62 | * by it) or exclusively owned by the DMA device. These helper functions |
63 | * is in pci.h | 63 | * represent the transitions between these two ownership states. |
64 | * | 64 | * |
65 | * Note: Drivers should NOT use this function directly, as it will break | 65 | * Note, however, that on later ARMs, this notion does not work due to |
66 | * platforms with CONFIG_DMABOUNCE. | 66 | * speculative prefetches. We model our approach on the assumption that |
67 | * Use the driver DMA support - see dma-mapping.h (dma_sync_*) | 67 | * the CPU does do speculative prefetches, which means we clean caches |
68 | * before transfers and delay cache invalidation until transfer completion. | ||
69 | * | ||
70 | * Private support functions: these are not part of the API and are | ||
71 | * liable to change. Drivers must not use these. | ||
68 | */ | 72 | */ |
69 | extern void dma_cache_maint(const void *kaddr, size_t size, int rw); | 73 | static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size, |
70 | extern void dma_cache_maint_page(struct page *page, unsigned long offset, | 74 | enum dma_data_direction dir) |
71 | size_t size, int rw); | 75 | { |
76 | extern void ___dma_single_cpu_to_dev(const void *, size_t, | ||
77 | enum dma_data_direction); | ||
78 | |||
79 | if (!arch_is_coherent()) | ||
80 | ___dma_single_cpu_to_dev(kaddr, size, dir); | ||
81 | } | ||
82 | |||
83 | static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size, | ||
84 | enum dma_data_direction dir) | ||
85 | { | ||
86 | extern void ___dma_single_dev_to_cpu(const void *, size_t, | ||
87 | enum dma_data_direction); | ||
88 | |||
89 | if (!arch_is_coherent()) | ||
90 | ___dma_single_dev_to_cpu(kaddr, size, dir); | ||
91 | } | ||
92 | |||
93 | static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off, | ||
94 | size_t size, enum dma_data_direction dir) | ||
95 | { | ||
96 | extern void ___dma_page_cpu_to_dev(struct page *, unsigned long, | ||
97 | size_t, enum dma_data_direction); | ||
98 | |||
99 | if (!arch_is_coherent()) | ||
100 | ___dma_page_cpu_to_dev(page, off, size, dir); | ||
101 | } | ||
102 | |||
103 | static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, | ||
104 | size_t size, enum dma_data_direction dir) | ||
105 | { | ||
106 | extern void ___dma_page_dev_to_cpu(struct page *, unsigned long, | ||
107 | size_t, enum dma_data_direction); | ||
108 | |||
109 | if (!arch_is_coherent()) | ||
110 | ___dma_page_dev_to_cpu(page, off, size, dir); | ||
111 | } | ||
72 | 112 | ||
73 | /* | 113 | /* |
74 | * Return whether the given device DMA address mask can be supported | 114 | * Return whether the given device DMA address mask can be supported |
@@ -88,6 +128,14 @@ static inline int dma_supported(struct device *dev, u64 mask) | |||
88 | 128 | ||
89 | static inline int dma_set_mask(struct device *dev, u64 dma_mask) | 129 | static inline int dma_set_mask(struct device *dev, u64 dma_mask) |
90 | { | 130 | { |
131 | #ifdef CONFIG_DMABOUNCE | ||
132 | if (dev->archdata.dmabounce) { | ||
133 | if (dma_mask >= ISA_DMA_THRESHOLD) | ||
134 | return 0; | ||
135 | else | ||
136 | return -EIO; | ||
137 | } | ||
138 | #endif | ||
91 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | 139 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) |
92 | return -EIO; | 140 | return -EIO; |
93 | 141 | ||
@@ -304,8 +352,7 @@ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, | |||
304 | { | 352 | { |
305 | BUG_ON(!valid_dma_direction(dir)); | 353 | BUG_ON(!valid_dma_direction(dir)); |
306 | 354 | ||
307 | if (!arch_is_coherent()) | 355 | __dma_single_cpu_to_dev(cpu_addr, size, dir); |
308 | dma_cache_maint(cpu_addr, size, dir); | ||
309 | 356 | ||
310 | return virt_to_dma(dev, cpu_addr); | 357 | return virt_to_dma(dev, cpu_addr); |
311 | } | 358 | } |
@@ -329,8 +376,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, | |||
329 | { | 376 | { |
330 | BUG_ON(!valid_dma_direction(dir)); | 377 | BUG_ON(!valid_dma_direction(dir)); |
331 | 378 | ||
332 | if (!arch_is_coherent()) | 379 | __dma_page_cpu_to_dev(page, offset, size, dir); |
333 | dma_cache_maint_page(page, offset, size, dir); | ||
334 | 380 | ||
335 | return page_to_dma(dev, page) + offset; | 381 | return page_to_dma(dev, page) + offset; |
336 | } | 382 | } |
@@ -352,7 +398,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, | |||
352 | static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, | 398 | static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, |
353 | size_t size, enum dma_data_direction dir) | 399 | size_t size, enum dma_data_direction dir) |
354 | { | 400 | { |
355 | /* nothing to do */ | 401 | __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); |
356 | } | 402 | } |
357 | 403 | ||
358 | /** | 404 | /** |
@@ -372,7 +418,8 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, | |||
372 | static inline void dma_unmap_page(struct device *dev, dma_addr_t handle, | 418 | static inline void dma_unmap_page(struct device *dev, dma_addr_t handle, |
373 | size_t size, enum dma_data_direction dir) | 419 | size_t size, enum dma_data_direction dir) |
374 | { | 420 | { |
375 | /* nothing to do */ | 421 | __dma_page_dev_to_cpu(dma_to_page(dev, handle), handle & ~PAGE_MASK, |
422 | size, dir); | ||
376 | } | 423 | } |
377 | #endif /* CONFIG_DMABOUNCE */ | 424 | #endif /* CONFIG_DMABOUNCE */ |
378 | 425 | ||
@@ -400,7 +447,10 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev, | |||
400 | { | 447 | { |
401 | BUG_ON(!valid_dma_direction(dir)); | 448 | BUG_ON(!valid_dma_direction(dir)); |
402 | 449 | ||
403 | dmabounce_sync_for_cpu(dev, handle, offset, size, dir); | 450 | if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir)) |
451 | return; | ||
452 | |||
453 | __dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir); | ||
404 | } | 454 | } |
405 | 455 | ||
406 | static inline void dma_sync_single_range_for_device(struct device *dev, | 456 | static inline void dma_sync_single_range_for_device(struct device *dev, |
@@ -412,8 +462,7 @@ static inline void dma_sync_single_range_for_device(struct device *dev, | |||
412 | if (!dmabounce_sync_for_device(dev, handle, offset, size, dir)) | 462 | if (!dmabounce_sync_for_device(dev, handle, offset, size, dir)) |
413 | return; | 463 | return; |
414 | 464 | ||
415 | if (!arch_is_coherent()) | 465 | __dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir); |
416 | dma_cache_maint(dma_to_virt(dev, handle) + offset, size, dir); | ||
417 | } | 466 | } |
418 | 467 | ||
419 | static inline void dma_sync_single_for_cpu(struct device *dev, | 468 | static inline void dma_sync_single_for_cpu(struct device *dev, |