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: 2f3edfd7e2)

Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
This commit is contained in:
Soren Brinkmann 2014-09-02 14:19:12 -07:00 committed by Michal Simek
parent 18aebf116b
commit 50c7960a45
4 changed files with 52 additions and 1 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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.