]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kvm/book3s_hv.c
KVM: PPC: Book3S HV: Native usage of the XIVE interrupt controller
[karo-tx-linux.git] / arch / powerpc / kvm / book3s_hv.c
index 1ec86d9e2a82a32b28cd175951048b3d2cef118e..128efb42ec4e62baf11d79afcd502bc3a167ef88 100644 (file)
 #include <linux/srcu.h>
 #include <linux/miscdevice.h>
 #include <linux/debugfs.h>
+#include <linux/gfp.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
+#include <linux/hugetlb.h>
+#include <linux/kvm_irqfd.h>
+#include <linux/irqbypass.h>
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/of.h>
 
 #include <asm/reg.h>
 #include <asm/cputable.h>
 #include <asm/mmu.h>
 #include <asm/opal.h>
 #include <asm/xics.h>
-#include <linux/gfp.h>
-#include <linux/vmalloc.h>
-#include <linux/highmem.h>
-#include <linux/hugetlb.h>
-#include <linux/kvm_irqfd.h>
-#include <linux/irqbypass.h>
-#include <linux/module.h>
-#include <linux/compiler.h>
-#include <linux/of.h>
+#include <asm/xive.h>
 
 #include "book3s.h"
 
@@ -837,6 +838,10 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
        case H_IPOLL:
        case H_XIRR_X:
                if (kvmppc_xics_enabled(vcpu)) {
+                       if (xive_enabled()) {
+                               ret = H_NOT_AVAILABLE;
+                               return RESUME_GUEST;
+                       }
                        ret = kvmppc_xics_hcall(vcpu, req);
                        break;
                }
@@ -2947,8 +2952,12 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        r = kvmppc_book3s_hv_page_fault(run, vcpu,
                                vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
                        srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
-               } else if (r == RESUME_PASSTHROUGH)
-                       r = kvmppc_xics_rm_complete(vcpu, 0);
+               } else if (r == RESUME_PASSTHROUGH) {
+                       if (WARN_ON(xive_enabled()))
+                               r = H_SUCCESS;
+                       else
+                               r = kvmppc_xics_rm_complete(vcpu, 0);
+               }
        } while (is_kvmppc_resume_guest(r));
 
  out:
@@ -3400,10 +3409,20 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
        /*
         * On POWER9, VPM0 bit is reserved (VPM0=1 behaviour is assumed)
         * Set HVICE bit to enable hypervisor virtualization interrupts.
+        * Set HEIC to prevent OS interrupts to go to hypervisor (should
+        * be unnecessary but better safe than sorry in case we re-enable
+        * EE in HV mode with this LPCR still set)
         */
        if (cpu_has_feature(CPU_FTR_ARCH_300)) {
                lpcr &= ~LPCR_VPM0;
-               lpcr |= LPCR_HVICE;
+               lpcr |= LPCR_HVICE | LPCR_HEIC;
+
+               /*
+                * If xive is enabled, we route 0x500 interrupts directly
+                * to the guest.
+                */
+               if (xive_enabled())
+                       lpcr |= LPCR_LPES;
        }
 
        /*
@@ -3533,7 +3552,7 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
        struct kvmppc_irq_map *irq_map;
        struct kvmppc_passthru_irqmap *pimap;
        struct irq_chip *chip;
-       int i;
+       int i, rc = 0;
 
        if (!kvm_irq_bypass)
                return 1;
@@ -3558,10 +3577,10 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
        /*
         * For now, we only support interrupts for which the EOI operation
         * is an OPAL call followed by a write to XIRR, since that's
-        * what our real-mode EOI code does.
+        * what our real-mode EOI code does, or a XIVE interrupt
         */
        chip = irq_data_get_irq_chip(&desc->irq_data);
-       if (!chip || !is_pnv_opal_msi(chip)) {
+       if (!chip || !(is_pnv_opal_msi(chip) || is_xive_irq(chip))) {
                pr_warn("kvmppc_set_passthru_irq_hv: Could not assign IRQ map for (%d,%d)\n",
                        host_irq, guest_gsi);
                mutex_unlock(&kvm->lock);
@@ -3603,7 +3622,12 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
        if (i == pimap->n_mapped)
                pimap->n_mapped++;
 
-       kvmppc_xics_set_mapped(kvm, guest_gsi, desc->irq_data.hwirq);
+       if (xive_enabled())
+               rc = kvmppc_xive_set_mapped(kvm, guest_gsi, desc);
+       else
+               kvmppc_xics_set_mapped(kvm, guest_gsi, desc->irq_data.hwirq);
+       if (rc)
+               irq_map->r_hwirq = 0;
 
        mutex_unlock(&kvm->lock);
 
@@ -3614,7 +3638,7 @@ static int kvmppc_clr_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
 {
        struct irq_desc *desc;
        struct kvmppc_passthru_irqmap *pimap;
-       int i;
+       int i, rc = 0;
 
        if (!kvm_irq_bypass)
                return 0;
@@ -3641,9 +3665,12 @@ static int kvmppc_clr_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
                return -ENODEV;
        }
 
-       kvmppc_xics_clr_mapped(kvm, guest_gsi, pimap->mapped[i].r_hwirq);
+       if (xive_enabled())
+               rc = kvmppc_xive_clr_mapped(kvm, guest_gsi, pimap->mapped[i].desc);
+       else
+               kvmppc_xics_clr_mapped(kvm, guest_gsi, pimap->mapped[i].r_hwirq);
 
-       /* invalidate the entry */
+       /* invalidate the entry (what do do on error from the above ?) */
        pimap->mapped[i].r_hwirq = 0;
 
        /*
@@ -3652,7 +3679,7 @@ static int kvmppc_clr_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
         */
 
        mutex_unlock(&kvm->lock);
-       return 0;
+       return rc;
 }
 
 static int kvmppc_irq_bypass_add_producer_hv(struct irq_bypass_consumer *cons,
@@ -3930,7 +3957,7 @@ static int kvmppc_book3s_init_hv(void)
         * indirectly, via OPAL.
         */
 #ifdef CONFIG_SMP
-       if (!get_paca()->kvm_hstate.xics_phys) {
+       if (!xive_enabled() && !get_paca()->kvm_hstate.xics_phys) {
                struct device_node *np;
 
                np = of_find_compatible_node(NULL, NULL, "ibm,opal-intc");