xref: /linux/arch/powerpc/kernel/swsusp_asm64.S (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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