Commit 8655802a authored by Max Filippov's avatar Max Filippov Committed by Greg Kroah-Hartman

xtensa: SMP: fix secondary CPU initialization

[ Upstream commit 32a7726c ]

- add missing memory barriers to the secondary CPU synchronization spin
  loops; add comment to the matching memory barrier in the boot_secondary
  and __cpu_die functions;
- use READ_ONCE/WRITE_ONCE to access cpu_start_id/cpu_start_ccount
  instead of reading/writing them directly;
- re-initialize cpu_running every time before starting secondary CPU to
  flush possible previous CPU startup results.
Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 0165df14
...@@ -280,12 +280,13 @@ should_never_return: ...@@ -280,12 +280,13 @@ should_never_return:
movi a2, cpu_start_ccount movi a2, cpu_start_ccount
1: 1:
memw
l32i a3, a2, 0 l32i a3, a2, 0
beqi a3, 0, 1b beqi a3, 0, 1b
movi a3, 0 movi a3, 0
s32i a3, a2, 0 s32i a3, a2, 0
memw
1: 1:
memw
l32i a3, a2, 0 l32i a3, a2, 0
beqi a3, 0, 1b beqi a3, 0, 1b
wsr a3, ccount wsr a3, ccount
...@@ -321,11 +322,13 @@ ENTRY(cpu_restart) ...@@ -321,11 +322,13 @@ ENTRY(cpu_restart)
rsr a0, prid rsr a0, prid
neg a2, a0 neg a2, a0
movi a3, cpu_start_id movi a3, cpu_start_id
memw
s32i a2, a3, 0 s32i a2, a3, 0
#if XCHAL_DCACHE_IS_WRITEBACK #if XCHAL_DCACHE_IS_WRITEBACK
dhwbi a3, 0 dhwbi a3, 0
#endif #endif
1: 1:
memw
l32i a2, a3, 0 l32i a2, a3, 0
dhi a3, 0 dhi a3, 0
bne a2, a0, 1b bne a2, a0, 1b
......
...@@ -195,9 +195,11 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts) ...@@ -195,9 +195,11 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts)
int i; int i;
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
cpu_start_id = cpu; WRITE_ONCE(cpu_start_id, cpu);
system_flush_invalidate_dcache_range( /* Pairs with the third memw in the cpu_restart */
(unsigned long)&cpu_start_id, sizeof(cpu_start_id)); mb();
system_flush_invalidate_dcache_range((unsigned long)&cpu_start_id,
sizeof(cpu_start_id));
#endif #endif
smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1); smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1);
...@@ -206,18 +208,21 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts) ...@@ -206,18 +208,21 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts)
ccount = get_ccount(); ccount = get_ccount();
while (!ccount); while (!ccount);
cpu_start_ccount = ccount; WRITE_ONCE(cpu_start_ccount, ccount);
while (time_before(jiffies, timeout)) { do {
/*
* Pairs with the first two memws in the
* .Lboot_secondary.
*/
mb(); mb();
if (!cpu_start_ccount) ccount = READ_ONCE(cpu_start_ccount);
break; } while (ccount && time_before(jiffies, timeout));
}
if (cpu_start_ccount) { if (ccount) {
smp_call_function_single(0, mx_cpu_stop, smp_call_function_single(0, mx_cpu_stop,
(void *)cpu, 1); (void *)cpu, 1);
cpu_start_ccount = 0; WRITE_ONCE(cpu_start_ccount, 0);
return -EIO; return -EIO;
} }
} }
...@@ -237,6 +242,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) ...@@ -237,6 +242,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n", pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n",
__func__, cpu, idle, start_info.stack); __func__, cpu, idle, start_info.stack);
init_completion(&cpu_running);
ret = boot_secondary(cpu, idle); ret = boot_secondary(cpu, idle);
if (ret == 0) { if (ret == 0) {
wait_for_completion_timeout(&cpu_running, wait_for_completion_timeout(&cpu_running,
...@@ -298,8 +304,10 @@ void __cpu_die(unsigned int cpu) ...@@ -298,8 +304,10 @@ void __cpu_die(unsigned int cpu)
unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned long timeout = jiffies + msecs_to_jiffies(1000);
while (time_before(jiffies, timeout)) { while (time_before(jiffies, timeout)) {
system_invalidate_dcache_range((unsigned long)&cpu_start_id, system_invalidate_dcache_range((unsigned long)&cpu_start_id,
sizeof(cpu_start_id)); sizeof(cpu_start_id));
if (cpu_start_id == -cpu) { /* Pairs with the second memw in the cpu_restart */
mb();
if (READ_ONCE(cpu_start_id) == -cpu) {
platform_cpu_kill(cpu); platform_cpu_kill(cpu);
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment