diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/kernel/swsusp.S |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc/kernel/swsusp.S')
-rw-r--r-- | arch/ppc/kernel/swsusp.S | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/arch/ppc/kernel/swsusp.S b/arch/ppc/kernel/swsusp.S new file mode 100644 index 000000000000..55148bb88d39 --- /dev/null +++ b/arch/ppc/kernel/swsusp.S | |||
@@ -0,0 +1,349 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/threads.h> | ||
3 | #include <asm/processor.h> | ||
4 | #include <asm/page.h> | ||
5 | #include <asm/cputable.h> | ||
6 | #include <asm/thread_info.h> | ||
7 | #include <asm/ppc_asm.h> | ||
8 | #include <asm/offsets.h> | ||
9 | |||
10 | |||
11 | /* | ||
12 | * Structure for storing CPU registers on the save area. | ||
13 | */ | ||
14 | #define SL_SP 0 | ||
15 | #define SL_PC 4 | ||
16 | #define SL_MSR 8 | ||
17 | #define SL_SDR1 0xc | ||
18 | #define SL_SPRG0 0x10 /* 4 sprg's */ | ||
19 | #define SL_DBAT0 0x20 | ||
20 | #define SL_IBAT0 0x28 | ||
21 | #define SL_DBAT1 0x30 | ||
22 | #define SL_IBAT1 0x38 | ||
23 | #define SL_DBAT2 0x40 | ||
24 | #define SL_IBAT2 0x48 | ||
25 | #define SL_DBAT3 0x50 | ||
26 | #define SL_IBAT3 0x58 | ||
27 | #define SL_TB 0x60 | ||
28 | #define SL_R2 0x68 | ||
29 | #define SL_CR 0x6c | ||
30 | #define SL_LR 0x70 | ||
31 | #define SL_R12 0x74 /* r12 to r31 */ | ||
32 | #define SL_SIZE (SL_R12 + 80) | ||
33 | |||
34 | .section .data | ||
35 | .align 5 | ||
36 | |||
37 | _GLOBAL(swsusp_save_area) | ||
38 | .space SL_SIZE | ||
39 | |||
40 | |||
41 | .section .text | ||
42 | .align 5 | ||
43 | |||
44 | _GLOBAL(swsusp_arch_suspend) | ||
45 | |||
46 | lis r11,swsusp_save_area@h | ||
47 | ori r11,r11,swsusp_save_area@l | ||
48 | |||
49 | mflr r0 | ||
50 | stw r0,SL_LR(r11) | ||
51 | mfcr r0 | ||
52 | stw r0,SL_CR(r11) | ||
53 | stw r1,SL_SP(r11) | ||
54 | stw r2,SL_R2(r11) | ||
55 | stmw r12,SL_R12(r11) | ||
56 | |||
57 | /* Save MSR & SDR1 */ | ||
58 | mfmsr r4 | ||
59 | stw r4,SL_MSR(r11) | ||
60 | mfsdr1 r4 | ||
61 | stw r4,SL_SDR1(r11) | ||
62 | |||
63 | /* Get a stable timebase and save it */ | ||
64 | 1: mftbu r4 | ||
65 | stw r4,SL_TB(r11) | ||
66 | mftb r5 | ||
67 | stw r5,SL_TB+4(r11) | ||
68 | mftbu r3 | ||
69 | cmpw r3,r4 | ||
70 | bne 1b | ||
71 | |||
72 | /* Save SPRGs */ | ||
73 | mfsprg r4,0 | ||
74 | stw r4,SL_SPRG0(r11) | ||
75 | mfsprg r4,1 | ||
76 | stw r4,SL_SPRG0+4(r11) | ||
77 | mfsprg r4,2 | ||
78 | stw r4,SL_SPRG0+8(r11) | ||
79 | mfsprg r4,3 | ||
80 | stw r4,SL_SPRG0+12(r11) | ||
81 | |||
82 | /* Save BATs */ | ||
83 | mfdbatu r4,0 | ||
84 | stw r4,SL_DBAT0(r11) | ||
85 | mfdbatl r4,0 | ||
86 | stw r4,SL_DBAT0+4(r11) | ||
87 | mfdbatu r4,1 | ||
88 | stw r4,SL_DBAT1(r11) | ||
89 | mfdbatl r4,1 | ||
90 | stw r4,SL_DBAT1+4(r11) | ||
91 | mfdbatu r4,2 | ||
92 | stw r4,SL_DBAT2(r11) | ||
93 | mfdbatl r4,2 | ||
94 | stw r4,SL_DBAT2+4(r11) | ||
95 | mfdbatu r4,3 | ||
96 | stw r4,SL_DBAT3(r11) | ||
97 | mfdbatl r4,3 | ||
98 | stw r4,SL_DBAT3+4(r11) | ||
99 | mfibatu r4,0 | ||
100 | stw r4,SL_IBAT0(r11) | ||
101 | mfibatl r4,0 | ||
102 | stw r4,SL_IBAT0+4(r11) | ||
103 | mfibatu r4,1 | ||
104 | stw r4,SL_IBAT1(r11) | ||
105 | mfibatl r4,1 | ||
106 | stw r4,SL_IBAT1+4(r11) | ||
107 | mfibatu r4,2 | ||
108 | stw r4,SL_IBAT2(r11) | ||
109 | mfibatl r4,2 | ||
110 | stw r4,SL_IBAT2+4(r11) | ||
111 | mfibatu r4,3 | ||
112 | stw r4,SL_IBAT3(r11) | ||
113 | mfibatl r4,3 | ||
114 | stw r4,SL_IBAT3+4(r11) | ||
115 | |||
116 | #if 0 | ||
117 | /* Backup various CPU config stuffs */ | ||
118 | bl __save_cpu_setup | ||
119 | #endif | ||
120 | /* Call the low level suspend stuff (we should probably have made | ||
121 | * a stackframe... | ||
122 | */ | ||
123 | bl swsusp_save | ||
124 | |||
125 | /* Restore LR from the save area */ | ||
126 | lis r11,swsusp_save_area@h | ||
127 | ori r11,r11,swsusp_save_area@l | ||
128 | lwz r0,SL_LR(r11) | ||
129 | mtlr r0 | ||
130 | |||
131 | blr | ||
132 | |||
133 | |||
134 | /* Resume code */ | ||
135 | _GLOBAL(swsusp_arch_resume) | ||
136 | |||
137 | /* Stop pending alitvec streams and memory accesses */ | ||
138 | BEGIN_FTR_SECTION | ||
139 | DSSALL | ||
140 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | ||
141 | sync | ||
142 | |||
143 | /* Disable MSR:DR to make sure we don't take a TLB or | ||
144 | * hash miss during the copy, as our hash table will | ||
145 | * for a while be unuseable. For .text, we assume we are | ||
146 | * covered by a BAT. This works only for non-G5 at this | ||
147 | * point. G5 will need a better approach, possibly using | ||
148 | * a small temporary hash table filled with large mappings, | ||
149 | * disabling the MMU completely isn't a good option for | ||
150 | * performance reasons. | ||
151 | * (Note that 750's may have the same performance issue as | ||
152 | * the G5 in this case, we should investigate using moving | ||
153 | * BATs for these CPUs) | ||
154 | */ | ||
155 | mfmsr r0 | ||
156 | sync | ||
157 | rlwinm r0,r0,0,28,26 /* clear MSR_DR */ | ||
158 | mtmsr r0 | ||
159 | sync | ||
160 | isync | ||
161 | |||
162 | /* Load ptr the list of pages to copy in r3 */ | ||
163 | lis r11,(pagedir_nosave - KERNELBASE)@h | ||
164 | ori r11,r11,pagedir_nosave@l | ||
165 | lwz r10,0(r11) | ||
166 | |||
167 | /* Copy the pages. This is a very basic implementation, to | ||
168 | * be replaced by something more cache efficient */ | ||
169 | 1: | ||
170 | tophys(r3,r10) | ||
171 | li r0,256 | ||
172 | mtctr r0 | ||
173 | lwz r11,pbe_address(r3) /* source */ | ||
174 | tophys(r5,r11) | ||
175 | lwz r10,pbe_orig_address(r3) /* destination */ | ||
176 | tophys(r6,r10) | ||
177 | 2: | ||
178 | lwz r8,0(r5) | ||
179 | lwz r9,4(r5) | ||
180 | lwz r10,8(r5) | ||
181 | lwz r11,12(r5) | ||
182 | addi r5,r5,16 | ||
183 | stw r8,0(r6) | ||
184 | stw r9,4(r6) | ||
185 | stw r10,8(r6) | ||
186 | stw r11,12(r6) | ||
187 | addi r6,r6,16 | ||
188 | bdnz 2b | ||
189 | lwz r10,pbe_next(r3) | ||
190 | cmpwi 0,r10,0 | ||
191 | bne 1b | ||
192 | |||
193 | /* Do a very simple cache flush/inval of the L1 to ensure | ||
194 | * coherency of the icache | ||
195 | */ | ||
196 | lis r3,0x0002 | ||
197 | mtctr r3 | ||
198 | li r3, 0 | ||
199 | 1: | ||
200 | lwz r0,0(r3) | ||
201 | addi r3,r3,0x0020 | ||
202 | bdnz 1b | ||
203 | isync | ||
204 | sync | ||
205 | |||
206 | /* Now flush those cache lines */ | ||
207 | lis r3,0x0002 | ||
208 | mtctr r3 | ||
209 | li r3, 0 | ||
210 | 1: | ||
211 | dcbf 0,r3 | ||
212 | addi r3,r3,0x0020 | ||
213 | bdnz 1b | ||
214 | sync | ||
215 | |||
216 | /* Ok, we are now running with the kernel data of the old | ||
217 | * kernel fully restored. We can get to the save area | ||
218 | * easily now. As for the rest of the code, it assumes the | ||
219 | * loader kernel and the booted one are exactly identical | ||
220 | */ | ||
221 | lis r11,swsusp_save_area@h | ||
222 | ori r11,r11,swsusp_save_area@l | ||
223 | tophys(r11,r11) | ||
224 | |||
225 | #if 0 | ||
226 | /* Restore various CPU config stuffs */ | ||
227 | bl __restore_cpu_setup | ||
228 | #endif | ||
229 | /* Restore the BATs, and SDR1. Then we can turn on the MMU. | ||
230 | * This is a bit hairy as we are running out of those BATs, | ||
231 | * but first, our code is probably in the icache, and we are | ||
232 | * writing the same value to the BAT, so that should be fine, | ||
233 | * though a better solution will have to be found long-term | ||
234 | */ | ||
235 | lwz r4,SL_SDR1(r11) | ||
236 | mtsdr1 r4 | ||
237 | lwz r4,SL_SPRG0(r11) | ||
238 | mtsprg 0,r4 | ||
239 | lwz r4,SL_SPRG0+4(r11) | ||
240 | mtsprg 1,r4 | ||
241 | lwz r4,SL_SPRG0+8(r11) | ||
242 | mtsprg 2,r4 | ||
243 | lwz r4,SL_SPRG0+12(r11) | ||
244 | mtsprg 3,r4 | ||
245 | |||
246 | #if 0 | ||
247 | lwz r4,SL_DBAT0(r11) | ||
248 | mtdbatu 0,r4 | ||
249 | lwz r4,SL_DBAT0+4(r11) | ||
250 | mtdbatl 0,r4 | ||
251 | lwz r4,SL_DBAT1(r11) | ||
252 | mtdbatu 1,r4 | ||
253 | lwz r4,SL_DBAT1+4(r11) | ||
254 | mtdbatl 1,r4 | ||
255 | lwz r4,SL_DBAT2(r11) | ||
256 | mtdbatu 2,r4 | ||
257 | lwz r4,SL_DBAT2+4(r11) | ||
258 | mtdbatl 2,r4 | ||
259 | lwz r4,SL_DBAT3(r11) | ||
260 | mtdbatu 3,r4 | ||
261 | lwz r4,SL_DBAT3+4(r11) | ||
262 | mtdbatl 3,r4 | ||
263 | lwz r4,SL_IBAT0(r11) | ||
264 | mtibatu 0,r4 | ||
265 | lwz r4,SL_IBAT0+4(r11) | ||
266 | mtibatl 0,r4 | ||
267 | lwz r4,SL_IBAT1(r11) | ||
268 | mtibatu 1,r4 | ||
269 | lwz r4,SL_IBAT1+4(r11) | ||
270 | mtibatl 1,r4 | ||
271 | lwz r4,SL_IBAT2(r11) | ||
272 | mtibatu 2,r4 | ||
273 | lwz r4,SL_IBAT2+4(r11) | ||
274 | mtibatl 2,r4 | ||
275 | lwz r4,SL_IBAT3(r11) | ||
276 | mtibatu 3,r4 | ||
277 | lwz r4,SL_IBAT3+4(r11) | ||
278 | mtibatl 3,r4 | ||
279 | #endif | ||
280 | |||
281 | BEGIN_FTR_SECTION | ||
282 | li r4,0 | ||
283 | mtspr SPRN_DBAT4U,r4 | ||
284 | mtspr SPRN_DBAT4L,r4 | ||
285 | mtspr SPRN_DBAT5U,r4 | ||
286 | mtspr SPRN_DBAT5L,r4 | ||
287 | mtspr SPRN_DBAT6U,r4 | ||
288 | mtspr SPRN_DBAT6L,r4 | ||
289 | mtspr SPRN_DBAT7U,r4 | ||
290 | mtspr SPRN_DBAT7L,r4 | ||
291 | mtspr SPRN_IBAT4U,r4 | ||
292 | mtspr SPRN_IBAT4L,r4 | ||
293 | mtspr SPRN_IBAT5U,r4 | ||
294 | mtspr SPRN_IBAT5L,r4 | ||
295 | mtspr SPRN_IBAT6U,r4 | ||
296 | mtspr SPRN_IBAT6L,r4 | ||
297 | mtspr SPRN_IBAT7U,r4 | ||
298 | mtspr SPRN_IBAT7L,r4 | ||
299 | END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) | ||
300 | |||
301 | /* Flush all TLBs */ | ||
302 | lis r4,0x1000 | ||
303 | 1: addic. r4,r4,-0x1000 | ||
304 | tlbie r4 | ||
305 | blt 1b | ||
306 | sync | ||
307 | |||
308 | /* restore the MSR and turn on the MMU */ | ||
309 | lwz r3,SL_MSR(r11) | ||
310 | bl turn_on_mmu | ||
311 | tovirt(r11,r11) | ||
312 | |||
313 | /* Restore TB */ | ||
314 | li r3,0 | ||
315 | mttbl r3 | ||
316 | lwz r3,SL_TB(r11) | ||
317 | lwz r4,SL_TB+4(r11) | ||
318 | mttbu r3 | ||
319 | mttbl r4 | ||
320 | |||
321 | /* Kick decrementer */ | ||
322 | li r0,1 | ||
323 | mtdec r0 | ||
324 | |||
325 | /* Restore the callee-saved registers and return */ | ||
326 | lwz r0,SL_CR(r11) | ||
327 | mtcr r0 | ||
328 | lwz r2,SL_R2(r11) | ||
329 | lmw r12,SL_R12(r11) | ||
330 | lwz r1,SL_SP(r11) | ||
331 | lwz r0,SL_LR(r11) | ||
332 | mtlr r0 | ||
333 | |||
334 | // XXX Note: we don't really need to call swsusp_resume | ||
335 | |||
336 | li r3,0 | ||
337 | blr | ||
338 | |||
339 | /* FIXME:This construct is actually not useful since we don't shut | ||
340 | * down the instruction MMU, we could just flip back MSR-DR on. | ||
341 | */ | ||
342 | turn_on_mmu: | ||
343 | mflr r4 | ||
344 | mtsrr0 r4 | ||
345 | mtsrr1 r3 | ||
346 | sync | ||
347 | isync | ||
348 | rfi | ||
349 | |||