Commit 50c7960a authored by Soren Brinkmann's avatar Soren Brinkmann Committed by Michal Simek
Browse files

ARM: zynq: Synchronise zynq_cpu_die/kill



Avoid races and add synchronisation between the arch specific
kill and die routines.

The same synchronisation issue was fixed on IMX platform
by this commit:
"ARM: imx: fix sync issue between imx_cpu_die and imx_cpu_kill"
(sha1: 2f3edfd7)

Signed-off-by: default avatarSoren Brinkmann <soren.brinkmann@xilinx.com>
Signed-off-by: default avatarMichal Simek <michal.simek@xilinx.com>
parent 18aebf11
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ extern int zynq_early_slcr_init(void);
extern void zynq_slcr_system_reset(void);
extern void zynq_slcr_cpu_stop(int cpu);
extern void zynq_slcr_cpu_start(int cpu);
extern bool zynq_slcr_cpu_state_read(int cpu);
extern void zynq_slcr_cpu_state_write(int cpu, bool die);
extern u32 zynq_slcr_get_device_id(void);

#ifdef CONFIG_SMP
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
 */
void zynq_platform_cpu_die(unsigned int cpu)
{
	zynq_slcr_cpu_state_write(cpu, true);

	/*
	 * there is no power-control hardware on this platform, so all
	 * we can do is put the core into WFI; this is safe as the calling
+6 −0
Original line number Diff line number Diff line
@@ -127,6 +127,12 @@ static void zynq_secondary_init(unsigned int cpu)
#ifdef CONFIG_HOTPLUG_CPU
static int zynq_cpu_kill(unsigned cpu)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(50);

	while (zynq_slcr_cpu_state_read(cpu))
		if (time_after(jiffies, timeout))
			return 0;

	zynq_slcr_cpu_stop(cpu);
	return 1;
}
+42 −1
Original line number Diff line number Diff line
@@ -138,6 +138,8 @@ void zynq_slcr_cpu_start(int cpu)
	zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
	reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
	zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);

	zynq_slcr_cpu_state_write(cpu, false);
}

/**
@@ -154,8 +156,47 @@ void zynq_slcr_cpu_stop(int cpu)
}

/**
 * zynq_slcr_init - Regular slcr driver init
 * zynq_slcr_cpu_state - Read/write cpu state
 * @cpu:	cpu number
 *
 * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
 * 0 means cpu is running, 1 cpu is going to die.
 *
 * Return: true if cpu is running, false if cpu is going to die
 */
bool zynq_slcr_cpu_state_read(int cpu)
{
	u32 state;

	state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
	state &= 1 << (31 - cpu);

	return !state;
}

/**
 * zynq_slcr_cpu_state - Read/write cpu state
 * @cpu:	cpu number
 * @die:	cpu state - true if cpu is going to die
 *
 * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
 * 0 means cpu is running, 1 cpu is going to die.
 */
void zynq_slcr_cpu_state_write(int cpu, bool die)
{
	u32 state, mask;

	state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
	mask = 1 << (31 - cpu);
	if (die)
		state |= mask;
	else
		state &= ~mask;
	writel(state, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
}

/**
 * zynq_slcr_init - Regular slcr driver init
 * Return:	0 on success, negative errno otherwise.
 *
 * Called early during boot from platform code to remap SLCR area.