]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
KVM: arm/arm64: Enable irqchip routing
authorEric Auger <eric.auger@redhat.com>
Fri, 22 Jul 2016 16:20:41 +0000 (16:20 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Fri, 22 Jul 2016 17:52:01 +0000 (18:52 +0100)
This patch adds compilation and link against irqchip.

Main motivation behind using irqchip code is to enable MSI
routing code. In the future irqchip routing may also be useful
when targeting multiple irqchips.

Routing standard callbacks now are implemented in vgic-irqfd:
- kvm_set_routing_entry
- kvm_set_irq
- kvm_set_msi

They only are supported with new_vgic code.

Both HAVE_KVM_IRQCHIP and HAVE_KVM_IRQ_ROUTING are defined.
KVM_CAP_IRQ_ROUTING is advertised and KVM_SET_GSI_ROUTING is allowed.

So from now on IRQCHIP routing is enabled and a routing table entry
must exist for irqfd injection to succeed for a given SPI. This patch
builds a default flat irqchip routing table (gsi=irqchip.pin) covering
all the VGIC SPI indexes. This routing table is overwritten by the
first first user-space call to KVM_SET_GSI_ROUTING ioctl.

MSI routing setup is not yet allowed.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
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/irq.h [new file with mode: 0644]
include/kvm/arm_vgic.h
virt/kvm/arm/vgic/vgic-init.c
virt/kvm/arm/vgic/vgic-irqfd.c
virt/kvm/arm/vgic/vgic.c

index 415cde1647e9249af9902cafc8dcb227ef4fbc98..7e5f9afcc693ed21d08eb4eaa5f74a34ec73a808 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;
@@ -2374,9 +2377,10 @@ 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.
 
 4.76 KVM_PPC_ALLOCATE_HTAB
 
index 95a000515e43286f822f541fe411902df42bdeb8..3e1cd0452d67b0eb761b39fb5094a1efdae183ed 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 5e28df80dca7a25608023f3060e037c00a32c91e..10d77a66cad5d83de04ea02987733169518c22f0 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 9d2eff0b3ad347b95d9e8a5ddd0b3e24f9ae24e1..9c9edc98d271fbcb4379cf0087744e7fc6396301 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 a5b96642a9cb9cf97d842e785711a9c7f9125a4c..695eb3c7ef41fa0436caa9e32b911f7268032cd6 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
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 540da5149ba7f0a6662d550002fc47e618ce30f6..19b698ef3336ffc947b4c01b62e026c779eb5af3 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 01a60dcd05d626f2d6a52b5e8bcefd1683184b5f..1aba785cd498e2dc891a2065e1b69423236731d2 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 c675513270bb8644f39adb534114c1cab22b0d32..6e84d530d9f73c39754937f6f37ae5e9edf4ddcb 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
+ *
+ * @e: kvm kernel routing entry handle
+ * @ue: user api routing entry handle
+ * return 0 on success, -EINVAL on errors.
+ */
+int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+                         const struct kvm_irq_routing_entry *ue)
 {
-       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;
+       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 39f3358c6d91a140eb3887f312cd10751848d4e6..e7aeac719e09175514a6a0c4dd349ac6500039a4 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;
-}