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> |
| 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 |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 49 | #define SL_SPRG1 0x100 |
| 50 | #define SL_TCR 0x108 |
| 51 | #define SL_SIZE SL_TCR+8 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 52 | |
| 53 | /* these macros rely on the save area being |
| 54 | * pointed to by r11 */ |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 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 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 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 ".toc","aw" |
| 80 | swsusp_save_area_ptr: |
| 81 | .tc swsusp_save_area[TC],swsusp_save_area |
| 82 | restore_pblist_ptr: |
| 83 | .tc restore_pblist[TC],restore_pblist |
| 84 | |
| 85 | .section .text |
| 86 | .align 5 |
| 87 | _GLOBAL(swsusp_arch_suspend) |
| 88 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 89 | SAVE_SPECIAL(LR) |
| 90 | SAVE_REGISTER(r1) |
| 91 | SAVE_SPECIAL(CR) |
| 92 | SAVE_SPECIAL(TB) |
| 93 | SAVE_REGISTER(r2) |
| 94 | SAVE_REGISTER(r12) |
| 95 | SAVE_REGISTER(r13) |
| 96 | SAVE_REGISTER(r14) |
| 97 | SAVE_REGISTER(r15) |
| 98 | SAVE_REGISTER(r16) |
| 99 | SAVE_REGISTER(r17) |
| 100 | SAVE_REGISTER(r18) |
| 101 | SAVE_REGISTER(r19) |
| 102 | SAVE_REGISTER(r20) |
| 103 | SAVE_REGISTER(r21) |
| 104 | SAVE_REGISTER(r22) |
| 105 | SAVE_REGISTER(r23) |
| 106 | SAVE_REGISTER(r24) |
| 107 | SAVE_REGISTER(r25) |
| 108 | SAVE_REGISTER(r26) |
| 109 | SAVE_REGISTER(r27) |
| 110 | SAVE_REGISTER(r28) |
| 111 | SAVE_REGISTER(r29) |
| 112 | SAVE_REGISTER(r30) |
| 113 | SAVE_REGISTER(r31) |
| 114 | SAVE_SPECIAL(MSR) |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 115 | SAVE_SPECIAL(XER) |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 116 | #ifdef CONFIG_PPC_BOOK3S_64 |
Dan Streetman | 711b513 | 2013-10-29 22:25:14 -0400 | [diff] [blame] | 117 | BEGIN_FW_FTR_SECTION |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 118 | SAVE_SPECIAL(SDR1) |
Dan Streetman | 711b513 | 2013-10-29 22:25:14 -0400 | [diff] [blame] | 119 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 120 | #else |
| 121 | SAVE_SPR(TCR) |
| 122 | |
| 123 | /* Save SPRG1, SPRG1 be used save paca */ |
| 124 | SAVE_SPR(SPRG1) |
| 125 | #endif |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 126 | |
| 127 | /* we push the stack up 128 bytes but don't store the |
| 128 | * stack pointer on the stack like a real stackframe */ |
| 129 | addi r1,r1,-128 |
| 130 | |
| 131 | bl _iommu_save |
| 132 | bl swsusp_save |
| 133 | |
| 134 | /* restore LR */ |
| 135 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 136 | RESTORE_SPECIAL(LR) |
| 137 | addi r1,r1,128 |
| 138 | |
| 139 | blr |
| 140 | |
| 141 | /* Resume code */ |
| 142 | _GLOBAL(swsusp_arch_resume) |
| 143 | /* Stop pending alitvec streams and memory accesses */ |
| 144 | BEGIN_FTR_SECTION |
| 145 | DSSALL |
| 146 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
| 147 | sync |
| 148 | |
| 149 | ld r12,restore_pblist_ptr@toc(r2) |
| 150 | ld r12,0(r12) |
| 151 | |
| 152 | cmpdi r12,0 |
| 153 | beq- nothing_to_copy |
Johannes Berg | 2e2b404 | 2008-09-24 04:01:09 +0000 | [diff] [blame] | 154 | li r15,PAGE_SIZE>>3 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 155 | copyloop: |
| 156 | ld r13,pbe_address(r12) |
| 157 | ld r14,pbe_orig_address(r12) |
| 158 | |
| 159 | mtctr r15 |
| 160 | li r10,0 |
| 161 | copy_page_loop: |
| 162 | ldx r0,r10,r13 |
| 163 | stdx r0,r10,r14 |
| 164 | addi r10,r10,8 |
| 165 | bdnz copy_page_loop |
| 166 | |
| 167 | ld r12,pbe_next(r12) |
| 168 | cmpdi r12,0 |
| 169 | bne+ copyloop |
| 170 | nothing_to_copy: |
| 171 | |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 172 | #ifdef CONFIG_PPC_BOOK3S_64 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 173 | /* flush caches */ |
| 174 | lis r3, 0x10 |
| 175 | mtctr r3 |
| 176 | li r3, 0 |
| 177 | ori r3, r3, CONFIG_KERNEL_START>>48 |
| 178 | li r0, 48 |
| 179 | sld r3, r3, r0 |
| 180 | li r0, 0 |
| 181 | 1: |
Andreas Schwab | 10f1dea | 2019-04-11 21:45:56 +1000 | [diff] [blame] | 182 | dcbf 0,r3 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 183 | addi r3,r3,0x20 |
| 184 | bdnz 1b |
| 185 | |
| 186 | sync |
| 187 | |
| 188 | tlbia |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 189 | #endif |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 190 | |
| 191 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 192 | |
| 193 | RESTORE_SPECIAL(CR) |
| 194 | |
| 195 | /* restore timebase */ |
| 196 | /* load saved tb */ |
| 197 | ld r1, SL_TB(r11) |
| 198 | /* get upper 32 bits of it */ |
| 199 | srdi r2, r1, 32 |
| 200 | /* clear tb lower to avoid wrap */ |
| 201 | li r0, 0 |
| 202 | mttbl r0 |
| 203 | /* set tb upper */ |
| 204 | mttbu r2 |
| 205 | /* set tb lower */ |
| 206 | mttbl r1 |
| 207 | |
| 208 | /* restore registers */ |
| 209 | RESTORE_REGISTER(r1) |
| 210 | RESTORE_REGISTER(r2) |
| 211 | RESTORE_REGISTER(r12) |
| 212 | RESTORE_REGISTER(r13) |
| 213 | RESTORE_REGISTER(r14) |
| 214 | RESTORE_REGISTER(r15) |
| 215 | RESTORE_REGISTER(r16) |
| 216 | RESTORE_REGISTER(r17) |
| 217 | RESTORE_REGISTER(r18) |
| 218 | RESTORE_REGISTER(r19) |
| 219 | RESTORE_REGISTER(r20) |
| 220 | RESTORE_REGISTER(r21) |
| 221 | RESTORE_REGISTER(r22) |
| 222 | RESTORE_REGISTER(r23) |
| 223 | RESTORE_REGISTER(r24) |
| 224 | RESTORE_REGISTER(r25) |
| 225 | RESTORE_REGISTER(r26) |
| 226 | RESTORE_REGISTER(r27) |
| 227 | RESTORE_REGISTER(r28) |
| 228 | RESTORE_REGISTER(r29) |
| 229 | RESTORE_REGISTER(r30) |
| 230 | RESTORE_REGISTER(r31) |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 231 | |
| 232 | #ifdef CONFIG_PPC_BOOK3S_64 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 233 | /* can't use RESTORE_SPECIAL(MSR) */ |
| 234 | ld r0, SL_MSR(r11) |
| 235 | mtmsrd r0, 0 |
Dan Streetman | 711b513 | 2013-10-29 22:25:14 -0400 | [diff] [blame] | 236 | BEGIN_FW_FTR_SECTION |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 237 | RESTORE_SPECIAL(SDR1) |
Dan Streetman | 711b513 | 2013-10-29 22:25:14 -0400 | [diff] [blame] | 238 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 239 | #else |
| 240 | /* Restore SPRG1, be used to save paca */ |
| 241 | ld r0, SL_SPRG1(r11) |
| 242 | mtsprg 1, r0 |
| 243 | |
| 244 | RESTORE_SPECIAL(MSR) |
| 245 | |
| 246 | /* Restore TCR and clear any pending bits in TSR. */ |
| 247 | RESTORE_SPR(TCR) |
| 248 | lis r0, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h |
| 249 | mtspr SPRN_TSR, r0 |
| 250 | |
| 251 | /* Kick decrementer */ |
| 252 | li r0, 1 |
| 253 | mtdec r0 |
| 254 | |
| 255 | /* Invalidate all tlbs */ |
| 256 | bl _tlbil_all |
| 257 | #endif |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 258 | RESTORE_SPECIAL(XER) |
| 259 | |
| 260 | sync |
| 261 | |
| 262 | addi r1,r1,-128 |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 263 | #ifdef CONFIG_PPC_BOOK3S_64 |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 264 | bl slb_flush_and_rebolt |
Wang Dongsheng | 5a31057 | 2013-08-08 10:06:45 +0800 | [diff] [blame] | 265 | #endif |
Johannes Berg | 543b9fd | 2007-05-03 22:31:38 +1000 | [diff] [blame] | 266 | bl do_after_copyback |
| 267 | addi r1,r1,128 |
| 268 | |
| 269 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 270 | RESTORE_SPECIAL(LR) |
| 271 | |
| 272 | li r3, 0 |
| 273 | blr |