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