diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/reg.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 138 |
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 | ||
119 | 25: 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 */ |
130 | 26: 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 | ||
132 | 27: /* 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? */ | 138 | 27: /* XXX should handle hypervisor maintenance interrupts etc. here */ |
141 | lbz r0,HSTATE_NAPPING(r13) | 139 | b kvm_no_guest |
142 | cmpwi r0,0 | 140 | 28: /* SRR1 said external but ICP said nope?? */ |
143 | bne kvm_end_cede | 141 | b kvm_no_guest |
142 | 29: /* 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 |
146 | kvmppc_hv_entry: | 147 | kvmppc_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) | ||
486 | kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ | 489 | kvmppc_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 */ |
525 | 5: mtspr SPRN_SRR0, r6 | 526 | 5: 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 | ||
530 | fast_guest_return: | 529 | fast_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 | */ |
690 | do_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 | |||
713 | 1: /* 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 | 730 | 3: |
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 | ||
755 | 2: 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 | ||
1490 | bounce_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 | ||
1603 | kvm_end_cede: | 1603 | kvm_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 */ |
1661 | kvm_cede_exit: | 1674 | kvm_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 */ |
1666 | machine_check_realmode: | 1678 | machine_check_realmode: |