Skip to content

Commit 56b84e4

Browse files
jcmvbkbcgregkh
authored andcommitted
xtensa: SMP: fix secondary CPU initialization
[ Upstream commit 32a7726 ] - 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: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent f6efc18 commit 56b84e4

2 files changed

Lines changed: 25 additions & 14 deletions

File tree

arch/xtensa/kernel/head.S

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,12 +286,13 @@ should_never_return:
286286

287287
movi a2, cpu_start_ccount
288288
1:
289+
memw
289290
l32i a3, a2, 0
290291
beqi a3, 0, 1b
291292
movi a3, 0
292293
s32i a3, a2, 0
293-
memw
294294
1:
295+
memw
295296
l32i a3, a2, 0
296297
beqi a3, 0, 1b
297298
wsr a3, ccount
@@ -328,11 +329,13 @@ ENTRY(cpu_restart)
328329
rsr a0, prid
329330
neg a2, a0
330331
movi a3, cpu_start_id
332+
memw
331333
s32i a2, a3, 0
332334
#if XCHAL_DCACHE_IS_WRITEBACK
333335
dhwbi a3, 0
334336
#endif
335337
1:
338+
memw
336339
l32i a2, a3, 0
337340
dhi a3, 0
338341
bne a2, a0, 1b

arch/xtensa/kernel/smp.c

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,11 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts)
192192
int i;
193193

194194
#ifdef CONFIG_HOTPLUG_CPU
195-
cpu_start_id = cpu;
196-
system_flush_invalidate_dcache_range(
197-
(unsigned long)&cpu_start_id, sizeof(cpu_start_id));
195+
WRITE_ONCE(cpu_start_id, cpu);
196+
/* Pairs with the third memw in the cpu_restart */
197+
mb();
198+
system_flush_invalidate_dcache_range((unsigned long)&cpu_start_id,
199+
sizeof(cpu_start_id));
198200
#endif
199201
smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1);
200202

@@ -203,18 +205,21 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts)
203205
ccount = get_ccount();
204206
while (!ccount);
205207

206-
cpu_start_ccount = ccount;
208+
WRITE_ONCE(cpu_start_ccount, ccount);
207209

208-
while (time_before(jiffies, timeout)) {
210+
do {
211+
/*
212+
* Pairs with the first two memws in the
213+
* .Lboot_secondary.
214+
*/
209215
mb();
210-
if (!cpu_start_ccount)
211-
break;
212-
}
216+
ccount = READ_ONCE(cpu_start_ccount);
217+
} while (ccount && time_before(jiffies, timeout));
213218

214-
if (cpu_start_ccount) {
219+
if (ccount) {
215220
smp_call_function_single(0, mx_cpu_stop,
216-
(void *)cpu, 1);
217-
cpu_start_ccount = 0;
221+
(void *)cpu, 1);
222+
WRITE_ONCE(cpu_start_ccount, 0);
218223
return -EIO;
219224
}
220225
}
@@ -234,6 +239,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
234239
pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n",
235240
__func__, cpu, idle, start_info.stack);
236241

242+
init_completion(&cpu_running);
237243
ret = boot_secondary(cpu, idle);
238244
if (ret == 0) {
239245
wait_for_completion_timeout(&cpu_running,
@@ -295,8 +301,10 @@ void __cpu_die(unsigned int cpu)
295301
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
296302
while (time_before(jiffies, timeout)) {
297303
system_invalidate_dcache_range((unsigned long)&cpu_start_id,
298-
sizeof(cpu_start_id));
299-
if (cpu_start_id == -cpu) {
304+
sizeof(cpu_start_id));
305+
/* Pairs with the second memw in the cpu_restart */
306+
mb();
307+
if (READ_ONCE(cpu_start_id) == -cpu) {
300308
platform_cpu_kill(cpu);
301309
return;
302310
}

0 commit comments

Comments
 (0)