aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-04-17 16:31:41 -0400
committerAlexander Graf <agraf@suse.de>2013-04-26 14:27:32 -0400
commit4619ac88b72c43c622ef1eae3069de0e6f2cba9d (patch)
treeba512ee99fba576f86cdf99a9bce1e8d0420abcc /arch
parente7d26f285b4be9466c9e393139e1c9cffe4cedfc (diff)
KVM: PPC: Book3S HV: Improve real-mode handling of external interrupts
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 <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/reg.h1
-rw-r--r--arch/powerpc/kvm/book3s_hv.c5
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S138
3 files changed, 80 insertions, 64 deletions
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index c9c67fc888c9..799322433620 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -290,6 +290,7 @@
290#define LPCR_PECE1 0x00002000 /* decrementer can cause exit */ 290#define LPCR_PECE1 0x00002000 /* decrementer can cause exit */
291#define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */ 291#define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */
292#define LPCR_MER 0x00000800 /* Mediated External Exception */ 292#define LPCR_MER 0x00000800 /* Mediated External Exception */
293#define LPCR_MER_SH 11
293#define LPCR_LPES 0x0000000c 294#define LPCR_LPES 0x0000000c
294#define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */ 295#define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */
295#define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */ 296#define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 16191915e8d0..178521e81ce4 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)
1384 break; 1384 break;
1385 vc->runner = vcpu; 1385 vc->runner = vcpu;
1386 n_ceded = 0; 1386 n_ceded = 0;
1387 list_for_each_entry(v, &vc->runnable_threads, arch.run_list) 1387 list_for_each_entry(v, &vc->runnable_threads, arch.run_list) {
1388 if (!v->arch.pending_exceptions) 1388 if (!v->arch.pending_exceptions)
1389 n_ceded += v->arch.ceded; 1389 n_ceded += v->arch.ceded;
1390 else
1391 v->arch.ceded = 0;
1392 }
1390 if (n_ceded == vc->n_runnable) 1393 if (n_ceded == vc->n_runnable)
1391 kvmppc_vcore_blocked(vc); 1394 kvmppc_vcore_blocked(vc);
1392 else 1395 else
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index fd3b72d5dfe6..b02f91e4c70d 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -97,50 +97,51 @@ kvm_start_guest:
97 li r0,1 97 li r0,1
98 stb r0,PACA_NAPSTATELOST(r13) 98 stb r0,PACA_NAPSTATELOST(r13)
99 99
100 /* get vcpu pointer, NULL if we have no vcpu to run */ 100 /* were we napping due to cede? */
101 ld r4,HSTATE_KVM_VCPU(r13) 101 lbz r0,HSTATE_NAPPING(r13)
102 cmpdi cr1,r4,0 102 cmpwi r0,0
103 bne kvm_end_cede
104
105 /*
106 * We weren't napping due to cede, so this must be a secondary
107 * thread being woken up to run a guest, or being woken up due
108 * to a stray IPI. (Or due to some machine check or hypervisor
109 * maintenance interrupt while the core is in KVM.)
110 */
103 111
104 /* Check the wake reason in SRR1 to see why we got here */ 112 /* Check the wake reason in SRR1 to see why we got here */
105 mfspr r3,SPRN_SRR1 113 mfspr r3,SPRN_SRR1
106 rlwinm r3,r3,44-31,0x7 /* extract wake reason field */ 114 rlwinm r3,r3,44-31,0x7 /* extract wake reason field */
107 cmpwi r3,4 /* was it an external interrupt? */ 115 cmpwi r3,4 /* was it an external interrupt? */
108 bne 27f 116 bne 27f /* if not */
109 117 ld r5,HSTATE_XICS_PHYS(r13)
110 /* 118 li r7,XICS_XIRR /* if it was an external interrupt, */
111 * External interrupt - for now assume it is an IPI, since we
112 * should never get any other interrupts sent to offline threads.
113 * Only do this for secondary threads.
114 */
115 beq cr1,25f
116 lwz r3,VCPU_PTID(r4)
117 cmpwi r3,0
118 beq 27f
11925: ld r5,HSTATE_XICS_PHYS(r13)
120 li r0,0xff
121 li r6,XICS_MFRR
122 li r7,XICS_XIRR
123 lwzcix r8,r5,r7 /* get and ack the interrupt */ 119 lwzcix r8,r5,r7 /* get and ack the interrupt */
124 sync 120 sync
125 clrldi. r9,r8,40 /* get interrupt source ID. */ 121 clrldi. r9,r8,40 /* get interrupt source ID. */
126 beq 27f /* none there? */ 122 beq 28f /* none there? */
127 cmpwi r9,XICS_IPI 123 cmpwi r9,XICS_IPI /* was it an IPI? */
128 bne 26f 124 bne 29f
125 li r0,0xff
126 li r6,XICS_MFRR
129 stbcix r0,r5,r6 /* clear IPI */ 127 stbcix r0,r5,r6 /* clear IPI */
13026: stwcix r8,r5,r7 /* EOI the interrupt */ 128 stwcix r8,r5,r7 /* EOI the interrupt */
129 sync /* order loading of vcpu after that */
131 130
13227: /* XXX should handle hypervisor maintenance interrupts etc. here */ 131 /* get vcpu pointer, NULL if we have no vcpu to run */
133
134 /* reload vcpu pointer after clearing the IPI */
135 ld r4,HSTATE_KVM_VCPU(r13) 132 ld r4,HSTATE_KVM_VCPU(r13)
136 cmpdi r4,0 133 cmpdi r4,0
137 /* if we have no vcpu to run, go back to sleep */ 134 /* if we have no vcpu to run, go back to sleep */
138 beq kvm_no_guest 135 beq kvm_no_guest
136 b kvmppc_hv_entry
139 137
140 /* were we napping due to cede? */ 13827: /* XXX should handle hypervisor maintenance interrupts etc. here */
141 lbz r0,HSTATE_NAPPING(r13) 139 b kvm_no_guest
142 cmpwi r0,0 14028: /* SRR1 said external but ICP said nope?? */
143 bne kvm_end_cede 141 b kvm_no_guest
14229: /* External non-IPI interrupt to offline secondary thread? help?? */
143 stw r8,HSTATE_SAVED_XIRR(r13)
144 b kvm_no_guest
144 145
145.global kvmppc_hv_entry 146.global kvmppc_hv_entry
146kvmppc_hv_entry: 147kvmppc_hv_entry:
@@ -483,20 +484,20 @@ toc_tlbie_lock:
483 mtctr r6 484 mtctr r6
484 mtxer r7 485 mtxer r7
485 486
487 ld r10, VCPU_PC(r4)
488 ld r11, VCPU_MSR(r4)
486kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ 489kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */
487 ld r6, VCPU_SRR0(r4) 490 ld r6, VCPU_SRR0(r4)
488 ld r7, VCPU_SRR1(r4) 491 ld r7, VCPU_SRR1(r4)
489 ld r10, VCPU_PC(r4)
490 ld r11, VCPU_MSR(r4) /* r11 = vcpu->arch.msr & ~MSR_HV */
491 492
493 /* r11 = vcpu->arch.msr & ~MSR_HV */
492 rldicl r11, r11, 63 - MSR_HV_LG, 1 494 rldicl r11, r11, 63 - MSR_HV_LG, 1
493 rotldi r11, r11, 1 + MSR_HV_LG 495 rotldi r11, r11, 1 + MSR_HV_LG
494 ori r11, r11, MSR_ME 496 ori r11, r11, MSR_ME
495 497
496 /* Check if we can deliver an external or decrementer interrupt now */ 498 /* Check if we can deliver an external or decrementer interrupt now */
497 ld r0,VCPU_PENDING_EXC(r4) 499 ld r0,VCPU_PENDING_EXC(r4)
498 li r8,(1 << BOOK3S_IRQPRIO_EXTERNAL) 500 lis r8,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h
499 oris r8,r8,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h
500 and r0,r0,r8 501 and r0,r0,r8
501 cmpdi cr1,r0,0 502 cmpdi cr1,r0,0
502 andi. r0,r11,MSR_EE 503 andi. r0,r11,MSR_EE
@@ -524,10 +525,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
524 /* Move SRR0 and SRR1 into the respective regs */ 525 /* Move SRR0 and SRR1 into the respective regs */
5255: mtspr SPRN_SRR0, r6 5265: mtspr SPRN_SRR0, r6
526 mtspr SPRN_SRR1, r7 527 mtspr SPRN_SRR1, r7
527 li r0,0
528 stb r0,VCPU_CEDED(r4) /* cancel cede */
529 528
530fast_guest_return: 529fast_guest_return:
530 li r0,0
531 stb r0,VCPU_CEDED(r4) /* cancel cede */
531 mtspr SPRN_HSRR0,r10 532 mtspr SPRN_HSRR0,r10
532 mtspr SPRN_HSRR1,r11 533 mtspr SPRN_HSRR1,r11
533 534
@@ -686,6 +687,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
686 /* External interrupt, first check for host_ipi. If this is 687 /* External interrupt, first check for host_ipi. If this is
687 * set, we know the host wants us out so let's do it now 688 * set, we know the host wants us out so let's do it now
688 */ 689 */
690do_ext_interrupt:
689 lbz r0, HSTATE_HOST_IPI(r13) 691 lbz r0, HSTATE_HOST_IPI(r13)
690 cmpwi r0, 0 692 cmpwi r0, 0
691 bne ext_interrupt_to_host 693 bne ext_interrupt_to_host
@@ -698,19 +700,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
698 lwzcix r3, r5, r7 700 lwzcix r3, r5, r7
699 rlwinm. r0, r3, 0, 0xffffff 701 rlwinm. r0, r3, 0, 0xffffff
700 sync 702 sync
701 bne 1f 703 beq 3f /* if nothing pending in the ICP */
702 704
703 /* Nothing pending in the ICP, check for mediated interrupts 705 /* We found something in the ICP...
704 * and bounce it to the guest
705 */
706 andi. r0, r11, MSR_EE
707 beq ext_interrupt_to_host /* shouldn't happen ?? */
708 mfspr r5, SPRN_LPCR
709 andi. r0, r5, LPCR_MER
710 bne bounce_ext_interrupt
711 b ext_interrupt_to_host /* shouldn't happen ?? */
712
7131: /* We found something in the ICP...
714 * 706 *
715 * If it's not an IPI, stash it in the PACA and return to 707 * If it's not an IPI, stash it in the PACA and return to
716 * the host, we don't (yet) handle directing real external 708 * the host, we don't (yet) handle directing real external
@@ -735,16 +727,33 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
735 bne- 1f 727 bne- 1f
736 728
737 /* Allright, looks like an IPI for the guest, we need to set MER */ 729 /* Allright, looks like an IPI for the guest, we need to set MER */
738 mfspr r8,SPRN_LPCR 7303:
739 ori r8,r8,LPCR_MER 731 /* Check if any CPU is heading out to the host, if so head out too */
740 mtspr SPRN_LPCR,r8 732 ld r5, HSTATE_KVM_VCORE(r13)
733 lwz r0, VCORE_ENTRY_EXIT(r5)
734 cmpwi r0, 0x100
735 bge ext_interrupt_to_host
736
737 /* See if there is a pending interrupt for the guest */
738 mfspr r8, SPRN_LPCR
739 ld r0, VCPU_PENDING_EXC(r9)
740 /* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */
741 rldicl. r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63
742 rldimi r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH
743 beq 2f
741 744
742 /* And if the guest EE is set, we can deliver immediately, else 745 /* And if the guest EE is set, we can deliver immediately, else
743 * we return to the guest with MER set 746 * we return to the guest with MER set
744 */ 747 */
745 andi. r0, r11, MSR_EE 748 andi. r0, r11, MSR_EE
746 bne bounce_ext_interrupt 749 beq 2f
747 mr r4, r9 750 mtspr SPRN_SRR0, r10
751 mtspr SPRN_SRR1, r11
752 li r10, BOOK3S_INTERRUPT_EXTERNAL
753 li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */
754 rotldi r11, r11, 63
7552: mr r4, r9
756 mtspr SPRN_LPCR, r8
748 b fast_guest_return 757 b fast_guest_return
749 758
750 /* We raced with the host, we need to resend that IPI, bummer */ 759 /* We raced with the host, we need to resend that IPI, bummer */
@@ -1487,15 +1496,6 @@ ignore_hdec:
1487 mr r4,r9 1496 mr r4,r9
1488 b fast_guest_return 1497 b fast_guest_return
1489 1498
1490bounce_ext_interrupt:
1491 mr r4,r9
1492 mtspr SPRN_SRR0,r10
1493 mtspr SPRN_SRR1,r11
1494 li r10,BOOK3S_INTERRUPT_EXTERNAL
1495 li r11,(MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */
1496 rotldi r11,r11,63
1497 b fast_guest_return
1498
1499_GLOBAL(kvmppc_h_set_dabr) 1499_GLOBAL(kvmppc_h_set_dabr)
1500 std r4,VCPU_DABR(r3) 1500 std r4,VCPU_DABR(r3)
1501 /* Work around P7 bug where DABR can get corrupted on mtspr */ 1501 /* Work around P7 bug where DABR can get corrupted on mtspr */
@@ -1601,6 +1601,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
1601 b . 1601 b .
1602 1602
1603kvm_end_cede: 1603kvm_end_cede:
1604 /* get vcpu pointer */
1605 ld r4, HSTATE_KVM_VCPU(r13)
1606
1604 /* Woken by external or decrementer interrupt */ 1607 /* Woken by external or decrementer interrupt */
1605 ld r1, HSTATE_HOST_R1(r13) 1608 ld r1, HSTATE_HOST_R1(r13)
1606 1609
@@ -1640,6 +1643,16 @@ kvm_end_cede:
1640 li r0,0 1643 li r0,0
1641 stb r0,HSTATE_NAPPING(r13) 1644 stb r0,HSTATE_NAPPING(r13)
1642 1645
1646 /* Check the wake reason in SRR1 to see why we got here */
1647 mfspr r3, SPRN_SRR1
1648 rlwinm r3, r3, 44-31, 0x7 /* extract wake reason field */
1649 cmpwi r3, 4 /* was it an external interrupt? */
1650 li r12, BOOK3S_INTERRUPT_EXTERNAL
1651 mr r9, r4
1652 ld r10, VCPU_PC(r9)
1653 ld r11, VCPU_MSR(r9)
1654 beq do_ext_interrupt /* if so */
1655
1643 /* see if any other thread is already exiting */ 1656 /* see if any other thread is already exiting */
1644 lwz r0,VCORE_ENTRY_EXIT(r5) 1657 lwz r0,VCORE_ENTRY_EXIT(r5)
1645 cmpwi r0,0x100 1658 cmpwi r0,0x100
@@ -1659,8 +1672,7 @@ kvm_cede_prodded:
1659 1672
1660 /* we've ceded but we want to give control to the host */ 1673 /* we've ceded but we want to give control to the host */
1661kvm_cede_exit: 1674kvm_cede_exit:
1662 li r3,H_TOO_HARD 1675 b hcall_real_fallback
1663 blr
1664 1676
1665 /* Try to handle a machine check in real mode */ 1677 /* Try to handle a machine check in real mode */
1666machine_check_realmode: 1678machine_check_realmode: