Commit 32a7726c authored by Max Filippov's avatar Max Filippov
Browse files

xtensa: SMP: fix secondary CPU initialization



- 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>
parent 4fe8713b
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -276,12 +276,13 @@ should_never_return:

	movi	a2, cpu_start_ccount
1:
	memw
	l32i	a3, a2, 0
	beqi	a3, 0, 1b
	movi	a3, 0
	s32i	a3, a2, 0
	memw
1:
	memw
	l32i	a3, a2, 0
	beqi	a3, 0, 1b
	wsr	a3, ccount
@@ -317,11 +318,13 @@ ENTRY(cpu_restart)
	rsr	a0, prid
	neg	a2, a0
	movi	a3, cpu_start_id
	memw
	s32i	a2, a3, 0
#if XCHAL_DCACHE_IS_WRITEBACK
	dhwbi	a3, 0
#endif
1:
	memw
	l32i	a2, a3, 0
	dhi	a3, 0
	bne	a2, a0, 1b
+21 −13
Original line number Diff line number Diff line
@@ -195,9 +195,11 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts)
	int i;

#ifdef CONFIG_HOTPLUG_CPU
	cpu_start_id = cpu;
	system_flush_invalidate_dcache_range(
			(unsigned long)&cpu_start_id, sizeof(cpu_start_id));
	WRITE_ONCE(cpu_start_id, cpu);
	/* Pairs with the third memw in the cpu_restart */
	mb();
	system_flush_invalidate_dcache_range((unsigned long)&cpu_start_id,
					     sizeof(cpu_start_id));
#endif
	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)
			ccount = get_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();
			if (!cpu_start_ccount)
				break;
		}
			ccount = READ_ONCE(cpu_start_ccount);
		} while (ccount && time_before(jiffies, timeout));

		if (cpu_start_ccount) {
		if (ccount) {
			smp_call_function_single(0, mx_cpu_stop,
						 (void *)cpu, 1);
			cpu_start_ccount = 0;
			WRITE_ONCE(cpu_start_ccount, 0);
			return -EIO;
		}
	}
@@ -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",
			__func__, cpu, idle, start_info.stack);

	init_completion(&cpu_running);
	ret = boot_secondary(cpu, idle);
	if (ret == 0) {
		wait_for_completion_timeout(&cpu_running,
@@ -299,7 +305,9 @@ void __cpu_die(unsigned int cpu)
	while (time_before(jiffies, timeout)) {
		system_invalidate_dcache_range((unsigned long)&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);
			return;
		}