[PATCH 8/9] KVM: PPC: Book3S HV: Improve real-mode handling of external interrupts

2013-02-14 Thread Paul Mackerras
This streamlines our handling of external interrupts that come in
while we're in the guest.  First, when waking up a hardware thread
that was napping, we split off the napping due to H_CEDE case
earlier, and use the code that handles an external interrupt (0x500)
in the guest to handle that too.  Secondly, the code that handles
those external interrupts now checks if any other thread is exiting
to the host before bouncing an external interrupt to the guest, and
also checks that there is actually an external interrupt pending for
the guest before setting the LPCR MER bit (mediated external request).

This also makes sure that we clear the ceded flag when we handle a
wakeup from cede in real mode, and fixes a potential infinite loop
in kvmppc_run_vcpu() which can occur if we ever end up with the ceded
flag set but MSR[EE] off.

Signed-off-by: Paul Mackerras pau...@samba.org
---
 arch/powerpc/include/asm/reg.h  |1 +
 arch/powerpc/kvm/book3s_hv.c|5 +-
 arch/powerpc/kvm/book3s_hv_rmhandlers.S |  140 +--
 3 files changed, 81 insertions(+), 65 deletions(-)

diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 11ae3d8..abe34e0 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -254,6 +254,7 @@
 #define LPCR_PECE1 0x2000  /* decrementer can cause exit */
 #define LPCR_PECE2 0x1000  /* machine check etc can cause exit */
 #define   LPCR_MER 0x0800  /* Mediated External Exception */
+#define   LPCR_MER_SH  11
 #define   LPCR_LPES0x000c
 #define   LPCR_LPES0   0x0008  /* LPAR Env selector 0 */
 #define   LPCR_LPES1   0x0004  /* LPAR Env selector 1 */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 1365440..bd751a3 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1384,9 +1384,12 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, 
struct kvm_vcpu *vcpu)
break;
vc-runner = vcpu;
n_ceded = 0;
-   list_for_each_entry(v, vc-runnable_threads, arch.run_list)
+   list_for_each_entry(v, vc-runnable_threads, arch.run_list) {
if (!v-arch.pending_exceptions)
n_ceded += v-arch.ceded;
+   else
+   v-arch.ceded = 0;
+   }
if (n_ceded == vc-n_runnable)
kvmppc_vcore_blocked(vc);
else
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S 
b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index fe908f5..0c519cb 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -97,50 +97,51 @@ kvm_start_guest:
li  r0,1
stb r0,PACA_NAPSTATELOST(r13)
 
-   /* get vcpu pointer, NULL if we have no vcpu to run */
-   ld  r4,HSTATE_KVM_VCPU(r13)
-   cmpdi   cr1,r4,0
+   /* were we napping due to cede? */
+   lbz r0,HSTATE_NAPPING(r13)
+   cmpwi   r0,0
+   bne kvm_end_cede
+
+   /*
+* We weren't napping due to cede, so this must be a secondary
+* thread being woken up to run a guest, or being woken up due
+* to a stray IPI.  (Or due to some machine check or hypervisor
+* maintenance interrupt while the core is in KVM.)
+*/
 
/* Check the wake reason in SRR1 to see why we got here */
mfspr   r3,SPRN_SRR1
rlwinm  r3,r3,44-31,0x7 /* extract wake reason field */
cmpwi   r3,4/* was it an external interrupt? */
-   bne 27f
-
-   /*
-* External interrupt - for now assume it is an IPI, since we
-* should never get any other interrupts sent to offline threads.
-* Only do this for secondary threads.
-*/
-   beq cr1,25f
-   lwz r3,VCPU_PTID(r4)
-   cmpwi   r3,0
-   beq 27f
-25:ld  r5,HSTATE_XICS_PHYS(r13)
-   li  r0,0xff
-   li  r6,XICS_MFRR
-   li  r7,XICS_XIRR
+   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 27f /* none there? */
-   cmpwi   r9,XICS_IPI
-   bne 26f
+   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 */
-26:stwcix  r8,r5,r7/* EOI the interrupt */
-
-27:/* XXX should handle hypervisor maintenance interrupts etc. here */
+  

