[PATCH 3/3] powerpc/powernv: Refactor hypervisor state restore code
From: Shreyas B. Prabhu
Date: Mon Feb 29 2016 - 07:26:03 EST
In the current code, when the thread wakes up in reset vector, some
of the state restore code and check for whether a thread needs to
branch to kvm is duplicated. Reorder the code such that this
duplication is avoided.
At a higher level this is what the change looks like-
Before this patch -
===================
power7_wakeup_tb_loss:
restore hypervisor state
if (thread needed by kvm)
goto kvm_start_guest
restore nvgprs, cr, pc
rfid to process context
power7_wakeup_loss:
restore nvgprs, cr, pc
rfid to process context
reset vector:
if (waking from deep idle states)
goto power7_wakeup_tb_loss
else
if (thread needed by kvm)
goto kvm_start_guest
goto power7_wakeup_loss
After this patch -
==================
power7_wakeup_tb_loss:
restore hypervisor state
return
power7_restore_hyp_resource():
if (waking from deep idle states)
goto power7_wakeup_tb_loss
return
power7_wakeup_loss:
restore nvgprs, cr, pc
rfid to process context
reset vector:
power7_restore_hyp_resource()
if (thread needed by kvm)
goto kvm_start_guest
goto power7_wakeup_loss
Signed-off-by: Shreyas B. Prabhu <shreyas@xxxxxxxxxxxxxxxxxx>
---
arch/powerpc/kernel/exceptions-64s.S | 29 +++-------------
arch/powerpc/kernel/idle_power7.S | 67 ++++++++++++++++++++----------------
2 files changed, 41 insertions(+), 55 deletions(-)
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 7716cebf4b8e..7ebfbb0c9992 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -107,25 +107,8 @@ BEGIN_FTR_SECTION
beq 9f
cmpwi cr3,r13,2
+ bl power7_restore_hyp_resource
- /*
- * Check if last bit of HSPGR0 is set. This indicates whether we are
- * waking up from winkle.
- */
- GET_PACA(r13)
- clrldi r5,r13,63
- clrrdi r13,r13,1
- cmpwi cr4,r5,1
- mtspr SPRN_HSPRG0,r13
-
- lbz r0,PACA_THREAD_IDLE_STATE(r13)
- cmpwi cr2,r0,PNV_THREAD_NAP
- bgt cr2,8f /* Either sleep or Winkle */
-
- /* Waking up from nap should not cause hypervisor state loss */
- bgt cr3,.
-
- /* Waking up from nap */
li r0,PNV_THREAD_RUNNING
stb r0,PACA_THREAD_IDLE_STATE(r13) /* Clear thread state */
@@ -143,13 +126,9 @@ BEGIN_FTR_SECTION
/* Return SRR1 from power7_nap() */
mfspr r3,SPRN_SRR1
- beq cr3,2f
- b power7_wakeup_noloss
-2: b power7_wakeup_loss
-
- /* Fast Sleep wakeup on PowerNV */
-8: GET_PACA(r13)
- b power7_wakeup_tb_loss
+ blt cr3,2f
+ b power7_wakeup_loss
+2: b power7_wakeup_noloss
9:
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 6af57e292848..0852685a22b8 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -197,6 +197,35 @@ _GLOBAL(power7_winkle)
b power7_powersave_common
/* No return */
+/*
+ * Called from reset vector. Check whether we have woken up with
+ * hypervisor state loss. If yes, restore hypervisor state and return
+ * back to reset vector.
+ */
+_GLOBAL(power7_restore_hyp_resource)
+ /*
+ * Check if last bit of HSPGR0 is set. This indicates whether we are
+ * waking up from winkle.
+ */
+ GET_PACA(r13)
+ clrldi r5,r13,63
+ clrrdi r13,r13,1
+ cmpwi cr4,r5,1
+ mtspr SPRN_HSPRG0,r13
+
+ lbz r0,PACA_THREAD_IDLE_STATE(r13)
+ cmpwi cr2,r0,PNV_THREAD_NAP
+ bgt cr2,power7_wakeup_tb_loss /* Either sleep or Winkle */
+
+ /*
+ * We fall through here if PACA_THREAD_IDLE_STATE shows we are waking
+ * up from nap. At this stage CR3 shouldn't contains 'gt' since that
+ * indicates we are waking with hypervisor state loss from nap.
+ */
+ bgt cr3,.
+
+ blr
+
_GLOBAL(power7_wakeup_tb_loss)
ld r2,PACATOC(r13);
ld r1,PACAR1(r13)
@@ -205,11 +234,13 @@ _GLOBAL(power7_wakeup_tb_loss)
* and they are restored before switching to the process context. Hence
* until they are restored, they are free to be used.
*
- * Save SRR1 in a NVGPR as it might be clobbered in opal_call_realmode
- * (called in CHECK_HMI_INTERRUPT). SRR1 is required to determine the
- * wakeup reason if we branch to kvm_start_guest.
+ * Save SRR1 and LR in NVGPRs as they might be clobbered in
+ * opal_call_realmode (called in CHECK_HMI_INTERRUPT). SRR1 is required
+ * to determine the wakeup reason if we branch to kvm_start_guest. LR
+ * is required to return back to reset vector after hypervisor state
+ * restore is complete.
*/
-
+ mflr r17
mfspr r16,SPRN_SRR1
BEGIN_FTR_SECTION
CHECK_HMI_INTERRUPT
@@ -359,33 +390,9 @@ common_exit:
hypervisor_state_restored:
- li r5,PNV_THREAD_RUNNING
- stb r5,PACA_THREAD_IDLE_STATE(r13)
-
mtspr SPRN_SRR1,r16
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
- li r0,KVM_HWTHREAD_IN_KERNEL
- stb r0,HSTATE_HWTHREAD_STATE(r13)
- /* Order setting hwthread_state vs. testing hwthread_req */
- sync
- lbz r0,HSTATE_HWTHREAD_REQ(r13)
- cmpwi r0,0
- beq 6f
- b kvm_start_guest
-6:
-#endif
-
- REST_NVGPRS(r1)
- REST_GPR(2, r1)
- ld r3,_CCR(r1)
- ld r4,_MSR(r1)
- ld r5,_NIP(r1)
- addi r1,r1,INT_FRAME_SIZE
- mtcr r3
- mfspr r3,SPRN_SRR1 /* Return SRR1 */
- mtspr SPRN_SRR1,r4
- mtspr SPRN_SRR0,r5
- rfid
+ mtlr r17
+ blr
fastsleep_workaround_at_exit:
li r3,1
--
1.9.3