diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2010-09-13 10:58:06 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-09-19 07:17:44 -0400 |
commit | 6012191aa9c6ffff3a23b81162298318b56d7cb3 (patch) | |
tree | 8f08d869b452d66f126743bcfd73aa6f5a701605 /arch/arm/mm/flush.c | |
parent | c01778001a4f5ad9c62d882776235f3f31922fdd (diff) |
ARM: 6380/1: Introduce __sync_icache_dcache() for VIPT caches
On SMP systems, there is a small chance of a PTE becoming visible to a
different CPU before the current cache maintenance operations in
update_mmu_cache(). To avoid this, cache maintenance must be handled in
set_pte_at() (similar to IA-64 and PowerPC).
This patch provides a unified VIPT cache handling mechanism and
implements the __sync_icache_dcache() function for ARMv6 onwards
architectures. It is called from set_pte_at() and replaces the
update_mmu_cache(). The latter is still used on VIVT hardware where a
vm_area_struct is required.
Tested-by: Rabin Vincent <rabin.vincent@stericsson.com>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mm/flush.c')
-rw-r--r-- | arch/arm/mm/flush.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index b4efce9b7985..dd5b0120b92e 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c | |||
@@ -215,6 +215,36 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p | |||
215 | flush_dcache_mmap_unlock(mapping); | 215 | flush_dcache_mmap_unlock(mapping); |
216 | } | 216 | } |
217 | 217 | ||
218 | #if __LINUX_ARM_ARCH__ >= 6 | ||
219 | void __sync_icache_dcache(pte_t pteval) | ||
220 | { | ||
221 | unsigned long pfn; | ||
222 | struct page *page; | ||
223 | struct address_space *mapping; | ||
224 | |||
225 | if (!pte_present_user(pteval)) | ||
226 | return; | ||
227 | if (cache_is_vipt_nonaliasing() && !pte_exec(pteval)) | ||
228 | /* only flush non-aliasing VIPT caches for exec mappings */ | ||
229 | return; | ||
230 | pfn = pte_pfn(pteval); | ||
231 | if (!pfn_valid(pfn)) | ||
232 | return; | ||
233 | |||
234 | page = pfn_to_page(pfn); | ||
235 | if (cache_is_vipt_aliasing()) | ||
236 | mapping = page_mapping(page); | ||
237 | else | ||
238 | mapping = NULL; | ||
239 | |||
240 | if (!test_and_set_bit(PG_dcache_clean, &page->flags)) | ||
241 | __flush_dcache_page(mapping, page); | ||
242 | /* pte_exec() already checked above for non-aliasing VIPT cache */ | ||
243 | if (cache_is_vipt_nonaliasing() || pte_exec(pteval)) | ||
244 | __flush_icache_all(); | ||
245 | } | ||
246 | #endif | ||
247 | |||
218 | /* | 248 | /* |
219 | * Ensure cache coherency between kernel mapping and userspace mapping | 249 | * Ensure cache coherency between kernel mapping and userspace mapping |
220 | * of this page. | 250 | * of this page. |