[PATCH 8/9] KVM: PPC: Book3S HV: Improve real-mode handling of external interrupts

2013-02-14 Thread Paul Mackerras
This streamlines our handling of external interrupts that come in
while we're in the guest.  First, when waking up a hardware thread
that was napping, we split off the napping due to H_CEDE case
earlier, and use the code that handles an external interrupt (0x500)
in the guest to handle that too.  Secondly, the code that handles
those external interrupts now checks if any other thread is exiting
to the host before bouncing an external interrupt to the guest, and
also checks that there is actually an external interrupt pending for
the guest before setting the LPCR MER bit (mediated external request).

This also makes sure that we clear the ceded flag when we handle a
wakeup from cede in real mode, and fixes a potential infinite loop
in kvmppc_run_vcpu() which can occur if we ever end up with the ceded
flag set but MSR[EE] off.

Signed-off-by: Paul Mackerras pau...@samba.org
---
 arch/powerpc/include/asm/reg.h  |1 +
 arch/powerpc/kvm/book3s_hv.c|5 +-
 arch/powerpc/kvm/book3s_hv_rmhandlers.S |  140 +--
 3 files changed, 81 insertions(+), 65 deletions(-)

diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 11ae3d8..abe34e0 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -254,6 +254,7 @@
 #define LPCR_PECE1 0x2000  /* decrementer can cause exit */
 #define LPCR_PECE2 0x1000  /* machine check etc can cause exit */
 #define   LPCR_MER 0x0800  /* Mediated External Exception */
+#define   LPCR_MER_SH  11
 #define   LPCR_LPES0x000c
 #define   LPCR_LPES0   0x0008  /* LPAR Env selector 0 */
 #define   LPCR_LPES1   0x0004  /* LPAR Env selector 1 */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 1365440..bd751a3 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1384,9 +1384,12 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, 
struct kvm_vcpu *vcpu)
break;
vc-runner = vcpu;
n_ceded = 0;
-   list_for_each_entry(v, vc-runnable_threads, arch.run_list)
+   list_for_each_entry(v, vc-runnable_threads, arch.run_list) {
if (!v-arch.pending_exceptions)
n_ceded += v-arch.ceded;
+   else
+   v-arch.ceded = 0;
+   }
if (n_ceded == vc-n_runnable)
kvmppc_vcore_blocked(vc);
else
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S 
b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index fe908f5..0c519cb 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -97,50 +97,51 @@ kvm_start_guest:
li  r0,1
stb r0,PACA_NAPSTATELOST(r13)
 
-   /* get vcpu pointer, NULL if we have no vcpu to run */
-   ld  r4,HSTATE_KVM_VCPU(r13)
-   cmpdi   cr1,r4,0
+   /* were we napping due to cede? */
+   lbz r0,HSTATE_NAPPING(r13)
+   cmpwi   r0,0
+   bne kvm_end_cede
+
+   /*
+* We weren't napping due to cede, so this must be a secondary
+* thread being woken up to run a guest, or being woken up due
+* to a stray IPI.  (Or due to some machine check or hypervisor
+* maintenance interrupt while the core is in KVM.)
+*/
 
/* Check the wake reason in SRR1 to see why we got here */
mfspr   r3,SPRN_SRR1
rlwinm  r3,r3,44-31,0x7 /* extract wake reason field */
cmpwi   r3,4/* was it an external interrupt? */
-   bne 27f
-
-   /*
-* External interrupt - for now assume it is an IPI, since we
-* should never get any other interrupts sent to offline threads.
-* Only do this for secondary threads.
-*/
-   beq cr1,25f
-   lwz r3,VCPU_PTID(r4)
-   cmpwi   r3,0
-   beq 27f
-25:ld  r5,HSTATE_XICS_PHYS(r13)
-   li  r0,0xff
-   li  r6,XICS_MFRR
-   li  r7,XICS_XIRR
+   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 27f /* none there? */
-   cmpwi   r9,XICS_IPI
-   bne 26f
+   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 */
-26:stwcix  r8,r5,r7/* EOI the interrupt */
-
-27:/* XXX should handle hypervisor maintenance interrupts etc. here */
+