linux/arch/s390/kernel/swsusp.S
<<
>>
Prefs
   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