Merge tag 'kvm-arm-for-4.8-take2' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorPaolo Bonzini <pbonzini@redhat.com>
Thu, 4 Aug 2016 11:59:56 +0000 (13:59 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 4 Aug 2016 11:59:56 +0000 (13:59 +0200)
KVM/ARM Changes for v4.8 - Take 2

Includes GSI routing support to go along with the new VGIC and a small fix that
has been cooking in -next for a while.

16 files changed:
Documentation/virtual/kvm/api.txt
arch/arm/kvm/Kconfig
arch/arm/kvm/Makefile
arch/arm/kvm/irq.h [new file with mode: 0644]
arch/arm64/kvm/Kconfig
arch/arm64/kvm/Makefile
arch/arm64/kvm/inject_fault.c
arch/arm64/kvm/irq.h [new file with mode: 0644]
arch/x86/kvm/irq.h
include/kvm/arm_vgic.h
include/linux/kvm_host.h
include/uapi/linux/kvm.h
virt/kvm/arm/vgic/vgic-init.c
virt/kvm/arm/vgic/vgic-irqfd.c
virt/kvm/arm/vgic/vgic.c
virt/kvm/irqchip.c

index 5237e1b..da3c395 100644 (file)
@@ -1433,13 +1433,16 @@ KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed.
 4.52 KVM_SET_GSI_ROUTING
 
 Capability: KVM_CAP_IRQ_ROUTING
-Architectures: x86 s390
+Architectures: x86 s390 arm arm64
 Type: vm ioctl
 Parameters: struct kvm_irq_routing (in)
 Returns: 0 on success, -1 on error
 
 Sets the GSI routing table entries, overwriting any previously set entries.
 
+On arm/arm64, GSI routing has the following limitation:
+- GSI routing does not apply to KVM_IRQ_LINE but only to KVM_IRQFD.
+
 struct kvm_irq_routing {
        __u32 nr;
        __u32 flags;
@@ -1468,7 +1471,13 @@ struct kvm_irq_routing_entry {
 #define KVM_IRQ_ROUTING_S390_ADAPTER 3
 #define KVM_IRQ_ROUTING_HV_SINT 4
 
-No flags are specified so far, the corresponding field must be set to zero.
+flags:
+- KVM_MSI_VALID_DEVID: used along with KVM_IRQ_ROUTING_MSI routing entry
+  type, specifies that the devid field contains a valid value.  The per-VM
+  KVM_CAP_MSI_DEVID capability advertises the requirement to provide
+  the device ID.  If this capability is not available, userspace should
+  never set the KVM_MSI_VALID_DEVID flag as the ioctl might fail.
+- zero otherwise
 
 struct kvm_irq_routing_irqchip {
        __u32 irqchip;
@@ -1479,9 +1488,16 @@ struct kvm_irq_routing_msi {
        __u32 address_lo;
        __u32 address_hi;
        __u32 data;
-       __u32 pad;
+       union {
+               __u32 pad;
+               __u32 devid;
+       };
 };
 
+If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
+for the device that wrote the MSI message.  For PCI, this is usually a
+BFD identifier in the lower 16 bits.
+
 On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
 feature of KVM_CAP_X2APIC_API capability is enabled.  If it is enabled,
 address_hi bits 31-8 provide bits 31-8 of the destination id.  Bits 7-0 of
@@ -2199,14 +2215,14 @@ struct kvm_msi {
        __u8  pad[12];
 };
 
-flags: KVM_MSI_VALID_DEVID: devid contains a valid value
-devid: If KVM_MSI_VALID_DEVID is set, contains a unique device identifier
-       for the device that wrote the MSI message.
-       For PCI, this is usually a BFD identifier in the lower 16 bits.
+flags: KVM_MSI_VALID_DEVID: devid contains a valid value.  The per-VM
+  KVM_CAP_MSI_DEVID capability advertises the requirement to provide
+  the device ID.  If this capability is not available, userspace
+  should never set the KVM_MSI_VALID_DEVID flag as the ioctl might fail.
 
-The per-VM KVM_CAP_MSI_DEVID capability advertises the need to provide
-the device ID. If this capability is not set, userland cannot rely on
-the kernel to allow the KVM_MSI_VALID_DEVID flag being set.
+If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
+for the device that wrote the MSI message.  For PCI, this is usually a
+BFD identifier in the lower 16 bits.
 
 On x86, address_hi is ignored unless the KVM_CAP_X2APIC_API capability is
 enabled.  If it is enabled, address_hi bits 31-8 provide bits 31-8 of the
@@ -2383,9 +2399,13 @@ Note that closing the resamplefd is not sufficient to disable the
 irqfd.  The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment
 and need not be specified with KVM_IRQFD_FLAG_DEASSIGN.
 
-On ARM/ARM64, the gsi field in the kvm_irqfd struct specifies the Shared
-Peripheral Interrupt (SPI) index, such that the GIC interrupt ID is
-given by gsi + 32.
+On arm/arm64, gsi routing being supported, the following can happen:
+- in case no routing entry is associated to this gsi, injection fails
+- in case the gsi is associated to an irqchip routing entry,
+  irqchip.pin + 32 corresponds to the injected SPI ID.
+- in case the gsi is associated to an MSI routing entry, the MSI
+  message and device ID are translated into an LPI (support restricted
+  to GICv3 ITS in-kernel emulation).
 
 4.76 KVM_PPC_ALLOCATE_HTAB
 
index 95a0005..3e1cd04 100644 (file)
@@ -32,6 +32,8 @@ config KVM
        select KVM_VFIO
        select HAVE_KVM_EVENTFD
        select HAVE_KVM_IRQFD
+       select HAVE_KVM_IRQCHIP
+       select HAVE_KVM_IRQ_ROUTING
        depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER
        ---help---
          Support hosting virtualized guest machines.
index 5e28df8..10d77a6 100644 (file)
@@ -29,4 +29,5 @@ obj-y += $(KVM)/arm/vgic/vgic-v2.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
 obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
+obj-y += $(KVM)/irqchip.o
 obj-y += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm/kvm/irq.h b/arch/arm/kvm/irq.h
new file mode 100644 (file)
index 0000000..b74099b
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * irq.h: in kernel interrupt controller related definitions
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This header is included by irqchip.c. However, on ARM, interrupt
+ * controller declarations are located in include/kvm/arm_vgic.h since
+ * they are mostly shared between arm and arm64.
+ */
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+#include <kvm/arm_vgic.h>
+
+#endif
index 9d2eff0..9c9edc9 100644 (file)
@@ -37,6 +37,8 @@ config KVM
        select KVM_ARM_VGIC_V3
        select KVM_ARM_PMU if HW_PERF_EVENTS
        select HAVE_KVM_MSI
+       select HAVE_KVM_IRQCHIP
+       select HAVE_KVM_IRQ_ROUTING
        ---help---
          Support hosting virtualized guest machines.
          We don't support KVM with 16K page tables yet, due to the multiple
index a5b9664..695eb3c 100644 (file)
@@ -30,5 +30,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
index e9e0e6d..898c0e6 100644 (file)
@@ -132,16 +132,14 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
 {
        unsigned long cpsr = *vcpu_cpsr(vcpu);
-       bool is_aarch32;
+       bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
        u32 esr = 0;
 
-       is_aarch32 = vcpu_mode_is_32bit(vcpu);
-
-       *vcpu_spsr(vcpu) = cpsr;
        *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
-
        *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
+
        *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+       *vcpu_spsr(vcpu) = cpsr;
 
        vcpu_sys_reg(vcpu, FAR_EL1) = addr;
 
@@ -172,11 +170,11 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
        unsigned long cpsr = *vcpu_cpsr(vcpu);
        u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
 
-       *vcpu_spsr(vcpu) = cpsr;
        *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
-
        *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
+
        *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+       *vcpu_spsr(vcpu) = cpsr;
 
        /*
         * Build an unknown exception, depending on the instruction
diff --git a/arch/arm64/kvm/irq.h b/arch/arm64/kvm/irq.h
new file mode 100644 (file)
index 0000000..b74099b
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * irq.h: in kernel interrupt controller related definitions
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This header is included by irqchip.c. However, on ARM, interrupt
+ * controller declarations are located in include/kvm/arm_vgic.h since
+ * they are mostly shared between arm and arm64.
+ */
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+#include <kvm/arm_vgic.h>
+
+#endif
index 61ebdc1..035731e 100644 (file)
@@ -120,4 +120,7 @@ void __kvm_migrate_timers(struct kvm_vcpu *vcpu);
 
 int apic_has_pending_timer(struct kvm_vcpu *vcpu);
 
+int kvm_setup_default_irq_routing(struct kvm *kvm);
+int kvm_setup_empty_irq_routing(struct kvm *kvm);
+
 #endif
index 540da51..19b698e 100644 (file)
@@ -34,6 +34,7 @@
 #define VGIC_MAX_SPI           1019
 #define VGIC_MAX_RESERVED      1023
 #define VGIC_MIN_LPI           8192
+#define KVM_IRQCHIP_NUM_PINS   (1020 - 32)
 
 enum vgic_type {
        VGIC_V2,                /* Good ol' GICv2 */
@@ -314,4 +315,10 @@ static inline int kvm_vgic_get_max_vcpus(void)
 
 int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
 
+/**
+ * kvm_vgic_setup_default_irq_routing:
+ * Setup a default flat gsi routing table mapping all SPIs
+ */
+int kvm_vgic_setup_default_irq_routing(struct kvm *kvm);
+
 #endif /* __KVM_ARM_VGIC_H */
index aafd702..01e908a 100644 (file)
@@ -317,7 +317,13 @@ struct kvm_kernel_irq_routing_entry {
                        unsigned irqchip;
                        unsigned pin;
                } irqchip;
-               struct msi_msg msi;
+               struct {
+                       u32 address_lo;
+                       u32 address_hi;
+                       u32 data;
+                       u32 flags;
+                       u32 devid;
+               } msi;
                struct kvm_s390_adapter_int adapter;
                struct kvm_hv_sint hv_sint;
        };
@@ -1003,12 +1009,12 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
 
 #ifdef CONFIG_S390
 #define KVM_MAX_IRQ_ROUTES 4096 //FIXME: we can have more than that...
+#elif defined(CONFIG_ARM64)
+#define KVM_MAX_IRQ_ROUTES 4096
 #else
 #define KVM_MAX_IRQ_ROUTES 1024
 #endif
 
-int kvm_setup_default_irq_routing(struct kvm *kvm);
-int kvm_setup_empty_irq_routing(struct kvm *kvm);
 int kvm_set_irq_routing(struct kvm *kvm,
                        const struct kvm_irq_routing_entry *entries,
                        unsigned nr,
index e98bb4c..300ef25 100644 (file)
@@ -882,7 +882,10 @@ struct kvm_irq_routing_msi {
        __u32 address_lo;
        __u32 address_hi;
        __u32 data;
-       __u32 pad;
+       union {
+               __u32 pad;
+               __u32 devid;
+       };
 };
 
 struct kvm_irq_routing_s390_adapter {
index 1e30ce0..fb4b0a7 100644 (file)
@@ -264,6 +264,10 @@ int vgic_init(struct kvm *kvm)
        kvm_for_each_vcpu(i, vcpu, kvm)
                kvm_vgic_vcpu_init(vcpu);
 
+       ret = kvm_vgic_setup_default_irq_routing(kvm);
+       if (ret)
+               goto out;
+
        dist->initialized = true;
 out:
        return ret;
index c675513..b31a51a 100644 (file)
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <trace/events/kvm.h>
+#include <kvm/arm_vgic.h>
+#include "vgic.h"
 
-int kvm_irq_map_gsi(struct kvm *kvm,
-                   struct kvm_kernel_irq_routing_entry *entries,
-                   int gsi)
+/**
+ * vgic_irqfd_set_irq: inject the IRQ corresponding to the
+ * irqchip routing entry
+ *
+ * This is the entry point for irqfd IRQ injection
+ */
+static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
+                       struct kvm *kvm, int irq_source_id,
+                       int level, bool line_status)
 {
-       return 0;
+       unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS;
+
+       if (!vgic_valid_spi(kvm, spi_id))
+               return -EINVAL;
+       return kvm_vgic_inject_irq(kvm, 0, spi_id, level);
 }
 
-int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip,
-                        unsigned int pin)
+/**
+ * kvm_set_routing_entry: populate a kvm routing entry
+ * from a user routing entry
+ *
+ * @kvm: the VM this entry is applied to
+ * @e: kvm kernel routing entry handle
+ * @ue: user api routing entry handle
+ * return 0 on success, -EINVAL on errors.
+ */
+#ifdef KVM_CAP_X2APIC_API
+int kvm_set_routing_entry(struct kvm *kvm,
+                         struct kvm_kernel_irq_routing_entry *e,
+                         const struct kvm_irq_routing_entry *ue)
+#else
+/* Remove this version and the ifdefery once merged into 4.8 */
+int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+                         const struct kvm_irq_routing_entry *ue)
+#endif
 {
-       return pin;
+       int r = -EINVAL;
+
+       switch (ue->type) {
+       case KVM_IRQ_ROUTING_IRQCHIP:
+               e->set = vgic_irqfd_set_irq;
+               e->irqchip.irqchip = ue->u.irqchip.irqchip;
+               e->irqchip.pin = ue->u.irqchip.pin;
+               if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
+                   (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
+                       goto out;
+               break;
+       case KVM_IRQ_ROUTING_MSI:
+               e->set = kvm_set_msi;
+               e->msi.address_lo = ue->u.msi.address_lo;
+               e->msi.address_hi = ue->u.msi.address_hi;
+               e->msi.data = ue->u.msi.data;
+               e->msi.flags = ue->flags;
+               e->msi.devid = ue->u.msi.devid;
+               break;
+       default:
+               goto out;
+       }
+       r = 0;
+out:
+       return r;
 }
 
-int kvm_set_irq(struct kvm *kvm, int irq_source_id,
-               u32 irq, int level, bool line_status)
+/**
+ * kvm_set_msi: inject the MSI corresponding to the
+ * MSI routing entry
+ *
+ * This is the entry point for irqfd MSI injection
+ * and userspace MSI injection.
+ */
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+               struct kvm *kvm, int irq_source_id,
+               int level, bool line_status)
 {
-       unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
+       struct kvm_msi msi;
 
-       trace_kvm_set_irq(irq, level, irq_source_id);
+       msi.address_lo = e->msi.address_lo;
+       msi.address_hi = e->msi.address_hi;
+       msi.data = e->msi.data;
+       msi.flags = e->msi.flags;
+       msi.devid = e->msi.devid;
 
-       BUG_ON(!vgic_initialized(kvm));
+       if (!vgic_has_its(kvm))
+               return -ENODEV;
 
-       return kvm_vgic_inject_irq(kvm, 0, spi, level);
+       return vgic_its_inject_msi(kvm, &msi);
 }
 
-/* MSI not implemented yet */
-int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
-               struct kvm *kvm, int irq_source_id,
-               int level, bool line_status)
+int kvm_vgic_setup_default_irq_routing(struct kvm *kvm)
 {
-       return 0;
+       struct kvm_irq_routing_entry *entries;
+       struct vgic_dist *dist = &kvm->arch.vgic;
+       u32 nr = dist->nr_spis;
+       int i, ret;
+
+       entries = kcalloc(nr, sizeof(struct kvm_kernel_irq_routing_entry),
+                         GFP_KERNEL);
+       if (!entries)
+               return -ENOMEM;
+
+       for (i = 0; i < nr; i++) {
+               entries[i].gsi = i;
+               entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
+               entries[i].u.irqchip.irqchip = 0;
+               entries[i].u.irqchip.pin = i;
+       }
+       ret = kvm_set_irq_routing(kvm, entries, nr, 0);
+       kfree(entries);
+       return ret;
 }
index 39f3358..e7aeac7 100644 (file)
@@ -711,10 +711,3 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
        return map_is_active;
 }
 
-int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
-{
-       if (vgic_has_its(kvm))
-               return vgic_its_inject_msi(kvm, msi);
-       else
-               return -ENODEV;
-}
index df99e9c..3bcc999 100644 (file)
@@ -62,12 +62,14 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
 {
        struct kvm_kernel_irq_routing_entry route;
 
-       if (!irqchip_in_kernel(kvm) || msi->flags != 0)
+       if (!irqchip_in_kernel(kvm) || (msi->flags & ~KVM_MSI_VALID_DEVID))
                return -EINVAL;
 
        route.msi.address_lo = msi->address_lo;
        route.msi.address_hi = msi->address_hi;
        route.msi.data = msi->data;
+       route.msi.flags = msi->flags;
+       route.msi.devid = msi->devid;
 
        return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, false);
 }
@@ -177,6 +179,7 @@ int kvm_set_irq_routing(struct kvm *kvm,
                        unsigned flags)
 {
        struct kvm_irq_routing_table *new, *old;
+       struct kvm_kernel_irq_routing_entry *e;
        u32 i, j, nr_rt_entries = 0;
        int r;
 
@@ -200,23 +203,25 @@ int kvm_set_irq_routing(struct kvm *kvm,
                        new->chip[i][j] = -1;
 
        for (i = 0; i < nr; ++i) {
-               struct kvm_kernel_irq_routing_entry *e;
-
                r = -ENOMEM;
                e = kzalloc(sizeof(*e), GFP_KERNEL);
                if (!e)
                        goto out;
 
                r = -EINVAL;
-               if (ue->flags) {
-                       kfree(e);
-                       goto out;
+               switch (ue->type) {
+               case KVM_IRQ_ROUTING_MSI:
+                       if (ue->flags & ~KVM_MSI_VALID_DEVID)
+                               goto free_entry;
+                       break;
+               default:
+                       if (ue->flags)
+                               goto free_entry;
+                       break;
                }
                r = setup_routing_entry(kvm, new, e, ue);
-               if (r) {
-                       kfree(e);
-                       goto out;
-               }
+               if (r)
+                       goto free_entry;
                ++ue;
        }
 
@@ -233,7 +238,10 @@ int kvm_set_irq_routing(struct kvm *kvm,
 
        new = old;
        r = 0;
+       goto out;
 
+free_entry:
+       kfree(e);
 out:
        free_irq_routing_table(new);