diff options
Diffstat (limited to 'arch/arm/mach-vexpress/dcscb.c')
-rw-r--r-- | arch/arm/mach-vexpress/dcscb.c | 66 |
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); |