diff options
author | Gary King <gking@nvidia.com> | 2009-12-08 13:51:56 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2009-12-08 13:52:45 -0800 |
commit | 886eaf043fb40bdb2ae023bd748a137cfdf4205b (patch) | |
tree | 45dd65f38b12e1c41d6095613a3ed485b47209fc /arch/arm/include | |
parent | 5f73d452bea42d23383bb87f9f6ede4c7306192c (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.h | 19 |
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 |