aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-vexpress/dcscb.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-vexpress/dcscb.c')
-rw-r--r--arch/arm/mach-vexpress/dcscb.c66
1 files changed, 45 insertions, 21 deletions
diff --git a/arch/arm/mach-vexpress/dcscb.c b/arch/arm/mach-vexpress/dcscb.c
index 16d57a8a9d5a..3a6384c6c435 100644
--- a/arch/arm/mach-vexpress/dcscb.c
+++ b/arch/arm/mach-vexpress/dcscb.c
@@ -136,14 +136,35 @@ 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.
147 *
148 * Note: fp is preserved to the stack explicitly prior doing
149 * this since adding it to the clobber list is incompatible
150 * with having CONFIG_FRAME_POINTER=y.
143 */ 151 */
144 flush_cache_all(); 152 asm volatile(
145 set_cr(get_cr() & ~CR_C); 153 "str fp, [sp, #-4]! \n\t"
146 flush_cache_all(); 154 "mrc p15, 0, r0, c1, c0, 0 @ get CR \n\t"
155 "bic r0, r0, #"__stringify(CR_C)" \n\t"
156 "mcr p15, 0, r0, c1, c0, 0 @ set CR \n\t"
157 "isb \n\t"
158 "bl v7_flush_dcache_all \n\t"
159 "clrex \n\t"
160 "mrc p15, 0, r0, c1, c0, 1 @ get AUXCR \n\t"
161 "bic r0, r0, #(1 << 6) @ disable local coherency \n\t"
162 "mcr p15, 0, r0, c1, c0, 1 @ set AUXCR \n\t"
163 "isb \n\t"
164 "dsb \n\t"
165 "ldr fp, [sp], #4"
166 : : : "r0","r1","r2","r3","r4","r5","r6","r7",
167 "r9","r10","lr","memory");
147 168
148 /* 169 /*
149 * This is a harmless no-op. On platforms with a real 170 * This is a harmless no-op. On platforms with a real
@@ -152,9 +173,6 @@ static void dcscb_power_down(void)
152 */ 173 */
153 outer_flush_all(); 174 outer_flush_all();
154 175
155 /* Disable local coherency by clearing the ACTLR "SMP" bit: */
156 set_auxcr(get_auxcr() & ~(1 << 6));
157
158 /* 176 /*
159 * Disable cluster-level coherency by masking 177 * Disable cluster-level coherency by masking
160 * incoming snoops and DVM messages: 178 * incoming snoops and DVM messages:
@@ -167,18 +185,24 @@ static void dcscb_power_down(void)
167 185
168 /* 186 /*
169 * Flush the local CPU cache. 187 * Flush the local CPU cache.
170 * 188 * 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 */ 189 */
176 flush_cache_louis(); 190 asm volatile(
177 set_cr(get_cr() & ~CR_C); 191 "str fp, [sp, #-4]! \n\t"
178 flush_cache_louis(); 192 "mrc p15, 0, r0, c1, c0, 0 @ get CR \n\t"
179 193 "bic r0, r0, #"__stringify(CR_C)" \n\t"
180 /* Disable local coherency by clearing the ACTLR "SMP" bit: */ 194 "mcr p15, 0, r0, c1, c0, 0 @ set CR \n\t"
181 set_auxcr(get_auxcr() & ~(1 << 6)); 195 "isb \n\t"
196 "bl v7_flush_dcache_louis \n\t"
197 "clrex \n\t"
198 "mrc p15, 0, r0, c1, c0, 1 @ get AUXCR \n\t"
199 "bic r0, r0, #(1 << 6) @ disable local coherency \n\t"
200 "mcr p15, 0, r0, c1, c0, 1 @ set AUXCR \n\t"
201 "isb \n\t"
202 "dsb \n\t"
203 "ldr fp, [sp], #4"
204 : : : "r0","r1","r2","r3","r4","r5","r6","r7",
205 "r9","r10","lr","memory");
182 } 206 }
183 207
184 __mcpm_cpu_down(cpu, cluster); 208 __mcpm_cpu_down(cpu, cluster);