ARM: pm: allow suspend finisher to return error codes
authorRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 2 Jul 2011 08:54:01 +0000 (09:54 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 2 Jul 2011 08:54:01 +0000 (09:54 +0100)
There are SoCs where attempting to enter a low power state is ignored,
and the CPU continues executing instructions with all state preserved.
It is over-complex at that point to disable the MMU just to call the
resume path.

Instead, allow the suspend finisher to return error codes to abort
suspend in this circumstance, where the cpu_suspend internals will then
unwind the saved state on the stack.  Also omit the tlb flush as no
changes to the page tables will have happened.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
12 files changed:
arch/arm/include/asm/suspend.h
arch/arm/kernel/sleep.S
arch/arm/mach-exynos4/pm.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-pxa/include/mach/pm.h
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-s3c2412/pm.c
arch/arm/mach-s3c2416/pm.c
arch/arm/mach-s3c64xx/pm.c
arch/arm/mach-sa1100/pm.c
arch/arm/plat-samsung/include/plat/pm.h
arch/arm/plat-samsung/pm.c

index f8db9d096bc70d82d511a426d2f151d250a7421c..b0e4e1a0231870c45d14bea0a9178d701737b673 100644 (file)
@@ -10,12 +10,13 @@ extern void cpu_resume(void);
  * Hide the first two arguments to __cpu_suspend - these are an implementation
  * detail which platform code shouldn't have to know about.
  */
-static inline void cpu_suspend(unsigned long arg, void (*fn)(unsigned long))
+static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
 {
-       extern void __cpu_suspend(int, long, unsigned long,
-                                 void (*)(unsigned long));
-       __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn);
+       extern int __cpu_suspend(int, long, unsigned long,
+                                int (*)(unsigned long));
+       int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn);
        flush_tlb_all();
+       return ret;
 }
 
 #endif
index c156d0e5f455399fb3f2e52c46a1cf7ba5869706..dc902f2c68457b0f3277b8112a7a1e867106cde8 100644 (file)
@@ -12,7 +12,6 @@
  *  r1 = v:p offset
  *  r2 = suspend function arg0
  *  r3 = suspend function
- * Note: does not return until system resumes
  */
 ENTRY(__cpu_suspend)
        stmfd   sp!, {r4 - r11, lr}
@@ -26,7 +25,7 @@ ENTRY(__cpu_suspend)
 #endif
        mov     r6, sp                  @ current virtual SP
        sub     sp, sp, r5              @ allocate CPU state on stack
-       mov     r0, sp                  @ save pointer
+       mov     r0, sp                  @ save pointer to CPU save block
        add     ip, ip, r1              @ convert resume fn to phys
        stmfd   sp!, {r1, r6, ip}       @ save v:p, virt SP, phys resume fn
        ldr     r5, =sleep_save_sp
@@ -55,10 +54,17 @@ ENTRY(__cpu_suspend)
 #else
        bl      __cpuc_flush_kern_all
 #endif
+       adr     lr, BSYM(cpu_suspend_abort)
        ldmfd   sp!, {r0, pc}           @ call suspend fn
 ENDPROC(__cpu_suspend)
        .ltorg
 
+cpu_suspend_abort:
+       ldmia   sp!, {r1 - r3}          @ pop v:p, virt SP, phys resume fn
+       mov     sp, r2
+       ldmfd   sp!, {r4 - r11, pc}
+ENDPROC(cpu_suspend_abort)
+
 /*
  * r0 = control register value
  * r1 = v:p offset (preserved by cpu_do_resume)
@@ -89,6 +95,7 @@ cpu_resume_after_mmu:
        str     r5, [r2, r4, lsl #2]    @ restore old mapping
        mcr     p15, 0, r0, c1, c0, 0   @ turn on D-cache
        bl      cpu_init                @ restore the und/abt/irq banked regs
+       mov     r0, #0                  @ return zero on success
        ldmfd   sp!, {r4 - r11, pc}
 ENDPROC(cpu_resume_after_mmu)
 
index 5c01c6076645a78c6a5d579d64e49645bc9aee8e..533c28f758ca437ba8f6ca2570a4ba006dca6e45 100644 (file)
@@ -280,7 +280,7 @@ static struct sleep_save exynos4_l2cc_save[] = {
        SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL),
 };
 
-void exynos4_cpu_suspend(unsigned long arg)
+static int exynos4_cpu_suspend(unsigned long arg)
 {
        unsigned long tmp;
        unsigned long mask = 0xFFFFFFFF;
index 7238a63e24e2d9d12ea387489307cbf7225396d6..b77d82665abb51a18b0dd663d51f731f81fd2354 100644 (file)
@@ -321,9 +321,10 @@ static void omap34xx_save_context(u32 *save)
        *save++ = val;
 }
 
-static void omap34xx_do_sram_idle(unsigned long save_state)
+static int omap34xx_do_sram_idle(unsigned long save_state)
 {
        omap34xx_cpu_suspend(save_state);
+       return 0;
 }
 
 void omap_sram_idle(void)
index a566720527cf24912a940a2bb01ecf16c52400c8..51558bcee999e949e32500e661b0a016a34da283 100644 (file)
@@ -22,8 +22,8 @@ struct pxa_cpu_pm_fns {
 extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
 
 /* sleep.S */
