Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: pm: allow suspend finisher to return error codes

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>

+31 -18
+5 -4
arch/arm/include/asm/suspend.h
··· 10 10 * Hide the first two arguments to __cpu_suspend - these are an implementation 11 11 * detail which platform code shouldn't have to know about. 12 12 */ 13 - static inline void cpu_suspend(unsigned long arg, void (*fn)(unsigned long)) 13 + static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) 14 14 { 15 - extern void __cpu_suspend(int, long, unsigned long, 16 - void (*)(unsigned long)); 17 - __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); 15 + extern int __cpu_suspend(int, long, unsigned long, 16 + int (*)(unsigned long)); 17 + int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); 18 18 flush_tlb_all(); 19 + return ret; 19 20 } 20 21 21 22 #endif
+9 -2
arch/arm/kernel/sleep.S
··· 12 12 * r1 = v:p offset 13 13 * r2 = suspend function arg0 14 14 * r3 = suspend function 15 - * Note: does not return until system resumes 16 15 */ 17 16 ENTRY(__cpu_suspend) 18 17 stmfd sp!, {r4 - r11, lr} ··· 25 26 #endif 26 27 mov r6, sp @ current virtual SP 27 28 sub sp, sp, r5 @ allocate CPU state on stack 28 - mov r0, sp @ save pointer 29 + mov r0, sp @ save pointer to CPU save block 29 30 add ip, ip, r1 @ convert resume fn to phys 30 31 stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn 31 32 ldr r5, =sleep_save_sp ··· 54 55 #else 55 56 bl __cpuc_flush_kern_all 56 57 #endif 58 + adr lr, BSYM(cpu_suspend_abort) 57 59 ldmfd sp!, {r0, pc} @ call suspend fn 58 60 ENDPROC(__cpu_suspend) 59 61 .ltorg 62 + 63 + cpu_suspend_abort: 64 + ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn 65 + mov sp, r2 66 + ldmfd sp!, {r4 - r11, pc} 67 + ENDPROC(cpu_suspend_abort) 60 68 61 69 /* 62 70 * r0 = control register value ··· 95 89 str r5, [r2, r4, lsl #2] @ restore old mapping 96 90 mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache 97 91 bl cpu_init @ restore the und/abt/irq banked regs 92 + mov r0, #0 @ return zero on success 98 93 ldmfd sp!, {r4 - r11, pc} 99 94 ENDPROC(cpu_resume_after_mmu) 100 95
+1 -1
arch/arm/mach-exynos4/pm.c
··· 280 280 SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL), 281 281 }; 282 282 283 - void exynos4_cpu_suspend(unsigned long arg) 283 + static int exynos4_cpu_suspend(unsigned long arg) 284 284 { 285 285 unsigned long tmp; 286 286 unsigned long mask = 0xFFFFFFFF;
+2 -1
arch/arm/mach-omap2/pm34xx.c
··· 321 321 *save++ = val; 322 322 } 323 323 324 - static void omap34xx_do_sram_idle(unsigned long save_state) 324 + static int omap34xx_do_sram_idle(unsigned long save_state) 325 325 { 326 326 omap34xx_cpu_suspend(save_state); 327 + return 0; 327 328 } 328 329 329 330 void omap_sram_idle(void)
+2 -2
arch/arm/mach-pxa/include/mach/pm.h
··· 22 22 extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns; 23 23 24 24 /* sleep.S */ 25 - extern void pxa25x_finish_suspend(unsigned long); 26 - extern void pxa27x_finish_suspend(unsigned long); 25 + extern int pxa25x_finish_suspend(unsigned long); 26 + extern int pxa27x_finish_suspend(unsigned long); 27 27 28 28 extern int pxa_pm_enter(suspend_state_t state); 29 29 extern int pxa_pm_prepare(void);
+1 -1
arch/arm/mach-pxa/pxa3xx.c
··· 148 148 asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0)); 149 149 #endif 150 150 151 - extern void pxa3xx_finish_suspend(unsigned long); 151 + extern int pxa3xx_finish_suspend(unsigned long); 152 152 153 153 /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */ 154 154 CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
+3 -1
arch/arm/mach-s3c2412/pm.c
··· 37 37 38 38 extern void s3c2412_sleep_enter(void); 39 39 40 - static void s3c2412_cpu_suspend(unsigned long arg) 40 + static int s3c2412_cpu_suspend(unsigned long arg) 41 41 { 42 42 unsigned long tmp; 43 43 ··· 48 48 __raw_writel(tmp, S3C2412_PWRCFG); 49 49 50 50 s3c2412_sleep_enter(); 51 + 52 + panic("sleep resumed to originator?"); 51 53 } 52 54 53 55 static void s3c2412_pm_prepare(void)
+3 -1
arch/arm/mach-s3c2416/pm.c
··· 24 24 25 25 extern void s3c2412_sleep_enter(void); 26 26 27 - static void s3c2416_cpu_suspend(unsigned long arg) 27 + static int s3c2416_cpu_suspend(unsigned long arg) 28 28 { 29 29 /* enable wakeup sources regardless of battery state */ 30 30 __raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG); ··· 33 33 __raw_writel(0x2BED, S3C2443_PWRMODE); 34 34 35 35 s3c2412_sleep_enter(); 36 + 37 + panic("sleep resumed to originator?"); 36 38 } 37 39 38 40 static void s3c2416_pm_prepare(void)
+1 -1
arch/arm/mach-s3c64xx/pm.c
··· 112 112 * this. 113 113 */ 114 114 115 - static void s3c64xx_cpu_suspend(unsigned long arg) 115 + static int s3c64xx_cpu_suspend(unsigned long arg) 116 116 { 117 117 unsigned long tmp; 118 118
+1 -1
arch/arm/mach-sa1100/pm.c
··· 33 33 #include <asm/system.h> 34 34 #include <asm/mach/time.h> 35 35 36 - extern void sa1100_finish_suspend(unsigned long); 36 + extern int sa1100_finish_suspend(unsigned long); 37 37 38 38 #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x 39 39 #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
+2 -2
arch/arm/plat-samsung/include/plat/pm.h
··· 42 42 /* per-cpu sleep functions */ 43 43 44 44 extern void (*pm_cpu_prep)(void); 45 - extern void (*pm_cpu_sleep)(unsigned long); 45 + extern int (*pm_cpu_sleep)(unsigned long); 46 46 47 47 /* Flags for PM Control */ 48 48 ··· 54 54 55 55 extern void s3c_cpu_resume(void); 56 56 57 - extern void s3c2410_cpu_suspend(unsigned long); 57 + extern int s3c2410_cpu_suspend(unsigned long); 58 58 59 59 /* sleep save info */ 60 60
+1 -1
arch/arm/plat-samsung/pm.c
··· 232 232 233 233 234 234 void (*pm_cpu_prep)(void); 235 - void (*pm_cpu_sleep)(unsigned long); 235 + int (*pm_cpu_sleep)(unsigned long); 236 236 237 237 #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) 238 238