1/* 2 * S390 64-bit swsusp implementation 3 * 4 * Copyright IBM Corp. 2009 5 * 6 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> 7 * Michael Holzheu <holzheu@linux.vnet.ibm.com> 8 */ 9 10#include <linux/linkage.h> 11#include <asm/page.h> 12#include <asm/ptrace.h> 13#include <asm/thread_info.h> 14#include <asm/asm-offsets.h> 15#include <asm/sigp.h> 16 17/* 18 * Save register context in absolute 0 lowcore and call swsusp_save() to 19 * create in-memory kernel image. The context is saved in the designated 20 * "store status" memory locations (see POP). 21 * We return from this function twice. The first time during the suspend to 22 * disk process. The second time via the swsusp_arch_resume() function 23 * (see below) in the resume process. 24 * This function runs with disabled interrupts. 25 */ 26 .section .text 27ENTRY(swsusp_arch_suspend) 28 stmg %r6,%r15,__SF_GPRS(%r15) 29 lgr %r1,%r15 30 aghi %r15,-STACK_FRAME_OVERHEAD 31 stg %r1,__SF_BACKCHAIN(%r15) 32 33 /* Deactivate DAT */ 34 stnsm __SF_EMPTY(%r15),0xfb 35 36 /* Store prefix register on stack */ 37 stpx __SF_EMPTY(%r15) 38 39 /* Save prefix register contents for lowcore copy */ 40 llgf %r10,__SF_EMPTY(%r15) 41 42 /* Get pointer to save area */ 43 lghi %r1,0x1000 44 45 /* Save CPU address */ 46 stap __LC_EXT_CPU_ADDR(%r0) 47 48 /* Store registers */ 49 mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ 50 stfpc 0x31c(%r1) /* store fpu control */ 51 std 0,0x200(%r1) /* store f0 */ 52 std 1,0x208(%r1) /* store f1 */ 53 std 2,0x210(%r1) /* store f2 */ 54 std 3,0x218(%r1) /* store f3 */ 55 std 4,0x220(%r1) /* store f4 */ 56 std 5,0x228(%r1) /* store f5 */ 57 std 6,0x230(%r1) /* store f6 */ 58 std 7,0x238(%r1) /* store f7 */ 59 std 8,0x240(%r1) /* store f8 */ 60 std 9,0x248(%r1) /* store f9 */ 61 std 10,0x250(%r1) /* store f10 */ 62 std 11,0x258(%r1) /* store f11 */ 63 std 12,0x260(%r1) /* store f12 */ 64 std 13,0x268(%r1) /* store f13 */ 65 std 14,0x270(%r1) /* store f14 */ 66 std 15,0x278(%r1) /* store f15 */ 67 stam %a0,%a15,0x340(%r1) /* store access registers */ 68 stctg %c0,%c15,0x380(%r1) /* store control registers */ 69 stmg %r0,%r15,0x280(%r1) /* store general registers */ 70 71 stpt 0x328(%r1) /* store timer */ 72 stck __SF_EMPTY(%r15) /* store clock */ 73 stckc 0x330(%r1) /* store clock comparator */ 74 75 /* Update cputime accounting before going to sleep */ 76 lg %r0,__LC_LAST_UPDATE_TIMER 77 slg %r0,0x328(%r1) 78 alg %r0,__LC_SYSTEM_TIMER 79 stg %r0,__LC_SYSTEM_TIMER 80 mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1) 81 lg %r0,__LC_LAST_UPDATE_CLOCK 82 slg %r0,__SF_EMPTY(%r15) 83 alg %r0,__LC_STEAL_TIMER 84 stg %r0,__LC_STEAL_TIMER 85 mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15) 86 87 /* Activate DAT */ 88 stosm __SF_EMPTY(%r15),0x04 89 90 /* Set prefix page to zero */ 91 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 92 spx __SF_EMPTY(%r15) 93 94 /* Save absolute zero pages */ 95 larl %r2,suspend_zero_pages 96 lg %r2,0(%r2) 97 lghi %r4,0 98 lghi %r3,2*PAGE_SIZE 99 lghi %r5,2*PAGE_SIZE 1001: mvcle %r2,%r4,0 101 jo 1b 102 103 /* Copy lowcore to absolute zero lowcore */ 104 lghi %r2,0 105 lgr %r4,%r10 106 lghi %r3,2*PAGE_SIZE 107 lghi %r5,2*PAGE_SIZE 1081: mvcle %r2,%r4,0 109 jo 1b 110 111 /* Save image */ 112 brasl %r14,swsusp_save 113 114 /* Restore prefix register and return */ 115 lghi %r1,0x1000 116 spx 0x318(%r1) 117 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 118 lghi %r2,0 119 br %r14 120 121/* 122 * Restore saved memory image to correct place and restore register context. 123 * Then we return to the function that called swsusp_arch_suspend(). 124 * swsusp_arch_resume() runs with disabled interrupts. 125 */ 126ENTRY(swsusp_arch_resume) 127 stmg %r6,%r15,__SF_GPRS(%r15) 128 lgr %r1,%r15 129 aghi %r15,-STACK_FRAME_OVERHEAD 130 stg %r1,__SF_BACKCHAIN(%r15) 131 132 /* Make all free pages stable */ 133 lghi %r2,1 134 brasl %r14,arch_set_page_states 135 136 /* Deactivate DAT */ 137 stnsm __SF_EMPTY(%r15),0xfb 138 139 /* Set prefix page to zero */ 140 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 141 spx __SF_EMPTY(%r15) 142 143 /* Restore saved image */ 144 larl %r1,restore_pblist 145 lg %r1,0(%r1) 146 ltgr %r1,%r1 147 jz 2f 1480: 149 lg %r2,8(%r1) 150 lg %r4,0(%r1) 151 iske %r0,%r4 152 lghi %r3,PAGE_SIZE 153 lghi %r5,PAGE_SIZE 1541: 155 mvcle %r2,%r4,0 156 jo 1b 157 lg %r2,8(%r1) 158 sske %r0,%r2 159 lg %r1,16(%r1) 160 ltgr %r1,%r1 161 jnz 0b 1622: 163 ptlb /* flush tlb */ 164 165 /* Reset System */ 166 larl %r1,restart_entry 167 larl %r2,.Lrestart_diag308_psw 168 og %r1,0(%r2) 169 stg %r1,0(%r0) 170 larl %r1,.Lnew_pgm_check_psw 171 epsw %r2,%r3 172 stm %r2,%r3,0(%r1) 173 mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) 174 lghi %r0,0 175 diag %r0,%r0,0x308 176restart_entry: 177 lhi %r1,1 178 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 179 sam64 180#ifdef CONFIG_SMP 181 larl %r1,smp_cpu_mt_shift 182 icm %r1,15,0(%r1) 183 jz smt_done 184 llgfr %r1,%r1 185smt_loop: 186 sigp %r1,%r0,SIGP_SET_MULTI_THREADING 187 brc 8,smt_done /* accepted */ 188 brc 2,smt_loop /* busy, try again */ 189smt_done: 190#endif 191 larl %r1,.Lnew_pgm_check_psw 192 lpswe 0(%r1) 193pgm_check_entry: 194 195 /* Switch to original suspend CPU */ 196 larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ 197 stap 0(%r1) 198 llgh %r2,0(%r1) 199 llgh %r1,__LC_EXT_CPU_ADDR(%r0) /* Suspend CPU address: r1 */ 200 cgr %r1,%r2 201 je restore_registers /* r1 = r2 -> nothing to do */ 202 larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ 203 mvc __LC_RST_NEW_PSW(16,%r0),0(%r4) 2043: 205 sigp %r9,%r1,SIGP_INITIAL_CPU_RESET /* sigp initial cpu reset */ 206 brc 8,4f /* accepted */ 207 brc 2,3b /* busy, try again */ 208 209 /* Suspend CPU not available -> panic */ 210 larl %r15,init_thread_union 211 ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) 212 larl %r2,.Lpanic_string 213 larl %r3,_sclp_print_early 214 lghi %r1,0 215 sam31 216 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 217 basr %r14,%r3 218 larl %r3,.Ldisabled_wait_31 219 lpsw 0(%r3) 2204: 221 /* Switch to suspend CPU */ 222 sigp %r9,%r1,SIGP_RESTART /* sigp restart to suspend CPU */ 223 brc 2,4b /* busy, try again */ 2245: 225 sigp %r9,%r2,SIGP_STOP /* sigp stop to current resume CPU */ 226 brc 2,5b /* busy, try again */ 2276: j 6b 228 229restart_suspend: 230 larl %r1,.Lresume_cpu 231 llgh %r2,0(%r1) 2327: 233 sigp %r9,%r2,SIGP_SENSE /* sigp sense, wait for resume CPU */ 234 brc 8,7b /* accepted, status 0, still running */ 235 brc 2,7b /* busy, try again */ 236 tmll %r9,0x40 /* Test if resume CPU is stopped */ 237 jz 7b 238 239restore_registers: 240 /* Restore registers */ 241 lghi %r13,0x1000 /* %r1 = pointer to save area */ 242 243 /* Ignore time spent in suspended state. */ 244 llgf %r1,0x318(%r13) 245 stck __LC_LAST_UPDATE_CLOCK(%r1) 246 spt 0x328(%r13) /* reprogram timer */ 247 //sckc 0x330(%r13) /* set clock comparator */ 248 249 lctlg %c0,%c15,0x380(%r13) /* load control registers */ 250 lam %a0,%a15,0x340(%r13) /* load access registers */ 251 252 lfpc 0x31c(%r13) /* load fpu control */ 253 ld 0,0x200(%r13) /* load f0 */ 254 ld 1,0x208(%r13) /* load f1 */ 255 ld 2,0x210(%r13) /* load f2 */ 256 ld 3,0x218(%r13) /* load f3 */ 257 ld 4,0x220(%r13) /* load f4 */ 258 ld 5,0x228(%r13) /* load f5 */ 259 ld 6,0x230(%r13) /* load f6 */ 260 ld 7,0x238(%r13) /* load f7 */ 261 ld 8,0x240(%r13) /* load f8 */ 262 ld 9,0x248(%r13) /* load f9 */ 263 ld 10,0x250(%r13) /* load f10 */ 264 ld 11,0x258(%r13) /* load f11 */ 265 ld 12,0x260(%r13) /* load f12 */ 266 ld 13,0x268(%r13) /* load f13 */ 267 ld 14,0x270(%r13) /* load f14 */ 268 ld 15,0x278(%r13) /* load f15 */ 269 270 /* Load old stack */ 271 lg %r15,0x2f8(%r13) 272 273 /* Save prefix register */ 274 mvc __SF_EMPTY(4,%r15),0x318(%r13) 275 276 /* Restore absolute zero pages */ 277 lghi %r2,0 278 larl %r4,suspend_zero_pages 279 lg %r4,0(%r4) 280 lghi %r3,2*PAGE_SIZE 281 lghi %r5,2*PAGE_SIZE 2821: mvcle %r2,%r4,0 283 jo 1b 284 285 /* Restore prefix register */ 286 spx __SF_EMPTY(%r15) 287 288 /* Activate DAT */ 289 stosm __SF_EMPTY(%r15),0x04 290 291 /* Make all free pages unstable */ 292 lghi %r2,0 293 brasl %r14,arch_set_page_states 294 295 /* Call arch specific early resume code */ 296 brasl %r14,s390_early_resume 297 298 /* Return 0 */ 299 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 300 lghi %r2,0 301 br %r14 302 303 .section .data..nosave,"aw",@progbits 304 .align 8 305.Ldisabled_wait_31: 306 .long 0x000a0000,0x00000000 307.Lpanic_string: 308 .asciz "Resume not possible because suspend CPU is no longer available" 309 .align 8 310.Lrestart_diag308_psw: 311 .long 0x00080000,0x80000000 312.Lrestart_suspend_psw: 313 .quad 0x0000000180000000,restart_suspend 314.Lnew_pgm_check_psw: 315 .quad 0,pgm_check_entry 316.Lresume_cpu: 317 .byte 0,0 318