]>
Commit | Line | Data |
---|---|---|
f2d4c738 GKH |
1 | From b46c0f74657d1fe1c1b0c1452631cc38a9e6987f Mon Sep 17 00:00:00 2001 |
2 | From: Stephen Boyd <sboyd@codeaurora.org> | |
3 | Date: Tue, 7 Feb 2012 19:42:07 +0100 | |
4 | Subject: ARM: 7321/1: cache-v7: Disable preemption when reading CCSIDR | |
5 | ||
6 | From: Stephen Boyd <sboyd@codeaurora.org> | |
7 | ||
8 | commit b46c0f74657d1fe1c1b0c1452631cc38a9e6987f upstream. | |
9 | ||
10 | armv7's flush_cache_all() flushes caches via set/way. To | |
11 | determine the cache attributes (line size, number of sets, | |
12 | etc.) the assembly first writes the CSSELR register to select a | |
13 | cache level and then reads the CCSIDR register. The CSSELR register | |
14 | is banked per-cpu and is used to determine which cache level CCSIDR | |
15 | reads. If the task is migrated between when the CSSELR is written and | |
16 | the CCSIDR is read the CCSIDR value may be for an unexpected cache | |
17 | level (for example L1 instead of L2) and incorrect cache flushing | |
18 | could occur. | |
19 | ||
20 | Disable interrupts across the write and read so that the correct | |
21 | cache attributes are read and used for the cache flushing | |
22 | routine. We disable interrupts instead of disabling preemption | |
23 | because the critical section is only 3 instructions and we want | |
24 | to call v7_dcache_flush_all from __v7_setup which doesn't have a | |
25 | full kernel stack with a struct thread_info. | |
26 | ||
27 | This fixes a problem we see in scm_call() when flush_cache_all() | |
28 | is called from preemptible context and sometimes the L2 cache is | |
29 | not properly flushed out. | |
30 | ||
31 | Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> | |
32 | Acked-by: Catalin Marinas <catalin.marinas@arm.com> | |
33 | Reviewed-by: Nicolas Pitre <nico@linaro.org> | |
34 | Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> | |
35 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
36 | ||
37 | --- | |
38 | arch/arm/mm/cache-v7.S | 6 ++++++ | |
39 | 1 file changed, 6 insertions(+) | |
40 | ||
41 | --- a/arch/arm/mm/cache-v7.S | |
42 | +++ b/arch/arm/mm/cache-v7.S | |
43 | @@ -54,9 +54,15 @@ loop1: | |
44 | and r1, r1, #7 @ mask of the bits for current cache only | |
45 | cmp r1, #2 @ see what cache we have at this level | |
46 | blt skip @ skip if no cache, or just i-cache | |
47 | +#ifdef CONFIG_PREEMPT | |
48 | + save_and_disable_irqs r9 @ make cssr&csidr read atomic | |
49 | +#endif | |
50 | mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr | |
51 | isb @ isb to sych the new cssr&csidr | |
52 | mrc p15, 1, r1, c0, c0, 0 @ read the new csidr | |
53 | +#ifdef CONFIG_PREEMPT | |
54 | + restore_irqs_notrace r9 | |
55 | +#endif | |
56 | and r2, r1, #7 @ extract the length of the cache lines | |
57 | add r2, r2, #4 @ add 4 (line length offset) | |
58 | ldr r4, =0x3ff |