blob: 884d1c3a187b5a352156c82ce5a8ed26a4660cb8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/threads.h>
2#include <asm/processor.h>
3#include <asm/page.h>
4#include <asm/cputable.h>
5#include <asm/thread_info.h>
6#include <asm/ppc_asm.h>
Sam Ravnborg0013a852005-09-09 20:57:26 +02007#include <asm/asm-offsets.h>
Benjamin Herrenschmidt7c03d652008-12-18 19:13:32 +00008#include <asm/mmu.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
10/*
11 * Structure for storing CPU registers on the save area.
12 */
13#define SL_SP 0
14#define SL_PC 4
15#define SL_MSR 8
16#define SL_SDR1 0xc
17#define SL_SPRG0 0x10 /* 4 sprg's */
18#define SL_DBAT0 0x20
19#define SL_IBAT0 0x28
20#define SL_DBAT1 0x30
21#define SL_IBAT1 0x38
22#define SL_DBAT2 0x40
23#define SL_IBAT2 0x48
24#define SL_DBAT3 0x50
25#define SL_IBAT3 0x58
Christophe Leroydae64e92019-06-17 21:42:14 +000026#define SL_DBAT4 0x60
27#define SL_IBAT4 0x68
28#define SL_DBAT5 0x70
29#define SL_IBAT5 0x78
30#define SL_DBAT6 0x80
31#define SL_IBAT6 0x88
32#define SL_DBAT7 0x90
33#define SL_IBAT7 0x98
34#define SL_TB 0xa0
35#define SL_R2 0xa8
36#define SL_CR 0xac
37#define SL_LR 0xb0
38#define SL_R12 0xb4 /* r12 to r31 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#define SL_SIZE (SL_R12 + 80)
40
41 .section .data
42 .align 5
43
44_GLOBAL(swsusp_save_area)
45 .space SL_SIZE
46
47
48 .section .text
49 .align 5
50
51_GLOBAL(swsusp_arch_suspend)
52
53 lis r11,swsusp_save_area@h
54 ori r11,r11,swsusp_save_area@l
55
56 mflr r0
57 stw r0,SL_LR(r11)
58 mfcr r0
59 stw r0,SL_CR(r11)
60 stw r1,SL_SP(r11)
61 stw r2,SL_R2(r11)
62 stmw r12,SL_R12(r11)
63
64 /* Save MSR & SDR1 */
65 mfmsr r4
66 stw r4,SL_MSR(r11)
67 mfsdr1 r4
68 stw r4,SL_SDR1(r11)
69
70 /* Get a stable timebase and save it */
711: mftbu r4
72 stw r4,SL_TB(r11)
73 mftb r5
74 stw r5,SL_TB+4(r11)
75 mftbu r3
76 cmpw r3,r4
77 bne 1b
78
79 /* Save SPRGs */
80 mfsprg r4,0
81 stw r4,SL_SPRG0(r11)
82 mfsprg r4,1
83 stw r4,SL_SPRG0+4(r11)
84 mfsprg r4,2
85 stw r4,SL_SPRG0+8(r11)
86 mfsprg r4,3
87 stw r4,SL_SPRG0+12(r11)
88
89 /* Save BATs */
90 mfdbatu r4,0
91 stw r4,SL_DBAT0(r11)
92 mfdbatl r4,0
93 stw r4,SL_DBAT0+4(r11)
94 mfdbatu r4,1
95 stw r4,SL_DBAT1(r11)
96 mfdbatl r4,1
97 stw r4,SL_DBAT1+4(r11)
98 mfdbatu r4,2
99 stw r4,SL_DBAT2(r11)
100 mfdbatl r4,2
101 stw r4,SL_DBAT2+4(r11)
102 mfdbatu r4,3
103 stw r4,SL_DBAT3(r11)
104 mfdbatl r4,3
105 stw r4,SL_DBAT3+4(r11)
106 mfibatu r4,0
107 stw r4,SL_IBAT0(r11)
108 mfibatl r4,0
109 stw r4,SL_IBAT0+4(r11)
110 mfibatu r4,1
111 stw r4,SL_IBAT1(r11)
112 mfibatl r4,1
113 stw r4,SL_IBAT1+4(r11)
114 mfibatu r4,2
115 stw r4,SL_IBAT2(r11)
116 mfibatl r4,2
117 stw r4,SL_IBAT2+4(r11)
118 mfibatu r4,3
119 stw r4,SL_IBAT3(r11)
120 mfibatl r4,3
121 stw r4,SL_IBAT3+4(r11)
122
Christophe Leroydae64e92019-06-17 21:42:14 +0000123BEGIN_MMU_FTR_SECTION
124 mfspr r4,SPRN_DBAT4U
125 stw r4,SL_DBAT4(r11)
126 mfspr r4,SPRN_DBAT4L
127 stw r4,SL_DBAT4+4(r11)
128 mfspr r4,SPRN_DBAT5U
129 stw r4,SL_DBAT5(r11)
130 mfspr r4,SPRN_DBAT5L
131 stw r4,SL_DBAT5+4(r11)
132 mfspr r4,SPRN_DBAT6U
133 stw r4,SL_DBAT6(r11)
134 mfspr r4,SPRN_DBAT6L
135 stw r4,SL_DBAT6+4(r11)
136 mfspr r4,SPRN_DBAT7U
137 stw r4,SL_DBAT7(r11)
138 mfspr r4,SPRN_DBAT7L
139 stw r4,SL_DBAT7+4(r11)
140 mfspr r4,SPRN_IBAT4U
141 stw r4,SL_IBAT4(r11)
142 mfspr r4,SPRN_IBAT4L
143 stw r4,SL_IBAT4+4(r11)
144 mfspr r4,SPRN_IBAT5U
145 stw r4,SL_IBAT5(r11)
146 mfspr r4,SPRN_IBAT5L
147 stw r4,SL_IBAT5+4(r11)
148 mfspr r4,SPRN_IBAT6U
149 stw r4,SL_IBAT6(r11)
150 mfspr r4,SPRN_IBAT6L
151 stw r4,SL_IBAT6+4(r11)
152 mfspr r4,SPRN_IBAT7U
153 stw r4,SL_IBAT7(r11)
154 mfspr r4,SPRN_IBAT7L
155 stw r4,SL_IBAT7+4(r11)
156END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158#if 0
159 /* Backup various CPU config stuffs */
160 bl __save_cpu_setup
161#endif
162 /* Call the low level suspend stuff (we should probably have made
163 * a stackframe...
164 */
165 bl swsusp_save
166
167 /* Restore LR from the save area */
168 lis r11,swsusp_save_area@h
169 ori r11,r11,swsusp_save_area@l
170 lwz r0,SL_LR(r11)
171 mtlr r0
172
173 blr
174
175
176/* Resume code */
177_GLOBAL(swsusp_arch_resume)
178
Johannes Berg2e6f40d2007-11-07 23:59:44 +1100179#ifdef CONFIG_ALTIVEC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 /* Stop pending alitvec streams and memory accesses */
181BEGIN_FTR_SECTION
182 DSSALL
183END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
Johannes Berg2e6f40d2007-11-07 23:59:44 +1100184#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 sync
186
187 /* Disable MSR:DR to make sure we don't take a TLB or
188 * hash miss during the copy, as our hash table will
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300189 * for a while be unusable. For .text, we assume we are
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 * covered by a BAT. This works only for non-G5 at this
191 * point. G5 will need a better approach, possibly using
192 * a small temporary hash table filled with large mappings,
193 * disabling the MMU completely isn't a good option for
194 * performance reasons.
195 * (Note that 750's may have the same performance issue as
196 * the G5 in this case, we should investigate using moving
197 * BATs for these CPUs)
198 */
199 mfmsr r0
200 sync
201 rlwinm r0,r0,0,28,26 /* clear MSR_DR */
202 mtmsr r0
203 sync
204 isync
205
206 /* Load ptr the list of pages to copy in r3 */
Rafael J. Wysocki75534b52006-09-25 23:32:52 -0700207 lis r11,(restore_pblist - KERNELBASE)@h
208 ori r11,r11,restore_pblist@l
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 lwz r10,0(r11)
210
211 /* Copy the pages. This is a very basic implementation, to
212 * be replaced by something more cache efficient */
2131:
214 tophys(r3,r10)
215 li r0,256
216 mtctr r0
217 lwz r11,pbe_address(r3) /* source */
218 tophys(r5,r11)
219 lwz r10,pbe_orig_address(r3) /* destination */
220 tophys(r6,r10)
2212:
222 lwz r8,0(r5)
223 lwz r9,4(r5)
224 lwz r10,8(r5)
225 lwz r11,12(r5)
226 addi r5,r5,16
227 stw r8,0(r6)
228 stw r9,4(r6)
229 stw r10,8(r6)
230 stw r11,12(r6)
231 addi r6,r6,16
232 bdnz 2b
233 lwz r10,pbe_next(r3)
234 cmpwi 0,r10,0
235 bne 1b
236
237 /* Do a very simple cache flush/inval of the L1 to ensure
238 * coherency of the icache
239 */
240 lis r3,0x0002
241 mtctr r3
242 li r3, 0
2431:
244 lwz r0,0(r3)
245 addi r3,r3,0x0020
246 bdnz 1b
247 isync
248 sync
249
250 /* Now flush those cache lines */
251 lis r3,0x0002
252 mtctr r3
253 li r3, 0
2541:
255 dcbf 0,r3
256 addi r3,r3,0x0020
257 bdnz 1b
258 sync
259
260 /* Ok, we are now running with the kernel data of the old
261 * kernel fully restored. We can get to the save area
262 * easily now. As for the rest of the code, it assumes the
263 * loader kernel and the booted one are exactly identical
264 */
265 lis r11,swsusp_save_area@h
266 ori r11,r11,swsusp_save_area@l
267 tophys(r11,r11)
268
269#if 0
270 /* Restore various CPU config stuffs */
271 bl __restore_cpu_setup
272#endif
273 /* Restore the BATs, and SDR1. Then we can turn on the MMU.
274 * This is a bit hairy as we are running out of those BATs,
275 * but first, our code is probably in the icache, and we are
276 * writing the same value to the BAT, so that should be fine,
277 * though a better solution will have to be found long-term
278 */
279 lwz r4,SL_SDR1(r11)
280 mtsdr1 r4
281 lwz r4,SL_SPRG0(r11)
282 mtsprg 0,r4
283 lwz r4,SL_SPRG0+4(r11)
284 mtsprg 1,r4
285 lwz r4,SL_SPRG0+8(r11)
286 mtsprg 2,r4
287 lwz r4,SL_SPRG0+12(r11)
288 mtsprg 3,r4
289
290#if 0
291 lwz r4,SL_DBAT0(r11)
292 mtdbatu 0,r4
293 lwz r4,SL_DBAT0+4(r11)
294 mtdbatl 0,r4
295 lwz r4,SL_DBAT1(r11)
296 mtdbatu 1,r4
297 lwz r4,SL_DBAT1+4(r11)
298 mtdbatl 1,r4
299 lwz r4,SL_DBAT2(r11)
300 mtdbatu 2,r4
301 lwz r4,SL_DBAT2+4(r11)
302 mtdbatl 2,r4
303 lwz r4,SL_DBAT3(r11)
304 mtdbatu 3,r4
305 lwz r4,SL_DBAT3+4(r11)
306 mtdbatl 3,r4
307 lwz r4,SL_IBAT0(r11)
308 mtibatu 0,r4
309 lwz r4,SL_IBAT0+4(r11)
310 mtibatl 0,r4
311 lwz r4,SL_IBAT1(r11)
312 mtibatu 1,r4
313 lwz r4,SL_IBAT1+4(r11)
314 mtibatl 1,r4
315 lwz r4,SL_IBAT2(r11)
316 mtibatu 2,r4
317 lwz r4,SL_IBAT2+4(r11)
318 mtibatl 2,r4
319 lwz r4,SL_IBAT3(r11)
320 mtibatu 3,r4
321 lwz r4,SL_IBAT3+4(r11)
322 mtibatl 3,r4
Benjamin Herrenschmidt7c03d652008-12-18 19:13:32 +0000323BEGIN_MMU_FTR_SECTION
Christophe Leroydae64e92019-06-17 21:42:14 +0000324 lwz r4,SL_DBAT4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 mtspr SPRN_DBAT4U,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000326 lwz r4,SL_DBAT4+4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 mtspr SPRN_DBAT4L,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000328 lwz r4,SL_DBAT5(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 mtspr SPRN_DBAT5U,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000330 lwz r4,SL_DBAT5+4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 mtspr SPRN_DBAT5L,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000332 lwz r4,SL_DBAT6(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 mtspr SPRN_DBAT6U,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000334 lwz r4,SL_DBAT6+4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 mtspr SPRN_DBAT6L,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000336 lwz r4,SL_DBAT7(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 mtspr SPRN_DBAT7U,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000338 lwz r4,SL_DBAT7+4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 mtspr SPRN_DBAT7L,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000340 lwz r4,SL_IBAT4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 mtspr SPRN_IBAT4U,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000342 lwz r4,SL_IBAT4+4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 mtspr SPRN_IBAT4L,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000344 lwz r4,SL_IBAT5(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 mtspr SPRN_IBAT5U,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000346 lwz r4,SL_IBAT5+4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 mtspr SPRN_IBAT5L,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000348 lwz r4,SL_IBAT6(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 mtspr SPRN_IBAT6U,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000350 lwz r4,SL_IBAT6+4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 mtspr SPRN_IBAT6L,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000352 lwz r4,SL_IBAT7(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 mtspr SPRN_IBAT7U,r4
Christophe Leroydae64e92019-06-17 21:42:14 +0000354 lwz r4,SL_IBAT7+4(r11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 mtspr SPRN_IBAT7L,r4
Benjamin Herrenschmidt7c03d652008-12-18 19:13:32 +0000356END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
Christophe Leroydae64e92019-06-17 21:42:14 +0000357#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 /* Flush all TLBs */
360 lis r4,0x1000
3611: addic. r4,r4,-0x1000
362 tlbie r4
Anton Vorontsove443ed32009-12-30 07:40:17 +0000363 bgt 1b
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 sync
365
366 /* restore the MSR and turn on the MMU */
367 lwz r3,SL_MSR(r11)
368 bl turn_on_mmu
369 tovirt(r11,r11)
370
371 /* Restore TB */
372 li r3,0
373 mttbl r3
374 lwz r3,SL_TB(r11)
375 lwz r4,SL_TB+4(r11)
376 mttbu r3
377 mttbl r4
378
379 /* Kick decrementer */
380 li r0,1
381 mtdec r0
382
383 /* Restore the callee-saved registers and return */
384 lwz r0,SL_CR(r11)
385 mtcr r0
386 lwz r2,SL_R2(r11)
387 lmw r12,SL_R12(r11)
388 lwz r1,SL_SP(r11)
389 lwz r0,SL_LR(r11)
390 mtlr r0
391
392 // XXX Note: we don't really need to call swsusp_resume
393
394 li r3,0
395 blr
396
397/* FIXME:This construct is actually not useful since we don't shut
398 * down the instruction MMU, we could just flip back MSR-DR on.
399 */
400turn_on_mmu:
401 mflr r4
402 mtsrr0 r4
403 mtsrr1 r3
404 sync
405 isync
406 rfi
407