Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 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> |
Christophe Leroy | 2c86cd1 | 2018-07-05 16:25:01 +0000 | [diff] [blame] | 16 | #include <asm/feature-fixups.h> |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 17 | |
| 18 | /* |
| 19 | * Structure for storing CPU registers on the save area. |
| 20 | */ |
| 21 | #define SL_r1 0x00 /* stack pointer */ |
| 22 | #define SL_PC 0x08 |
| 23 | #define SL_MSR 0x10 |
| 24 | #define SL_SDR1 0x18 |
| 25 | #define SL_XER 0x20 |
| 26 | #define SL_TB 0x40 |
| 27 | #define SL_r2 0x48 |
| 28 | #define SL_CR 0x50 |
| 29 | #define SL_LR 0x58 |
| 30 | #define SL_r12 0x60 |
| 31 | #define SL_r13 0x68 |
| 32 | #define SL_r14 0x70 |
| 33 | #define SL_r15 0x78 |
| 34 | #define SL_r16 0x80 |
| 35 | #define SL_r17 0x88 |
| 36 | #define SL_r18 0x90 |
| 37 | #define SL_r19 0x98 |
| 38 | #define SL_r20 0xa0 |
| 39 | #define SL_r21 0xa8 |
| 40 | #define SL_r22 0xb0 |
| 41 | #define SL_r23 0xb8 |
| 42 | #define SL_r24 0xc0 |
| 43 | #define SL_r25 0xc8 |
| 44 | #define SL_r26 0xd0 |
| 45 | #define SL_r27 0xd8 |
| 46 | #define SL_r28 0xe0 |
| 47 | #define SL_r29 0xe8 |
| 48 | #define SL_r30 0xf0 |
| 49 | #define SL_r31 0xf8 |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 50 | #define SL_SPRG1 0x100 |
| 51 | #define SL_TCR 0x108 |
| 52 | #define SL_SIZE SL_TCR+8 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 53 | |
| 54 | /* these macros rely on the save area being |
| 55 | * pointed to by r11 */ |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 56 | |
| 57 | #define SAVE_SPR(register) \ |
| 58 | mfspr r0, SPRN_##register ;\ |
| 59 | std r0, SL_##register(r11) |
| 60 | #define RESTORE_SPR(register) \ |
| 61 | ld r0, SL_##register(r11) ;\ |
| 62 | mtspr SPRN_##register, r0 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 63 | #define SAVE_SPECIAL(special) \ |
| 64 | mf##special r0 ;\ |
| 65 | std r0, SL_##special(r11) |
| 66 | #define RESTORE_SPECIAL(special) \ |
| 67 | ld r0, SL_##special(r11) ;\ |
| 68 | mt##special r0 |
| 69 | #define SAVE_REGISTER(reg) \ |
| 70 | std reg, SL_##reg(r11) |
| 71 | #define RESTORE_REGISTER(reg) \ |
| 72 | ld reg, SL_##reg(r11) |
| 73 | |
| 74 | /* space for storing cpu state */ |
| 75 | .section .data |
| 76 | .align 5 |
| 77 | swsusp_save_area: |
| 78 | .space SL_SIZE |
| 79 | |
| 80 | .section ".toc","aw" |
| 81 | swsusp_save_area_ptr: |
| 82 | .tc swsusp_save_area[TC],swsusp_save_area |
| 83 | restore_pblist_ptr: |
| 84 | .tc restore_pblist[TC],restore_pblist |
| 85 | |
| 86 | .section .text |
| 87 | .align 5 |
| 88 | _GLOBAL(swsusp_arch_suspend) |
| 89 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 90 | SAVE_SPECIAL(LR) |
| 91 | SAVE_REGISTER(r1) |
| 92 | SAVE_SPECIAL(CR) |
| 93 | SAVE_SPECIAL(TB) |
| 94 | SAVE_REGISTER(r2) |
| 95 | SAVE_REGISTER(r12) |
| 96 | SAVE_REGISTER(r13) |
| 97 | SAVE_REGISTER(r14) |
| 98 | SAVE_REGISTER(r15) |
| 99 | SAVE_REGISTER(r16) |
| 100 | SAVE_REGISTER(r17) |
| 101 | SAVE_REGISTER(r18) |
| 102 | SAVE_REGISTER(r19) |
| 103 | SAVE_REGISTER(r20) |
| 104 | SAVE_REGISTER(r21) |
| 105 | SAVE_REGISTER(r22) |
| 106 | SAVE_REGISTER(r23) |
| 107 | SAVE_REGISTER(r24) |
| 108 | SAVE_REGISTER(r25) |
| 109 | SAVE_REGISTER(r26) |
| 110 | SAVE_REGISTER(r27) |
| 111 | SAVE_REGISTER(r28) |
| 112 | SAVE_REGISTER(r29) |
| 113 | SAVE_REGISTER(r30) |
| 114 | SAVE_REGISTER(r31) |
| 115 | SAVE_SPECIAL(MSR) |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 116 | SAVE_SPECIAL(XER) |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 117 | #ifdef CONFIG_PPC_BOOK3S_64 |
Dan Streetman | 711b513 | 2013-10-29 22:25:14 -0400 | [diff] [blame] | 118 | BEGIN_FW_FTR_SECTION |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 119 | SAVE_SPECIAL(SDR1) |
Dan Streetman | 711b513 | 2013-10-29 22:25:14 -0400 | [diff] [blame] | 120 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 121 | #else |
| 122 | SAVE_SPR(TCR) |
| 123 | |
| 124 | /* Save SPRG1, SPRG1 be used save paca */ |
| 125 | SAVE_SPR(SPRG1) |
| 126 | #endif |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 127 | |
| 128 | /* we push the stack up 128 bytes but don't store the |
| 129 | * stack pointer on the stack like a real stackframe */ |
| 130 | addi r1,r1,-128 |
| 131 | |
| 132 | bl _iommu_save |
| 133 | bl swsusp_save |
| 134 | |
| 135 | /* restore LR */ |
| 136 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 137 | RESTORE_SPECIAL(LR) |
| 138 | addi r1,r1,128 |
| 139 | |
| 140 | blr |
| 141 | |
| 142 | /* Resume code */ |
| 143 | _GLOBAL(swsusp_arch_resume) |
| 144 | /* Stop pending alitvec streams and memory accesses */ |
| 145 | BEGIN_FTR_SECTION |
| 146 | DSSALL |
| 147 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
| 148 | sync |
| 149 | |
| 150 | ld r12,restore_pblist_ptr@toc(r2) |
| 151 | ld r12,0(r12) |
| 152 | |
| 153 | cmpdi r12,0 |
| 154 | beq- nothing_to_copy |
Johannes Berg | 2e2b404 | 2008-09-24 04:01:09 +0000 | [diff] [blame] | 155 | li r15,PAGE_SIZE>>3 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 156 | copyloop: |
| 157 | ld r13,pbe_address(r12) |
| 158 | ld r14,pbe_orig_address(r12) |
| 159 | |
| 160 | mtctr r15 |
| 161 | li r10,0 |
| 162 | copy_page_loop: |
| 163 | ldx r0,r10,r13 |
| 164 | stdx r0,r10,r14 |
| 165 | addi r10,r10,8 |
| 166 | bdnz copy_page_loop |
| 167 | |
| 168 | ld r12,pbe_next(r12) |
| 169 | cmpdi r12,0 |
| 170 | bne+ copyloop |
| 171 | nothing_to_copy: |
| 172 | |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 173 | #ifdef CONFIG_PPC_BOOK3S_64 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 174 | /* flush caches */ |
| 175 | lis r3, 0x10 |
| 176 | mtctr r3 |
| 177 | li r3, 0 |
| 178 | ori r3, r3, CONFIG_KERNEL_START>>48 |
| 179 | li r0, 48 |
| 180 | sld r3, r3, r0 |
| 181 | li r0, 0 |
| 182 | 1: |
Andreas Schwab | 8a583c0 | 2017-08-05 19:55:11 +0200 | [diff] [blame] | 183 | dcbf 0,r3 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 184 | addi r3,r3,0x20 |
| 185 | bdnz 1b |
| 186 | |
| 187 | sync |
| 188 | |
| 189 | tlbia |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 190 | #endif |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 191 | |
| 192 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 193 | |
| 194 | RESTORE_SPECIAL(CR) |
| 195 | |
| 196 | /* restore timebase */ |
| 197 | /* load saved tb */ |
| 198 | ld r1, SL_TB(r11) |
| 199 | /* get upper 32 bits of it */ |
| 200 | srdi r2, r1, 32 |
| 201 | /* clear tb lower to avoid wrap */ |
| 202 | li r0, 0 |
| 203 | mttbl r0 |
| 204 | /* set tb upper */ |
| 205 | mttbu r2 |
| 206 | /* set tb lower */ |
| 207 | mttbl r1 |
| 208 | |
| 209 | /* restore registers */ |
| 210 | RESTORE_REGISTER(r1) |
| 211 | RESTORE_REGISTER(r2) |
| 212 | RESTORE_REGISTER(r12) |
| 213 | RESTORE_REGISTER(r13) |
| 214 | RESTORE_REGISTER(r14) |
| 215 | RESTORE_REGISTER(r15) |
| 216 | RESTORE_REGISTER(r16) |
| 217 | RESTORE_REGISTER(r17) |
| 218 | RESTORE_REGISTER(r18) |
| 219 | RESTORE_REGISTER(r19) |
| 220 | RESTORE_REGISTER(r20) |
| 221 | RESTORE_REGISTER(r21) |
| 222 | RESTORE_REGISTER(r22) |
| 223 | RESTORE_REGISTER(r23) |
| 224 | RESTORE_REGISTER(r24) |
| 225 | RESTORE_REGISTER(r25) |
| 226 | RESTORE_REGISTER(r26) |
| 227 | RESTORE_REGISTER(r27) |
| 228 | RESTORE_REGISTER(r28) |
| 229 | RESTORE_REGISTER(r29) |
| 230 | RESTORE_REGISTER(r30) |
| 231 | RESTORE_REGISTER(r31) |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 232 | |
| 233 | #ifdef CONFIG_PPC_BOOK3S_64 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 234 | /* can't use RESTORE_SPECIAL(MSR) */ |
| 235 | ld r0, SL_MSR(r11) |
| 236 | mtmsrd r0, 0 |
Dan Streetman | 711b513 | 2013-10-29 22:25:14 -0400 | [diff] [blame] | 237 | BEGIN_FW_FTR_SECTION |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 238 | RESTORE_SPECIAL(SDR1) |
Dan Streetman | 711b513 | 2013-10-29 22:25:14 -0400 | [diff] [blame] | 239 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 240 | #else |
| 241 | /* Restore SPRG1, be used to save paca */ |
| 242 | ld r0, SL_SPRG1(r11) |
| 243 | mtsprg 1, r0 |
| 244 | |
| 245 | RESTORE_SPECIAL(MSR) |
| 246 | |
| 247 | /* Restore TCR and clear any pending bits in TSR. */ |
| 248 | RESTORE_SPR(TCR) |
| 249 | lis r0, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h |
| 250 | mtspr SPRN_TSR, r0 |
| 251 | |
| 252 | /* Kick decrementer */ |
| 253 | li r0, 1 |
| 254 | mtdec r0 |
| 255 | |
| 256 | /* Invalidate all tlbs */ |
| 257 | bl _tlbil_all |
| 258 | #endif |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 259 | RESTORE_SPECIAL(XER) |
| 260 | |
| 261 | sync |
| 262 | |
| 263 | addi r1,r1,-128 |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 264 | #ifdef CONFIG_PPC_BOOK3S_64 |
Nicholas Piggin | 94ee4272 | 2018-10-03 00:27:58 +1000 | [diff] [blame] | 265 | bl slb_flush_and_restore_bolted |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 266 | #endif |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 267 | bl do_after_copyback |
| 268 | addi r1,r1,128 |
| 269 | |
| 270 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 271 | RESTORE_SPECIAL(LR) |
| 272 | |
| 273 | li r3, 0 |
| 274 | blr |