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 /* Store FPU registers */ 34 brasl %r14,save_fpu_regs 35 36 /* Deactivate DAT */ 37 stnsm __SF_EMPTY(%r15),0xfb 38 39 /* Store prefix register on stack */ 40 stpx __SF_EMPTY(%r15) 41 42 /* Save prefix register contents for lowcore copy */ 43 llgf %r10,__SF_EMPTY(%r15) 44 45 /* Get pointer to save area */ 46 lghi %r1,0x1000 47 48 /* Save CPU address */ 49 stap __LC_EXT_CPU_ADDR(%r0) 50 51 /* Store registers */ 52 mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ 53 stam %a0,%a15,0x340(%r1) /* store access registers */ 54 stctg %c0,%c15,0x380(%r1) /* store control registers */ 55 stmg %r0,%r15,0x280(%r1) /* store general registers */ 56 57 stpt 0x328(%r1) /* store timer */ 58 stck __SF_EMPTY(%r15) /* store clock */ 59 stckc 0x330(%r1) /* store clock comparator */ 60 61 /* Update cputime accounting before going to sleep */ 62 lg %r0,__LC_LAST_UPDATE_TIMER 63 slg %r0,0x328(%r1) 64 alg %r0,__LC_SYSTEM_TIMER 65 stg %r0,__LC_SYSTEM_TIMER 66 mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1) 67 lg %r0,__LC_LAST_UPDATE_CLOCK 68 slg %r0,__SF_EMPTY(%r15) 69 alg %r0,__LC_STEAL_TIMER 70 stg %r0,__LC_STEAL_TIMER 71 mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15) 72 73 /* Activate DAT */ 74 stosm __SF_EMPTY(%r15),0x04 75 76 /* Set prefix page to zero */ 77 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 78 spx __SF_EMPTY(%r15) 79 80 /* Save absolute zero pages */ 81 larl %r2,suspend_zero_pages 82 lg %r2,0(%r2) 83 lghi %r4,0 84 lghi %r3,2*PAGE_SIZE 85 lghi %r5,2*PAGE_SIZE 861: mvcle %r2,%r4,0 87 jo 1b 88 89 /* Copy lowcore to absolute zero lowcore */ 90 lghi %r2,0 91 lgr %r4,%r10 92 lghi %r3,2*PAGE_SIZE 93 lghi %r5,2*PAGE_SIZE 941: mvcle %r2,%r4,0 95 jo 1b 96 97 /* Save image */ 98 brasl %r14,swsusp_save 99 100 /* Restore prefix register and return */ 101 lghi %r1,0x1000 102 spx 0x318(%r1) 103 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 104 lghi %r2,0 105 br %r14 106 107/* 108 * Restore saved memory image to correct place and restore register context. 109 * Then we return to the function that called swsusp_arch_suspend(). 110 * swsusp_arch_resume() runs with disabled interrupts. 111 */ 112ENTRY(swsusp_arch_resume) 113 stmg %r6,%r15,__SF_GPRS(%r15) 114 lgr %r1,%r15 115 aghi %r15,-STACK_FRAME_OVERHEAD 116 stg %r1,__SF_BACKCHAIN(%r15) 117 118 /* Make all free pages stable */ 119 lghi %r2,1 120 brasl %r14,arch_set_page_states 121 122 /* Deactivate DAT */ 123 stnsm __SF_EMPTY(%r15),0xfb 124 125 /* Set prefix page to zero */ 126 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 127 spx __SF_EMPTY(%r15) 128 129 /* Restore saved image */ 130 larl %r1,restore_pblist 131 lg %r1,0(%r1) 132 ltgr %r1,%r1 133 jz 2f 1340: 135 lg %r2,8(%r1) 136 lg %r4,0(%r1) 137 iske %r0,%r4 138 lghi %r3,PAGE_SIZE 139 lghi %r5,PAGE_SIZE 1401: 141 mvcle %r2,%r4,0 142 jo 1b 143 lg %r2,8(%r1) 144 sske %r0,%r2 145 lg %r1,16(%r1) 146 ltgr %r1,%r1 147 jnz 0b 1482: 149 ptlb /* flush tlb */ 150 151 /* Reset System */ 152 larl %r1,restart_entry 153 larl %r2,.Lrestart_diag308_psw 154 og %r1,0(%r2) 155 stg %r1,0(%r0) 156 larl %r1,.Lnew_pgm_check_psw 157 epsw %r2,%r3 158 stm %r2,%r3,0(%r1) 159 mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) 160 lghi %r0,0 161 diag %r0,%r0,0x308 162restart_entry: 163 lhi %r1,1 164 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 165 sam64 166#ifdef CONFIG_SMP 167 larl %r1,smp_cpu_mt_shift 168 icm %r1,15,0(%r1) 169 jz smt_done 170 llgfr %r1,%r1 171smt_loop: 172 sigp %r1,%r0,SIGP_SET_MULTI_THREADING 173 brc 8,smt_done /* accepted */ 174 brc 2,smt_loop /* busy, try again */ 175smt_done: 176#endif 177 larl %r1,.Lnew_pgm_check_psw 178 lpswe 0(%r1) 179pgm_check_entry: 180 181 /* Switch to original suspend CPU */ 182 larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ 183 stap 0(%r1) 184 llgh %r2,0(%r1) 185 llgh %r1,__LC_EXT_CPU_ADDR(%r0) /* Suspend CPU address: r1 */ 186 cgr %r1,%r2 187 je restore_registers /* r1 = r2 -> nothing to do */ 188 larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ 189 mvc __LC_RST_NEW_PSW(16,%r0),0(%r4) 1903: 191 sigp %r9,%r1,SIGP_INITIAL_CPU_RESET /* sigp initial cpu reset */ 192 brc 8,4f /* accepted */ 193 brc 2,3b /* busy, try again */ 194 195 /* Suspend CPU not available -> panic */ 196 larl %r15,init_thread_union 197 ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) 198 larl %r2,.Lpanic_string 199 larl %r3,_sclp_print_early 200 lghi %r1,0 201 sam31 202 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 203 basr %r14,%r3 204 larl %r3,.Ldisabled_wait_31 205 lpsw 0(%r3) 2064: 207 /* Switch to suspend CPU */ 208 sigp %r9,%r1,SIGP_RESTART /* sigp restart to suspend CPU */ 209 brc 2,4b /* busy, try again */ 2105: 211 sigp %r9,%r2,SIGP_STOP /* sigp stop to current resume CPU */ 212 brc 2,5b /* busy, try again */ 2136: j 6b 214 215restart_suspend: 216 larl %r1,.Lresume_cpu 217 llgh %r2,0(%r1) 2187: 219 sigp %r9,%r2,SIGP_SENSE /* sigp sense, wait for resume CPU */ 220 brc 8,7b /* accepted, status 0, still running */ 221 brc 2,7b /* busy, try again */ 222 tmll %r9,0x40 /* Test if resume CPU is stopped */ 223 jz 7b 224 225restore_registers: 226 /* Restore registers */ 227 lghi %r13,0x1000 /* %r1 = pointer to save area */ 228 229 /* Ignore time spent in suspended state. */ 230 llgf %r1,0x318(%r13) 231 stck __LC_LAST_UPDATE_CLOCK(%r1) 232 spt 0x328(%r13) /* reprogram timer */ 233 //sckc 0x330(%r13) /* set clock comparator */ 234 235 lctlg %c0,%c15,0x380(%r13) /* load control registers */ 236 lam %a0,%a15,0x340(%r13) /* load access registers */ 237 238 /* Load old stack */ 239 lg %r15,0x2f8(%r13) 240 241 /* Save prefix register */ 242 mvc __SF_EMPTY(4,%r15),0x318(%r13) 243 244 /* Restore absolute zero pages */ 245 lghi %r2,0 246 larl %r4,suspend_zero_pages 247 lg %r4,0(%r4) 248 lghi %r3,2*PAGE_SIZE 249 lghi %r5,2*PAGE_SIZE 2501: mvcle %r2,%r4,0 251 jo 1b 252 253 /* Restore prefix register */ 254 spx __SF_EMPTY(%r15) 255 256 /* Activate DAT */ 257 stosm __SF_EMPTY(%r15),0x04 258 259 /* Make all free pages unstable */ 260 lghi %r2,0 261 brasl %r14,arch_set_page_states 262 263 /* Call arch specific early resume code */ 264 brasl %r14,s390_early_resume 265 266 /* Return 0 */ 267 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 268 lghi %r2,0 269 br %r14 270 271 .section .data..nosave,"aw",@progbits 272 .align 8 273.Ldisabled_wait_31: 274 .long 0x000a0000,0x00000000 275.Lpanic_string: 276 .asciz "Resume not possible because suspend CPU is no longer available" 277 .align 8 278.Lrestart_diag308_psw: 279 .long 0x00080000,0x80000000 280.Lrestart_suspend_psw: 281 .quad 0x0000000180000000,restart_suspend 282.Lnew_pgm_check_psw: 283 .quad 0,pgm_check_entry 284.Lresume_cpu: 285 .byte 0,0 286