summaryrefslogtreecommitdiff
path: root/arch/arm/include
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2009-12-08 13:51:56 -0800
committerGary King <gking@nvidia.com>2009-12-08 13:52:45 -0800
commit886eaf043fb40bdb2ae023bd748a137cfdf4205b (patch)
tree45dd65f38b12e1c41d6095613a3ed485b47209fc /arch/arm/include
parent5f73d452bea42d23383bb87f9f6ede4c7306192c (diff)
cherry-pick commit 6dd5056b9abe1e38fae... from arm-devel.org/devel
Broadcast the DMA cache operations on ARMv6 SMP hardware The Snoop Control Unit on the ARM11MPCore hardware does not detect the cache operations and the dma_cache_maint() function may leave stale cache entries on other CPUs. The solution is to broadcast the cache operations to the other CPUs in software. However, there is no restriction to the contexts in which dma_cache_maint() function can be called (interrupt context or IRQs disabled). This patch implements the smp_dma_cache_op() function which performs the broadcast and it can be called with interrupts disabled or from interrupt context. To avoid deadlocking when more than one CPU try to invoke this function, the implementation uses spin_trylock() loop if the IRQs are disabled and, if the lock cannot be acquired, it polls for an incoming IPI and executes it. In the unlikely situation of two or more CPUs calling the smp_dma_cache_op() function with interrupts disabled, there may be spurious (or delayed) IPIs after a CPU completes and enables the IRQs. These are handled by checking the corresponding "unfinished" bits in the IPI handler. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Conflicts: arch/arm/include/asm/cacheflush.h arch/arm/kernel/smp.c
Diffstat (limited to 'arch/arm/include')
-rw-r--r--arch/arm/include/asm/cacheflush.h19
1 files changed, 16 insertions, 3 deletions
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index b753d915e4df..b802fbdac7b8 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -294,10 +294,23 @@ enum smp_dma_cache_type {
SMP_DMA_CACHE_CLEAN,
SMP_DMA_CACHE_FLUSH,
};
+
extern void smp_dma_cache_op(int type, const void *start, const void *end);
-#define smp_dma_inv_range(s, e) smp_dma_cache_op(SMP_DMA_CACHE_INV, s, e)
-#define smp_dma_clean_range(s, e) smp_dma_cache_op(SMP_DMA_CACHE_CLEAN, s, e)
-#define smp_dma_flush_range(s, e) smp_dma_cache_op(SMP_DMA_CACHE_FLUSH, s, e)
+
+static inline void smp_dma_inv_range(const void *start, const void *end)
+{
+ smp_dma_cache_op(SMP_DMA_CACHE_INV, start, end);
+}
+
+static inline void smp_dma_clean_range(const void *start, const void *end)
+{
+ smp_dma_cache_op(SMP_DMA_CACHE_CLEAN, start, end);
+}
+
+static inline void smp_dma_flush_range(const void *start, const void *end)
+{
+ smp_dma_cache_op(SMP_DMA_CACHE_FLUSH, start, end);
+}
#else
#define smp_dma_inv_range dmac_inv_range
#define smp_dma_clean_range dmac_clean_range