aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Warrier <warrier@linux.vnet.ibm.com>2016-08-19 01:35:52 -0400
committerPaul Mackerras <paulus@ozlabs.org>2016-09-11 20:12:07 -0400
commitf7af5209b87c592aad81da65bd104241aa43d36a (patch)
treefa79559eef76511beb8713dcc802efc6d272ed2a
parente3c13e56a4717ee334837a20c596e527eb6355e1 (diff)
KVM: PPC: Book3S HV: Complete passthrough interrupt in host
In existing real mode ICP code, when updating the virtual ICP state, if there is a required action that cannot be completely handled in real mode, as for instance, a VCPU needs to be woken up, flags are set in the ICP to indicate the required action. This is checked when returning from hypercalls to decide whether the call needs switch back to the host where the action can be performed in virtual mode. Note that if h_ipi_redirect is enabled, real mode code will first try to message a free host CPU to complete this job instead of returning the host to do it ourselves. Currently, the real mode PCI passthrough interrupt handling code checks if any of these flags are set and simply returns to the host. This is not good enough as the trap value (0x500) is treated as an external interrupt by the host code. It is only when the trap value is a hypercall that the host code searches for and acts on unfinished work by calling kvmppc_xics_rm_complete. This patch introduces a special trap BOOK3S_INTERRUPT_HV_RM_HARD which is returned by KVM if there is unfinished business to be completed in host virtual mode after handling a PCI passthrough interrupt. The host checks for this special interrupt condition and calls into the kvmppc_xics_rm_complete, which is made an exported function for this reason. [paulus@ozlabs.org - moved logic to set r12 to BOOK3S_INTERRUPT_HV_RM_HARD in book3s_hv_rmhandlers.S into the end of kvmppc_check_wake_reason.] Signed-off-by: Suresh Warrier <warrier@linux.vnet.ibm.com> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
-rw-r--r--arch/powerpc/include/asm/kvm_asm.h10
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h3
-rw-r--r--arch/powerpc/kvm/book3s_hv.c8
-rw-r--r--arch/powerpc/kvm/book3s_hv_builtin.c1
-rw-r--r--arch/powerpc/kvm/book3s_hv_rm_xics.c2
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S25
-rw-r--r--arch/powerpc/kvm/book3s_xics.c3
7 files changed, 49 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h
index 5bca220bbb60..05cabed3d1bd 100644
--- a/arch/powerpc/include/asm/kvm_asm.h
+++ b/arch/powerpc/include/asm/kvm_asm.h
@@ -105,6 +105,15 @@
105#define BOOK3S_INTERRUPT_FAC_UNAVAIL 0xf60 105#define BOOK3S_INTERRUPT_FAC_UNAVAIL 0xf60
106#define BOOK3S_INTERRUPT_H_FAC_UNAVAIL 0xf80 106#define BOOK3S_INTERRUPT_H_FAC_UNAVAIL 0xf80
107 107
108/* book3s_hv */
109
110/*
111 * Special trap used to indicate to host that this is a
112 * passthrough interrupt that could not be handled
113 * completely in the guest.
114 */
115#define BOOK3S_INTERRUPT_HV_RM_HARD 0x5555
116
108#define BOOK3S_IRQPRIO_SYSTEM_RESET 0 117#define BOOK3S_IRQPRIO_SYSTEM_RESET 0
109#define BOOK3S_IRQPRIO_DATA_SEGMENT 1 118#define BOOK3S_IRQPRIO_DATA_SEGMENT 1
110#define BOOK3S_IRQPRIO_INST_SEGMENT 2 119#define BOOK3S_IRQPRIO_INST_SEGMENT 2
@@ -136,6 +145,7 @@
136#define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ 145#define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */
137#define RESUME_FLAG_HOST (1<<1) /* Resume host? */ 146#define RESUME_FLAG_HOST (1<<1) /* Resume host? */
138#define RESUME_FLAG_ARCH1 (1<<2) 147#define RESUME_FLAG_ARCH1 (1<<2)
148#define RESUME_FLAG_ARCH2 (1<<3)
139 149
140#define RESUME_GUEST 0 150#define RESUME_GUEST 0
141#define RESUME_GUEST_NV RESUME_FLAG_NV 151#define RESUME_GUEST_NV RESUME_FLAG_NV
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 4299a1f79a91..e0ada3138649 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -469,6 +469,7 @@ static inline struct kvmppc_passthru_irqmap *kvmppc_get_passthru_irqmap(
469extern void kvmppc_alloc_host_rm_ops(void); 469extern void kvmppc_alloc_host_rm_ops(void);
470extern void kvmppc_free_host_rm_ops(void); 470extern void kvmppc_free_host_rm_ops(void);
471extern void kvmppc_free_pimap(struct kvm *kvm); 471extern void kvmppc_free_pimap(struct kvm *kvm);
472extern int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall);
472extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu); 473extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
473extern int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server); 474extern int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server);
474extern int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args); 475extern int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args);
@@ -489,6 +490,8 @@ static inline struct kvmppc_passthru_irqmap *kvmppc_get_passthru_irqmap(
489static inline void kvmppc_alloc_host_rm_ops(void) {}; 490static inline void kvmppc_alloc_host_rm_ops(void) {};
490static inline void kvmppc_free_host_rm_ops(void) {}; 491static inline void kvmppc_free_host_rm_ops(void) {};
491static inline void kvmppc_free_pimap(struct kvm *kvm) {}; 492static inline void kvmppc_free_pimap(struct kvm *kvm) {};
493static inline int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall)
494 { return 0; }
492static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu) 495static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu)
493 { return 0; } 496 { return 0; }
494static inline void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) { } 497static inline void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) { }
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index a393c2b6b1b6..90beb96a0df6 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -74,6 +74,8 @@
74 74
75/* Used to indicate that a guest page fault needs to be handled */ 75/* Used to indicate that a guest page fault needs to be handled */
76#define RESUME_PAGE_FAULT (RESUME_GUEST | RESUME_FLAG_ARCH1) 76#define RESUME_PAGE_FAULT (RESUME_GUEST | RESUME_FLAG_ARCH1)
77/* Used to indicate that a guest passthrough interrupt needs to be handled */
78#define RESUME_PASSTHROUGH (RESUME_GUEST | RESUME_FLAG_ARCH2)
77 79
78/* Used as a "null" value for timebase values */ 80/* Used as a "null" value for timebase values */
79#define TB_NIL (~(u64)0) 81#define TB_NIL (~(u64)0)
@@ -1032,6 +1034,9 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
1032 kvmppc_core_queue_program(vcpu, SRR1_PROGILL); 1034 kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
1033 r = RESUME_GUEST; 1035 r = RESUME_GUEST;
1034 break; 1036 break;
1037 case BOOK3S_INTERRUPT_HV_RM_HARD:
1038 r = RESUME_PASSTHROUGH;
1039 break;
1035 default: 1040 default:
1036 kvmppc_dump_regs(vcpu); 1041 kvmppc_dump_regs(vcpu);
1037 printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n", 1042 printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n",
@@ -2951,7 +2956,8 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
2951 r = kvmppc_book3s_hv_page_fault(run, vcpu, 2956 r = kvmppc_book3s_hv_page_fault(run, vcpu,
2952 vcpu->arch.fault_dar, vcpu->arch.fault_dsisr); 2957 vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
2953 srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); 2958 srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
2954 } 2959 } else if (r == RESUME_PASSTHROUGH)
2960 r = kvmppc_xics_rm_complete(vcpu, 0);
2955 } while (is_kvmppc_resume_guest(r)); 2961 } while (is_kvmppc_resume_guest(r));
2956 2962
2957 out: 2963 out:
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index 7531e29f90bd..0c84d6bc8356 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -363,6 +363,7 @@ static inline int kvmppc_check_passthru(u32 xisr, __be32 xirr)
363 * Returns: 363 * Returns:
364 * 0 if no interrupt is pending 364 * 0 if no interrupt is pending
365 * 1 if an interrupt is pending that needs to be handled by the host 365 * 1 if an interrupt is pending that needs to be handled by the host
366 * 2 Passthrough that needs completion in the host
366 * -1 if there was a guest wakeup IPI (which has now been cleared) 367 * -1 if there was a guest wakeup IPI (which has now been cleared)
367 * -2 if there is PCI passthrough external interrupt that was handled 368 * -2 if there is PCI passthrough external interrupt that was handled
368 */ 369 */
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c
index 17f5b851db8c..3b8d7ac0be7c 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -751,7 +751,7 @@ long kvmppc_deliver_irq_passthru(struct kvm_vcpu *vcpu,
751 icp_eoi(irq_desc_get_chip(irq_map->desc), irq_map->r_hwirq, xirr); 751 icp_eoi(irq_desc_get_chip(irq_map->desc), irq_map->r_hwirq, xirr);
752 752
753 if (check_too_hard(xics, icp) == H_TOO_HARD) 753 if (check_too_hard(xics, icp) == H_TOO_HARD)
754 return 1; 754 return 2;
755 else 755 else
756 return -2; 756 return -2;
757} 757}
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 12fb2afb23fc..7cc924b5eea2 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1189,6 +1189,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
1189 * 1 An interrupt is pending that needs to be handled by the host 1189 * 1 An interrupt is pending that needs to be handled by the host
1190 * Exit guest and return to host by branching to guest_exit_cont 1190 * Exit guest and return to host by branching to guest_exit_cont
1191 * 1191 *
1192 * 2 Passthrough that needs completion in the host
1193 * Exit guest and return to host by branching to guest_exit_cont
1194 * However, we also set r12 to BOOK3S_INTERRUPT_HV_RM_HARD
1195 * to indicate to the host to complete handling the interrupt
1196 *
1192 * Before returning to guest, we check if any CPU is heading out 1197 * Before returning to guest, we check if any CPU is heading out
1193 * to the host and if so, we head out also. If no CPUs are heading 1198 * to the host and if so, we head out also. If no CPUs are heading
1194 * check return values <= 0. 1199 * check return values <= 0.
@@ -1204,6 +1209,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
1204 * Return to guest to deliver any pending guest interrupts. 1209 * Return to guest to deliver any pending guest interrupts.
1205 */ 1210 */
1206 1211
1212 cmpdi r3, 1
1213 ble 1f
1214
1215 /* Return code = 2 */
1216 li r12, BOOK3S_INTERRUPT_HV_RM_HARD
1217 stw r12, VCPU_TRAP(r9)
1218 b guest_exit_cont
1219
12201: /* Return code <= 1 */
1207 cmpdi r3, 0 1221 cmpdi r3, 0
1208 bgt guest_exit_cont 1222 bgt guest_exit_cont
1209 1223
@@ -2419,6 +2433,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
2419 bl kvmppc_read_intr 2433 bl kvmppc_read_intr
2420 nop 2434 nop
2421 li r12, BOOK3S_INTERRUPT_EXTERNAL 2435 li r12, BOOK3S_INTERRUPT_EXTERNAL
2436 cmpdi r3, 1
2437 ble 1f
2438
2439 /*
2440 * Return code of 2 means PCI passthrough interrupt, but
2441 * we need to return back to host to complete handling the
2442 * interrupt. Trap reason is expected in r12 by guest
2443 * exit code.
2444 */
2445 li r12, BOOK3S_INTERRUPT_HV_RM_HARD
24461:
2422 ld r0, PPC_MIN_STKFRM+PPC_LR_STKOFF(r1) 2447 ld r0, PPC_MIN_STKFRM+PPC_LR_STKOFF(r1)
2423 addi r1, r1, PPC_MIN_STKFRM 2448 addi r1, r1, PPC_MIN_STKFRM
2424 mtlr r0 2449 mtlr r0
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index 686147efbac5..4edbe7b93eb5 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -812,7 +812,7 @@ static noinline int kvmppc_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
812 return H_SUCCESS; 812 return H_SUCCESS;
813} 813}
814 814
815static noinline int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall) 815int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall)
816{ 816{
817 struct kvmppc_xics *xics = vcpu->kvm->arch.xics; 817 struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
818 struct kvmppc_icp *icp = vcpu->arch.icp; 818 struct kvmppc_icp *icp = vcpu->arch.icp;
@@ -841,6 +841,7 @@ static noinline int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall)
841 841
842 return H_SUCCESS; 842 return H_SUCCESS;
843} 843}
844EXPORT_SYMBOL_GPL(kvmppc_xics_rm_complete);
844 845
845int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 req) 846int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 req)
846{ 847{