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:
parent
18aebf116b
commit
50c7960a45
4 changed files with 52 additions and 1 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue