aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2013-07-16 20:59:53 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2013-07-22 12:26:09 -0400
commite8f9bb1bd6bb93fff773345cc54c42585e0e3ece (patch)
tree730257640b01d6b83b3a37d0c4961e0189faaddc
parent3b2f64d00c46e1e4e9bd0bb9bb12619adac27a4b (diff)
ARM: vexpress/dcscb: fix cache disabling sequences
Unlike real A15/A7's, the RTSM simulation doesn't appear to hit the cache when the CTRL.C bit is cleared. Let's ensure there is no memory access within the disable and flush cache sequence, including to the stack. Signed-off-by: Nicolas Pitre <nico@linaro.org>
-rw-r--r--arch/arm/mach-vexpress/dcscb.c58
1 files changed, 37 insertions, 21 deletions
diff --git a/arch/arm/mach-vexpress/dcscb.c b/arch/arm/mach-vexpress/dcscb.c
index 16d57a8a9d5a..85fffa702f5b 100644
--- a/arch/arm/mach-vexpress/dcscb.c
+++ b/arch/arm/mach-vexpress/dcscb.c
@@ -136,14 +136,29 @@ static void dcscb_power_down(void)
136 /* 136 /*
137 * Flush all cache levels for this cluster. 137 * Flush all cache levels for this cluster.
138 * 138 *
139 * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need 139 * To do so we do:
140 * a preliminary flush here for those CPUs. At least, that's 140 * - Clear the SCTLR.C bit to prevent further cache allocations
141 * the theory -- without the extra flush, Linux explodes on 141 * - Flush the whole cache
142 * RTSM (to be investigated). 142 * - Clear the ACTLR "SMP" bit to disable local coherency
143 *
144 * Let's do it in the safest possible way i.e. with
145 * no memory access within the following sequence
146 * including to the stack.
143 */ 147 */
144 flush_cache_all(); 148 asm volatile(
145 set_cr(get_cr() & ~CR_C); 149 "mrc p15, 0, r0, c1, c0, 0 @ get CR \n\t"
146 flush_cache_all(); 150 "bic r0, r0, #"__stringify(CR_C)" \n\t"
151 "mcr p15, 0, r0, c1, c0, 0 @ set CR \n\t"
152 "isb \n\t"
153 "bl v7_flush_dcache_all \n\t"
154 "clrex \n\t"
155 "mrc p15, 0, r0, c1, c0, 1 @ get AUXCR \n\t"
156 "bic r0, r0, #(1 << 6) @ disable local coherency \n\t"
157 "mcr p15, 0, r0, c1, c0, 1 @ set AUXCR \n\t"
158 "isb \n\t"
159 "dsb "
160 : : : "r0","r1","r2","r3","r4","r5","r6","r7",
161 "r9","r10","r11","lr","memory");
147 162
148 /* 163 /*
149 * This is a harmless no-op. On platforms with a real 164 * This is a harmless no-op. On platforms with a real
@@ -152,9 +167,6 @@ static void dcscb_power_down(void)
152 */ 167 */
153 outer_flush_all(); 168 outer_flush_all();
154 169
155 /* Disable local coherency by clearing the ACTLR "SMP" bit: */
156 set_auxcr(get_auxcr() & ~(1 << 6));
157
158 /* 170 /*
159 * Disable cluster-level coherency by masking 171 * Disable cluster-level coherency by masking
160 * incoming snoops and DVM messages: 172 * incoming snoops and DVM messages:
@@ -167,18 +179,22 @@ static void dcscb_power_down(void)
167 179
168 /* 180 /*
169 * Flush the local CPU cache. 181 * Flush the local CPU cache.
170 * 182 * Let's do it in the safest possible way as above.
171 * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
172 * a preliminary flush here for those CPUs. At least, that's
173 * the theory -- without the extra flush, Linux explodes on
174 * RTSM (to be investigated).
175 */ 183 */
176 flush_cache_louis(); 184 asm volatile(
177 set_cr(get_cr() & ~CR_C); 185 "mrc p15, 0, r0, c1, c0, 0 @ get CR \n\t"
178 flush_cache_louis(); 186 "bic r0, r0, #"__stringify(CR_C)" \n\t"
179 187 "mcr p15, 0, r0, c1, c0, 0 @ set CR \n\t"
180 /* Disable local coherency by clearing the ACTLR "SMP" bit: */ 188 "isb \n\t"
181 set_auxcr(get_auxcr() & ~(1 << 6)); 189 "bl v7_flush_dcache_louis \n\t"
190 "clrex \n\t"
191 "mrc p15, 0, r0, c1, c0, 1 @ get AUXCR \n\t"
192 "bic r0, r0, #(1 << 6) @ disable local coherency \n\t"
193 "mcr p15, 0, r0, c1, c0, 1 @ set AUXCR \n\t"
194 "isb \n\t"
195 "dsb "
196 : : : "r0","r1","r2","r3","r4","r5","r6","r7",
197 "r9","r10","r11","lr","memory");
182 } 198 }
183 199
184 __mcpm_cpu_down(cpu, cluster); 200 __mcpm_cpu_down(cpu, cluster);