1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * PowerPC 64-bit swsusp implementation |
4 | * |
5 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> |
6 | */ |
7 | |
8 | #include <linux/threads.h> |
9 | #include <asm/processor.h> |
10 | #include <asm/page.h> |
11 | #include <asm/cputable.h> |
12 | #include <asm/thread_info.h> |
13 | #include <asm/ppc_asm.h> |
14 | #include <asm/asm-offsets.h> |
15 | #include <asm/feature-fixups.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_SPRG1 0x100 |
50 | #define SL_TCR 0x108 |
51 | #define SL_SIZE SL_TCR+8 |
52 | |
53 | /* these macros rely on the save area being |
54 | * pointed to by r11 */ |
55 | |
56 | #define SAVE_SPR(register) \ |
57 | mfspr r0, SPRN_##register ;\ |
58 | std r0, SL_##register(r11) |
59 | #define RESTORE_SPR(register) \ |
60 | ld r0, SL_##register(r11) ;\ |
61 | mtspr SPRN_##register, r0 |
62 | #define SAVE_SPECIAL(special) \ |
63 | mf##special r0 ;\ |
64 | std r0, SL_##special(r11) |
65 | #define RESTORE_SPECIAL(special) \ |
66 | ld r0, SL_##special(r11) ;\ |
67 | mt##special r0 |
68 | #define SAVE_REGISTER(reg) \ |
69 | std reg, SL_##reg(r11) |
70 | #define RESTORE_REGISTER(reg) \ |
71 | ld reg, SL_##reg(r11) |
72 | |
73 | /* space for storing cpu state */ |
74 | .section .data |
75 | .align 5 |
76 | swsusp_save_area: |
77 | .space SL_SIZE |
78 | |
79 | .section .text |
80 | .align 5 |
81 | _GLOBAL(swsusp_arch_suspend) |
82 | LOAD_REG_ADDR(r11, swsusp_save_area) |
83 | SAVE_SPECIAL(LR) |
84 | SAVE_REGISTER(r1) |
85 | SAVE_SPECIAL(CR) |
86 | SAVE_SPECIAL(TB) |
87 | SAVE_REGISTER(r2) |
88 | SAVE_REGISTER(r12) |
89 | SAVE_REGISTER(r13) |
90 | SAVE_REGISTER(r14) |
91 | SAVE_REGISTER(r15) |
92 | SAVE_REGISTER(r16) |
93 | SAVE_REGISTER(r17) |
94 | SAVE_REGISTER(r18) |
95 | SAVE_REGISTER(r19) |
96 | SAVE_REGISTER(r20) |
97 | SAVE_REGISTER(r21) |
98 | SAVE_REGISTER(r22) |
99 | SAVE_REGISTER(r23) |
100 | SAVE_REGISTER(r24) |
101 | SAVE_REGISTER(r25) |
102 | SAVE_REGISTER(r26) |
103 | SAVE_REGISTER(r27) |
104 | SAVE_REGISTER(r28) |
105 | SAVE_REGISTER(r29) |
106 | SAVE_REGISTER(r30) |
107 | SAVE_REGISTER(r31) |
108 | SAVE_SPECIAL(MSR) |
109 | SAVE_SPECIAL(XER) |
110 | #ifdef CONFIG_PPC_BOOK3S_64 |
111 | BEGIN_FW_FTR_SECTION |
112 | SAVE_SPECIAL(SDR1) |
113 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) |
114 | #else |
115 | SAVE_SPR(TCR) |
116 | |
117 | /* Save SPRG1, SPRG1 be used save paca */ |
118 | SAVE_SPR(SPRG1) |
119 | #endif |
120 | |
121 | /* we push the stack up 128 bytes but don't store the |
122 | * stack pointer on the stack like a real stackframe */ |
123 | addi r1,r1,-128 |
124 | |
125 | bl swsusp_save |
126 | |
127 | /* restore LR */ |
128 | LOAD_REG_ADDR(r11, swsusp_save_area) |
129 | RESTORE_SPECIAL(LR) |
130 | addi r1,r1,128 |
131 | |
132 | blr |
133 | |
134 | /* Resume code */ |
135 | _GLOBAL(swsusp_arch_resume) |
136 | /* Stop pending alitvec streams and memory accesses */ |
137 | BEGIN_FTR_SECTION |
138 | PPC_DSSALL |
139 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
140 | sync |
141 | |
142 | LOAD_REG_ADDR(r11, restore_pblist) |
143 | ld r12,0(r12) |
144 | |
145 | cmpdi r12,0 |
146 | beq- nothing_to_copy |
147 | li r15,PAGE_SIZE>>3 |
148 | copyloop: |
149 | ld r13,pbe_address(r12) |
150 | ld r14,pbe_orig_address(r12) |
151 | |
152 | mtctr r15 |
153 | li r10,0 |
154 | copy_page_loop: |
155 | ldx r0,r10,r13 |
156 | stdx r0,r10,r14 |
157 | addi r10,r10,8 |
158 | bdnz copy_page_loop |
159 | |
160 | ld r12,pbe_next(r12) |
161 | cmpdi r12,0 |
162 | bne+ copyloop |
163 | nothing_to_copy: |
164 | |
165 | #ifdef CONFIG_PPC_BOOK3S_64 |
166 | /* flush caches */ |
167 | lis r3, 0x10 |
168 | mtctr r3 |
169 | li r3, 0 |
170 | ori r3, r3, CONFIG_KERNEL_START>>48 |
171 | li r0, 48 |
172 | sld r3, r3, r0 |
173 | li r0, 0 |
174 | 1: |
175 | dcbf 0,r3 |
176 | addi r3,r3,0x20 |
177 | bdnz 1b |
178 | |
179 | sync |
180 | |
181 | tlbia |
182 | #endif |
183 | |
184 | LOAD_REG_ADDR(r11, swsusp_save_area) |
185 | |
186 | RESTORE_SPECIAL(CR) |
187 | |
188 | /* restore timebase */ |
189 | /* load saved tb */ |
190 | ld r1, SL_TB(r11) |
191 | /* get upper 32 bits of it */ |
192 | srdi r2, r1, 32 |
193 | /* clear tb lower to avoid wrap */ |
194 | li r0, 0 |
195 | mttbl r0 |
196 | /* set tb upper */ |
197 | mttbu r2 |
198 | /* set tb lower */ |
199 | mttbl r1 |
200 | |
201 | /* restore registers */ |
202 | RESTORE_REGISTER(r1) |
203 | RESTORE_REGISTER(r2) |
204 | RESTORE_REGISTER(r12) |
205 | RESTORE_REGISTER(r13) |
206 | RESTORE_REGISTER(r14) |
207 | RESTORE_REGISTER(r15) |
208 | RESTORE_REGISTER(r16) |
209 | RESTORE_REGISTER(r17) |
210 | RESTORE_REGISTER(r18) |
211 | RESTORE_REGISTER(r19) |
212 | RESTORE_REGISTER(r20) |
213 | RESTORE_REGISTER(r21) |
214 | RESTORE_REGISTER(r22) |
215 | RESTORE_REGISTER(r23) |
216 | RESTORE_REGISTER(r24) |
217 | RESTORE_REGISTER(r25) |
218 | RESTORE_REGISTER(r26) |
219 | RESTORE_REGISTER(r27) |
220 | RESTORE_REGISTER(r28) |
221 | RESTORE_REGISTER(r29) |
222 | RESTORE_REGISTER(r30) |
223 | RESTORE_REGISTER(r31) |
224 | |
225 | #ifdef CONFIG_PPC_BOOK3S_64 |
226 | /* can't use RESTORE_SPECIAL(MSR) */ |
227 | ld r0, SL_MSR(r11) |
228 | mtmsrd r0, 0 |
229 | BEGIN_FW_FTR_SECTION |
230 | RESTORE_SPECIAL(SDR1) |
231 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) |
232 | #else |
233 | /* Restore SPRG1, be used to save paca */ |
234 | ld r0, SL_SPRG1(r11) |
235 | mtsprg 1, r0 |
236 | |
237 | RESTORE_SPECIAL(MSR) |
238 | |
239 | /* Restore TCR and clear any pending bits in TSR. */ |
240 | RESTORE_SPR(TCR) |
241 | lis r0, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h |
242 | mtspr SPRN_TSR, r0 |
243 | |
244 | /* Kick decrementer */ |
245 | li r0, 1 |
246 | mtdec r0 |
247 | |
248 | /* Invalidate all tlbs */ |
249 | bl _tlbil_all |
250 | #endif |
251 | RESTORE_SPECIAL(XER) |
252 | |
253 | sync |
254 | |
255 | addi r1,r1,-128 |
256 | #ifdef CONFIG_PPC_BOOK3S_64 |
257 | bl slb_flush_and_restore_bolted |
258 | #endif |
259 | bl do_after_copyback |
260 | addi r1,r1,128 |
261 | |
262 | LOAD_REG_ADDR(r11, swsusp_save_area) |
263 | RESTORE_SPECIAL(LR) |
264 | |
265 | li r3, 0 |
266 | blr |
267 | |