ARM: imx: fix sync issue between imx_cpu_die and imx_cpu_kill

There is a sync issue with hotplug operation.  It's possible that when
imx_cpu_kill gets running on primary core, the imx_cpu_die execution
on the core which is to be killed hasn't been finished yet.  The problem
will very likely be hit when running suspend without no_console_suspend
setting on kernel cmdline.

It uses cpu jumping argument register to sync imx_cpu_die and
imx_cpu_kill.  The register will be set in imx_cpu_die and imx_cpu_kill
will wait for the register being cleared to actually kill the cpu.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: <stable@vger.kernel.org>
This commit is contained in:
Shawn Guo 2013-03-26 16:46:07 +08:00
parent 287939a369
commit 2f3edfd7e2
3 changed files with 26 additions and 0 deletions

View File

@ -110,6 +110,8 @@ void tzic_handle_irq(struct pt_regs *);
extern void imx_enable_cpu(int cpu, bool enable);
extern void imx_set_cpu_jump(int cpu, void *jump_addr);
extern u32 imx_get_cpu_arg(int cpu);
extern void imx_set_cpu_arg(int cpu, u32 arg);
extern void v7_cpu_resume(void);
extern u32 *pl310_get_save_ptr(void);
#ifdef CONFIG_SMP

View File

@ -46,11 +46,23 @@ static inline void cpu_enter_lowpower(void)
void imx_cpu_die(unsigned int cpu)
{
cpu_enter_lowpower();
/*
* We use the cpu jumping argument register to sync with
* imx_cpu_kill() which is running on cpu0 and waiting for
* the register being cleared to kill the cpu.
*/
imx_set_cpu_arg(cpu, ~0);
cpu_do_idle();
}
int imx_cpu_kill(unsigned int cpu)
{
unsigned long timeout = jiffies + msecs_to_jiffies(50);
while (imx_get_cpu_arg(cpu) == 0)
if (time_after(jiffies, timeout))
return 0;
imx_enable_cpu(cpu, false);
imx_set_cpu_arg(cpu, 0);
return 1;
}

View File

@ -43,6 +43,18 @@ void imx_set_cpu_jump(int cpu, void *jump_addr)
src_base + SRC_GPR1 + cpu * 8);
}
u32 imx_get_cpu_arg(int cpu)
{
cpu = cpu_logical_map(cpu);
return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4);
}
void imx_set_cpu_arg(int cpu, u32 arg)
{
cpu = cpu_logical_map(cpu);
writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4);
}
void imx_src_prepare_restart(void)
{
u32 val;