18
18
#include <asm/hw_irq.h>
19
19
#include <asm/kvm_book3s_asm.h>
20
20
#include <asm/opal.h>
21
+ #include <asm/cpuidle.h>
21
22
22
23
#undef DEBUG
23
24
37
38
38
39
/*
39
40
* Pass requested state in r3:
40
- * 0 - nap
41
- * 1 - sleep
41
+ * r3 - PNV_THREAD_NAP/SLEEP/WINKLE
42
42
*
43
43
* To check IRQ_HAPPENED in r4
44
44
* 0 - don't check
@@ -123,12 +123,58 @@ power7_enter_nap_mode:
123
123
li r4,KVM_HWTHREAD_IN_NAP
124
124
stb r4,HSTATE_HWTHREAD_STATE(r13)
125
125
#endif
126
- cmpwi cr0,r3,1
127
- beq 2f
126
+ stb r3,PACA_THREAD_IDLE_STATE(r13)
127
+ cmpwi cr1,r3,PNV_THREAD_SLEEP
128
+ bge cr1,2f
128
129
IDLE_STATE_ENTER_SEQ(PPC_NAP)
129
130
/* No return */
130
- 2: IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
131
- /* No return */
131
+ 2:
132
+ /* Sleep or winkle */
133
+ lbz r7,PACA_THREAD_MASK(r13)
134
+ ld r14,PACA_CORE_IDLE_STATE_PTR(r13)
135
+ lwarx_loop1:
136
+ lwarx r15,0 ,r14
137
+ andc r15,r15,r7 /* Clear thread bit */
138
+
139
+ andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS
140
+
141
+ /*
142
+ * If cr0 = 0, then current thread is the last thread of the core entering
143
+ * sleep. Last thread needs to execute the hardware bug workaround code if
144
+ * required by the platform.
145
+ * Make the workaround call unconditionally here. The below branch call is
146
+ * patched out when the idle states are discovered if the platform does not
147
+ * require it.
148
+ */
149
+ .global pnv_fastsleep_workaround_at_entry
150
+ pnv_fastsleep_workaround_at_entry:
151
+ beq fastsleep_workaround_at_entry
152
+
153
+ stwcx. r15,0 ,r14
154
+ bne- lwarx_loop1
155
+ isync
156
+
157
+ common_enter: /* common code for all the threads entering sleep */
158
+ IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
159
+
160
+ fastsleep_workaround_at_entry:
161
+ ori r15,r15,PNV_CORE_IDLE_LOCK_BIT
162
+ stwcx. r15,0 ,r14
163
+ bne- lwarx_loop1
164
+ isync
165
+
166
+ /* Fast sleep workaround */
167
+ li r3,1
168
+ li r4,1
169
+ li r0,OPAL_CONFIG_CPU_IDLE_STATE
170
+ bl opal_call_realmode
171
+
172
+ /* Clear Lock bit */
173
+ li r0,0
174
+ lwsync
175
+ stw r0,0 (r14)
176
+ b common_enter
177
+
132
178
133
179
_GLOBAL(power7_idle)
134
180
/* Now check if user or arch enabled NAP mode */
@@ -141,49 +187,16 @@ _GLOBAL(power7_idle)
141
187
142
188
_GLOBAL(power7_nap)
143
189
mr r4,r3
144
- li r3,0
190
+ li r3,PNV_THREAD_NAP
145
191
b power7_powersave_common
146
192
/* No return */
147
193
148
194
_GLOBAL(power7_sleep)
149
- li r3,1
195
+ li r3,PNV_THREAD_SLEEP
150
196
li r4,1
151
197
b power7_powersave_common
152
198
/* No return */
153
199
154
- /*
155
- * Make opal call in realmode. This is a generic function to be called
156
- * from realmode from reset vector. It handles endianess.
157
- *
158
- * r13 - paca pointer
159
- * r1 - stack pointer
160
- * r3 - opal token
161
- */
162
- opal_call_realmode:
163
- mflr r12
164
- std r12,_LINK(r1)
165
- ld r2,PACATOC(r13)
166
- /* Set opal return address */
167
- LOAD_REG_ADDR(r0,return_from_opal_call)
168
- mtlr r0
169
- /* Handle endian-ness */
170
- li r0,MSR_LE
171
- mfmsr r12
172
- andc r12,r12,r0
173
- mtspr SPRN_HSRR1,r12
174
- mr r0,r3 /* Move opal token to r0 */
175
- LOAD_REG_ADDR(r11,opal)
176
- ld r12,8 (r11)
177
- ld r2,0 (r11)
178
- mtspr SPRN_HSRR0,r12
179
- hrfid
180
-
181
- return_from_opal_call:
182
- FIXUP_ENDIAN
183
- ld r0,_LINK(r1)
184
- mtlr r0
185
- blr
186
-
187
200
#define CHECK_HMI_INTERRUPT \
188
201
mfspr r0,SPRN_SRR1; \
189
202
BEGIN_FTR_SECTION_NESTED(66 ); \
@@ -197,7 +210,7 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66); \
197
210
ld r2,PACATOC(r13); \
198
211
ld r1,PACAR1(r13); \
199
212
std r3,ORIG_GPR3(r1); /* Save original r3 */ \
200
- li r3 ,OPAL_HANDLE_HMI; /* Pass opal token argument*/ \
213
+ li r0 ,OPAL_HANDLE_HMI; /* Pass opal token argument*/ \
201
214
bl opal_call_realmode; \
202
215
ld r3,ORIG_GPR3(r1); /* Restore original r3 */ \
203
216
20: nop ;
@@ -206,16 +219,105 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66); \
206
219
_GLOBAL(power7_wakeup_tb_loss)
207
220
ld r2,PACATOC(r13);
208
221
ld r1,PACAR1(r13)
222
+ /*
223
+ * Before entering any idle state, the NVGPRs are saved in the stack
224
+ * and they are restored before switching to the process context. Hence
225
+ * until they are restored, they are free to be used.
226
+ *
227
+ * Save SRR1 in a NVGPR as it might be clobbered in opal_call_realmode
228
+ * (called in CHECK_HMI_INTERRUPT). SRR1 is required to determine the
229
+ * wakeup reason if we branch to kvm_start_guest.
230
+ */
209
231
232
+ mfspr r16,SPRN_SRR1
210
233
BEGIN_FTR_SECTION
211
234
CHECK_HMI_INTERRUPT
212
235
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
236
+
237
+ lbz r7,PACA_THREAD_MASK(r13)
238
+ ld r14,PACA_CORE_IDLE_STATE_PTR(r13)
239
+ lwarx_loop2:
240
+ lwarx r15,0 ,r14
241
+ andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT
242
+ /*
243
+ * Lock bit is set in one of the 2 cases-
244
+ * a. In the sleep/winkle enter path, the last thread is executing
245
+ * fastsleep workaround code.
246
+ * b. In the wake up path, another thread is executing fastsleep
247
+ * workaround undo code or resyncing timebase or restoring context
248
+ * In either case loop until the lock bit is cleared.
249
+ */
250
+ bne core_idle_lock_held
251
+
252
+ cmpwi cr2,r15,0
253
+ or r15,r15,r7 /* Set thread bit */
254
+
255
+ beq cr2,first_thread
256
+
257
+ /* Not first thread in core to wake up */
258
+ stwcx. r15,0 ,r14
259
+ bne- lwarx_loop2
260
+ isync
261
+ b common_exit
262
+
263
+ core_idle_lock_held:
264
+ HMT_LOW
265
+ core_idle_lock_loop:
266
+ lwz r15,0 (14 )
267
+ andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT
268
+ bne core_idle_lock_loop
269
+ HMT_MEDIUM
270
+ b lwarx_loop2
271
+
272
+ first_thread:
273
+ /* First thread in core to wakeup */
274
+ ori r15,r15,PNV_CORE_IDLE_LOCK_BIT
275
+ stwcx. r15,0 ,r14
276
+ bne- lwarx_loop2
277
+ isync
278
+
279
+ /*
280
+ * First thread in the core waking up from fastsleep. It needs to
281
+ * call the fastsleep workaround code if the platform requires it.
282
+ * Call it unconditionally here. The below branch instruction will
283
+ * be patched out when the idle states are discovered if platform
284
+ * does not require workaround.
285
+ */
286
+ .global pnv_fastsleep_workaround_at_exit
287
+ pnv_fastsleep_workaround_at_exit:
288
+ b fastsleep_workaround_at_exit
289
+
290
+ timebase_resync:
291
+ /* Do timebase resync if we are waking up from sleep. Use cr3 value
292
+ * set in exceptions-64s.S */
293
+ ble cr3,clear_lock
213
294
/* Time base re-sync */
214
- li r3 ,OPAL_RESYNC_TIMEBASE
295
+ li r0 ,OPAL_RESYNC_TIMEBASE
215
296
bl opal_call_realmode;
216
-
217
297
/* TODO: Check r3 for failure */
218
298
299
+ clear_lock:
300
+ andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS
301
+ lwsync
302
+ stw r15,0 (r14)
303
+
304
+ common_exit:
305
+ li r5,PNV_THREAD_RUNNING
306
+ stb r5,PACA_THREAD_IDLE_STATE(r13)
307
+
308
+ mtspr SPRN_SRR1,r16
309
+ #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
310
+ li r0,KVM_HWTHREAD_IN_KERNEL
311
+ stb r0,HSTATE_HWTHREAD_STATE(r13)
312
+ /* Order setting hwthread_state vs. testing hwthread_req */
313
+ sync
314
+ lbz r0,HSTATE_HWTHREAD_REQ(r13)
315
+ cmpwi r0,0
316
+ beq 6f
317
+ b kvm_start_guest
318
+ 6:
319
+ #endif
320
+
219
321
REST_NVGPRS(r1)
220
322
REST_GPR(2 , r1)
221
323
ld r3,_CCR(r1)
@@ -228,6 +330,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
228
330
mtspr SPRN_SRR0,r5
229
331
rfid
230
332
333
+ fastsleep_workaround_at_exit:
334
+ li r3,1
335
+ li r4,0
336
+ li r0,OPAL_CONFIG_CPU_IDLE_STATE
337
+ bl opal_call_realmode
338
+ b timebase_resync
339
+
231
340
/*
232
341
* R3 here contains the value that will be returned to the caller
233
342
* of power7_nap.
0 commit comments