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

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
...@@ -24,6 +24,8 @@ extern int zynq_early_slcr_init(void); ...@@ -24,6 +24,8 @@ extern int zynq_early_slcr_init(void);
extern void zynq_slcr_system_reset(void); extern void zynq_slcr_system_reset(void);
extern void zynq_slcr_cpu_stop(int cpu); extern void zynq_slcr_cpu_stop(int cpu);
extern void zynq_slcr_cpu_start(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); extern u32 zynq_slcr_get_device_id(void);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
*/ */
void zynq_platform_cpu_die(unsigned int cpu) 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 * 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 * we can do is put the core into WFI; this is safe as the calling
......
...@@ -127,6 +127,12 @@ static void zynq_secondary_init(unsigned int cpu) ...@@ -127,6 +127,12 @@ static void zynq_secondary_init(unsigned int cpu)
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static int zynq_cpu_kill(unsigned 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); zynq_slcr_cpu_stop(cpu);
return 1; return 1;
} }
......
...@@ -138,6 +138,8 @@ void zynq_slcr_cpu_start(int cpu) ...@@ -138,6 +138,8 @@ void zynq_slcr_cpu_start(int cpu)
zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu); reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); 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) ...@@ -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. * Return: 0 on success, negative errno otherwise.
* *
* Called early during boot from platform code to remap SLCR area. * Called early during boot from platform code to remap SLCR area.
......
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