aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2016-06-22 04:59:39 -0400
committerTony Lindgren <tony@atomide.com>2016-06-23 01:55:51 -0400
commit0573b957fc21c6a6cee01fdb08c1f7ce556afbac (patch)
tree26c28496da0cb970e04f01f9520758313c39ed63
parentf4b9f40ae95bad3df68d4a9b275714ef04abb1b5 (diff)
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>
-rw-r--r--arch/arm/mach-omap2/Makefile4
-rw-r--r--arch/arm/mach-omap2/common.h6
-rw-r--r--arch/arm/mach-omap2/io.c1
-rw-r--r--arch/arm/mach-omap2/omap-mpuss-lowpower.c29
4 files changed, 32 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 04e276ce8413..cd820f5df028 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -8,7 +8,7 @@ ccflags-y := -I$(srctree)/$(src)/include \
8# Common support 8# Common support
9obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \ 9obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \
10 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \ 10 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
12 12
13hwmod-common = omap_hwmod.o omap_hwmod_reset.o \ 13hwmod-common = omap_hwmod.o omap_hwmod_reset.o \
14 omap_hwmod_common_data.o 14 omap_hwmod_common_data.o
@@ -32,7 +32,7 @@ obj-$(CONFIG_SOC_HAS_OMAP2_SDRC) += sdrc.o
32 32
33# SMP support ONLY available for OMAP4 33# SMP support ONLY available for OMAP4
34 34
35smp-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o 35smp-$(CONFIG_SMP) += omap-smp.o
36smp-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o 36smp-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o
37omap-4-5-common = omap4-common.o omap-wakeupgen.o 37omap-4-5-common = omap4-common.o omap-wakeupgen.o
38obj-$(CONFIG_ARCH_OMAP4) += $(omap-4-5-common) $(smp-y) sleep44xx.o 38obj-$(CONFIG_ARCH_OMAP4) += $(omap-4-5-common) $(smp-y) sleep44xx.o
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 9cbae6e059a3..0136405a465f 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -259,12 +259,14 @@ extern void gic_timer_retrigger(void);
259extern void omap_smc1(u32 fn, u32 arg); 259extern void omap_smc1(u32 fn, u32 arg);
260extern void omap4_sar_ram_init(void); 260extern void omap4_sar_ram_init(void);
261extern void __iomem *omap4_get_sar_ram_base(void); 261extern void __iomem *omap4_get_sar_ram_base(void);
262extern void omap4_mpuss_early_init(void);
262extern void omap_do_wfi(void); 263extern void omap_do_wfi(void);
263 264
264#ifdef CONFIG_SMP
265/* Needed for secondary core boot */
266extern void omap4_secondary_startup(void); 265extern void omap4_secondary_startup(void);
267extern void omap4460_secondary_startup(void); 266extern void omap4460_secondary_startup(void);
267
268#ifdef CONFIG_SMP
269/* Needed for secondary core boot */
268extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask); 270extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
269extern void omap_auxcoreboot_addr(u32 cpu_addr); 271extern void omap_auxcoreboot_addr(u32 cpu_addr);
270extern u32 omap_read_auxcoreboot0(void); 272extern u32 omap_read_auxcoreboot0(void);
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 4548cb9f673e..0e9acdd95d70 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -691,6 +691,7 @@ void __init omap4430_init_early(void)
691 omap4xxx_check_features(); 691 omap4xxx_check_features();
692 omap2_prcm_base_init(); 692 omap2_prcm_base_init();
693 omap4_sar_ram_init(); 693 omap4_sar_ram_init();
694 omap4_mpuss_early_init();
694 omap4_pm_init_early(); 695 omap4_pm_init_early();
695 omap44xx_voltagedomains_init(); 696 omap44xx_voltagedomains_init();
696 omap44xx_powerdomains_init(); 697 omap44xx_powerdomains_init();
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 65024af169d3..17515179e6ae 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -62,6 +62,8 @@
62#include "prm44xx.h" 62#include "prm44xx.h"
63#include "prm-regbits-44xx.h" 63#include "prm-regbits-44xx.h"
64 64
65static void __iomem *sar_base;
66
65#ifdef CONFIG_SMP 67#ifdef CONFIG_SMP
66 68
67struct omap4_cpu_pm_info { 69struct omap4_cpu_pm_info {
@@ -90,7 +92,6 @@ struct cpu_pm_ops {
90 92
91static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); 93static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
92static struct powerdomain *mpuss_pd; 94static struct powerdomain *mpuss_pd;
93static void __iomem *sar_base;
94static u32 cpu_context_offset; 95static u32 cpu_context_offset;
95 96
96static int default_finish_suspend(unsigned long cpu_state) 97static int default_finish_suspend(unsigned long cpu_state)
@@ -366,9 +367,6 @@ int __init omap4_mpuss_init(void)
366 return -ENODEV; 367 return -ENODEV;
367 } 368 }
368 369
369 if (cpu_is_omap44xx())
370 sar_base = omap4_get_sar_ram_base();
371
372 /* Initilaise per CPU PM information */ 370 /* Initilaise per CPU PM information */
373 pm_info = &per_cpu(omap4_pm_info, 0x0); 371 pm_info = &per_cpu(omap4_pm_info, 0x0);
374 if (sar_base) { 372 if (sar_base) {
@@ -444,3 +442,26 @@ int __init omap4_mpuss_init(void)
444} 442}
445 443
446#endif 444#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 */
452void __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}