Skip to content

Commit 0573b95

Browse files
committed
ARM: OMAP4+: Prevent CPU1 related hang with kexec
Kexec booted kernels on omap4 will hang early during the boot if the booted kernel is different version from the previous kernel. This is because the previous kernel may have configured low-power mode using CPU1_WAKEUP_NS_PA_ADDR. In that case it points to the previous kernel's omap4_secondary_startup(), and CPU1 can be in low power mode from the previous kernel. When the new kernel configures the CPU1 clockdomain, CPU1 can wake from low power state prematurely during omap44xx_clockdomains_init() running random code. Let's fix the issue by configuring CPU1_WAKEUP_NS_PA_ADDR before we call omap44xx_clockdomains_init(). Note that this is very early during the init, and we will do proper CPU1 reset during SMP init a bit later on in omap4_smp_prepare_cpus(). And we need to do this when SMP is not enabled as the previous kernel may have had it enabled. Acked-by: Santosh Shilimkar <ssantosh@kernel.org> Tested-by: Keerthy <j-keerthy@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
1 parent f4b9f40 commit 0573b95

File tree

4 files changed

+32
-8
lines changed

4 files changed

+32
-8
lines changed

arch/arm/mach-omap2/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ccflags-y := -I$(srctree)/$(src)/include \
88
# Common support
99
obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \
1010
common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
11-
omap_device.o sram.o drm.o
11+
omap_device.o omap-headsmp.o sram.o drm.o
1212

1313
hwmod-common = omap_hwmod.o omap_hwmod_reset.o \
1414
omap_hwmod_common_data.o
@@ -32,7 +32,7 @@ obj-$(CONFIG_SOC_HAS_OMAP2_SDRC) += sdrc.o
3232

3333
# SMP support ONLY available for OMAP4
3434

35-
smp-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o
35+
smp-$(CONFIG_SMP) += omap-smp.o
3636
smp-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o
3737
omap-4-5-common = omap4-common.o omap-wakeupgen.o
3838
obj-$(CONFIG_ARCH_OMAP4) += $(omap-4-5-common) $(smp-y) sleep44xx.o

arch/arm/mach-omap2/common.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,12 +259,14 @@ extern void gic_timer_retrigger(void);
259259
extern void omap_smc1(u32 fn, u32 arg);
260260
extern void omap4_sar_ram_init(void);
261261
extern void __iomem *omap4_get_sar_ram_base(void);
262+
extern void omap4_mpuss_early_init(void);
262263
extern void omap_do_wfi(void);
263264

264-
#ifdef CONFIG_SMP
265-
/* Needed for secondary core boot */
266265
extern void omap4_secondary_startup(void);
267266
extern void omap4460_secondary_startup(void);
267+
268+
#ifdef CONFIG_SMP
269+
/* Needed for secondary core boot */
268270
extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
269271
extern void omap_auxcoreboot_addr(u32 cpu_addr);
270272
extern u32 omap_read_auxcoreboot0(void);

arch/arm/mach-omap2/io.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,7 @@ void __init omap4430_init_early(void)
691691
omap4xxx_check_features();
692692
omap2_prcm_base_init();
693693
omap4_sar_ram_init();
694+
omap4_mpuss_early_init();
694695
omap4_pm_init_early();
695696
omap44xx_voltagedomains_init();
696697
omap44xx_powerdomains_init();

arch/arm/mach-omap2/omap-mpuss-lowpower.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
#include "prm44xx.h"
6363
#include "prm-regbits-44xx.h"
6464

65+
static void __iomem *sar_base;
66+
6567
#ifdef CONFIG_SMP
6668

6769
struct omap4_cpu_pm_info {
@@ -90,7 +92,6 @@ struct cpu_pm_ops {
9092

9193
static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
9294
static struct powerdomain *mpuss_pd;
93-
static void __iomem *sar_base;
9495
static u32 cpu_context_offset;
9596

9697
static int default_finish_suspend(unsigned long cpu_state)
@@ -366,9 +367,6 @@ int __init omap4_mpuss_init(void)
366367
return -ENODEV;
367368
}
368369

369-
if (cpu_is_omap44xx())
370-
sar_base = omap4_get_sar_ram_base();
371-
372370
/* Initilaise per CPU PM information */
373371
pm_info = &per_cpu(omap4_pm_info, 0x0);
374372
if (sar_base) {
@@ -444,3 +442,26 @@ int __init omap4_mpuss_init(void)
444442
}
445443

446444
#endif
445+
446+
/*
447+
* For kexec, we must set CPU1_WAKEUP_NS_PA_ADDR to point to
448+
* current kernel's secondary_startup() early before
449+
* clockdomains_init(). Otherwise clockdomain_init() can
450+
* wake CPU1 and cause a hang.
451+
*/
452+
void __init omap4_mpuss_early_init(void)
453+
{
454+
unsigned long startup_pa;
455+
456+
if (!cpu_is_omap44xx())
457+
return;
458+
459+
sar_base = omap4_get_sar_ram_base();
460+
461+
if (cpu_is_omap443x())
462+
startup_pa = virt_to_phys(omap4_secondary_startup);
463+
else
464+
startup_pa = virt_to_phys(omap4460_secondary_startup);
465+
466+
writel_relaxed(startup_pa, sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET);
467+
}

0 commit comments

Comments
 (0)