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