[RFC PATCH 2/3] ARM: mm: v7 cache level operations
Lorenzo Pieralisi
lorenzo.pieralisi at arm.com
Thu Apr 12 09:08:30 EDT 2012
ARM v7 architecture introduces the concept of cache levels and registers
to probe and manage cache levels accordingly.
This patch adds v7 support for dcache level operations and defines a
preferred cache level hook that by default is set to Level of
Unification Inner Shareable (LoUIS).
Allowed cache levels are:
-1: flush the entire cache system
0: no-op
[1-7] flush the corresponding data cache level
[LoUIS] has been chosen as preferred level since it represents the cache
levels which are not shared by CPUs in most of the current systems (i.e.
cache levels that are per-CPU as e.g. an integrated L1).
Power-down operations like hotplug and CPU idle require to clean/invalidate
only cache levels that are within the CPU power domain, and LoUIS reflects
this requirement properly in most of the systems.
To improve configurability and possibly optimize cache operations a DT binding
is in the making to allow platforms to define the preferred cache level in a
more flexible way.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi at arm.com>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will.deacon at arm.com>
Cc: Russell King <linux at arm.linux.org.uk>
Cc: Vincent Guittot <vincent.guittot at linaro.org>
Cc: Nicolas Pitre <nicolas.pitre at linaro.org>
Cc: Colin Cross <ccross at android.com>
Cc: Santosh Shilimkar <santosh.shilimkar at ti.com>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: Amit Kachhap <amit.kachhap at linaro.org>
---
arch/arm/include/asm/cacheflush.h | 16 ++++++++++++++
arch/arm/mm/cache-v7.S | 43 ++++++++++++++++++++++++++++++++++++-
2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 741ae25..0c9e4fa 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -204,7 +204,23 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
#define __flush_icache_preferred __flush_icache_all_generic
#endif
+#if __LINUX_ARM_ARCH__ >= 7
+/*
+ * Hotplug and CPU idle code requires to flush only cache levels
+ * impacted by power down operations. In v7 the upper level is
+ * retrieved by reading LoUIS field of CLIDR, since inner shareability
+ * represents the cache boundaries affected by per-CPU shutdown
+ * operations in the most common platforms.
+ */
+#define __cache_level_v7_uis ({ \
+ u32 val; \
+ asm volatile("mrc p15, 1, %0, c0, c0, 1" : "=r"(val)); \
+ ((val & 0xe00000) >> 21); })
+
+#define flush_cache_level_preferred() __cache_level_v7_uis
+#else
#define flush_cache_level_preferred() (-1)
+#endif
static inline int flush_cache_level_cpu(void)
{
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 07c4bc8..c79f152 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -33,6 +33,23 @@ ENTRY(v7_flush_icache_all)
ENDPROC(v7_flush_icache_all)
/*
+ * v7_flush_dcache_level(level)
+ *
+ * Flush the D-cache up to the level passed as first input parameter.
+ *
+ * r0 - cache level
+ *
+ * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
+ */
+
+ENTRY(v7_flush_dcache_level)
+ dmb
+ mov r3, r0, lsl #1 @ level * 2
+ mrc p15, 1, r0, c0, c0, 1 @ read clidr
+ b __flush_level
+ENDPROC(v7_flush_dcache_level)
+
+/*
* v7_flush_dcache_all()
*
* Flush the whole D-cache.
@@ -47,6 +64,7 @@ ENTRY(v7_flush_dcache_all)
ands r3, r0, #0x7000000 @ extract loc from clidr
mov r3, r3, lsr #23 @ left align loc bit field
beq finished @ if loc is 0, then no need to clean
+__flush_level:
mov r10, #0 @ start clean at cache level 0
loop1:
add r2, r10, r10, lsr #1 @ work out 3x current cache level
@@ -114,6 +132,29 @@ ENTRY(v7_flush_kern_cache_all)
ENDPROC(v7_flush_kern_cache_all)
/*
+ * v7_flush_kern_dcache_level(int level)
+ * level - upper level that should be cleaned/invalidated
+ * [valid values (-1,7)]
+ * level == -1 forces a flush_kern_cache_all
+ * level == 0 is a nop
+ * 1 < level <=7 flush dcache up to level
+ * Flush the data cache up to a level passed as a platform
+ * specific parameter
+ */
+ENTRY(v7_flush_kern_dcache_level)
+ cmp r0, #-1 @ -1 defaults to flush all
+ beq v7_flush_kern_cache_all
+ ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( stmfd sp!, {r4-r7, r9-r11, lr} )
+ sub r2, r0, #1
+ cmp r2, #6
+ blls v7_flush_dcache_level @ jump if 0 < level <=7
+ ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} )
+ mov pc, lr
+ENDPROC(v7_flush_kern_dcache_level)
+
+/*
* v7_flush_cache_all()
*
* Flush all TLB entries in a particular address space
@@ -346,4 +387,4 @@ ENDPROC(v7_dma_unmap_area)
__INITDATA
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
- define_cache_functions v7
+ define_cache_functions v7, cachelevel=1
--
1.7.9.5
More information about the linux-arm-kernel
mailing list