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