aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Warrier <warrier@linux.vnet.ibm.com>2016-08-19 01:35:51 -0400
committerPaul Mackerras <paulus@ozlabs.org>2016-09-11 20:11:00 -0400
commite3c13e56a4717ee334837a20c596e527eb6355e1 (patch)
tree03e130e4dbcbcf0df85ba04d3acb49233ef7afc6
parentc57875f5f9be2cea1f1cc83f815a3aadabedcdd3 (diff)
KVM: PPC: Book3S HV: Handle passthrough interrupts in guest
Currently, KVM switches back to the host to handle any external interrupt (when the interrupt is received while running in the guest). This patch updates real-mode KVM to check if an interrupt is generated by a passthrough adapter that is owned by this guest. If so, the real mode KVM will directly inject the corresponding virtual interrupt to the guest VCPU's ICS and also EOI the interrupt in hardware. In short, the interrupt is handled entirely in real mode in the guest context without switching back to the host. In some rare cases, the interrupt cannot be completely handled in real mode, for instance, a VCPU that is sleeping needs to be woken up. In this case, KVM simply switches back to the host with trap reason set to 0x500. This works, but it is clearly not very efficient. A following patch will distinguish this case and handle it correctly in the host. Note that we can use the existing check_too_hard() routine even though we are not in a hypercall to determine if there is unfinished business that needs to be completed in host virtual mode. The patch assumes that the mapping between hardware interrupt IRQ and virtual IRQ to be injected to the guest already exists for the PCI passthrough interrupts that need to be handled in real mode. If the mapping does not exist, KVM falls back to the default existing behavior. The KVM real mode code reads mappings from the mapped array in the passthrough IRQ map without taking any lock. We carefully order the loads and stores of the fields in the kvmppc_irq_map data structure using memory barriers to avoid an inconsistent mapping being seen by the reader. Thus, although it is possible to miss a map entry, it is not possible to read a stale value. [paulus@ozlabs.org - get irq_chip from irq_map rather than pimap, pulled out powernv eoi change into a separate patch, made kvmppc_read_intr get the vcpu from the paca rather than being passed in, rewrote the logic at the end of kvmppc_read_intr to avoid deep indentation, simplified logic in book3s_hv_rmhandlers.S since we were always restoring SRR0/1 anyway, get rid of the cached array (just use the mapped array), removed the kick_all_cpus_sync() call, clear saved_xirr PACA field when we handle the interrupt in real mode, fix compilation with CONFIG_KVM_XICS=n.] 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_ppc.h3
-rw-r--r--arch/powerpc/kvm/book3s_hv.c8
-rw-r--r--arch/powerpc/kvm/book3s_hv_builtin.c73
-rw-r--r--arch/powerpc/kvm/book3s_hv_rm_xics.c44
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S6
5 files changed, 132 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 4ca2ba36a860..4299a1f79a91 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -478,6 +478,9 @@ extern int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
478extern int kvmppc_xics_connect_vcpu(struct kvm_device *dev, 478extern int kvmppc_xics_connect_vcpu(struct kvm_device *dev,
479 struct kvm_vcpu *vcpu, u32 cpu); 479 struct kvm_vcpu *vcpu, u32 cpu);
480extern void kvmppc_xics_ipi_action(void); 480extern void kvmppc_xics_ipi_action(void);
481extern long kvmppc_deliver_irq_passthru(struct kvm_vcpu *vcpu, u32 xirr,
482 struct kvmppc_irq_map *irq_map,
483 struct kvmppc_passthru_irqmap *pimap);
481extern int h_ipi_redirect; 484extern int h_ipi_redirect;
482#else 485#else
483static inline struct kvmppc_passthru_irqmap *kvmppc_get_passthru_irqmap( 486static inline struct kvmppc_passthru_irqmap *kvmppc_get_passthru_irqmap(
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index a7fe1783d245..a393c2b6b1b6 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -3490,9 +3490,15 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
3490 irq_map = &pimap->mapped[i]; 3490 irq_map = &pimap->mapped[i];
3491 3491
3492 irq_map->v_hwirq = guest_gsi; 3492 irq_map->v_hwirq = guest_gsi;
3493 irq_map->r_hwirq = desc->irq_data.hwirq;
3494 irq_map->desc = desc; 3493 irq_map->desc = desc;
3495 3494
3495 /*
3496 * Order the above two stores before the next to serialize with
3497 * the KVM real mode handler.
3498 */
3499 smp_wmb();
3500 irq_map->r_hwirq = desc->irq_data.hwirq;
3501
3496 if (i == pimap->n_mapped) 3502 if (i == pimap->n_mapped)
3497 pimap->n_mapped++; 3503 pimap->n_mapped++;
3498 3504
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index b476a6af893f..7531e29f90bd 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -288,12 +288,83 @@ void kvmhv_commence_exit(int trap)
288struct kvmppc_host_rm_ops *kvmppc_host_rm_ops_hv; 288struct kvmppc_host_rm_ops *kvmppc_host_rm_ops_hv;
289EXPORT_SYMBOL_GPL(kvmppc_host_rm_ops_hv); 289EXPORT_SYMBOL_GPL(kvmppc_host_rm_ops_hv);
290 290
291#ifdef CONFIG_KVM_XICS
292static struct kvmppc_irq_map *get_irqmap(struct kvmppc_passthru_irqmap *pimap,
293 u32 xisr)
294{
295 int i;
296
297 /*
298 * We access the mapped array here without a lock. That
299 * is safe because we never reduce the number of entries
300 * in the array and we never change the v_hwirq field of
301 * an entry once it is set.
302 *
303 * We have also carefully ordered the stores in the writer
304 * and the loads here in the reader, so that if we find a matching
305 * hwirq here, the associated GSI and irq_desc fields are valid.
306 */
307 for (i = 0; i < pimap->n_mapped; i++) {
308 if (xisr == pimap->mapped[i].r_hwirq) {
309 /*
310 * Order subsequent reads in the caller to serialize
311 * with the writer.
312 */
313 smp_rmb();
314 return &pimap->mapped[i];
315 }
316 }
317 return NULL;
318}
319
320/*
321 * If we have an interrupt that's not an IPI, check if we have a
322 * passthrough adapter and if so, check if this external interrupt
323 * is for the adapter.
324 * We will attempt to deliver the IRQ directly to the target VCPU's
325 * ICP, the virtual ICP (based on affinity - the xive value in ICS).
326 *
327 * If the delivery fails or if this is not for a passthrough adapter,
328 * return to the host to handle this interrupt. We earlier
329 * saved a copy of the XIRR in the PACA, it will be picked up by
330 * the host ICP driver.
331 */
332static int kvmppc_check_passthru(u32 xisr, __be32 xirr)
333{
334 struct kvmppc_passthru_irqmap *pimap;
335 struct kvmppc_irq_map *irq_map;
336 struct kvm_vcpu *vcpu;
337
338 vcpu = local_paca->kvm_hstate.kvm_vcpu;
339 if (!vcpu)
340 return 1;
341 pimap = kvmppc_get_passthru_irqmap(vcpu->kvm);
342 if (!pimap)
343 return 1;
344 irq_map = get_irqmap(pimap, xisr);
345 if (!irq_map)
346 return 1;
347
348 /* We're handling this interrupt, generic code doesn't need to */
349 local_paca->kvm_hstate.saved_xirr = 0;
350
351 return kvmppc_deliver_irq_passthru(vcpu, xirr, irq_map, pimap);
352}
353
354#else
355static inline int kvmppc_check_passthru(u32 xisr, __be32 xirr)
356{
357 return 1;
358}
359#endif
360
291/* 361/*
292 * Determine what sort of external interrupt is pending (if any). 362 * Determine what sort of external interrupt is pending (if any).
293 * Returns: 363 * Returns:
294 * 0 if no interrupt is pending 364 * 0 if no interrupt is pending
295 * 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
296 * -1 if there was a guest wakeup IPI (which has now been cleared) 366 * -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
297 */ 368 */
298 369
299long kvmppc_read_intr(void) 370long kvmppc_read_intr(void)
@@ -368,5 +439,5 @@ long kvmppc_read_intr(void)
368 return -1; 439 return -1;
369 } 440 }
370 441
371 return 1; 442 return kvmppc_check_passthru(xisr, xirr);
372} 443}
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c
index 980d8a6f7284..17f5b851db8c 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -19,6 +19,7 @@
19#include <asm/synch.h> 19#include <asm/synch.h>
20#include <asm/cputhreads.h> 20#include <asm/cputhreads.h>
21#include <asm/ppc-opcode.h> 21#include <asm/ppc-opcode.h>
22#include <asm/pnv-pci.h>
22 23
23#include "book3s_xics.h" 24#include "book3s_xics.h"
24 25
@@ -712,6 +713,49 @@ int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
712 return check_too_hard(xics, icp); 713 return check_too_hard(xics, icp);
713} 714}
714 715
716unsigned long eoi_rc;
717
718static void icp_eoi(struct irq_chip *c, u32 hwirq, u32 xirr)
719{
720 unsigned long xics_phys;
721 int64_t rc;
722
723 rc = pnv_opal_pci_msi_eoi(c, hwirq);
724
725 if (rc)
726 eoi_rc = rc;
727
728 iosync();
729
730 /* EOI it */
731 xics_phys = local_paca->kvm_hstate.xics_phys;
732 _stwcix(xics_phys + XICS_XIRR, xirr);
733}
734
735long kvmppc_deliver_irq_passthru(struct kvm_vcpu *vcpu,
736 u32 xirr,
737 struct kvmppc_irq_map *irq_map,
738 struct kvmppc_passthru_irqmap *pimap)
739{
740 struct kvmppc_xics *xics;
741 struct kvmppc_icp *icp;
742 u32 irq;
743
744 irq = irq_map->v_hwirq;
745 xics = vcpu->kvm->arch.xics;
746 icp = vcpu->arch.icp;
747
748 icp_rm_deliver_irq(xics, icp, irq);
749
750 /* EOI the interrupt */
751 icp_eoi(irq_desc_get_chip(irq_map->desc), irq_map->r_hwirq, xirr);
752
753 if (check_too_hard(xics, icp) == H_TOO_HARD)
754 return 1;
755 else
756 return -2;
757}
758
715/* --- Non-real mode XICS-related built-in routines --- */ 759/* --- Non-real mode XICS-related built-in routines --- */
716 760
717/** 761/**
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index dccfa85d35df..12fb2afb23fc 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1198,6 +1198,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
1198 * -1 A guest wakeup IPI (which has now been cleared) 1198 * -1 A guest wakeup IPI (which has now been cleared)
1199 * In either case, we return to guest to deliver any pending 1199 * In either case, we return to guest to deliver any pending
1200 * guest interrupts. 1200 * guest interrupts.
1201 *
1202 * -2 A PCI passthrough external interrupt was handled
1203 * (interrupt was delivered directly to guest)
1204 * Return to guest to deliver any pending guest interrupts.
1201 */ 1205 */
1202 1206
1203 cmpdi r3, 0 1207 cmpdi r3, 0
@@ -2352,6 +2356,8 @@ machine_check_realmode:
2352 * 0 if nothing needs to be done 2356 * 0 if nothing needs to be done
2353 * 1 if something happened that needs to be handled by the host 2357 * 1 if something happened that needs to be handled by the host
2354 * -1 if there was a guest wakeup (IPI or msgsnd) 2358 * -1 if there was a guest wakeup (IPI or msgsnd)
2359 * -2 if we handled a PCI passthrough interrupt (returned by
2360 * kvmppc_read_intr only)
2355 * 2361 *
2356 * Also sets r12 to the interrupt vector for any interrupt that needs 2362 * Also sets r12 to the interrupt vector for any interrupt that needs
2357 * to be handled now by the host (0x500 for external interrupt), or zero. 2363 * to be handled now by the host (0x500 for external interrupt), or zero.