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

sh: hibernation support

Add Suspend-to-disk / swsusp / CONFIG_HIBERNATION support
to the SuperH architecture.

To suspend, use "swapon /dev/sda2; echo disk > /sys/power/state"
To resume, pass "resume=/dev/sda2" on the kernel command line.

The patch "pm: rework includes, remove arch ifdefs V2" is
needed to allow the generic swsusp code to build properly.

Hibernation is not enabled with this patch though, a patch
setting ARCH_HIBERNATION_POSSIBLE will be submitted later.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

authored by

Magnus Damm and committed by
Paul Mundt
2ef7f0da edab56f4

+228 -5
+1
arch/sh/include/asm/sections.h
··· 3 3 4 4 #include <asm-generic/sections.h> 5 5 6 + extern void __nosave_begin, __nosave_end; 6 7 extern long __machvec_start, __machvec_end; 7 8 extern char __uncached_start, __uncached_end; 8 9 extern char _ebss[];
+13
arch/sh/include/asm/suspend.h
··· 1 + #ifndef _ASM_SH_SUSPEND_H 2 + #define _ASM_SH_SUSPEND_H 3 + 4 + static inline int arch_prepare_suspend(void) { return 0; } 5 + 6 + #include <asm/ptrace.h> 7 + 8 + struct swsusp_arch_regs { 9 + struct pt_regs user_regs; 10 + unsigned long bank1_regs[8]; 11 + }; 12 + 13 + #endif /* _ASM_SH_SUSPEND_H */
+1
arch/sh/kernel/Makefile_32
··· 30 30 obj-$(CONFIG_GENERIC_GPIO) += gpio.o 31 31 obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o 32 32 obj-$(CONFIG_DUMP_CODE) += disassemble.o 33 + obj-$(CONFIG_HIBERNATION) += swsusp.o 33 34 34 35 EXTRA_CFLAGS += -Werror
+8
arch/sh/kernel/asm-offsets.c
··· 12 12 #include <linux/types.h> 13 13 #include <linux/mm.h> 14 14 #include <linux/kbuild.h> 15 + #include <linux/suspend.h> 15 16 16 17 #include <asm/thread_info.h> 18 + #include <asm/suspend.h> 17 19 18 20 int main(void) 19 21 { ··· 27 25 DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count)); 28 26 DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block)); 29 27 28 + #ifdef CONFIG_HIBERNATION 29 + DEFINE(PBE_ADDRESS, offsetof(struct pbe, address)); 30 + DEFINE(PBE_ORIG_ADDRESS, offsetof(struct pbe, orig_address)); 31 + DEFINE(PBE_NEXT, offsetof(struct pbe, next)); 32 + DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs)); 33 + #endif 30 34 return 0; 31 35 }
+2
arch/sh/kernel/cpu/sh3/Makefile
··· 4 4 5 5 obj-y := ex.o probe.o entry.o setup-sh3.o 6 6 7 + obj-$(CONFIG_HIBERNATION) += swsusp.o 8 + 7 9 # CPU subtype setup 8 10 obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o 9 11 obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh770x.o
+17 -5
arch/sh/kernel/cpu/sh3/entry.S
··· 216 216 ! r9 trashed 217 217 ! BL=0 on entry, on exit BL=1 (depending on r8). 218 218 219 - restore_regs: 219 + ENTRY(restore_regs) 220 220 mov.l @r15+, r0 221 221 mov.l @r15+, r1 222 222 mov.l @r15+, r2 ··· 362 362 nop 363 363 364 364 ! Save registers / Switch to bank 0 365 + mov.l k4, k2 ! keep vector in k2 366 + mov.l 1f, k4 ! SR bits to clear in k4 365 367 bsr save_regs ! needs original pr value in k3 366 - mov k4, k2 ! keep vector in k2 368 + nop 367 369 368 370 bra handle_exception_special 369 371 nop ··· 473 471 474 472 ! Save registers / Switch to bank 0 475 473 mov.l 5f, k2 ! vector register address 474 + mov.l 1f, k4 ! SR bits to clear in k4 476 475 bsr save_regs ! needs original pr value in k3 477 476 mov.l @k2, k2 ! read out vector and keep in k2 478 477 ··· 498 495 ! k0 contains original stack pointer* 499 496 ! k1 trashed 500 497 ! k3 passes original pr* 501 - ! k4 trashed 498 + ! k4 passes SR bitmask 502 499 ! BL=1 on entry, on exit BL=0. 503 500 504 - save_regs: 501 + ENTRY(save_regs) 505 502 mov #-1, r1 506 503 mov.l k1, @-r15 ! set TRA (default: -1) 507 504 sts.l macl, @-r15 ··· 521 518 mov.l r8, @-r15 522 519 523 520 mov.l 0f, k3 ! SR bits to set in k3 524 - mov.l 1f, k4 ! SR bits to clear in k4 525 521 522 + ! fall-through 523 + 524 + ! save_low_regs() 525 + ! - modify SR for bank switch 526 + ! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack 527 + ! k3 passes bits to set in SR 528 + ! k4 passes bits to clear in SR 529 + 530 + ENTRY(save_low_regs) 526 531 stc sr, r8 527 532 or k3, r8 528 533 and k4, r8 ··· 576 565 PREF(k0) 577 566 578 567 ! Save registers / Switch to bank 0 568 + mov.l 1f, k4 ! SR bits to clear in k4 579 569 bsr save_regs ! needs original pr value in k3 580 570 mov #-1, k2 ! default vector kept in k2 581 571
+147
arch/sh/kernel/cpu/sh3/swsusp.S
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh3/swsusp.S 3 + * 4 + * Copyright (C) 2009 Magnus Damm 5 + * 6 + * This file is subject to the terms and conditions of the GNU General Public 7 + * License. See the file "COPYING" in the main directory of this archive 8 + * for more details. 9 + */ 10 + #include <linux/sys.h> 11 + #include <linux/errno.h> 12 + #include <linux/linkage.h> 13 + #include <asm/asm-offsets.h> 14 + #include <asm/page.h> 15 + 16 + #define k0 r0 17 + #define k1 r1 18 + #define k2 r2 19 + #define k3 r3 20 + #define k4 r4 21 + 22 + ! swsusp_arch_resume() 23 + ! - copy restore_pblist pages 24 + ! - restore registers from swsusp_arch_regs_cpu0 25 + 26 + ENTRY(swsusp_arch_resume) 27 + mov.l 1f, r15 28 + mov.l 2f, r4 29 + mov.l @r4, r4 30 + 31 + swsusp_copy_loop: 32 + mov r4, r0 33 + cmp/eq #0, r0 34 + bt swsusp_restore_regs 35 + 36 + mov.l @(PBE_ADDRESS, r4), r2 37 + mov.l @(PBE_ORIG_ADDRESS, r4), r5 38 + 39 + mov #(PAGE_SIZE >> 10), r3 40 + shll8 r3 41 + shlr2 r3 /* PAGE_SIZE / 16 */ 42 + swsusp_copy_page: 43 + dt r3 44 + mov.l @r2+,r1 /* 16n+0 */ 45 + mov.l r1,@r5 46 + add #4,r5 47 + mov.l @r2+,r1 /* 16n+4 */ 48 + mov.l r1,@r5 49 + add #4,r5 50 + mov.l @r2+,r1 /* 16n+8 */ 51 + mov.l r1,@r5 52 + add #4,r5 53 + mov.l @r2+,r1 /* 16n+12 */ 54 + mov.l r1,@r5 55 + bf/s swsusp_copy_page 56 + add #4,r5 57 + 58 + bra swsusp_copy_loop 59 + mov.l @(PBE_NEXT, r4), r4 60 + 61 + swsusp_restore_regs: 62 + ! BL=0: R7->R0 is bank0 63 + mov.l 3f, r8 64 + mov.l 4f, r5 65 + jsr @r5 66 + nop 67 + 68 + ! BL=1: R7->R0 is bank1 69 + lds k2, pr 70 + ldc k3, ssr 71 + 72 + mov.l @r15+, r0 73 + mov.l @r15+, r1 74 + mov.l @r15+, r2 75 + mov.l @r15+, r3 76 + mov.l @r15+, r4 77 + mov.l @r15+, r5 78 + mov.l @r15+, r6 79 + mov.l @r15+, r7 80 + 81 + rte 82 + nop 83 + ! BL=0: R7->R0 is bank0 84 + 85 + .align 2 86 + 1: .long swsusp_arch_regs_cpu0 87 + 2: .long restore_pblist 88 + 3: .long 0x20000000 ! RB=1 89 + 4: .long restore_regs 90 + 91 + ! swsusp_arch_suspend() 92 + ! - prepare pc for resume, return from function without swsusp_save on resume 93 + ! - save registers in swsusp_arch_regs_cpu0 94 + ! - call swsusp_save write suspend image 95 + 96 + ENTRY(swsusp_arch_suspend) 97 + sts pr, r0 ! save pr in r0 98 + mov r15, r2 ! save sp in r2 99 + mov r8, r5 ! save r8 in r5 100 + stc sr, r1 101 + ldc r1, ssr ! save sr in ssr 102 + mov.l 1f, r1 103 + ldc r1, spc ! setup pc value for resuming 104 + mov.l 5f, r15 ! use swsusp_arch_regs_cpu0 as stack 105 + mov.l 6f, r3 106 + add r3, r15 ! save from top of structure 107 + 108 + ! BL=0: R7->R0 is bank0 109 + mov.l 2f, r3 ! get new SR value for bank1 110 + mov #0, r4 111 + mov.l 7f, r1 112 + jsr @r1 ! switch to bank1 and save bank1 r7->r0 113 + not r4, r4 114 + 115 + ! BL=1: R7->R0 is bank1 116 + stc r2_bank, k0 ! fetch old sp from r2_bank0 117 + mov.l 3f, k4 ! SR bits to clear in k4 118 + mov.l 8f, k1 119 + jsr @k1 ! switch to bank0 and save all regs 120 + stc r0_bank, k3 ! fetch old pr from r0_bank0 121 + 122 + ! BL=0: R7->R0 is bank0 123 + mov r2, r15 ! restore old sp 124 + mov r5, r8 ! restore old r8 125 + stc ssr, r1 126 + ldc r1, sr ! restore old sr 127 + lds r0, pr ! restore old pr 128 + mov.l 4f, r0 129 + jmp @r0 130 + nop 131 + 132 + swsusp_call_save: 133 + mov r2, r15 ! restore old sp 134 + mov r5, r8 ! restore old r8 135 + lds r0, pr ! restore old pr 136 + rts 137 + mov #0, r0 138 + 139 + .align 2 140 + 1: .long swsusp_call_save 141 + 2: .long 0x20000000 ! RB=1 142 + 3: .long 0xdfffffff ! RB=0 143 + 4: .long swsusp_save 144 + 5: .long swsusp_arch_regs_cpu0 145 + 6: .long SWSUSP_ARCH_REGS_SIZE 146 + 7: .long save_low_regs 147 + 8: .long save_regs
+1
arch/sh/kernel/cpu/sh4/Makefile
··· 5 5 obj-y := probe.o common.o 6 6 common-y += $(addprefix ../sh3/, entry.o ex.o) 7 7 8 + obj-$(CONFIG_HIBERNATION) += $(addprefix ../sh3/, swsusp.o) 8 9 obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o 9 10 obj-$(CONFIG_SH_STORE_QUEUES) += sq.o 10 11
+38
arch/sh/kernel/swsusp.c
··· 1 + /* 2 + * swsusp.c - SuperH hibernation support 3 + * 4 + * Copyright (C) 2009 Magnus Damm 5 + * 6 + * This file is subject to the terms and conditions of the GNU General Public 7 + * License. See the file "COPYING" in the main directory of this archive 8 + * for more details. 9 + */ 10 + 11 + #include <linux/mm.h> 12 + #include <linux/sched.h> 13 + #include <linux/suspend.h> 14 + #include <asm/suspend.h> 15 + #include <asm/sections.h> 16 + #include <asm/tlbflush.h> 17 + #include <asm/page.h> 18 + #include <asm/fpu.h> 19 + 20 + struct swsusp_arch_regs swsusp_arch_regs_cpu0; 21 + 22 + int pfn_is_nosave(unsigned long pfn) 23 + { 24 + unsigned long begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; 25 + unsigned long end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT; 26 + 27 + return (pfn >= begin_pfn) && (pfn < end_pfn); 28 + } 29 + 30 + void save_processor_state(void) 31 + { 32 + init_fpu(current); 33 + } 34 + 35 + void restore_processor_state(void) 36 + { 37 + local_flush_tlb_all(); 38 + }