KVM: PPC: Book3S HV: Consolidate code that checks reason for wake from nap
Currently in book3s_hv_rmhandlers.S we have three places where we have woken up from nap mode and we check the reason field in SRR1 to see what event woke us up. This consolidates them into a new function, kvmppc_check_wake_reason. It looks at the wake reason field in SRR1, and if it indicates that an external interrupt caused the wakeup, calls kvmppc_read_intr to check what sort of interrupt it was. This also consolidates the two places where we synthesize an external interrupt (0x500 vector) for the guest. Now, if the guest exit code finds that there was an external interrupt which has been handled (i.e. it was an IPI indicating that there is now an interrupt pending for the guest), it jumps to deliver_guest_interrupt, which is in the last part of the guest entry code, where we synthesize guest external and decrementer interrupts. That code has been streamlined a little and now clears LPCR[MER] when appropriate as well as setting it. The extra clearing of any pending IPI on a secondary, offline CPU thread before going back to nap mode has been removed. It is no longer necessary now that we have code to read and acknowledge IPIs in the guest exit path. This fixes a minor bug in the H_CEDE real-mode handling - previously, if we found that other threads were already exiting the guest when we were about to go to nap mode, we would branch to the cede wakeup path and end up looking in SRR1 for a wakeup reason. Now we branch to a point after we have checked the wakeup reason. This also fixes a minor bug in kvmppc_read_intr - previously it could return 0xff rather than 1, in the case where we find that a host IPI is pending after we have cleared the IPI. Now it returns 1. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
5557ae0ec7
commit
e3bbbbfa13
|
@ -193,8 +193,10 @@ kvm_novcpu_wakeup:
|
||||||
stb r0, HSTATE_NAPPING(r13)
|
stb r0, HSTATE_NAPPING(r13)
|
||||||
stb r0, HSTATE_HWTHREAD_REQ(r13)
|
stb r0, HSTATE_HWTHREAD_REQ(r13)
|
||||||
|
|
||||||
|
/* check the wake reason */
|
||||||
|
bl kvmppc_check_wake_reason
|
||||||
|
|
||||||
/* see if any other thread is already exiting */
|
/* see if any other thread is already exiting */
|
||||||
li r12, 0
|
|
||||||
lwz r0, VCORE_ENTRY_EXIT(r5)
|
lwz r0, VCORE_ENTRY_EXIT(r5)
|
||||||
cmpwi r0, 0x100
|
cmpwi r0, 0x100
|
||||||
bge kvm_novcpu_exit
|
bge kvm_novcpu_exit
|
||||||
|
@ -204,23 +206,14 @@ kvm_novcpu_wakeup:
|
||||||
li r0, 1
|
li r0, 1
|
||||||
sld r0, r0, r7
|
sld r0, r0, r7
|
||||||
addi r6, r5, VCORE_NAPPING_THREADS
|
addi r6, r5, VCORE_NAPPING_THREADS
|
||||||
4: lwarx r3, 0, r6
|
4: lwarx r7, 0, r6
|
||||||
andc r3, r3, r0
|
andc r7, r7, r0
|
||||||
stwcx. r3, 0, r6
|
stwcx. r7, 0, r6
|
||||||
bne 4b
|
bne 4b
|
||||||
|
|
||||||
/* Check the wake reason in SRR1 to see why we got here */
|
/* See if the wake reason means we need to exit */
|
||||||
mfspr r3, SPRN_SRR1
|
|
||||||
rlwinm r3, r3, 44-31, 0x7 /* extract wake reason field */
|
|
||||||
cmpwi r3, 4 /* was it an external interrupt? */
|
|
||||||
bne kvm_novcpu_exit /* if not, exit the guest */
|
|
||||||
|
|
||||||
/* extern interrupt - read and handle it */
|
|
||||||
li r12, BOOK3S_INTERRUPT_EXTERNAL
|
|
||||||
bl kvmppc_read_intr
|
|
||||||
cmpdi r3, 0
|
cmpdi r3, 0
|
||||||
bge kvm_novcpu_exit
|
bge kvm_novcpu_exit
|
||||||
li r12, 0
|
|
||||||
|
|
||||||
/* Got an IPI but other vcpus aren't yet exiting, must be a latecomer */
|
/* Got an IPI but other vcpus aren't yet exiting, must be a latecomer */
|
||||||
ld r4, HSTATE_KVM_VCPU(r13)
|
ld r4, HSTATE_KVM_VCPU(r13)
|
||||||
|
@ -264,40 +257,16 @@ kvm_start_guest:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Check the wake reason in SRR1 to see why we got here */
|
/* Check the wake reason in SRR1 to see why we got here */
|
||||||
mfspr r3,SPRN_SRR1
|
bl kvmppc_check_wake_reason
|
||||||
rlwinm r3,r3,44-31,0x7 /* extract wake reason field */
|
cmpdi r3, 0
|
||||||
cmpwi r3,4 /* was it an external interrupt? */
|
bge kvm_no_guest
|
||||||
bne 27f /* if not */
|
|
||||||
ld r5,HSTATE_XICS_PHYS(r13)
|
|
||||||
li r7,XICS_XIRR /* if it was an external interrupt, */
|
|
||||||
lwzcix r8,r5,r7 /* get and ack the interrupt */
|
|
||||||
sync
|
|
||||||
clrldi. r9,r8,40 /* get interrupt source ID. */
|
|
||||||
beq 28f /* none there? */
|
|
||||||
cmpwi r9,XICS_IPI /* was it an IPI? */
|
|
||||||
bne 29f
|
|
||||||
li r0,0xff
|
|
||||||
li r6,XICS_MFRR
|
|
||||||
stbcix r0,r5,r6 /* clear IPI */
|
|
||||||
stwcix r8,r5,r7 /* EOI the interrupt */
|
|
||||||
sync /* order loading of vcpu after that */
|
|
||||||
|
|
||||||
/* get vcpu pointer, NULL if we have no vcpu to run */
|
/* get vcpu pointer, NULL if we have no vcpu to run */
|
||||||
ld r4,HSTATE_KVM_VCPU(r13)
|
ld r4,HSTATE_KVM_VCPU(r13)
|
||||||
cmpdi r4,0
|
cmpdi r4,0
|
||||||
/* if we have no vcpu to run, go back to sleep */
|
/* if we have no vcpu to run, go back to sleep */
|
||||||
beq kvm_no_guest
|
beq kvm_no_guest
|
||||||
b 30f
|
|
||||||
|
|
||||||
27: /* XXX should handle hypervisor maintenance interrupts etc. here */
|
|
||||||
b kvm_no_guest
|
|
||||||
28: /* SRR1 said external but ICP said nope?? */
|
|
||||||
b kvm_no_guest
|
|
||||||
29: /* External non-IPI interrupt to offline secondary thread? help?? */
|
|
||||||
stw r8,HSTATE_SAVED_XIRR(r13)
|
|
||||||
b kvm_no_guest
|
|
||||||
|
|
||||||
30:
|
|
||||||
/* Set HSTATE_DSCR(r13) to something sensible */
|
/* Set HSTATE_DSCR(r13) to something sensible */
|
||||||
LOAD_REG_ADDR(r6, dscr_default)
|
LOAD_REG_ADDR(r6, dscr_default)
|
||||||
ld r6, 0(r6)
|
ld r6, 0(r6)
|
||||||
|
@ -310,18 +279,6 @@ kvm_start_guest:
|
||||||
li r0, 0
|
li r0, 0
|
||||||
std r0, HSTATE_KVM_VCPU(r13)
|
std r0, HSTATE_KVM_VCPU(r13)
|
||||||
lwsync
|
lwsync
|
||||||
/* Clear any pending IPI - we're an offline thread */
|
|
||||||
ld r5, HSTATE_XICS_PHYS(r13)
|
|
||||||
li r7, XICS_XIRR
|
|
||||||
lwzcix r3, r5, r7 /* ack any pending interrupt */
|
|
||||||
rlwinm. r0, r3, 0, 0xffffff /* any pending? */
|
|
||||||
beq 37f
|
|
||||||
sync
|
|
||||||
li r0, 0xff
|
|
||||||
li r6, XICS_MFRR
|
|
||||||
stbcix r0, r5, r6 /* clear the IPI */
|
|
||||||
stwcix r3, r5, r7 /* EOI it */
|
|
||||||
37: sync
|
|
||||||
|
|
||||||
/* increment the nap count and then go to nap mode */
|
/* increment the nap count and then go to nap mode */
|
||||||
ld r4, HSTATE_KVM_VCORE(r13)
|
ld r4, HSTATE_KVM_VCORE(r13)
|
||||||
|
@ -818,47 +775,46 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
|
||||||
mtctr r6
|
mtctr r6
|
||||||
mtxer r7
|
mtxer r7
|
||||||
|
|
||||||
|
kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */
|
||||||
ld r10, VCPU_PC(r4)
|
ld r10, VCPU_PC(r4)
|
||||||
ld r11, VCPU_MSR(r4)
|
ld r11, VCPU_MSR(r4)
|
||||||
kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */
|
|
||||||
ld r6, VCPU_SRR0(r4)
|
ld r6, VCPU_SRR0(r4)
|
||||||
ld r7, VCPU_SRR1(r4)
|
ld r7, VCPU_SRR1(r4)
|
||||||
|
mtspr SPRN_SRR0, r6
|
||||||
|
mtspr SPRN_SRR1, r7
|
||||||
|
|
||||||
|
deliver_guest_interrupt:
|
||||||
/* r11 = vcpu->arch.msr & ~MSR_HV */
|
/* r11 = vcpu->arch.msr & ~MSR_HV */
|
||||||
rldicl r11, r11, 63 - MSR_HV_LG, 1
|
rldicl r11, r11, 63 - MSR_HV_LG, 1
|
||||||
rotldi r11, r11, 1 + MSR_HV_LG
|
rotldi r11, r11, 1 + MSR_HV_LG
|
||||||
ori r11, r11, MSR_ME
|
ori r11, r11, MSR_ME
|
||||||
|
|
||||||
/* Check if we can deliver an external or decrementer interrupt now */
|
/* Check if we can deliver an external or decrementer interrupt now */
|
||||||
ld r0,VCPU_PENDING_EXC(r4)
|
ld r0, VCPU_PENDING_EXC(r4)
|
||||||
lis r8,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h
|
rldicl r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63
|
||||||
and r0,r0,r8
|
cmpdi cr1, r0, 0
|
||||||
cmpdi cr1,r0,0
|
andi. r8, r11, MSR_EE
|
||||||
andi. r0,r11,MSR_EE
|
|
||||||
beq cr1,11f
|
|
||||||
BEGIN_FTR_SECTION
|
BEGIN_FTR_SECTION
|
||||||
mfspr r8,SPRN_LPCR
|
mfspr r8, SPRN_LPCR
|
||||||
ori r8,r8,LPCR_MER
|
/* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */
|
||||||
mtspr SPRN_LPCR,r8
|
rldimi r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH
|
||||||
|
mtspr SPRN_LPCR, r8
|
||||||
isync
|
isync
|
||||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
|
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
|
||||||
beq 5f
|
beq 5f
|
||||||
li r0,BOOK3S_INTERRUPT_EXTERNAL
|
li r0, BOOK3S_INTERRUPT_EXTERNAL
|
||||||
12: mr r6,r10
|
bne cr1, 12f
|
||||||
|
mfspr r0, SPRN_DEC
|
||||||
|
cmpwi r0, 0
|
||||||
|
li r0, BOOK3S_INTERRUPT_DECREMENTER
|
||||||
|
bge 5f
|
||||||
|
|
||||||
|
12: mtspr SPRN_SRR0, r10
|
||||||
mr r10,r0
|
mr r10,r0
|
||||||
mr r7,r11
|
mtspr SPRN_SRR1, r11
|
||||||
li r11,(MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */
|
li r11,(MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */
|
||||||
rotldi r11,r11,63
|
rotldi r11,r11,63
|
||||||
b 5f
|
5:
|
||||||
11: beq 5f
|
|
||||||
mfspr r0,SPRN_DEC
|
|
||||||
cmpwi r0,0
|
|
||||||
li r0,BOOK3S_INTERRUPT_DECREMENTER
|
|
||||||
blt 12b
|
|
||||||
|
|
||||||
/* Move SRR0 and SRR1 into the respective regs */
|
|
||||||
5: mtspr SPRN_SRR0, r6
|
|
||||||
mtspr SPRN_SRR1, r7
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Required state:
|
* Required state:
|
||||||
|
@ -1047,39 +1003,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
|
||||||
/* External interrupt, first check for host_ipi. If this is
|
/* External interrupt, first check for host_ipi. If this is
|
||||||
* set, we know the host wants us out so let's do it now
|
* set, we know the host wants us out so let's do it now
|
||||||
*/
|
*/
|
||||||
do_ext_interrupt:
|
|
||||||
bl kvmppc_read_intr
|
bl kvmppc_read_intr
|
||||||
cmpdi r3, 0
|
cmpdi r3, 0
|
||||||
bgt ext_interrupt_to_host
|
bgt ext_interrupt_to_host
|
||||||
|
|
||||||
/* Allright, looks like an IPI for the guest, we need to set MER */
|
|
||||||
/* Check if any CPU is heading out to the host, if so head out too */
|
/* Check if any CPU is heading out to the host, if so head out too */
|
||||||
ld r5, HSTATE_KVM_VCORE(r13)
|
ld r5, HSTATE_KVM_VCORE(r13)
|
||||||
lwz r0, VCORE_ENTRY_EXIT(r5)
|
lwz r0, VCORE_ENTRY_EXIT(r5)
|
||||||
cmpwi r0, 0x100
|
cmpwi r0, 0x100
|
||||||
bge ext_interrupt_to_host
|
bge ext_interrupt_to_host
|
||||||
|
|
||||||
/* See if there is a pending interrupt for the guest */
|
/* Return to guest after delivering any pending interrupt */
|
||||||
mfspr r8, SPRN_LPCR
|
mr r4, r9
|
||||||
ld r0, VCPU_PENDING_EXC(r9)
|
b deliver_guest_interrupt
|
||||||
/* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */
|
|
||||||
rldicl. r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63
|
|
||||||
rldimi r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH
|
|
||||||
beq 2f
|
|
||||||
|
|
||||||
/* And if the guest EE is set, we can deliver immediately, else
|
|
||||||
* we return to the guest with MER set
|
|
||||||
*/
|
|
||||||
andi. r0, r11, MSR_EE
|
|
||||||
beq 2f
|
|
||||||
mtspr SPRN_SRR0, r10
|
|
||||||
mtspr SPRN_SRR1, r11
|
|
||||||
li r10, BOOK3S_INTERRUPT_EXTERNAL
|
|
||||||
li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */
|
|
||||||
rotldi r11, r11, 63
|
|
||||||
2: mr r4, r9
|
|
||||||
mtspr SPRN_LPCR, r8
|
|
||||||
b fast_guest_return
|
|
||||||
|
|
||||||
ext_interrupt_to_host:
|
ext_interrupt_to_host:
|
||||||
|
|
||||||
|
@ -1887,7 +1823,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
|
||||||
stb r0,HSTATE_NAPPING(r13)
|
stb r0,HSTATE_NAPPING(r13)
|
||||||
/* order napping_threads update vs testing entry_exit_count */
|
/* order napping_threads update vs testing entry_exit_count */
|
||||||
lwsync
|
lwsync
|
||||||
mr r4,r3
|
|
||||||
lwz r7,VCORE_ENTRY_EXIT(r5)
|
lwz r7,VCORE_ENTRY_EXIT(r5)
|
||||||
cmpwi r7,0x100
|
cmpwi r7,0x100
|
||||||
bge 33f /* another thread already exiting */
|
bge 33f /* another thread already exiting */
|
||||||
|
@ -1940,6 +1875,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
|
||||||
nap
|
nap
|
||||||
b .
|
b .
|
||||||
|
|
||||||
|
33: mr r4, r3
|
||||||
|
li r3, 0
|
||||||
|
li r12, 0
|
||||||
|
b 34f
|
||||||
|
|
||||||
kvm_end_cede:
|
kvm_end_cede:
|
||||||
/* get vcpu pointer */
|
/* get vcpu pointer */
|
||||||
ld r4, HSTATE_KVM_VCPU(r13)
|
ld r4, HSTATE_KVM_VCPU(r13)
|
||||||
|
@ -1969,12 +1909,15 @@ kvm_end_cede:
|
||||||
ld r29, VCPU_GPR(R29)(r4)
|
ld r29, VCPU_GPR(R29)(r4)
|
||||||
ld r30, VCPU_GPR(R30)(r4)
|
ld r30, VCPU_GPR(R30)(r4)
|
||||||
ld r31, VCPU_GPR(R31)(r4)
|
ld r31, VCPU_GPR(R31)(r4)
|
||||||
|
|
||||||
|
/* Check the wake reason in SRR1 to see why we got here */
|
||||||
|
bl kvmppc_check_wake_reason
|
||||||
|
|
||||||
/* clear our bit in vcore->napping_threads */
|
/* clear our bit in vcore->napping_threads */
|
||||||
33: ld r5,HSTATE_KVM_VCORE(r13)
|
34: ld r5,HSTATE_KVM_VCORE(r13)
|
||||||
lbz r3,HSTATE_PTID(r13)
|
lbz r7,HSTATE_PTID(r13)
|
||||||
li r0,1
|
li r0,1
|
||||||
sld r0,r0,r3
|
sld r0,r0,r7
|
||||||
addi r6,r5,VCORE_NAPPING_THREADS
|
addi r6,r5,VCORE_NAPPING_THREADS
|
||||||
32: lwarx r7,0,r6
|
32: lwarx r7,0,r6
|
||||||
andc r7,r7,r0
|
andc r7,r7,r0
|
||||||
|
@ -1983,23 +1926,18 @@ kvm_end_cede:
|
||||||
li r0,0
|
li r0,0
|
||||||
stb r0,HSTATE_NAPPING(r13)
|
stb r0,HSTATE_NAPPING(r13)
|
||||||
|
|
||||||
/* Check the wake reason in SRR1 to see why we got here */
|
/* See if the wake reason means we need to exit */
|
||||||
mfspr r3, SPRN_SRR1
|
stw r12, VCPU_TRAP(r4)
|
||||||
rlwinm r3, r3, 44-31, 0x7 /* extract wake reason field */
|
|
||||||
cmpwi r3, 4 /* was it an external interrupt? */
|
|
||||||
li r12, BOOK3S_INTERRUPT_EXTERNAL
|
|
||||||
mr r9, r4
|
mr r9, r4
|
||||||
ld r10, VCPU_PC(r9)
|
cmpdi r3, 0
|
||||||
ld r11, VCPU_MSR(r9)
|
bgt guest_exit_cont
|
||||||
beq do_ext_interrupt /* if so */
|
|
||||||
|
|
||||||
/* see if any other thread is already exiting */
|
/* see if any other thread is already exiting */
|
||||||
lwz r0,VCORE_ENTRY_EXIT(r5)
|
lwz r0,VCORE_ENTRY_EXIT(r5)
|
||||||
cmpwi r0,0x100
|
cmpwi r0,0x100
|
||||||
blt kvmppc_cede_reentry /* if not go back to guest */
|
bge guest_exit_cont
|
||||||
|
|
||||||
/* some threads are exiting, so go to the guest exit path */
|
b kvmppc_cede_reentry /* if not go back to guest */
|
||||||
b hcall_real_fallback
|
|
||||||
|
|
||||||
/* cede when already previously prodded case */
|
/* cede when already previously prodded case */
|
||||||
kvm_cede_prodded:
|
kvm_cede_prodded:
|
||||||
|
@ -2029,6 +1967,29 @@ machine_check_realmode:
|
||||||
rotldi r11, r11, 63
|
rotldi r11, r11, 63
|
||||||
b fast_interrupt_c_return
|
b fast_interrupt_c_return
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the reason we woke from nap, and take appropriate action.
|
||||||
|
* Returns:
|
||||||
|
* 0 if nothing needs to be done
|
||||||
|
* 1 if something happened that needs to be handled by the host
|
||||||
|
* -1 if there was a guest wakeup (IPI)
|
||||||
|
*
|
||||||
|
* Also sets r12 to the interrupt vector for any interrupt that needs
|
||||||
|
* to be handled now by the host (0x500 for external interrupt), or zero.
|
||||||
|
*/
|
||||||
|
kvmppc_check_wake_reason:
|
||||||
|
mfspr r6, SPRN_SRR1
|
||||||
|
rlwinm r6, r6, 44-31, 0x7 /* extract wake reason field */
|
||||||
|
cmpwi r6, 4 /* was it an external interrupt? */
|
||||||
|
li r12, BOOK3S_INTERRUPT_EXTERNAL
|
||||||
|
beq kvmppc_read_intr /* if so, see what it was */
|
||||||
|
li r3, 0
|
||||||
|
li r12, 0
|
||||||
|
cmpwi r6, 6 /* was it the decrementer? */
|
||||||
|
beq 0f
|
||||||
|
li r3, 1 /* anything else, return 1 */
|
||||||
|
0: blr
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine what sort of external interrupt is pending (if any).
|
* Determine what sort of external interrupt is pending (if any).
|
||||||
* Returns:
|
* Returns:
|
||||||
|
@ -2060,7 +2021,6 @@ kvmppc_read_intr:
|
||||||
* interrupts directly to the guest
|
* interrupts directly to the guest
|
||||||
*/
|
*/
|
||||||
cmpwi r3, XICS_IPI /* if there is, is it an IPI? */
|
cmpwi r3, XICS_IPI /* if there is, is it an IPI? */
|
||||||
li r3, 1
|
|
||||||
bne 42f
|
bne 42f
|
||||||
|
|
||||||
/* It's an IPI, clear the MFRR and EOI it */
|
/* It's an IPI, clear the MFRR and EOI it */
|
||||||
|
@ -2086,12 +2046,14 @@ kvmppc_read_intr:
|
||||||
* before exit, it will be picked up by the host ICP driver
|
* before exit, it will be picked up by the host ICP driver
|
||||||
*/
|
*/
|
||||||
stw r0, HSTATE_SAVED_XIRR(r13)
|
stw r0, HSTATE_SAVED_XIRR(r13)
|
||||||
|
li r3, 1
|
||||||
b 1b
|
b 1b
|
||||||
|
|
||||||
43: /* We raced with the host, we need to resend that IPI, bummer */
|
43: /* We raced with the host, we need to resend that IPI, bummer */
|
||||||
li r0, IPI_PRIORITY
|
li r0, IPI_PRIORITY
|
||||||
stbcix r0, r6, r8 /* set the IPI */
|
stbcix r0, r6, r8 /* set the IPI */
|
||||||
sync
|
sync
|
||||||
|
li r3, 1
|
||||||
b 1b
|
b 1b
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue