diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-05-03 08:31:38 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-05-07 06:31:14 -0400 |
commit | 543b9fd3528f64c4b20439de0edb453764482de7 (patch) | |
tree | 50271e7d5365b088bea63a5a2938aedf3aa87741 /arch/powerpc | |
parent | 7e11580b362fc64693de7ad5c11fbf3d1d9d0e50 (diff) |
[POWERPC] powermac: Suspend to disk on G5
Powermac G5 suspend to disk implementation. The code is platform
agnostic but only tested on powermac, no other 64-bit powerpc
machines.
Because nvidiafb still breaks suspend I have marked it EXPERIMENTAL on
powermac and because I can't test it and some lowlevel code will need
changes it is BROKEN on all other 64-bit platforms.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/Kconfig | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/idle.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/swsusp.c | 9 | ||||
-rw-r--r-- | arch/powerpc/kernel/swsusp_64.c | 24 | ||||
-rw-r--r-- | arch/powerpc/kernel/swsusp_asm64.S | 228 |
7 files changed, 273 insertions, 3 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a8e08f4b62d3..49b1ea275eba 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -126,6 +126,11 @@ config DEFAULT_UIMAGE | |||
126 | Used to allow a board to specify it wants a uImage built by default | 126 | Used to allow a board to specify it wants a uImage built by default |
127 | default n | 127 | default n |
128 | 128 | ||
129 | config PPC64_SWSUSP | ||
130 | bool | ||
131 | depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL)) | ||
132 | default y | ||
133 | |||
129 | menu "Processor support" | 134 | menu "Processor support" |
130 | choice | 135 | choice |
131 | prompt "Processor Type" | 136 | prompt "Processor Type" |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 949f36a62aae..4dc73b8c25ba 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -38,6 +38,7 @@ obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o | |||
38 | obj-$(CONFIG_TAU) += tau_6xx.o | 38 | obj-$(CONFIG_TAU) += tau_6xx.o |
39 | obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o | 39 | obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o |
40 | obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o | 40 | obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o |
41 | obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o | ||
41 | obj32-$(CONFIG_MODULES) += module_32.o | 42 | obj32-$(CONFIG_MODULES) += module_32.o |
42 | 43 | ||
43 | ifeq ($(CONFIG_PPC_MERGE),y) | 44 | ifeq ($(CONFIG_PPC_MERGE),y) |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 0c5150c69175..8f48560b7ee2 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -21,12 +21,12 @@ | |||
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/mman.h> | 22 | #include <linux/mman.h> |
23 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
24 | #include <linux/suspend.h> | ||
24 | #ifdef CONFIG_PPC64 | 25 | #ifdef CONFIG_PPC64 |
25 | #include <linux/time.h> | 26 | #include <linux/time.h> |
26 | #include <linux/hardirq.h> | 27 | #include <linux/hardirq.h> |
27 | #else | 28 | #else |
28 | #include <linux/ptrace.h> | 29 | #include <linux/ptrace.h> |
29 | #include <linux/suspend.h> | ||
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | #include <asm/io.h> | 32 | #include <asm/io.h> |
@@ -257,11 +257,11 @@ int main(void) | |||
257 | DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); | 257 | DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); |
258 | DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); | 258 | DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); |
259 | 259 | ||
260 | #ifndef CONFIG_PPC64 | ||
261 | DEFINE(pbe_address, offsetof(struct pbe, address)); | 260 | DEFINE(pbe_address, offsetof(struct pbe, address)); |
262 | DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); | 261 | DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); |
263 | DEFINE(pbe_next, offsetof(struct pbe, next)); | 262 | DEFINE(pbe_next, offsetof(struct pbe, next)); |
264 | 263 | ||
264 | #ifndef CONFIG_PPC64 | ||
265 | DEFINE(TASK_SIZE, TASK_SIZE); | 265 | DEFINE(TASK_SIZE, TASK_SIZE); |
266 | DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); | 266 | DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); |
267 | #endif /* ! CONFIG_PPC64 */ | 267 | #endif /* ! CONFIG_PPC64 */ |
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 6e7f50967bab..a9e9cbd32975 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c | |||
@@ -33,8 +33,11 @@ | |||
33 | #include <asm/smp.h> | 33 | #include <asm/smp.h> |
34 | 34 | ||
35 | #ifdef CONFIG_HOTPLUG_CPU | 35 | #ifdef CONFIG_HOTPLUG_CPU |
36 | /* this is used for software suspend, and that shuts down | ||
37 | * CPUs even while the system is still booting... */ | ||
36 | #define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \ | 38 | #define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \ |
37 | system_state == SYSTEM_RUNNING) | 39 | (system_state == SYSTEM_RUNNING \ |
40 | || system_state == SYSTEM_BOOTING)) | ||
38 | #else | 41 | #else |
39 | #define cpu_should_die() 0 | 42 | #define cpu_should_die() 0 |
40 | #endif | 43 | #endif |
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c index b89e4f5a0b08..064a7ba4f02c 100644 --- a/arch/powerpc/kernel/swsusp.c +++ b/arch/powerpc/kernel/swsusp.c | |||
@@ -24,6 +24,11 @@ void save_processor_state(void) | |||
24 | flush_fp_to_thread(current); | 24 | flush_fp_to_thread(current); |
25 | flush_altivec_to_thread(current); | 25 | flush_altivec_to_thread(current); |
26 | flush_spe_to_thread(current); | 26 | flush_spe_to_thread(current); |
27 | |||
28 | #ifdef CONFIG_PPC64 | ||
29 | hard_irq_disable(); | ||
30 | #endif | ||
31 | |||
27 | } | 32 | } |
28 | 33 | ||
29 | void restore_processor_state(void) | 34 | void restore_processor_state(void) |
@@ -31,4 +36,8 @@ void restore_processor_state(void) | |||
31 | #ifdef CONFIG_PPC32 | 36 | #ifdef CONFIG_PPC32 |
32 | set_context(current->active_mm->context.id, current->active_mm->pgd); | 37 | set_context(current->active_mm->context.id, current->active_mm->pgd); |
33 | #endif | 38 | #endif |
39 | |||
40 | #ifdef CONFIG_PPC64 | ||
41 | hard_irq_enable(); | ||
42 | #endif | ||
34 | } | 43 | } |
diff --git a/arch/powerpc/kernel/swsusp_64.c b/arch/powerpc/kernel/swsusp_64.c new file mode 100644 index 000000000000..6f3f0697274e --- /dev/null +++ b/arch/powerpc/kernel/swsusp_64.c | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * PowerPC 64-bit swsusp implementation | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPLv2 | ||
7 | */ | ||
8 | |||
9 | #include <asm/system.h> | ||
10 | #include <asm/iommu.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | |||
14 | void do_after_copyback(void) | ||
15 | { | ||
16 | iommu_restore(); | ||
17 | touch_softlockup_watchdog(); | ||
18 | mb(); | ||
19 | } | ||
20 | |||
21 | void _iommu_save(void) | ||
22 | { | ||
23 | iommu_save(); | ||
24 | } | ||
diff --git a/arch/powerpc/kernel/swsusp_asm64.S b/arch/powerpc/kernel/swsusp_asm64.S new file mode 100644 index 000000000000..e092c3cbdb9b --- /dev/null +++ b/arch/powerpc/kernel/swsusp_asm64.S | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * PowerPC 64-bit swsusp implementation | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPLv2 | ||
7 | */ | ||
8 | |||
9 | #include <linux/threads.h> | ||
10 | #include <asm/processor.h> | ||
11 | #include <asm/page.h> | ||
12 | #include <asm/cputable.h> | ||
13 | #include <asm/thread_info.h> | ||
14 | #include <asm/ppc_asm.h> | ||
15 | #include <asm/asm-offsets.h> | ||
16 | |||
17 | /* | ||
18 | * Structure for storing CPU registers on the save area. | ||
19 | */ | ||
20 | #define SL_r1 0x00 /* stack pointer */ | ||
21 | #define SL_PC 0x08 | ||
22 | #define SL_MSR 0x10 | ||
23 | #define SL_SDR1 0x18 | ||
24 | #define SL_XER 0x20 | ||
25 | #define SL_TB 0x40 | ||
26 | #define SL_r2 0x48 | ||
27 | #define SL_CR 0x50 | ||
28 | #define SL_LR 0x58 | ||
29 | #define SL_r12 0x60 | ||
30 | #define SL_r13 0x68 | ||
31 | #define SL_r14 0x70 | ||
32 | #define SL_r15 0x78 | ||
33 | #define SL_r16 0x80 | ||
34 | #define SL_r17 0x88 | ||
35 | #define SL_r18 0x90 | ||
36 | #define SL_r19 0x98 | ||
37 | #define SL_r20 0xa0 | ||
38 | #define SL_r21 0xa8 | ||
39 | #define SL_r22 0xb0 | ||
40 | #define SL_r23 0xb8 | ||
41 | #define SL_r24 0xc0 | ||
42 | #define SL_r25 0xc8 | ||
43 | #define SL_r26 0xd0 | ||
44 | #define SL_r27 0xd8 | ||
45 | #define SL_r28 0xe0 | ||
46 | #define SL_r29 0xe8 | ||
47 | #define SL_r30 0xf0 | ||
48 | #define SL_r31 0xf8 | ||
49 | #define SL_SIZE SL_r31+8 | ||
50 | |||
51 | /* these macros rely on the save area being | ||
52 | * pointed to by r11 */ | ||
53 | #define SAVE_SPECIAL(special) \ | ||
54 | mf##special r0 ;\ | ||
55 | std r0, SL_##special(r11) | ||
56 | #define RESTORE_SPECIAL(special) \ | ||
57 | ld r0, SL_##special(r11) ;\ | ||
58 | mt##special r0 | ||
59 | #define SAVE_REGISTER(reg) \ | ||
60 | std reg, SL_##reg(r11) | ||
61 | #define RESTORE_REGISTER(reg) \ | ||
62 | ld reg, SL_##reg(r11) | ||
63 | |||
64 | /* space for storing cpu state */ | ||
65 | .section .data | ||
66 | .align 5 | ||
67 | swsusp_save_area: | ||
68 | .space SL_SIZE | ||
69 | |||
70 | .section ".toc","aw" | ||
71 | swsusp_save_area_ptr: | ||
72 | .tc swsusp_save_area[TC],swsusp_save_area | ||
73 | restore_pblist_ptr: | ||
74 | .tc restore_pblist[TC],restore_pblist | ||
75 | |||
76 | .section .text | ||
77 | .align 5 | ||
78 | _GLOBAL(swsusp_arch_suspend) | ||
79 | ld r11,swsusp_save_area_ptr@toc(r2) | ||
80 | SAVE_SPECIAL(LR) | ||
81 | SAVE_REGISTER(r1) | ||
82 | SAVE_SPECIAL(CR) | ||
83 | SAVE_SPECIAL(TB) | ||
84 | SAVE_REGISTER(r2) | ||
85 | SAVE_REGISTER(r12) | ||
86 | SAVE_REGISTER(r13) | ||
87 | SAVE_REGISTER(r14) | ||
88 | SAVE_REGISTER(r15) | ||
89 | SAVE_REGISTER(r16) | ||
90 | SAVE_REGISTER(r17) | ||
91 | SAVE_REGISTER(r18) | ||
92 | SAVE_REGISTER(r19) | ||
93 | SAVE_REGISTER(r20) | ||
94 | SAVE_REGISTER(r21) | ||
95 | SAVE_REGISTER(r22) | ||
96 | SAVE_REGISTER(r23) | ||
97 | SAVE_REGISTER(r24) | ||
98 | SAVE_REGISTER(r25) | ||
99 | SAVE_REGISTER(r26) | ||
100 | SAVE_REGISTER(r27) | ||
101 | SAVE_REGISTER(r28) | ||
102 | SAVE_REGISTER(r29) | ||
103 | SAVE_REGISTER(r30) | ||
104 | SAVE_REGISTER(r31) | ||
105 | SAVE_SPECIAL(MSR) | ||
106 | SAVE_SPECIAL(SDR1) | ||
107 | SAVE_SPECIAL(XER) | ||
108 | |||
109 | /* we push the stack up 128 bytes but don't store the | ||
110 | * stack pointer on the stack like a real stackframe */ | ||
111 | addi r1,r1,-128 | ||
112 | |||
113 | bl _iommu_save | ||
114 | bl swsusp_save | ||
115 | |||
116 | /* restore LR */ | ||
117 | ld r11,swsusp_save_area_ptr@toc(r2) | ||
118 | RESTORE_SPECIAL(LR) | ||
119 | addi r1,r1,128 | ||
120 | |||
121 | blr | ||
122 | |||
123 | /* Resume code */ | ||
124 | _GLOBAL(swsusp_arch_resume) | ||
125 | /* Stop pending alitvec streams and memory accesses */ | ||
126 | BEGIN_FTR_SECTION | ||
127 | DSSALL | ||
128 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | ||
129 | sync | ||
130 | |||
131 | ld r12,restore_pblist_ptr@toc(r2) | ||
132 | ld r12,0(r12) | ||
133 | |||
134 | cmpdi r12,0 | ||
135 | beq- nothing_to_copy | ||
136 | li r15,512 | ||
137 | copyloop: | ||
138 | ld r13,pbe_address(r12) | ||
139 | ld r14,pbe_orig_address(r12) | ||
140 | |||
141 | mtctr r15 | ||
142 | li r10,0 | ||
143 | copy_page_loop: | ||
144 | ldx r0,r10,r13 | ||
145 | stdx r0,r10,r14 | ||
146 | addi r10,r10,8 | ||
147 | bdnz copy_page_loop | ||
148 | |||
149 | ld r12,pbe_next(r12) | ||
150 | cmpdi r12,0 | ||
151 | bne+ copyloop | ||
152 | nothing_to_copy: | ||
153 | |||
154 | /* flush caches */ | ||
155 | lis r3, 0x10 | ||
156 | mtctr r3 | ||
157 | li r3, 0 | ||
158 | ori r3, r3, CONFIG_KERNEL_START>>48 | ||
159 | li r0, 48 | ||
160 | sld r3, r3, r0 | ||
161 | li r0, 0 | ||
162 | 1: | ||
163 | dcbf r0,r3 | ||
164 | addi r3,r3,0x20 | ||
165 | bdnz 1b | ||
166 | |||
167 | sync | ||
168 | |||
169 | tlbia | ||
170 | |||
171 | ld r11,swsusp_save_area_ptr@toc(r2) | ||
172 | |||
173 | RESTORE_SPECIAL(CR) | ||
174 | |||
175 | /* restore timebase */ | ||
176 | /* load saved tb */ | ||
177 | ld r1, SL_TB(r11) | ||
178 | /* get upper 32 bits of it */ | ||
179 | srdi r2, r1, 32 | ||
180 | /* clear tb lower to avoid wrap */ | ||
181 | li r0, 0 | ||
182 | mttbl r0 | ||
183 | /* set tb upper */ | ||
184 | mttbu r2 | ||
185 | /* set tb lower */ | ||
186 | mttbl r1 | ||
187 | |||
188 | /* restore registers */ | ||
189 | RESTORE_REGISTER(r1) | ||
190 | RESTORE_REGISTER(r2) | ||
191 | RESTORE_REGISTER(r12) | ||
192 | RESTORE_REGISTER(r13) | ||
193 | RESTORE_REGISTER(r14) | ||
194 | RESTORE_REGISTER(r15) | ||
195 | RESTORE_REGISTER(r16) | ||
196 | RESTORE_REGISTER(r17) | ||
197 | RESTORE_REGISTER(r18) | ||
198 | RESTORE_REGISTER(r19) | ||
199 | RESTORE_REGISTER(r20) | ||
200 | RESTORE_REGISTER(r21) | ||
201 | RESTORE_REGISTER(r22) | ||
202 | RESTORE_REGISTER(r23) | ||
203 | RESTORE_REGISTER(r24) | ||
204 | RESTORE_REGISTER(r25) | ||
205 | RESTORE_REGISTER(r26) | ||
206 | RESTORE_REGISTER(r27) | ||
207 | RESTORE_REGISTER(r28) | ||
208 | RESTORE_REGISTER(r29) | ||
209 | RESTORE_REGISTER(r30) | ||
210 | RESTORE_REGISTER(r31) | ||
211 | /* can't use RESTORE_SPECIAL(MSR) */ | ||
212 | ld r0, SL_MSR(r11) | ||
213 | mtmsrd r0, 0 | ||
214 | RESTORE_SPECIAL(SDR1) | ||
215 | RESTORE_SPECIAL(XER) | ||
216 | |||
217 | sync | ||
218 | |||
219 | addi r1,r1,-128 | ||
220 | bl slb_flush_and_rebolt | ||
221 | bl do_after_copyback | ||
222 | addi r1,r1,128 | ||
223 | |||
224 | ld r11,swsusp_save_area_ptr@toc(r2) | ||
225 | RESTORE_SPECIAL(LR) | ||
226 | |||
227 | li r3, 0 | ||
228 | blr | ||