aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Auger <eric.auger@redhat.com>2016-07-22 12:20:41 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2016-07-22 13:52:01 -0400
commit180ae7b1182344ca617d8b5200306b02a6b5075d (patch)
tree927863bc629927451b925be0a483ec9e57307cd3
parentd9565a7399d665fa7313122504778cb3d5ef3e19 (diff)
KVM: arm/arm64: Enable irqchip routing
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>
-rw-r--r--Documentation/virtual/kvm/api.txt12
-rw-r--r--arch/arm/kvm/Kconfig2
-rw-r--r--arch/arm/kvm/Makefile1
-rw-r--r--arch/arm/kvm/irq.h19
-rw-r--r--arch/arm64/kvm/Kconfig2
-rw-r--r--arch/arm64/kvm/Makefile1
-rw-r--r--arch/arm64/kvm/irq.h19
-rw-r--r--include/kvm/arm_vgic.h7
-rw-r--r--virt/kvm/arm/vgic/vgic-init.c4
-rw-r--r--virt/kvm/arm/vgic/vgic-irqfd.c100
-rw-r--r--virt/kvm/arm/vgic/vgic.c7
11 files changed, 145 insertions, 29 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 415cde1647e9..7e5f9afcc693 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1433,13 +1433,16 @@ KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed.
14334.52 KVM_SET_GSI_ROUTING 14334.52 KVM_SET_GSI_ROUTING
1434 1434
1435Capability: KVM_CAP_IRQ_ROUTING 1435Capability: KVM_CAP_IRQ_ROUTING
1436Architectures: x86 s390 1436Architectures: x86 s390 arm arm64
1437Type: vm ioctl 1437Type: vm ioctl
1438Parameters: struct kvm_irq_routing (in) 1438Parameters: struct kvm_irq_routing (in)
1439Returns: 0 on success, -1 on error 1439Returns: 0 on success, -1 on error
1440 1440
1441Sets the GSI routing table entries, overwriting any previously set entries. 1441Sets the GSI routing table entries, overwriting any previously set entries.
1442 1442
1443On arm/arm64, GSI routing has the following limitation:
1444- GSI routing does not apply to KVM_IRQ_LINE but only to KVM_IRQFD.
1445
1443struct kvm_irq_routing { 1446struct kvm_irq_routing {
1444 __u32 nr; 1447 __u32 nr;
1445 __u32 flags; 1448 __u32 flags;
@@ -2374,9 +2377,10 @@ Note that closing the resamplefd is not sufficient to disable the
2374irqfd. The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment 2377irqfd. The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment
2375and need not be specified with KVM_IRQFD_FLAG_DEASSIGN. 2378and need not be specified with KVM_IRQFD_FLAG_DEASSIGN.
2376 2379
2377On ARM/ARM64, the gsi field in the kvm_irqfd struct specifies the Shared 2380On arm/arm64, gsi routing being supported, the following can happen:
2378Peripheral Interrupt (SPI) index, such that the GIC interrupt ID is 2381- in case no routing entry is associated to this gsi, injection fails
2379given by gsi + 32. 2382- in case the gsi is associated to an irqchip routing entry,
2383 irqchip.pin + 32 corresponds to the injected SPI ID.
2380 2384
23814.76 KVM_PPC_ALLOCATE_HTAB 23854.76 KVM_PPC_ALLOCATE_HTAB
2382 2386
diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index 95a000515e43..3e1cd0452d67 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -32,6 +32,8 @@ config KVM
32 select KVM_VFIO 32 select KVM_VFIO
33 select HAVE_KVM_EVENTFD 33 select HAVE_KVM_EVENTFD
34 select HAVE_KVM_IRQFD 34 select HAVE_KVM_IRQFD
35 select HAVE_KVM_IRQCHIP
36 select HAVE_KVM_IRQ_ROUTING
35 depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER 37 depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER
36 ---help--- 38 ---help---
37 Support hosting virtualized guest machines. 39 Support hosting virtualized guest machines.
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index 5e28df80dca7..10d77a66cad5 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -29,4 +29,5 @@ obj-y += $(KVM)/arm/vgic/vgic-v2.o
29obj-y += $(KVM)/arm/vgic/vgic-mmio.o 29obj-y += $(KVM)/arm/vgic/vgic-mmio.o
30obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o 30obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
31obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o 31obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
32obj-y += $(KVM)/irqchip.o
32obj-y += $(KVM)/arm/arch_timer.o 33obj-y += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm/kvm/irq.h b/arch/arm/kvm/irq.h
new file mode 100644
index 000000000000..b74099b905fd
--- /dev/null
+++ b/arch/arm/kvm/irq.h
@@ -0,0 +1,19 @@
1/*
2 * irq.h: in kernel interrupt controller related definitions
3 * Copyright (c) 2016 Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This header is included by irqchip.c. However, on ARM, interrupt
10 * controller declarations are located in include/kvm/arm_vgic.h since
11 * they are mostly shared between arm and arm64.
12 */
13
14#ifndef __IRQ_H
15#define __IRQ_H
16
17#include <kvm/arm_vgic.h>
18
19#endif
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 9d2eff0b3ad3..9c9edc98d271 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -37,6 +37,8 @@ config KVM
37 select KVM_ARM_VGIC_V3 37 select KVM_ARM_VGIC_V3
38 select KVM_ARM_PMU if HW_PERF_EVENTS 38 select KVM_ARM_PMU if HW_PERF_EVENTS
39 select HAVE_KVM_MSI 39 select HAVE_KVM_MSI
40 select HAVE_KVM_IRQCHIP
41 select HAVE_KVM_IRQ_ROUTING
40 ---help--- 42 ---help---
41 Support hosting virtualized guest machines. 43 Support hosting virtualized guest machines.
42 We don't support KVM with 16K page tables yet, due to the multiple 44 We don't support KVM with 16K page tables yet, due to the multiple
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index a5b96642a9cb..695eb3c7ef41 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -30,5 +30,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
30kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o 30kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
31kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o 31kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
32kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o 32kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
33kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
33kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o 34kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
34kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o 35kvm-$(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
index 000000000000..b74099b905fd
--- /dev/null
+++ b/arch/arm64/kvm/irq.h
@@ -0,0 +1,19 @@
1/*
2 * irq.h: in kernel interrupt controller related definitions
3 * Copyright (c) 2016 Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This header is included by irqchip.c. However, on ARM, interrupt
10 * controller declarations are located in include/kvm/arm_vgic.h since
11 * they are mostly shared between arm and arm64.
12 */
13
14#ifndef __IRQ_H
15#define __IRQ_H
16
17#include <kvm/arm_vgic.h>
18
19#endif
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 540da5149ba7..19b698ef3336 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -34,6 +34,7 @@
34#define VGIC_MAX_SPI 1019 34#define VGIC_MAX_SPI 1019
35#define VGIC_MAX_RESERVED 1023 35#define VGIC_MAX_RESERVED 1023
36#define VGIC_MIN_LPI 8192 36#define VGIC_MIN_LPI 8192
37#define KVM_IRQCHIP_NUM_PINS (1020 - 32)
37 38
38enum vgic_type { 39enum vgic_type {
39 VGIC_V2, /* Good ol' GICv2 */ 40 VGIC_V2, /* Good ol' GICv2 */
@@ -314,4 +315,10 @@ static inline int kvm_vgic_get_max_vcpus(void)
314 315
315int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi); 316int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
316 317
318/**
319 * kvm_vgic_setup_default_irq_routing:
320 * Setup a default flat gsi routing table mapping all SPIs
321 */
322int kvm_vgic_setup_default_irq_routing(struct kvm *kvm);
323
317#endif /* __KVM_ARM_VGIC_H */ 324#endif /* __KVM_ARM_VGIC_H */
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 01a60dcd05d6..1aba785cd498 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -264,6 +264,10 @@ int vgic_init(struct kvm *kvm)
264 kvm_for_each_vcpu(i, vcpu, kvm) 264 kvm_for_each_vcpu(i, vcpu, kvm)
265 kvm_vgic_vcpu_init(vcpu); 265 kvm_vgic_vcpu_init(vcpu);
266 266
267 ret = kvm_vgic_setup_default_irq_routing(kvm);
268 if (ret)
269 goto out;
270
267 dist->initialized = true; 271 dist->initialized = true;
268out: 272out:
269 return ret; 273 return ret;
diff --git a/virt/kvm/arm/vgic/vgic-irqfd.c b/virt/kvm/arm/vgic/vgic-irqfd.c
index c675513270bb..6e84d530d9f7 100644
--- a/virt/kvm/arm/vgic/vgic-irqfd.c
+++ b/virt/kvm/arm/vgic/vgic-irqfd.c
@@ -17,36 +17,100 @@
17#include <linux/kvm.h> 17#include <linux/kvm.h>
18#include <linux/kvm_host.h> 18#include <linux/kvm_host.h>
19#include <trace/events/kvm.h> 19#include <trace/events/kvm.h>
20#include <kvm/arm_vgic.h>
21#include "vgic.h"
20 22
21int kvm_irq_map_gsi(struct kvm *kvm, 23/**
22 struct kvm_kernel_irq_routing_entry *entries, 24 * vgic_irqfd_set_irq: inject the IRQ corresponding to the
23 int gsi) 25 * irqchip routing entry
26 *
27 * This is the entry point for irqfd IRQ injection
28 */
29static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
30 struct kvm *kvm, int irq_source_id,
31 int level, bool line_status)
24{ 32{
25 return 0; 33 unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS;
34
35 if (!vgic_valid_spi(kvm, spi_id))
36 return -EINVAL;
37 return kvm_vgic_inject_irq(kvm, 0, spi_id, level);
26} 38}
27 39
28int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip, 40/**
29 unsigned int pin) 41 * kvm_set_routing_entry: populate a kvm routing entry
42 * from a user routing entry
43 *
44 * @e: kvm kernel routing entry handle
45 * @ue: user api routing entry handle
46 * return 0 on success, -EINVAL on errors.
47 */
48int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
49 const struct kvm_irq_routing_entry *ue)
30{ 50{
31 return pin; 51 int r = -EINVAL;
52
53 switch (ue->type) {
54 case KVM_IRQ_ROUTING_IRQCHIP:
55 e->set = vgic_irqfd_set_irq;
56 e->irqchip.irqchip = ue->u.irqchip.irqchip;
57 e->irqchip.pin = ue->u.irqchip.pin;
58 if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
59 (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
60 goto out;
61 break;
62 default:
63 goto out;
64 }
65 r = 0;
66out:
67 return r;
32} 68}
33 69
34int kvm_set_irq(struct kvm *kvm, int irq_source_id, 70/**
35 u32 irq, int level, bool line_status) 71 * kvm_set_msi: inject the MSI corresponding to the
72 * MSI routing entry
73 *
74 * This is the entry point for irqfd MSI injection
75 * and userspace MSI injection.
76 */
77int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
78 struct kvm *kvm, int irq_source_id,
79 int level, bool line_status)
36{ 80{
37 unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS; 81 struct kvm_msi msi;
38 82
39 trace_kvm_set_irq(irq, level, irq_source_id); 83 msi.address_lo = e->msi.address_lo;
84 msi.address_hi = e->msi.address_hi;
85 msi.data = e->msi.data;
86 msi.flags = e->msi.flags;
87 msi.devid = e->msi.devid;
40 88
41 BUG_ON(!vgic_initialized(kvm)); 89 if (!vgic_has_its(kvm))
90 return -ENODEV;
42 91
43 return kvm_vgic_inject_irq(kvm, 0, spi, level); 92 return vgic_its_inject_msi(kvm, &msi);
44} 93}
45 94
46/* MSI not implemented yet */ 95int kvm_vgic_setup_default_irq_routing(struct kvm *kvm)
47int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
48 struct kvm *kvm, int irq_source_id,
49 int level, bool line_status)
50{ 96{
51 return 0; 97 struct kvm_irq_routing_entry *entries;
98 struct vgic_dist *dist = &kvm->arch.vgic;
99 u32 nr = dist->nr_spis;
100 int i, ret;
101
102 entries = kcalloc(nr, sizeof(struct kvm_kernel_irq_routing_entry),
103 GFP_KERNEL);
104 if (!entries)
105 return -ENOMEM;
106
107 for (i = 0; i < nr; i++) {
108 entries[i].gsi = i;
109 entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
110 entries[i].u.irqchip.irqchip = 0;
111 entries[i].u.irqchip.pin = i;
112 }
113 ret = kvm_set_irq_routing(kvm, entries, nr, 0);
114 kfree(entries);
115 return ret;
52} 116}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 39f3358c6d91..e7aeac719e09 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -711,10 +711,3 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
711 return map_is_active; 711 return map_is_active;
712} 712}
713 713
714int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
715{
716 if (vgic_has_its(kvm))
717 return vgic_its_inject_msi(kvm, msi);
718 else
719 return -ENODEV;
720}