18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PowerPC 64-bit swsusp implementation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/threads.h> 98c2ecf20Sopenharmony_ci#include <asm/processor.h> 108c2ecf20Sopenharmony_ci#include <asm/page.h> 118c2ecf20Sopenharmony_ci#include <asm/cputable.h> 128c2ecf20Sopenharmony_ci#include <asm/thread_info.h> 138c2ecf20Sopenharmony_ci#include <asm/ppc_asm.h> 148c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h> 158c2ecf20Sopenharmony_ci#include <asm/feature-fixups.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * Structure for storing CPU registers on the save area. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci#define SL_r1 0x00 /* stack pointer */ 218c2ecf20Sopenharmony_ci#define SL_PC 0x08 228c2ecf20Sopenharmony_ci#define SL_MSR 0x10 238c2ecf20Sopenharmony_ci#define SL_SDR1 0x18 248c2ecf20Sopenharmony_ci#define SL_XER 0x20 258c2ecf20Sopenharmony_ci#define SL_TB 0x40 268c2ecf20Sopenharmony_ci#define SL_r2 0x48 278c2ecf20Sopenharmony_ci#define SL_CR 0x50 288c2ecf20Sopenharmony_ci#define SL_LR 0x58 298c2ecf20Sopenharmony_ci#define SL_r12 0x60 308c2ecf20Sopenharmony_ci#define SL_r13 0x68 318c2ecf20Sopenharmony_ci#define SL_r14 0x70 328c2ecf20Sopenharmony_ci#define SL_r15 0x78 338c2ecf20Sopenharmony_ci#define SL_r16 0x80 348c2ecf20Sopenharmony_ci#define SL_r17 0x88 358c2ecf20Sopenharmony_ci#define SL_r18 0x90 368c2ecf20Sopenharmony_ci#define SL_r19 0x98 378c2ecf20Sopenharmony_ci#define SL_r20 0xa0 388c2ecf20Sopenharmony_ci#define SL_r21 0xa8 398c2ecf20Sopenharmony_ci#define SL_r22 0xb0 408c2ecf20Sopenharmony_ci#define SL_r23 0xb8 418c2ecf20Sopenharmony_ci#define SL_r24 0xc0 428c2ecf20Sopenharmony_ci#define SL_r25 0xc8 438c2ecf20Sopenharmony_ci#define SL_r26 0xd0 448c2ecf20Sopenharmony_ci#define SL_r27 0xd8 458c2ecf20Sopenharmony_ci#define SL_r28 0xe0 468c2ecf20Sopenharmony_ci#define SL_r29 0xe8 478c2ecf20Sopenharmony_ci#define SL_r30 0xf0 488c2ecf20Sopenharmony_ci#define SL_r31 0xf8 498c2ecf20Sopenharmony_ci#define SL_SPRG1 0x100 508c2ecf20Sopenharmony_ci#define SL_TCR 0x108 518c2ecf20Sopenharmony_ci#define SL_SIZE SL_TCR+8 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* these macros rely on the save area being 548c2ecf20Sopenharmony_ci * pointed to by r11 */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define SAVE_SPR(register) \ 578c2ecf20Sopenharmony_ci mfspr r0, SPRN_##register ;\ 588c2ecf20Sopenharmony_ci std r0, SL_##register(r11) 598c2ecf20Sopenharmony_ci#define RESTORE_SPR(register) \ 608c2ecf20Sopenharmony_ci ld r0, SL_##register(r11) ;\ 618c2ecf20Sopenharmony_ci mtspr SPRN_##register, r0 628c2ecf20Sopenharmony_ci#define SAVE_SPECIAL(special) \ 638c2ecf20Sopenharmony_ci mf##special r0 ;\ 648c2ecf20Sopenharmony_ci std r0, SL_##special(r11) 658c2ecf20Sopenharmony_ci#define RESTORE_SPECIAL(special) \ 668c2ecf20Sopenharmony_ci ld r0, SL_##special(r11) ;\ 678c2ecf20Sopenharmony_ci mt##special r0 688c2ecf20Sopenharmony_ci#define SAVE_REGISTER(reg) \ 698c2ecf20Sopenharmony_ci std reg, SL_##reg(r11) 708c2ecf20Sopenharmony_ci#define RESTORE_REGISTER(reg) \ 718c2ecf20Sopenharmony_ci ld reg, SL_##reg(r11) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* space for storing cpu state */ 748c2ecf20Sopenharmony_ci .section .data 758c2ecf20Sopenharmony_ci .align 5 768c2ecf20Sopenharmony_ciswsusp_save_area: 778c2ecf20Sopenharmony_ci .space SL_SIZE 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci .section ".toc","aw" 808c2ecf20Sopenharmony_ciswsusp_save_area_ptr: 818c2ecf20Sopenharmony_ci .tc swsusp_save_area[TC],swsusp_save_area 828c2ecf20Sopenharmony_cirestore_pblist_ptr: 838c2ecf20Sopenharmony_ci .tc restore_pblist[TC],restore_pblist 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci .section .text 868c2ecf20Sopenharmony_ci .align 5 878c2ecf20Sopenharmony_ci_GLOBAL(swsusp_arch_suspend) 888c2ecf20Sopenharmony_ci ld r11,swsusp_save_area_ptr@toc(r2) 898c2ecf20Sopenharmony_ci SAVE_SPECIAL(LR) 908c2ecf20Sopenharmony_ci SAVE_REGISTER(r1) 918c2ecf20Sopenharmony_ci SAVE_SPECIAL(CR) 928c2ecf20Sopenharmony_ci SAVE_SPECIAL(TB) 938c2ecf20Sopenharmony_ci SAVE_REGISTER(r2) 948c2ecf20Sopenharmony_ci SAVE_REGISTER(r12) 958c2ecf20Sopenharmony_ci SAVE_REGISTER(r13) 968c2ecf20Sopenharmony_ci SAVE_REGISTER(r14) 978c2ecf20Sopenharmony_ci SAVE_REGISTER(r15) 988c2ecf20Sopenharmony_ci SAVE_REGISTER(r16) 998c2ecf20Sopenharmony_ci SAVE_REGISTER(r17) 1008c2ecf20Sopenharmony_ci SAVE_REGISTER(r18) 1018c2ecf20Sopenharmony_ci SAVE_REGISTER(r19) 1028c2ecf20Sopenharmony_ci SAVE_REGISTER(r20) 1038c2ecf20Sopenharmony_ci SAVE_REGISTER(r21) 1048c2ecf20Sopenharmony_ci SAVE_REGISTER(r22) 1058c2ecf20Sopenharmony_ci SAVE_REGISTER(r23) 1068c2ecf20Sopenharmony_ci SAVE_REGISTER(r24) 1078c2ecf20Sopenharmony_ci SAVE_REGISTER(r25) 1088c2ecf20Sopenharmony_ci SAVE_REGISTER(r26) 1098c2ecf20Sopenharmony_ci SAVE_REGISTER(r27) 1108c2ecf20Sopenharmony_ci SAVE_REGISTER(r28) 1118c2ecf20Sopenharmony_ci SAVE_REGISTER(r29) 1128c2ecf20Sopenharmony_ci SAVE_REGISTER(r30) 1138c2ecf20Sopenharmony_ci SAVE_REGISTER(r31) 1148c2ecf20Sopenharmony_ci SAVE_SPECIAL(MSR) 1158c2ecf20Sopenharmony_ci SAVE_SPECIAL(XER) 1168c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 1178c2ecf20Sopenharmony_ciBEGIN_FW_FTR_SECTION 1188c2ecf20Sopenharmony_ci SAVE_SPECIAL(SDR1) 1198c2ecf20Sopenharmony_ciEND_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) 1208c2ecf20Sopenharmony_ci#else 1218c2ecf20Sopenharmony_ci SAVE_SPR(TCR) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* Save SPRG1, SPRG1 be used save paca */ 1248c2ecf20Sopenharmony_ci SAVE_SPR(SPRG1) 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* we push the stack up 128 bytes but don't store the 1288c2ecf20Sopenharmony_ci * stack pointer on the stack like a real stackframe */ 1298c2ecf20Sopenharmony_ci addi r1,r1,-128 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci bl _iommu_save 1328c2ecf20Sopenharmony_ci bl swsusp_save 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* restore LR */ 1358c2ecf20Sopenharmony_ci ld r11,swsusp_save_area_ptr@toc(r2) 1368c2ecf20Sopenharmony_ci RESTORE_SPECIAL(LR) 1378c2ecf20Sopenharmony_ci addi r1,r1,128 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci blr 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* Resume code */ 1428c2ecf20Sopenharmony_ci_GLOBAL(swsusp_arch_resume) 1438c2ecf20Sopenharmony_ci /* Stop pending alitvec streams and memory accesses */ 1448c2ecf20Sopenharmony_ciBEGIN_FTR_SECTION 1458c2ecf20Sopenharmony_ci PPC_DSSALL 1468c2ecf20Sopenharmony_ciEND_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) 1478c2ecf20Sopenharmony_ci sync 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci ld r12,restore_pblist_ptr@toc(r2) 1508c2ecf20Sopenharmony_ci ld r12,0(r12) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci cmpdi r12,0 1538c2ecf20Sopenharmony_ci beq- nothing_to_copy 1548c2ecf20Sopenharmony_ci li r15,PAGE_SIZE>>3 1558c2ecf20Sopenharmony_cicopyloop: 1568c2ecf20Sopenharmony_ci ld r13,pbe_address(r12) 1578c2ecf20Sopenharmony_ci ld r14,pbe_orig_address(r12) 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci mtctr r15 1608c2ecf20Sopenharmony_ci li r10,0 1618c2ecf20Sopenharmony_cicopy_page_loop: 1628c2ecf20Sopenharmony_ci ldx r0,r10,r13 1638c2ecf20Sopenharmony_ci stdx r0,r10,r14 1648c2ecf20Sopenharmony_ci addi r10,r10,8 1658c2ecf20Sopenharmony_ci bdnz copy_page_loop 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ld r12,pbe_next(r12) 1688c2ecf20Sopenharmony_ci cmpdi r12,0 1698c2ecf20Sopenharmony_ci bne+ copyloop 1708c2ecf20Sopenharmony_cinothing_to_copy: 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 1738c2ecf20Sopenharmony_ci /* flush caches */ 1748c2ecf20Sopenharmony_ci lis r3, 0x10 1758c2ecf20Sopenharmony_ci mtctr r3 1768c2ecf20Sopenharmony_ci li r3, 0 1778c2ecf20Sopenharmony_ci ori r3, r3, CONFIG_KERNEL_START>>48 1788c2ecf20Sopenharmony_ci li r0, 48 1798c2ecf20Sopenharmony_ci sld r3, r3, r0 1808c2ecf20Sopenharmony_ci li r0, 0 1818c2ecf20Sopenharmony_ci1: 1828c2ecf20Sopenharmony_ci dcbf 0,r3 1838c2ecf20Sopenharmony_ci addi r3,r3,0x20 1848c2ecf20Sopenharmony_ci bdnz 1b 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci sync 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci tlbia 1898c2ecf20Sopenharmony_ci#endif 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ld r11,swsusp_save_area_ptr@toc(r2) 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci RESTORE_SPECIAL(CR) 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* restore timebase */ 1968c2ecf20Sopenharmony_ci /* load saved tb */ 1978c2ecf20Sopenharmony_ci ld r1, SL_TB(r11) 1988c2ecf20Sopenharmony_ci /* get upper 32 bits of it */ 1998c2ecf20Sopenharmony_ci srdi r2, r1, 32 2008c2ecf20Sopenharmony_ci /* clear tb lower to avoid wrap */ 2018c2ecf20Sopenharmony_ci li r0, 0 2028c2ecf20Sopenharmony_ci mttbl r0 2038c2ecf20Sopenharmony_ci /* set tb upper */ 2048c2ecf20Sopenharmony_ci mttbu r2 2058c2ecf20Sopenharmony_ci /* set tb lower */ 2068c2ecf20Sopenharmony_ci mttbl r1 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* restore registers */ 2098c2ecf20Sopenharmony_ci RESTORE_REGISTER(r1) 2108c2ecf20Sopenharmony_ci RESTORE_REGISTER(r2) 2118c2ecf20Sopenharmony_ci RESTORE_REGISTER(r12) 2128c2ecf20Sopenharmony_ci RESTORE_REGISTER(r13) 2138c2ecf20Sopenharmony_ci RESTORE_REGISTER(r14) 2148c2ecf20Sopenharmony_ci RESTORE_REGISTER(r15) 2158c2ecf20Sopenharmony_ci RESTORE_REGISTER(r16) 2168c2ecf20Sopenharmony_ci RESTORE_REGISTER(r17) 2178c2ecf20Sopenharmony_ci RESTORE_REGISTER(r18) 2188c2ecf20Sopenharmony_ci RESTORE_REGISTER(r19) 2198c2ecf20Sopenharmony_ci RESTORE_REGISTER(r20) 2208c2ecf20Sopenharmony_ci RESTORE_REGISTER(r21) 2218c2ecf20Sopenharmony_ci RESTORE_REGISTER(r22) 2228c2ecf20Sopenharmony_ci RESTORE_REGISTER(r23) 2238c2ecf20Sopenharmony_ci RESTORE_REGISTER(r24) 2248c2ecf20Sopenharmony_ci RESTORE_REGISTER(r25) 2258c2ecf20Sopenharmony_ci RESTORE_REGISTER(r26) 2268c2ecf20Sopenharmony_ci RESTORE_REGISTER(r27) 2278c2ecf20Sopenharmony_ci RESTORE_REGISTER(r28) 2288c2ecf20Sopenharmony_ci RESTORE_REGISTER(r29) 2298c2ecf20Sopenharmony_ci RESTORE_REGISTER(r30) 2308c2ecf20Sopenharmony_ci RESTORE_REGISTER(r31) 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 2338c2ecf20Sopenharmony_ci /* can't use RESTORE_SPECIAL(MSR) */ 2348c2ecf20Sopenharmony_ci ld r0, SL_MSR(r11) 2358c2ecf20Sopenharmony_ci mtmsrd r0, 0 2368c2ecf20Sopenharmony_ciBEGIN_FW_FTR_SECTION 2378c2ecf20Sopenharmony_ci RESTORE_SPECIAL(SDR1) 2388c2ecf20Sopenharmony_ciEND_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) 2398c2ecf20Sopenharmony_ci#else 2408c2ecf20Sopenharmony_ci /* Restore SPRG1, be used to save paca */ 2418c2ecf20Sopenharmony_ci ld r0, SL_SPRG1(r11) 2428c2ecf20Sopenharmony_ci mtsprg 1, r0 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci RESTORE_SPECIAL(MSR) 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Restore TCR and clear any pending bits in TSR. */ 2478c2ecf20Sopenharmony_ci RESTORE_SPR(TCR) 2488c2ecf20Sopenharmony_ci lis r0, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h 2498c2ecf20Sopenharmony_ci mtspr SPRN_TSR, r0 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* Kick decrementer */ 2528c2ecf20Sopenharmony_ci li r0, 1 2538c2ecf20Sopenharmony_ci mtdec r0 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Invalidate all tlbs */ 2568c2ecf20Sopenharmony_ci bl _tlbil_all 2578c2ecf20Sopenharmony_ci#endif 2588c2ecf20Sopenharmony_ci RESTORE_SPECIAL(XER) 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci sync 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci addi r1,r1,-128 2638c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 2648c2ecf20Sopenharmony_ci bl slb_flush_and_restore_bolted 2658c2ecf20Sopenharmony_ci#endif 2668c2ecf20Sopenharmony_ci bl do_after_copyback 2678c2ecf20Sopenharmony_ci addi r1,r1,128 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ld r11,swsusp_save_area_ptr@toc(r2) 2708c2ecf20Sopenharmony_ci RESTORE_SPECIAL(LR) 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci li r3, 0 2738c2ecf20Sopenharmony_ci blr 274