17f904d7eSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */ 2543b9fd3SJohannes Berg/* 3543b9fd3SJohannes Berg * PowerPC 64-bit swsusp implementation 4543b9fd3SJohannes Berg * 5543b9fd3SJohannes Berg * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 6543b9fd3SJohannes Berg */ 7543b9fd3SJohannes Berg 8543b9fd3SJohannes Berg#include <linux/threads.h> 9543b9fd3SJohannes Berg#include <asm/processor.h> 10543b9fd3SJohannes Berg#include <asm/page.h> 11543b9fd3SJohannes Berg#include <asm/cputable.h> 12543b9fd3SJohannes Berg#include <asm/thread_info.h> 13543b9fd3SJohannes Berg#include <asm/ppc_asm.h> 14543b9fd3SJohannes Berg#include <asm/asm-offsets.h> 152c86cd18SChristophe Leroy#include <asm/feature-fixups.h> 16543b9fd3SJohannes Berg 17543b9fd3SJohannes Berg/* 18543b9fd3SJohannes Berg * Structure for storing CPU registers on the save area. 19543b9fd3SJohannes Berg */ 20543b9fd3SJohannes Berg#define SL_r1 0x00 /* stack pointer */ 21543b9fd3SJohannes Berg#define SL_PC 0x08 22543b9fd3SJohannes Berg#define SL_MSR 0x10 23543b9fd3SJohannes Berg#define SL_SDR1 0x18 24543b9fd3SJohannes Berg#define SL_XER 0x20 25543b9fd3SJohannes Berg#define SL_TB 0x40 26543b9fd3SJohannes Berg#define SL_r2 0x48 27543b9fd3SJohannes Berg#define SL_CR 0x50 28543b9fd3SJohannes Berg#define SL_LR 0x58 29543b9fd3SJohannes Berg#define SL_r12 0x60 30543b9fd3SJohannes Berg#define SL_r13 0x68 31543b9fd3SJohannes Berg#define SL_r14 0x70 32543b9fd3SJohannes Berg#define SL_r15 0x78 33543b9fd3SJohannes Berg#define SL_r16 0x80 34543b9fd3SJohannes Berg#define SL_r17 0x88 35543b9fd3SJohannes Berg#define SL_r18 0x90 36543b9fd3SJohannes Berg#define SL_r19 0x98 37543b9fd3SJohannes Berg#define SL_r20 0xa0 38543b9fd3SJohannes Berg#define SL_r21 0xa8 39543b9fd3SJohannes Berg#define SL_r22 0xb0 40543b9fd3SJohannes Berg#define SL_r23 0xb8 41543b9fd3SJohannes Berg#define SL_r24 0xc0 42543b9fd3SJohannes Berg#define SL_r25 0xc8 43543b9fd3SJohannes Berg#define SL_r26 0xd0 44543b9fd3SJohannes Berg#define SL_r27 0xd8 45543b9fd3SJohannes Berg#define SL_r28 0xe0 46543b9fd3SJohannes Berg#define SL_r29 0xe8 47543b9fd3SJohannes Berg#define SL_r30 0xf0 48543b9fd3SJohannes Berg#define SL_r31 0xf8 495a31057fSWang Dongsheng#define SL_SPRG1 0x100 505a31057fSWang Dongsheng#define SL_TCR 0x108 515a31057fSWang Dongsheng#define SL_SIZE SL_TCR+8 52543b9fd3SJohannes Berg 53543b9fd3SJohannes Berg/* these macros rely on the save area being 54543b9fd3SJohannes Berg * pointed to by r11 */ 555a31057fSWang Dongsheng 565a31057fSWang Dongsheng#define SAVE_SPR(register) \ 575a31057fSWang Dongsheng mfspr r0, SPRN_##register ;\ 585a31057fSWang Dongsheng std r0, SL_##register(r11) 595a31057fSWang Dongsheng#define RESTORE_SPR(register) \ 605a31057fSWang Dongsheng ld r0, SL_##register(r11) ;\ 615a31057fSWang Dongsheng mtspr SPRN_##register, r0 62543b9fd3SJohannes Berg#define SAVE_SPECIAL(special) \ 63543b9fd3SJohannes Berg mf##special r0 ;\ 64543b9fd3SJohannes Berg std r0, SL_##special(r11) 65543b9fd3SJohannes Berg#define RESTORE_SPECIAL(special) \ 66543b9fd3SJohannes Berg ld r0, SL_##special(r11) ;\ 67543b9fd3SJohannes Berg mt##special r0 68543b9fd3SJohannes Berg#define SAVE_REGISTER(reg) \ 69543b9fd3SJohannes Berg std reg, SL_##reg(r11) 70543b9fd3SJohannes Berg#define RESTORE_REGISTER(reg) \ 71543b9fd3SJohannes Berg ld reg, SL_##reg(r11) 72543b9fd3SJohannes Berg 73543b9fd3SJohannes Berg/* space for storing cpu state */ 74543b9fd3SJohannes Berg .section .data 75543b9fd3SJohannes Berg .align 5 76543b9fd3SJohannes Bergswsusp_save_area: 77543b9fd3SJohannes Berg .space SL_SIZE 78543b9fd3SJohannes Berg 79543b9fd3SJohannes Berg .section .text 80543b9fd3SJohannes Berg .align 5 81543b9fd3SJohannes Berg_GLOBAL(swsusp_arch_suspend) 82*dab3b8f4SNicholas Piggin LOAD_REG_ADDR(r11, swsusp_save_area) 83543b9fd3SJohannes Berg SAVE_SPECIAL(LR) 84543b9fd3SJohannes Berg SAVE_REGISTER(r1) 85543b9fd3SJohannes Berg SAVE_SPECIAL(CR) 86543b9fd3SJohannes Berg SAVE_SPECIAL(TB) 87543b9fd3SJohannes Berg SAVE_REGISTER(r2) 88543b9fd3SJohannes Berg SAVE_REGISTER(r12) 89543b9fd3SJohannes Berg SAVE_REGISTER(r13) 90543b9fd3SJohannes Berg SAVE_REGISTER(r14) 91543b9fd3SJohannes Berg SAVE_REGISTER(r15) 92543b9fd3SJohannes Berg SAVE_REGISTER(r16) 93543b9fd3SJohannes Berg SAVE_REGISTER(r17) 94543b9fd3SJohannes Berg SAVE_REGISTER(r18) 95543b9fd3SJohannes Berg SAVE_REGISTER(r19) 96543b9fd3SJohannes Berg SAVE_REGISTER(r20) 97543b9fd3SJohannes Berg SAVE_REGISTER(r21) 98543b9fd3SJohannes Berg SAVE_REGISTER(r22) 99543b9fd3SJohannes Berg SAVE_REGISTER(r23) 100543b9fd3SJohannes Berg SAVE_REGISTER(r24) 101543b9fd3SJohannes Berg SAVE_REGISTER(r25) 102543b9fd3SJohannes Berg SAVE_REGISTER(r26) 103543b9fd3SJohannes Berg SAVE_REGISTER(r27) 104543b9fd3SJohannes Berg SAVE_REGISTER(r28) 105543b9fd3SJohannes Berg SAVE_REGISTER(r29) 106543b9fd3SJohannes Berg SAVE_REGISTER(r30) 107543b9fd3SJohannes Berg SAVE_REGISTER(r31) 108543b9fd3SJohannes Berg SAVE_SPECIAL(MSR) 109543b9fd3SJohannes Berg SAVE_SPECIAL(XER) 1105a31057fSWang Dongsheng#ifdef CONFIG_PPC_BOOK3S_64 111711b5138SDan StreetmanBEGIN_FW_FTR_SECTION 1125a31057fSWang Dongsheng SAVE_SPECIAL(SDR1) 113711b5138SDan StreetmanEND_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) 1145a31057fSWang Dongsheng#else 1155a31057fSWang Dongsheng SAVE_SPR(TCR) 1165a31057fSWang Dongsheng 1175a31057fSWang Dongsheng /* Save SPRG1, SPRG1 be used save paca */ 1185a31057fSWang Dongsheng SAVE_SPR(SPRG1) 1195a31057fSWang Dongsheng#endif 120543b9fd3SJohannes Berg 121543b9fd3SJohannes Berg /* we push the stack up 128 bytes but don't store the 122543b9fd3SJohannes Berg * stack pointer on the stack like a real stackframe */ 123543b9fd3SJohannes Berg addi r1,r1,-128 124543b9fd3SJohannes Berg 125543b9fd3SJohannes Berg bl swsusp_save 126543b9fd3SJohannes Berg 127543b9fd3SJohannes Berg /* restore LR */ 128*dab3b8f4SNicholas Piggin LOAD_REG_ADDR(r11, swsusp_save_area) 129543b9fd3SJohannes Berg RESTORE_SPECIAL(LR) 130543b9fd3SJohannes Berg addi r1,r1,128 131543b9fd3SJohannes Berg 132543b9fd3SJohannes Berg blr 133543b9fd3SJohannes Berg 134543b9fd3SJohannes Berg/* Resume code */ 135543b9fd3SJohannes Berg_GLOBAL(swsusp_arch_resume) 136543b9fd3SJohannes Berg /* Stop pending alitvec streams and memory accesses */ 137543b9fd3SJohannes BergBEGIN_FTR_SECTION 138d51f86cfSAlexey Kardashevskiy PPC_DSSALL 139543b9fd3SJohannes BergEND_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) 140543b9fd3SJohannes Berg sync 141543b9fd3SJohannes Berg 142*dab3b8f4SNicholas Piggin LOAD_REG_ADDR(r11, restore_pblist) 143543b9fd3SJohannes Berg ld r12,0(r12) 144543b9fd3SJohannes Berg 145543b9fd3SJohannes Berg cmpdi r12,0 146543b9fd3SJohannes Berg beq- nothing_to_copy 1472e2b4043SJohannes Berg li r15,PAGE_SIZE>>3 148543b9fd3SJohannes Bergcopyloop: 149543b9fd3SJohannes Berg ld r13,pbe_address(r12) 150543b9fd3SJohannes Berg ld r14,pbe_orig_address(r12) 151543b9fd3SJohannes Berg 152543b9fd3SJohannes Berg mtctr r15 153543b9fd3SJohannes Berg li r10,0 154543b9fd3SJohannes Bergcopy_page_loop: 155543b9fd3SJohannes Berg ldx r0,r10,r13 156543b9fd3SJohannes Berg stdx r0,r10,r14 157543b9fd3SJohannes Berg addi r10,r10,8 158543b9fd3SJohannes Berg bdnz copy_page_loop 159543b9fd3SJohannes Berg 160543b9fd3SJohannes Berg ld r12,pbe_next(r12) 161543b9fd3SJohannes Berg cmpdi r12,0 162543b9fd3SJohannes Berg bne+ copyloop 163543b9fd3SJohannes Bergnothing_to_copy: 164543b9fd3SJohannes Berg 1655a31057fSWang Dongsheng#ifdef CONFIG_PPC_BOOK3S_64 166543b9fd3SJohannes Berg /* flush caches */ 167543b9fd3SJohannes Berg lis r3, 0x10 168543b9fd3SJohannes Berg mtctr r3 169543b9fd3SJohannes Berg li r3, 0 170543b9fd3SJohannes Berg ori r3, r3, CONFIG_KERNEL_START>>48 171543b9fd3SJohannes Berg li r0, 48 172543b9fd3SJohannes Berg sld r3, r3, r0 173543b9fd3SJohannes Berg li r0, 0 174543b9fd3SJohannes Berg1: 1758a583c0aSAndreas Schwab dcbf 0,r3 176543b9fd3SJohannes Berg addi r3,r3,0x20 177543b9fd3SJohannes Berg bdnz 1b 178543b9fd3SJohannes Berg 179543b9fd3SJohannes Berg sync 180543b9fd3SJohannes Berg 181543b9fd3SJohannes Berg tlbia 1825a31057fSWang Dongsheng#endif 183543b9fd3SJohannes Berg 184*dab3b8f4SNicholas Piggin LOAD_REG_ADDR(r11, swsusp_save_area) 185543b9fd3SJohannes Berg 186543b9fd3SJohannes Berg RESTORE_SPECIAL(CR) 187543b9fd3SJohannes Berg 188543b9fd3SJohannes Berg /* restore timebase */ 189543b9fd3SJohannes Berg /* load saved tb */ 190543b9fd3SJohannes Berg ld r1, SL_TB(r11) 191543b9fd3SJohannes Berg /* get upper 32 bits of it */ 192543b9fd3SJohannes Berg srdi r2, r1, 32 193543b9fd3SJohannes Berg /* clear tb lower to avoid wrap */ 194543b9fd3SJohannes Berg li r0, 0 195543b9fd3SJohannes Berg mttbl r0 196543b9fd3SJohannes Berg /* set tb upper */ 197543b9fd3SJohannes Berg mttbu r2 198543b9fd3SJohannes Berg /* set tb lower */ 199543b9fd3SJohannes Berg mttbl r1 200543b9fd3SJohannes Berg 201543b9fd3SJohannes Berg /* restore registers */ 202543b9fd3SJohannes Berg RESTORE_REGISTER(r1) 203543b9fd3SJohannes Berg RESTORE_REGISTER(r2) 204543b9fd3SJohannes Berg RESTORE_REGISTER(r12) 205543b9fd3SJohannes Berg RESTORE_REGISTER(r13) 206543b9fd3SJohannes Berg RESTORE_REGISTER(r14) 207543b9fd3SJohannes Berg RESTORE_REGISTER(r15) 208543b9fd3SJohannes Berg RESTORE_REGISTER(r16) 209543b9fd3SJohannes Berg RESTORE_REGISTER(r17) 210543b9fd3SJohannes Berg RESTORE_REGISTER(r18) 211543b9fd3SJohannes Berg RESTORE_REGISTER(r19) 212543b9fd3SJohannes Berg RESTORE_REGISTER(r20) 213543b9fd3SJohannes Berg RESTORE_REGISTER(r21) 214543b9fd3SJohannes Berg RESTORE_REGISTER(r22) 215543b9fd3SJohannes Berg RESTORE_REGISTER(r23) 216543b9fd3SJohannes Berg RESTORE_REGISTER(r24) 217543b9fd3SJohannes Berg RESTORE_REGISTER(r25) 218543b9fd3SJohannes Berg RESTORE_REGISTER(r26) 219543b9fd3SJohannes Berg RESTORE_REGISTER(r27) 220543b9fd3SJohannes Berg RESTORE_REGISTER(r28) 221543b9fd3SJohannes Berg RESTORE_REGISTER(r29) 222543b9fd3SJohannes Berg RESTORE_REGISTER(r30) 223543b9fd3SJohannes Berg RESTORE_REGISTER(r31) 2245a31057fSWang Dongsheng 2255a31057fSWang Dongsheng#ifdef CONFIG_PPC_BOOK3S_64 226543b9fd3SJohannes Berg /* can't use RESTORE_SPECIAL(MSR) */ 227543b9fd3SJohannes Berg ld r0, SL_MSR(r11) 228543b9fd3SJohannes Berg mtmsrd r0, 0 229711b5138SDan StreetmanBEGIN_FW_FTR_SECTION 230543b9fd3SJohannes Berg RESTORE_SPECIAL(SDR1) 231711b5138SDan StreetmanEND_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) 2325a31057fSWang Dongsheng#else 2335a31057fSWang Dongsheng /* Restore SPRG1, be used to save paca */ 2345a31057fSWang Dongsheng ld r0, SL_SPRG1(r11) 2355a31057fSWang Dongsheng mtsprg 1, r0 2365a31057fSWang Dongsheng 2375a31057fSWang Dongsheng RESTORE_SPECIAL(MSR) 2385a31057fSWang Dongsheng 2395a31057fSWang Dongsheng /* Restore TCR and clear any pending bits in TSR. */ 2405a31057fSWang Dongsheng RESTORE_SPR(TCR) 2415a31057fSWang Dongsheng lis r0, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h 2425a31057fSWang Dongsheng mtspr SPRN_TSR, r0 2435a31057fSWang Dongsheng 2445a31057fSWang Dongsheng /* Kick decrementer */ 2455a31057fSWang Dongsheng li r0, 1 2465a31057fSWang Dongsheng mtdec r0 2475a31057fSWang Dongsheng 2485a31057fSWang Dongsheng /* Invalidate all tlbs */ 2495a31057fSWang Dongsheng bl _tlbil_all 2505a31057fSWang Dongsheng#endif 251543b9fd3SJohannes Berg RESTORE_SPECIAL(XER) 252543b9fd3SJohannes Berg 253543b9fd3SJohannes Berg sync 254543b9fd3SJohannes Berg 255543b9fd3SJohannes Berg addi r1,r1,-128 2565a31057fSWang Dongsheng#ifdef CONFIG_PPC_BOOK3S_64 25794ee4272SNicholas Piggin bl slb_flush_and_restore_bolted 2585a31057fSWang Dongsheng#endif 259543b9fd3SJohannes Berg bl do_after_copyback 260543b9fd3SJohannes Berg addi r1,r1,128 261543b9fd3SJohannes Berg 262*dab3b8f4SNicholas Piggin LOAD_REG_ADDR(r11, swsusp_save_area) 263543b9fd3SJohannes Berg RESTORE_SPECIAL(LR) 264543b9fd3SJohannes Berg 265543b9fd3SJohannes Berg li r3, 0 266543b9fd3SJohannes Berg blr 267