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/kernel/swsusp_asm64.S | |
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/kernel/swsusp_asm64.S')
-rw-r--r-- | arch/powerpc/kernel/swsusp_asm64.S | 228 |
1 files changed, 228 insertions, 0 deletions
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 | ||