aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-05-03 08:31:38 -0400
committerPaul Mackerras <paulus@samba.org>2007-05-07 06:31:14 -0400
commit543b9fd3528f64c4b20439de0edb453764482de7 (patch)
tree50271e7d5365b088bea63a5a2938aedf3aa87741 /arch/powerpc
parent7e11580b362fc64693de7ad5c11fbf3d1d9d0e50 (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/Kconfig5
-rw-r--r--arch/powerpc/kernel/Makefile1
-rw-r--r--arch/powerpc/kernel/asm-offsets.c4
-rw-r--r--arch/powerpc/kernel/idle.c5
-rw-r--r--arch/powerpc/kernel/swsusp.c9
-rw-r--r--arch/powerpc/kernel/swsusp_64.c24
-rw-r--r--arch/powerpc/kernel/swsusp_asm64.S228
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
129config PPC64_SWSUSP
130 bool
131 depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
132 default y
133
129menu "Processor support" 134menu "Processor support"
130choice 135choice
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
38obj-$(CONFIG_TAU) += tau_6xx.o 38obj-$(CONFIG_TAU) += tau_6xx.o
39obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o 39obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
40obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o 40obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
41obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o
41obj32-$(CONFIG_MODULES) += module_32.o 42obj32-$(CONFIG_MODULES) += module_32.o
42 43
43ifeq ($(CONFIG_PPC_MERGE),y) 44ifeq ($(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
29void restore_processor_state(void) 34void 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
14void do_after_copyback(void)
15{
16 iommu_restore();
17 touch_softlockup_watchdog();
18 mb();
19}
20
21void _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
67swsusp_save_area:
68 .space SL_SIZE
69
70 .section ".toc","aw"
71swsusp_save_area_ptr:
72 .tc swsusp_save_area[TC],swsusp_save_area
73restore_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 */
126BEGIN_FTR_SECTION
127 DSSALL
128END_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
137copyloop:
138 ld r13,pbe_address(r12)
139 ld r14,pbe_orig_address(r12)
140
141 mtctr r15
142 li r10,0
143copy_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
152nothing_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
1621:
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