aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/swsusp_asm64.S
blob: 86ac1d90d02bcb3d80060d7531da58022f685987 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/*
 * PowerPC 64-bit swsusp implementation
 *
 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
 *
 * GPLv2
 */

#include <linux/threads.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/cputable.h>
#include <asm/thread_info.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>

/*
 * Structure for storing CPU registers on the save area.
 */
#define SL_r1		0x00	/* stack pointer */
#define SL_PC		0x08
#define SL_MSR		0x10
#define SL_SDR1		0x18
#define SL_XER		0x20
#define SL_TB		0x40
#define SL_r2		0x48
#define SL_CR		0x50
#define SL_LR		0x58
#define SL_r12		0x60
#define SL_r13		0x68
#define SL_r14		0x70
#define SL_r15		0x78
#define SL_r16		0x80
#define SL_r17		0x88
#define SL_r18		0x90
#define SL_r19		0x98
#define SL_r20		0xa0
#define SL_r21		0xa8
#define SL_r22		0xb0
#define SL_r23		0xb8
#define SL_r24		0xc0
#define SL_r25		0xc8
#define SL_r26		0xd0
#define SL_r27		0xd8
#define SL_r28		0xe0
#define SL_r29		0xe8
#define SL_r30		0xf0
#define SL_r31		0xf8
#define SL_SIZE		SL_r31+8

/* these macros rely on the save area being
 * pointed to by r11 */
#define SAVE_SPECIAL(special)		\
	mf##special	r0		;\
	std	r0, SL_##special(r11)
#define RESTORE_SPECIAL(special)	\
	ld	r0, SL_##special(r11)	;\
	mt##special	r0
#define SAVE_REGISTER(reg)		\
	std	reg, SL_##reg(r11)
#define RESTORE_REGISTER(reg)		\
	ld	reg, SL_##reg(r11)

/* space for storing cpu state */
	.section .data
	.align  5
swsusp_save_area:
	.space SL_SIZE

	.section ".toc","aw"
swsusp_save_area_ptr:
	.tc	swsusp_save_area[TC],swsusp_save_area
restore_pblist_ptr:
	.tc	restore_pblist[TC],restore_pblist

	.section .text
	.align  5
_GLOBAL(swsusp_arch_suspend)
	ld	r11,swsusp_save_area_ptr@toc(r2)
	SAVE_SPECIAL(LR)
	SAVE_REGISTER(r1)
	SAVE_SPECIAL(CR)
	SAVE_SPECIAL(TB)
	SAVE_REGISTER(r2)
	SAVE_REGISTER(r12)
	SAVE_REGISTER(r13)
	SAVE_REGISTER(r14)
	SAVE_REGISTER(r15)
	SAVE_REGISTER(r16)
	SAVE_REGISTER(r17)
	SAVE_REGISTER(r18)
	SAVE_REGISTER(r19)
	SAVE_REGISTER(r20)
	SAVE_REGISTER(r21)
	SAVE_REGISTER(r22)
	SAVE_REGISTER(r23)
	SAVE_REGISTER(r24)
	SAVE_REGISTER(r25)
	SAVE_REGISTER(r26)
	SAVE_REGISTER(r27)
	SAVE_REGISTER(r28)
	SAVE_REGISTER(r29)
	SAVE_REGISTER(r30)
	SAVE_REGISTER(r31)
	SAVE_SPECIAL(MSR)
	SAVE_SPECIAL(SDR1)
	SAVE_SPECIAL(XER)

	/* we push the stack up 128 bytes but don't store the
	 * stack pointer on the stack like a real stackframe */
	addi	r1,r1,-128

	bl _iommu_save
	bl swsusp_save

	/* restore LR */
	ld	r11,swsusp_save_area_ptr@toc(r2)
	RESTORE_SPECIAL(LR)
	addi	r1,r1,128

	blr

/* Resume code */
_GLOBAL(swsusp_arch_resume)
	/* Stop pending alitvec streams and memory accesses */
BEGIN_FTR_SECTION
	DSSALL
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
	sync

	ld	r12,restore_pblist_ptr@toc(r2)
	ld	r12,0(r12)

	cmpdi	r12,0
	beq-	nothing_to_copy
	li	r15,PAGE_SIZE>>3
copyloop:
	ld	r13,pbe_address(r12)
	ld	r14,pbe_orig_address(r12)

	mtctr	r15
	li	r10,0
copy_page_loop:
	ldx	r0,r10,r13
	stdx	r0,r10,r14
	addi	r10,r10,8
	bdnz copy_page_loop

	ld	r12,pbe_next(r12)
	cmpdi	r12,0
	bne+	copyloop
nothing_to_copy:

	/* flush caches */
	lis	r3, 0x10
	mtctr	r3
	li	r3, 0
	ori	r3, r3, CONFIG_KERNEL_START>>48
	li	r0, 48
	sld	r3, r3, r0
	li	r0, 0
1:
	dcbf	r0,r3
	addi	r3,r3,0x20
	bdnz	1b

	sync

	tlbia

	ld	r11,swsusp_save_area_ptr@toc(r2)

	RESTORE_SPECIAL(CR)

	/* restore timebase */
	/* load saved tb */
	ld	r1, SL_TB(r11)
	/* get upper 32 bits of it */
	srdi	r2, r1, 32
	/* clear tb lower to avoid wrap */
	li	r0, 0
	mttbl	r0
	/* set tb upper */
	mttbu	r2
	/* set tb lower */
	mttbl	r1

	/* restore registers */
	RESTORE_REGISTER(r1)
	RESTORE_REGISTER(r2)
	RESTORE_REGISTER(r12)
	RESTORE_REGISTER(r13)
	RESTORE_REGISTER(r14)
	RESTORE_REGISTER(r15)
	RESTORE_REGISTER(r16)
	RESTORE_REGISTER(r17)
	RESTORE_REGISTER(r18)
	RESTORE_REGISTER(r19)
	RESTORE_REGISTER(r20)
	RESTORE_REGISTER(r21)
	RESTORE_REGISTER(r22)
	RESTORE_REGISTER(r23)
	RESTORE_REGISTER(r24)
	RESTORE_REGISTER(r25)
	RESTORE_REGISTER(r26)
	RESTORE_REGISTER(r27)
	RESTORE_REGISTER(r28)
	RESTORE_REGISTER(r29)
	RESTORE_REGISTER(r30)
	RESTORE_REGISTER(r31)
	/* can't use RESTORE_SPECIAL(MSR) */
	ld	r0, SL_MSR(r11)
	mtmsrd	r0, 0
	RESTORE_SPECIAL(SDR1)
	RESTORE_SPECIAL(XER)

	sync

	addi	r1,r1,-128
	bl	slb_flush_and_rebolt
	bl	do_after_copyback
	addi	r1,r1,128

	ld	r11,swsusp_save_area_ptr@toc(r2)
	RESTORE_SPECIAL(LR)

	li	r3, 0
	blr