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