-extern void pxa25x_finish_suspend(unsigned long);
-extern void pxa27x_finish_suspend(unsigned long);
+extern int pxa25x_finish_suspend(unsigned long);
+extern int pxa27x_finish_suspend(unsigned long);
 
 extern int pxa_pm_enter(suspend_state_t state);
 extern int pxa_pm_prepare(void);
index 9fe947b5d5f7de9967852ff473a48fb97d1724fd..ef1c56a67afcbd0ebcdfc70ab7c078e7b256ea11 100644 (file)
@@ -148,7 +148,7 @@ static void pxa3xx_cpu_pm_suspend(void)
        asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0));
 #endif
 
-       extern void pxa3xx_finish_suspend(unsigned long);
+       extern int pxa3xx_finish_suspend(unsigned long);
 
        /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
        CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
index 9a1fb898db53288d272760259dbc0daa61f7872b..f4077efa51fa4d4b4a2f7550c8298cc392cd9010 100644 (file)
@@ -37,7 +37,7 @@
 
 extern void s3c2412_sleep_enter(void);
 
-static void s3c2412_cpu_suspend(unsigned long arg)
+static int s3c2412_cpu_suspend(unsigned long arg)
 {
        unsigned long tmp;
 
@@ -48,6 +48,8 @@ static void s3c2412_cpu_suspend(unsigned long arg)
        __raw_writel(tmp, S3C2412_PWRCFG);
 
        s3c2412_sleep_enter();
+
+       panic("sleep resumed to originator?");
 }
 
 static void s3c2412_pm_prepare(void)
index 9e67a2a07a8654eeac06bbe1d845fa3cdf68e4f4..9ec54f1d8e75349a665f5cd1dcd40742da7d1808 100644 (file)
@@ -24,7 +24,7 @@
 
 extern void s3c2412_sleep_enter(void);
 
-static void s3c2416_cpu_suspend(unsigned long arg)
+static int s3c2416_cpu_suspend(unsigned long arg)
 {
        /* enable wakeup sources regardless of battery state */
        __raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG);
@@ -33,6 +33,8 @@ static void s3c2416_cpu_suspend(unsigned long arg)
        __raw_writel(0x2BED, S3C2443_PWRMODE);
 
        s3c2412_sleep_enter();
+
+       panic("sleep resumed to originator?");
 }
 
 static void s3c2416_pm_prepare(void)
index 7cc1879af722510d01cc70ee0c4aada0fcde3e1a..8bad64370689b4163501631e3b7fc85f7e184510 100644 (file)
@@ -112,7 +112,7 @@ void s3c_pm_save_core(void)
  * this.
  */
 
-static void s3c64xx_cpu_suspend(unsigned long arg)
+static int s3c64xx_cpu_suspend(unsigned long arg)
 {
        unsigned long tmp;
 
index cf9a1e9fb70dc33bd569ec87ba63878d29156e58..bf85b8b259d5b08a1f2b8e61f9a8792a800298f3 100644 (file)
@@ -33,7 +33,7 @@
 #include <asm/system.h>
 #include <asm/mach/time.h>
 
-extern void sa1100_finish_suspend(unsigned long);
+extern int sa1100_finish_suspend(unsigned long);
 
 #define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
 #define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
index 0a5b7faca83631d6af73b0be0b1c03e98d306716..f6749916d194b8d1e2a2e0a59cc35ccfa44ded16 100644 (file)
@@ -42,7 +42,7 @@ extern unsigned long s3c_irqwake_eintallow;
 /* per-cpu sleep functions */
 
 extern void (*pm_cpu_prep)(void);
-extern void (*pm_cpu_sleep)(unsigned long);
+extern int (*pm_cpu_sleep)(unsigned long);
 
 /* Flags for PM Control */
 
@@ -54,7 +54,7 @@ extern unsigned char pm_uart_udivslot;  /* true to save UART UDIVSLOT */
 
 extern void s3c_cpu_resume(void);
 
-extern void s3c2410_cpu_suspend(unsigned long);
+extern int s3c2410_cpu_suspend(unsigned long);
 
 /* sleep save info */
 
index 69d6b040a019cbe0535b7f4d5f8cc6229e520d74..5fa1742d019bed872067426b1e1a16452eb32217 100644 (file)
@@ -232,7 +232,7 @@ static void __maybe_unused s3c_pm_show_resume_irqs(int start,
 
 
 void (*pm_cpu_prep)(void);
-void (*pm_cpu_sleep)(unsigned long);
+int (*pm_cpu_sleep)(unsigned long);
 
 #define any_allowed(mask, allow) (((mask) & (allow)) != (allow))