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 |
| 49 | #define SL_SIZE SL_r31+8 |
| 50 | |
| 51 | /* these macros rely on the save area being |
| 52 | * pointed to by r11 */ |
| 53 | #define SAVE_SPECIAL(special) \ |
| 54 | mf##special r0 ;\ |
| 55 | std r0, SL_##special(r11) |
| 56 | #define RESTORE_SPECIAL(special) \ |
| 57 | ld r0, SL_##special(r11) ;\ |
| 58 | mt##special r0 |
| 59 | #define SAVE_REGISTER(reg) \ |
| 60 | std reg, SL_##reg(r11) |
| 61 | #define RESTORE_REGISTER(reg) \ |
| 62 | ld reg, SL_##reg(r11) |
| 63 | |
| 64 | /* space for storing cpu state */ |
| 65 | .section .data |
| 66 | .align 5 |
| 67 | swsusp_save_area: |
| 68 | .space SL_SIZE |
| 69 | |
| 70 | .section ".toc","aw" |
| 71 | swsusp_save_area_ptr: |
| 72 | .tc swsusp_save_area[TC],swsusp_save_area |
| 73 | restore_pblist_ptr: |
| 74 | .tc restore_pblist[TC],restore_pblist |
| 75 | |
| 76 | .section .text |
| 77 | .align 5 |
| 78 | _GLOBAL(swsusp_arch_suspend) |
| 79 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 80 | SAVE_SPECIAL(LR) |
| 81 | SAVE_REGISTER(r1) |
| 82 | SAVE_SPECIAL(CR) |
| 83 | SAVE_SPECIAL(TB) |
| 84 | SAVE_REGISTER(r2) |
| 85 | SAVE_REGISTER(r12) |
| 86 | SAVE_REGISTER(r13) |
| 87 | SAVE_REGISTER(r14) |
| 88 | SAVE_REGISTER(r15) |
| 89 | SAVE_REGISTER(r16) |
| 90 | SAVE_REGISTER(r17) |
| 91 | SAVE_REGISTER(r18) |
| 92 | SAVE_REGISTER(r19) |
| 93 | SAVE_REGISTER(r20) |
| 94 | SAVE_REGISTER(r21) |
| 95 | SAVE_REGISTER(r22) |
| 96 | SAVE_REGISTER(r23) |
| 97 | SAVE_REGISTER(r24) |
| 98 | SAVE_REGISTER(r25) |
| 99 | SAVE_REGISTER(r26) |
| 100 | SAVE_REGISTER(r27) |
| 101 | SAVE_REGISTER(r28) |
| 102 | SAVE_REGISTER(r29) |
| 103 | SAVE_REGISTER(r30) |
| 104 | SAVE_REGISTER(r31) |
| 105 | SAVE_SPECIAL(MSR) |
| 106 | SAVE_SPECIAL(SDR1) |
| 107 | SAVE_SPECIAL(XER) |
| 108 | |
| 109 | /* we push the stack up 128 bytes but don't store the |
| 110 | * stack pointer on the stack like a real stackframe */ |
| 111 | addi r1,r1,-128 |
| 112 | |
| 113 | bl _iommu_save |
| 114 | bl swsusp_save |
| 115 | |
| 116 | /* restore LR */ |
| 117 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 118 | RESTORE_SPECIAL(LR) |
| 119 | addi r1,r1,128 |
| 120 | |
| 121 | blr |
| 122 | |
| 123 | /* Resume code */ |
| 124 | _GLOBAL(swsusp_arch_resume) |
| 125 | /* Stop pending alitvec streams and memory accesses */ |
| 126 | BEGIN_FTR_SECTION |
| 127 | DSSALL |
| 128 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
| 129 | sync |
| 130 | |
| 131 | ld r12,restore_pblist_ptr@toc(r2) |
| 132 | ld r12,0(r12) |
| 133 | |
| 134 | cmpdi r12,0 |
| 135 | beq- nothing_to_copy |
| 136 | li r15,512 |
| 137 | copyloop: |
| 138 | ld r13,pbe_address(r12) |
| 139 | ld r14,pbe_orig_address(r12) |
| 140 | |
| 141 | mtctr r15 |
| 142 | li r10,0 |
| 143 | copy_page_loop: |
| 144 | ldx r0,r10,r13 |
| 145 | stdx r0,r10,r14 |
| 146 | addi r10,r10,8 |
| 147 | bdnz copy_page_loop |
| 148 | |
| 149 | ld r12,pbe_next(r12) |
| 150 | cmpdi r12,0 |
| 151 | bne+ copyloop |
| 152 | nothing_to_copy: |
| 153 | |
| 154 | /* flush caches */ |
| 155 | lis r3, 0x10 |
| 156 | mtctr r3 |
| 157 | li r3, 0 |
| 158 | ori r3, r3, CONFIG_KERNEL_START>>48 |
| 159 | li r0, 48 |
| 160 | sld r3, r3, r0 |
| 161 | li r0, 0 |
| 162 | 1: |
| 163 | dcbf r0,r3 |
| 164 | addi r3,r3,0x20 |
| 165 | bdnz 1b |
| 166 | |
| 167 | sync |
| 168 | |
| 169 | tlbia |
| 170 | |
| 171 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 172 | |
| 173 | RESTORE_SPECIAL(CR) |
| 174 | |
| 175 | /* restore timebase */ |
| 176 | /* load saved tb */ |
| 177 | ld r1, SL_TB(r11) |
| 178 | /* get upper 32 bits of it */ |
| 179 | srdi r2, r1, 32 |
| 180 | /* clear tb lower to avoid wrap */ |
| 181 | li r0, 0 |
| 182 | mttbl r0 |
| 183 | /* set tb upper */ |
| 184 | mttbu r2 |
| 185 | /* set tb lower */ |
| 186 | mttbl r1 |
| 187 | |
| 188 | /* restore registers */ |
| 189 | RESTORE_REGISTER(r1) |
| 190 | RESTORE_REGISTER(r2) |
| 191 | RESTORE_REGISTER(r12) |
| 192 | RESTORE_REGISTER(r13) |
| 193 | RESTORE_REGISTER(r14) |
| 194 | RESTORE_REGISTER(r15) |
| 195 | RESTORE_REGISTER(r16) |
| 196 | RESTORE_REGISTER(r17) |
| 197 | RESTORE_REGISTER(r18) |
| 198 | RESTORE_REGISTER(r19) |
| 199 | RESTORE_REGISTER(r20) |
| 200 | RESTORE_REGISTER(r21) |
| 201 | RESTORE_REGISTER(r22) |
| 202 | RESTORE_REGISTER(r23) |
| 203 | RESTORE_REGISTER(r24) |
| 204 | RESTORE_REGISTER(r25) |
| 205 | RESTORE_REGISTER(r26) |
| 206 | RESTORE_REGISTER(r27) |
| 207 | RESTORE_REGISTER(r28) |
| 208 | RESTORE_REGISTER(r29) |
| 209 | RESTORE_REGISTER(r30) |
| 210 | RESTORE_REGISTER(r31) |
| 211 | /* can't use RESTORE_SPECIAL(MSR) */ |
| 212 | ld r0, SL_MSR(r11) |
| 213 | mtmsrd r0, 0 |
| 214 | RESTORE_SPECIAL(SDR1) |
| 215 | RESTORE_SPECIAL(XER) |
| 216 | |
| 217 | sync |
| 218 | |
| 219 | addi r1,r1,-128 |
| 220 | bl slb_flush_and_rebolt |
| 221 | bl do_after_copyback |
| 222 | addi r1,r1,128 |
| 223 | |
| 224 | ld r11,swsusp_save_area_ptr@toc(r2) |
| 225 | RESTORE_SPECIAL(LR) |
| 226 | |
| 227 | li r3, 0 |
| 228 | blr |