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:
parent
287939a369
commit
2f3edfd7e2
3 changed files with 26 additions and 0 deletions
|
@ -110,6 +110,8 @@ void tzic_handle_irq(struct pt_regs *);
|
||||||
|
|
||||||
extern void imx_enable_cpu(int cpu, bool enable);
|
extern void imx_enable_cpu(int cpu, bool enable);
|
||||||
extern void imx_set_cpu_jump(int cpu, void *jump_addr);
|
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 void v7_cpu_resume(void);
|
||||||
extern u32 *pl310_get_save_ptr(void);
|
extern u32 *pl310_get_save_ptr(void);
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
|
|
@ -46,11 +46,23 @@ static inline void cpu_enter_lowpower(void)
|
||||||
void imx_cpu_die(unsigned int cpu)
|
void imx_cpu_die(unsigned int cpu)
|
||||||
{
|
{
|
||||||
cpu_enter_lowpower();
|
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();
|
cpu_do_idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
int imx_cpu_kill(unsigned int cpu)
|
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_enable_cpu(cpu, false);
|
||||||
|
imx_set_cpu_arg(cpu, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,18 @@ void imx_set_cpu_jump(int cpu, void *jump_addr)
|
||||||
src_base + SRC_GPR1 + cpu * 8);
|
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)
|
void imx_src_prepare_restart(void)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
Loading…
Add table
Reference in a new issue