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