summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/idle_book3s.S
blob: d32751994a62c7ea8de19b3a5935637a6c9dbb2a (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
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 *  Copyright 2018, IBM Corporation.
 *
 *  This file contains general idle entry/exit functions to save
 *  and restore stack and NVGPRs which allows C code to call idle
 *  states that lose GPRs, and it will return transparently with
 *  SRR1 wakeup reason return value.
 *
 *  The platform / CPU caller must ensure SPRs and any other non-GPR
 *  state is saved and restored correctly, handle KVM, interrupts, etc.
 */

#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
#include <asm/ppc-opcode.h>
#include <asm/cpuidle.h>

/*
 * Desired PSSCR in r3
 *
 * No state will be lost regardless of wakeup mechanism (interrupt or NIA).
 *
 * An EC=0 type wakeup will return with a value of 0. SRESET wakeup (which can
 * happen with xscom SRESET and possibly MCE) may clobber volatiles except LR,
 * and must blr, to return to caller with r3 set according to caller's expected
 * return code (for Book3S/64 that is SRR1).
 */
_GLOBAL(isa300_idle_stop_noloss)
	mtspr 	SPRN_PSSCR,r3
	PPC_STOP
	li	r3,0
	blr

/*
 * Desired PSSCR in r3
 *
 * GPRs may be lost, so they are saved here. Wakeup is by interrupt only.
 * The SRESET wakeup returns to this function's caller by calling
 * idle_return_gpr_loss with r3 set to desired return value.
 *
 * A wakeup without GPR loss may alteratively be handled as in
 * isa300_idle_stop_noloss and blr directly, as an optimisation.
 *
 * The caller is responsible for saving/restoring SPRs, MSR, timebase,
 * etc.
 */
_GLOBAL(isa300_idle_stop_mayloss)
	mtspr 	SPRN_PSSCR,r3
	std	r1,PACAR1(r13)
	mflr	r4
	mfcr	r5
	/* use stack red zone rather than a new frame for saving regs */
	std	r2,-8*0(r1)
	std	r14,-8*1(r1)
	std	r15,-8*2(r1)
	std	r16,-8*3(r1)
	std	r17,-8*4(r1)
	std	r18,-8*5(r1)
	std	r19,-8*6(r1)
	std	r20,-8*7(r1)
	std	r21,-8*8(r1)
	std	r22,-8*9(r1)
	std	r23,-8*10(r1)
	std	r24,-8*11(r1)
	std	r25,-8*12(r1)
	std	r26,-8*13(r1)
	std	r27,-8*14(r1)
	std	r28,-8*15(r1)
	std	r29,-8*16(r1)
	std	r30,-8*17(r1)
	std	r31,-8*18(r1)
	std	r4,-8*19(r1)
	std	r5,-8*20(r1)
	/* 168 bytes */
	PPC_STOP
	b	.	/* catch bugs */

/*
 * Desired return value in r3
 *
 * The idle wakeup SRESET interrupt can call this after calling
 * to return to the idle sleep function caller with r3 as the return code.
 *
 * This must not be used if idle was entered via a _noloss function (use
 * a simple blr instead).
 */
_GLOBAL(idle_return_gpr_loss)
	ld	r1,PACAR1(r13)
	ld	r4,-8*19(r1)
	ld	r5,-8*20(r1)
	mtlr	r4
	mtcr	r5
	/*
	 * KVM nap requires r2 to be saved, rather than just restoring it
	 * from PACATOC. This could be avoided for that less common case
	 * if KVM saved its r2.
	 */
	ld	r2,-8*0(r1)
	ld	r14,-8*1(r1)
	ld	r15,-8*2(r1)
	ld	r16,-8*3(r1)
	ld	r17,-8*4(r1)
	ld	r18,-8*5(r1)
	ld	r19,-8*6(r1)
	ld	r20,-8*7(r1)
	ld	r21,-8*8(r1)
	ld	r22,-8*9(r1)
	ld	r23,-8*10(r1)
	ld	r24,-8*11(r1)
	ld	r25,-8*12(r1)
	ld	r26,-8*13(r1)
	ld	r27,-8*14(r1)
	ld	r28,-8*15(r1)
	ld	r29,-8*16(r1)
	ld	r30,-8*17(r1)
	ld	r31,-8*18(r1)
	blr

/*
 * This is the sequence required to execute idle instructions, as
 * specified in ISA v2.07 (and earlier). MSR[IR] and MSR[DR] must be 0.
 *
 * The 0(r1) slot is used to save r2 in isa206, so use that here.
 */
#define IDLE_STATE_ENTER_SEQ_NORET(IDLE_INST)			\
	/* Magic NAP/SLEEP/WINKLE mode enter sequence */	\
	std	r2,0(r1);					\
	ptesync;						\
	ld	r2,0(r1);					\
236:	cmpd	cr0,r2,r2;					\
	bne	236b;						\
	IDLE_INST;						\
	b	.	/* catch bugs */

/*
 * Desired instruction type in r3
 *
 * GPRs may be lost, so they are saved here. Wakeup is by interrupt only.
 * The SRESET wakeup returns to this function's caller by calling
 * idle_return_gpr_loss with r3 set to desired return value.
 *
 * A wakeup without GPR loss may alteratively be handled as in
 * isa300_idle_stop_noloss and blr directly, as an optimisation.
 *
 * The caller is responsible for saving/restoring SPRs, MSR, timebase,
 * etc.
 *
 * This must be called in real-mode (MSR_IDLE).
 */
_GLOBAL(isa206_idle_insn_mayloss)
	std	r1,PACAR1(r13)
	mflr	r4
	mfcr	r5
	/* use stack red zone rather than a new frame for saving regs */
	std	r2,-8*0(r1)
	std	r14,-8*1(r1)
	std	r15,-8*2(r1)
	std	r16,-8*3(r1)
	std	r17,-8*4(r1)
	std	r18,-8*5(r1)
	std	r19,-8*6(r1)
	std	r20,-8*7(r1)
	std	r21,-8*8(r1)
	std	r22,-8*9(r1)
	std	r23,-8*10(r1)
	std	r24,-8*11(r1)
	std	r25,-8*12(r1)
	std	r26,-8*13(r1)
	std	r27,-8*14(r1)
	std	r28,-8*15(r1)
	std	r29,-8*16(r1)
	std	r30,-8*17(r1)
	std	r31,-8*18(r1)
	std	r4,-8*19(r1)
	std	r5,-8*20(r1)
	cmpwi	r3,PNV_THREAD_NAP
	bne	1f
	IDLE_STATE_ENTER_SEQ_NORET(PPC_NAP)
1:	cmpwi	r3,PNV_THREAD_SLEEP
	bne	2f
	IDLE_STATE_ENTER_SEQ_NORET(PPC_SLEEP)
2:	IDLE_STATE_ENTER_SEQ_NORET(PPC_WINKLE)