1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * PowerPC 64-bit swsusp implementation
4 *
5 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
6 */
7
8#include <linux/threads.h>
9#include <asm/processor.h>
10#include <asm/page.h>
11#include <asm/cputable.h>
12#include <asm/thread_info.h>
13#include <asm/ppc_asm.h>
14#include <asm/asm-offsets.h>
15#include <asm/feature-fixups.h>
16
17/*
18 * Structure for storing CPU registers on the save area.
19 */
20#define SL_r1		0x00	/* stack pointer */
21#define SL_PC		0x08
22#define SL_MSR		0x10
23#define SL_SDR1		0x18
24#define SL_XER		0x20
25#define SL_TB		0x40
26#define SL_r2		0x48
27#define SL_CR		0x50
28#define SL_LR		0x58
29#define SL_r12		0x60
30#define SL_r13		0x68
31#define SL_r14		0x70
32#define SL_r15		0x78
33#define SL_r16		0x80
34#define SL_r17		0x88
35#define SL_r18		0x90
36#define SL_r19		0x98
37#define SL_r20		0xa0
38#define SL_r21		0xa8
39#define SL_r22		0xb0
40#define SL_r23		0xb8
41#define SL_r24		0xc0
42#define SL_r25		0xc8
43#define SL_r26		0xd0
44#define SL_r27		0xd8
45#define SL_r28		0xe0
46#define SL_r29		0xe8
47#define SL_r30		0xf0
48#define SL_r31		0xf8
49#define SL_SPRG1	0x100
50#define SL_TCR		0x108
51#define SL_SIZE		SL_TCR+8
52
53/* these macros rely on the save area being
54 * pointed to by r11 */
55
56#define SAVE_SPR(register)		\
57	mfspr	r0, SPRN_##register	;\
58	std	r0, SL_##register(r11)
59#define RESTORE_SPR(register)		\
60	ld	r0, SL_##register(r11)	;\
61	mtspr	SPRN_##register, r0
62#define SAVE_SPECIAL(special)		\
63	mf##special	r0		;\
64	std	r0, SL_##special(r11)
65#define RESTORE_SPECIAL(special)	\
66	ld	r0, SL_##special(r11)	;\
67	mt##special	r0
68#define SAVE_REGISTER(reg)		\
69	std	reg, SL_##reg(r11)
70#define RESTORE_REGISTER(reg)		\
71	ld	reg, SL_##reg(r11)
72
73/* space for storing cpu state */
74	.section .data
75	.align  5
76swsusp_save_area:
77	.space SL_SIZE
78
79	.section ".toc","aw"
80swsusp_save_area_ptr:
81	.tc	swsusp_save_area[TC],swsusp_save_area
82restore_pblist_ptr:
83	.tc	restore_pblist[TC],restore_pblist
84
85	.section .text
86	.align  5
87_GLOBAL(swsusp_arch_suspend)
88	ld	r11,swsusp_save_area_ptr@toc(r2)
89	SAVE_SPECIAL(LR)
90	SAVE_REGISTER(r1)
91	SAVE_SPECIAL(CR)
92	SAVE_SPECIAL(TB)
93	SAVE_REGISTER(r2)
94	SAVE_REGISTER(r12)
95	SAVE_REGISTER(r13)
96	SAVE_REGISTER(r14)
97	SAVE_REGISTER(r15)
98	SAVE_REGISTER(r16)
99	SAVE_REGISTER(r17)
100	SAVE_REGISTER(r18)
101	SAVE_REGISTER(r19)
102	SAVE_REGISTER(r20)
103	SAVE_REGISTER(r21)
104	SAVE_REGISTER(r22)
105	SAVE_REGISTER(r23)
106	SAVE_REGISTER(r24)
107	SAVE_REGISTER(r25)
108	SAVE_REGISTER(r26)
109	SAVE_REGISTER(r27)
110	SAVE_REGISTER(r28)
111	SAVE_REGISTER(r29)
112	SAVE_REGISTER(r30)
113	SAVE_REGISTER(r31)
114	SAVE_SPECIAL(MSR)
115	SAVE_SPECIAL(XER)
116#ifdef CONFIG_PPC_BOOK3S_64
117BEGIN_FW_FTR_SECTION
118	SAVE_SPECIAL(SDR1)
119END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR)
120#else
121	SAVE_SPR(TCR)
122
123	/* Save SPRG1, SPRG1 be used save paca */
124	SAVE_SPR(SPRG1)
125#endif
126
127	/* we push the stack up 128 bytes but don't store the
128	 * stack pointer on the stack like a real stackframe */
129	addi	r1,r1,-128
130
131	bl swsusp_save
132
133	/* restore LR */
134	ld	r11,swsusp_save_area_ptr@toc(r2)
135	RESTORE_SPECIAL(LR)
136	addi	r1,r1,128
137
138	blr
139
140/* Resume code */
141_GLOBAL(swsusp_arch_resume)
142	/* Stop pending alitvec streams and memory accesses */
143BEGIN_FTR_SECTION
144	DSSALL
145END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
146	sync
147
148	ld	r12,restore_pblist_ptr@toc(r2)
149	ld	r12,0(r12)
150
151	cmpdi	r12,0
152	beq-	nothing_to_copy
153	li	r15,PAGE_SIZE>>3
154copyloop:
155	ld	r13,pbe_address(r12)
156	ld	r14,pbe_orig_address(r12)
157
158	mtctr	r15
159	li	r10,0
160copy_page_loop:
161	ldx	r0,r10,r13
162	stdx	r0,r10,r14
163	addi	r10,r10,8
164	bdnz copy_page_loop
165
166	ld	r12,pbe_next(r12)
167	cmpdi	r12,0
168	bne+	copyloop
169nothing_to_copy:
170
171#ifdef CONFIG_PPC_BOOK3S_64
172	/* flush caches */
173	lis	r3, 0x10
174	mtctr	r3
175	li	r3, 0
176	ori	r3, r3, CONFIG_KERNEL_START>>48
177	li	r0, 48
178	sld	r3, r3, r0
179	li	r0, 0
1801:
181	dcbf	0,r3
182	addi	r3,r3,0x20
183	bdnz	1b
184
185	sync
186
187	tlbia
188#endif
189
190	ld	r11,swsusp_save_area_ptr@toc(r2)
191
192	RESTORE_SPECIAL(CR)
193
194	/* restore timebase */
195	/* load saved tb */
196	ld	r1, SL_TB(r11)
197	/* get upper 32 bits of it */
198	srdi	r2, r1, 32
199	/* clear tb lower to avoid wrap */
200	li	r0, 0
201	mttbl	r0
202	/* set tb upper */
203	mttbu	r2
204	/* set tb lower */
205	mttbl	r1
206
207	/* restore registers */
208	RESTORE_REGISTER(r1)
209	RESTORE_REGISTER(r2)
210	RESTORE_REGISTER(r12)
211	RESTORE_REGISTER(r13)
212	RESTORE_REGISTER(r14)
213	RESTORE_REGISTER(r15)
214	RESTORE_REGISTER(r16)
215	RESTORE_REGISTER(r17)
216	RESTORE_REGISTER(r18)
217	RESTORE_REGISTER(r19)
218	RESTORE_REGISTER(r20)
219	RESTORE_REGISTER(r21)
220	RESTORE_REGISTER(r22)
221	RESTORE_REGISTER(r23)
222	RESTORE_REGISTER(r24)
223	RESTORE_REGISTER(r25)
224	RESTORE_REGISTER(r26)
225	RESTORE_REGISTER(r27)
226	RESTORE_REGISTER(r28)
227	RESTORE_REGISTER(r29)
228	RESTORE_REGISTER(r30)
229	RESTORE_REGISTER(r31)
230
231#ifdef CONFIG_PPC_BOOK3S_64
232	/* can't use RESTORE_SPECIAL(MSR) */
233	ld	r0, SL_MSR(r11)
234	mtmsrd	r0, 0
235BEGIN_FW_FTR_SECTION
236	RESTORE_SPECIAL(SDR1)
237END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR)
238#else
239	/* Restore SPRG1, be used to save paca */
240	ld	r0, SL_SPRG1(r11)
241	mtsprg	1, r0
242
243	RESTORE_SPECIAL(MSR)
244
245	/* Restore TCR and clear any pending bits in TSR. */
246	RESTORE_SPR(TCR)
247	lis	r0, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h
248	mtspr	SPRN_TSR, r0
249
250	/* Kick decrementer */
251	li	r0, 1
252	mtdec	r0
253
254	/* Invalidate all tlbs */
255	bl	_tlbil_all
256#endif
257	RESTORE_SPECIAL(XER)
258
259	sync
260
261	addi	r1,r1,-128
262#ifdef CONFIG_PPC_BOOK3S_64
263	bl	slb_flush_and_restore_bolted
264#endif
265	bl	do_after_copyback
266	addi	r1,r1,128
267
268	ld	r11,swsusp_save_area_ptr@toc(r2)
269	RESTORE_SPECIAL(LR)
270
271	li	r3, 0
272	blr
273