aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/xtensa/kernel/head.S5
-rw-r--r--arch/xtensa/kernel/smp.c34
2 files changed, 25 insertions, 14 deletions
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
index da08e75100ab..7f009719304e 100644
--- a/arch/xtensa/kernel/head.S
+++ b/arch/xtensa/kernel/head.S
@@ -276,12 +276,13 @@ should_never_return:
276 276
277 movi a2, cpu_start_ccount 277 movi a2, cpu_start_ccount
2781: 2781:
279 memw
279 l32i a3, a2, 0 280 l32i a3, a2, 0
280 beqi a3, 0, 1b 281 beqi a3, 0, 1b
281 movi a3, 0 282 movi a3, 0
282 s32i a3, a2, 0 283 s32i a3, a2, 0
283 memw
2841: 2841:
285 memw
285 l32i a3, a2, 0 286 l32i a3, a2, 0
286 beqi a3, 0, 1b 287 beqi a3, 0, 1b
287 wsr a3, ccount 288 wsr a3, ccount
@@ -317,11 +318,13 @@ ENTRY(cpu_restart)
317 rsr a0, prid 318 rsr a0, prid
318 neg a2, a0 319 neg a2, a0
319 movi a3, cpu_start_id 320 movi a3, cpu_start_id
321 memw
320 s32i a2, a3, 0 322 s32i a2, a3, 0
321#if XCHAL_DCACHE_IS_WRITEBACK 323#if XCHAL_DCACHE_IS_WRITEBACK
322 dhwbi a3, 0 324 dhwbi a3, 0
323#endif 325#endif
3241: 3261:
327 memw
325 l32i a2, a3, 0 328 l32i a2, a3, 0
326 dhi a3, 0 329 dhi a3, 0
327 bne a2, a0, 1b 330 bne a2, a0, 1b
diff --git a/arch/xtensa/kernel/smp.c b/arch/xtensa/kernel/smp.c
index 932d64689bac..c9fc2c4f71b3 100644
--- a/arch/xtensa/kernel/smp.c
+++ b/arch/xtensa/kernel/smp.c
@@ -195,9 +195,11 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts)
195 int i; 195 int i;
196 196
197#ifdef CONFIG_HOTPLUG_CPU 197#ifdef CONFIG_HOTPLUG_CPU
198 cpu_start_id = cpu; 198 WRITE_ONCE(cpu_start_id, cpu);
199 system_flush_invalidate_dcache_range( 199 /* Pairs with the third memw in the cpu_restart */
200 (unsigned long)&cpu_start_id, sizeof(cpu_start_id)); 200 mb();
201 system_flush_invalidate_dcache_range((unsigned long)&cpu_start_id,
202 sizeof(cpu_start_id));
201#endif 203#endif
202 smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1); 204 smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1);
203 205
@@ -206,18 +208,21 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts)
206 ccount = get_ccount(); 208 ccount = get_ccount();
207 while (!ccount); 209 while (!ccount);
208 210
209 cpu_start_ccount = ccount; 211 WRITE_ONCE(cpu_start_ccount, ccount);
210 212
211 while (time_before(jiffies, timeout)) { 213 do {
214 /*
215 * Pairs with the first two memws in the
216 * .Lboot_secondary.
217 */
212 mb(); 218 mb();
213 if (!cpu_start_ccount) 219 ccount = READ_ONCE(cpu_start_ccount);
214 break; 220 } while (ccount && time_before(jiffies, timeout));
215 }
216 221
217 if (cpu_start_ccount) { 222 if (ccount) {
218 smp_call_function_single(0, mx_cpu_stop, 223 smp_call_function_single(0, mx_cpu_stop,
219 (void *)cpu, 1); 224 (void *)cpu, 1);
220 cpu_start_ccount = 0; 225 WRITE_ONCE(cpu_start_ccount, 0);
221 return -EIO; 226 return -EIO;
222 } 227 }
223 } 228 }
@@ -237,6 +242,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
237 pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n", 242 pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n",
238 __func__, cpu, idle, start_info.stack); 243 __func__, cpu, idle, start_info.stack);
239 244
245 init_completion(&cpu_running);
240 ret = boot_secondary(cpu, idle); 246 ret = boot_secondary(cpu, idle);
241 if (ret == 0) { 247 if (ret == 0) {
242 wait_for_completion_timeout(&cpu_running, 248 wait_for_completion_timeout(&cpu_running,
@@ -298,8 +304,10 @@ void __cpu_die(unsigned int cpu)
298 unsigned long timeout = jiffies + msecs_to_jiffies(1000); 304 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
299 while (time_before(jiffies, timeout)) { 305 while (time_before(jiffies, timeout)) {
300 system_invalidate_dcache_range((unsigned long)&cpu_start_id, 306 system_invalidate_dcache_range((unsigned long)&cpu_start_id,
301 sizeof(cpu_start_id)); 307 sizeof(cpu_start_id));
302 if (cpu_start_id == -cpu) { 308 /* Pairs with the second memw in the cpu_restart */
309 mb();
310 if (READ_ONCE(cpu_start_id) == -cpu) {
303 platform_cpu_kill(cpu); 311 platform_cpu_kill(cpu);
304 return; 312 return;
305 } 313 }