All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH kvmtool 0/2] Add GICv2m support
@ 2017-11-03 11:38 Jean-Philippe Brucker
  2017-11-03 11:38 ` [PATCH kvmtool 1/2] Prevent segfault when kvm_pause is called too early Jean-Philippe Brucker
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Jean-Philippe Brucker @ 2017-11-03 11:38 UTC (permalink / raw)
  To: kvm; +Cc: kvmarm, marc.zyngier, andre.przywara, punit.agrawal, will.deacon

GICv2m is an extension to GICv2 defined in the Server Base System
Architecture (SBSA) [1], allowing pre-GICv3 platforms to support MSIs.

Presenting GICv2m frames to the guest can be useful for testing PCI
pass-through on platforms that have a GICv2m, for example AMD Seattle.
Otherwise they are forced to use legacy INTx.

This series adds a GICv2m frame to kvmtool, which is basically an MMIO
register telling the guest which SPIs (Shared Peripheral Interrupts) are
reserved for MSIs. When configuring MSI vectors, the guest writes the
desired SPI number into the MSI data field. Then in kvmtool we create
the IRQFD routes such that they inject the given SPI.

[1] https://developer.arm.com/products/architecture/a-profile/docs/den0029/latest/server-base-system-architecture

Jean-Philippe Brucker (2):
  Prevent segfault when kvm_pause is called too early
  Add GICv2m support

 Makefile                                 |   2 +-
 arm/aarch32/include/asm/kvm.h            |   2 +
 arm/aarch64/include/asm/kvm.h            |   2 +
 arm/gic.c                                |  13 +++
 arm/gicv2m.c                             | 153 +++++++++++++++++++++++++++++++
 arm/include/arm-common/gic.h             |   3 +
 arm/include/arm-common/kvm-config-arch.h |   2 +-
 include/kvm/irq.h                        |  11 +++
 irq.c                                    |  68 +++++++++++---
 kvm.c                                    |   2 +-
 virtio/pci.c                             |   4 +-
 11 files changed, 245 insertions(+), 17 deletions(-)
 create mode 100644 arm/gicv2m.c

-- 
2.14.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH kvmtool 1/2] Prevent segfault when kvm_pause is called too early
  2017-11-03 11:38 [PATCH kvmtool 0/2] Add GICv2m support Jean-Philippe Brucker
@ 2017-11-03 11:38 ` Jean-Philippe Brucker
  2017-11-03 11:38 ` [PATCH kvmtool 2/2] Add GICv2m support Jean-Philippe Brucker
  2017-11-03 13:46 ` [PATCH kvmtool 0/2] " Marc Zyngier
  2 siblings, 0 replies; 6+ messages in thread
From: Jean-Philippe Brucker @ 2017-11-03 11:38 UTC (permalink / raw)
  To: kvm; +Cc: kvmarm, marc.zyngier, andre.przywara, punit.agrawal, will.deacon

When kvm_pause is called early (from taking the rwlock), it segfaults
because the CPU array is initialized slightly later. Fix this.

This doesn't happen at the moment but the gicv2m patch will register an
MMIO region, which requires br_write_lock. gicv2m is instantiated by
kvm__arch_init from within core_init (level 0). The CPU array is
initialized later in base_init (level 1).

Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
---
 kvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kvm.c b/kvm.c
index 9078a026411b..7de825a9d063 100644
--- a/kvm.c
+++ b/kvm.c
@@ -512,7 +512,7 @@ void kvm__pause(struct kvm *kvm)
 	mutex_lock(&pause_lock);
 
 	/* Check if the guest is running */
-	if (!kvm->cpus[0] || kvm->cpus[0]->thread == 0)
+	if (!kvm->cpus || !kvm->cpus[0] || kvm->cpus[0]->thread == 0)
 		return;
 
 	pause_event = eventfd(0, 0);
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH kvmtool 2/2] Add GICv2m support
  2017-11-03 11:38 [PATCH kvmtool 0/2] Add GICv2m support Jean-Philippe Brucker
  2017-11-03 11:38 ` [PATCH kvmtool 1/2] Prevent segfault when kvm_pause is called too early Jean-Philippe Brucker
@ 2017-11-03 11:38 ` Jean-Philippe Brucker
  2017-11-03 14:27   ` Andre Przywara
  2017-11-03 13:46 ` [PATCH kvmtool 0/2] " Marc Zyngier
  2 siblings, 1 reply; 6+ messages in thread
From: Jean-Philippe Brucker @ 2017-11-03 11:38 UTC (permalink / raw)
  To: kvm; +Cc: kvmarm, marc.zyngier, andre.przywara, punit.agrawal, will.deacon

GICv2m is a small extension to the GICv2 architecture, specified in the
Server Base System Architecture (SBSA). It adds a set of register to
converts MSIs into SPIs, effectively enabling MSI support for pre-GICv3
platforms.

Implement a GICv2m emulation entirely in userspace. Add a thin translation
layer in irq.c to catch the MSI->SPI routing setup of the guest, and then
transform irqfd injection of MSI into the associated SPI. There shouldn't
be any significant runtime overhead compared to gicv3-its.

The device can be enabled by passing "--irqchip gicv2m" to kvmtool.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
---
 Makefile                                 |   2 +-
 arm/aarch32/include/asm/kvm.h            |   2 +
 arm/aarch64/include/asm/kvm.h            |   2 +
 arm/gic.c                                |  13 +++
 arm/gicv2m.c                             | 153 +++++++++++++++++++++++++++++++
 arm/include/arm-common/gic.h             |   3 +
 arm/include/arm-common/kvm-config-arch.h |   2 +-
 include/kvm/irq.h                        |  11 +++
 irq.c                                    |  68 +++++++++++---
 virtio/pci.c                             |   4 +-
 10 files changed, 244 insertions(+), 16 deletions(-)
 create mode 100644 arm/gicv2m.c

diff --git a/Makefile b/Makefile
index 6414b5853947..93dc0673571d 100644
--- a/Makefile
+++ b/Makefile
@@ -153,7 +153,7 @@ ifeq ($(ARCH), powerpc)
 endif
 
 # ARM
-OBJS_ARM_COMMON		:= arm/fdt.o arm/gic.o arm/ioport.o \
+OBJS_ARM_COMMON		:= arm/fdt.o arm/gic.o arm/gicv2m.o arm/ioport.o \
 			   arm/kvm.o arm/kvm-cpu.o arm/pci.o arm/timer.o \
 			   arm/pmu.o
 HDRS_ARM_COMMON		:= arm/include
diff --git a/arm/aarch32/include/asm/kvm.h b/arm/aarch32/include/asm/kvm.h
index 6ebd3e6a1fd1..022066730dc7 100644
--- a/arm/aarch32/include/asm/kvm.h
+++ b/arm/aarch32/include/asm/kvm.h
@@ -84,6 +84,8 @@ struct kvm_regs {
 #define KVM_VGIC_V2_DIST_SIZE		0x1000
 #define KVM_VGIC_V2_CPU_SIZE		0x2000
 
+#define KVM_VGIC_V2M_SIZE		0x1000
+
 /* Supported VGICv3 address types  */
 #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
 #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
diff --git a/arm/aarch64/include/asm/kvm.h b/arm/aarch64/include/asm/kvm.h
index c2860358ae3e..7d14507bd329 100644
--- a/arm/aarch64/include/asm/kvm.h
+++ b/arm/aarch64/include/asm/kvm.h
@@ -84,6 +84,8 @@ struct kvm_regs {
 #define KVM_VGIC_V2_DIST_SIZE		0x1000
 #define KVM_VGIC_V2_CPU_SIZE		0x2000
 
+#define KVM_VGIC_V2M_SIZE		0x1000
+
 /* Supported VGICv3 address types  */
 #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
 #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
diff --git a/arm/gic.c b/arm/gic.c
index e53f932e28c3..46cfa245e590 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -32,6 +32,8 @@ int irqchip_parser(const struct option *opt, const char *arg, int unset)
 
 	if (!strcmp(arg, "gicv2")) {
 		*type = IRQCHIP_GICV2;
+	} else if (!strcmp(arg, "gicv2m")) {
+		*type = IRQCHIP_GICV2M;
 	} else if (!strcmp(arg, "gicv3")) {
 		*type = IRQCHIP_GICV3;
 	} else if (!strcmp(arg, "gicv3-its")) {
@@ -134,6 +136,8 @@ static int gic__create_msi_frame(struct kvm *kvm, enum irqchip_type type,
 				 u64 msi_frame_addr)
 {
 	switch (type) {
+	case IRQCHIP_GICV2M:
+		return gic__create_gicv2m_frame(kvm, msi_frame_addr);
 	case IRQCHIP_GICV3_ITS:
 		return gic__create_its_frame(kvm, msi_frame_addr);
 	default:	/* No MSI frame needed */
@@ -165,6 +169,7 @@ static int gic__create_device(struct kvm *kvm, enum irqchip_type type)
 	};
 
 	switch (type) {
+	case IRQCHIP_GICV2M:
 	case IRQCHIP_GICV2:
 		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V2;
 		dist_attr.attr  = KVM_VGIC_V2_ADDR_TYPE_DIST;
@@ -183,6 +188,7 @@ static int gic__create_device(struct kvm *kvm, enum irqchip_type type)
 	gic_fd = gic_device.fd;
 
 	switch (type) {
+	case IRQCHIP_GICV2M:
 	case IRQCHIP_GICV2:
 		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &cpu_if_attr);
 		break;
@@ -243,6 +249,10 @@ int gic__create(struct kvm *kvm, enum irqchip_type type)
 	int err;
 
 	switch (type) {
+	case IRQCHIP_GICV2M:
+		gic_msi_size = KVM_VGIC_V2M_SIZE;
+		gic_msi_base = ARM_GIC_DIST_BASE - gic_msi_size;
+		break;
 	case IRQCHIP_GICV2:
 		break;
 	case IRQCHIP_GICV3_ITS:
@@ -325,6 +335,9 @@ void gic__generate_fdt_nodes(void *fdt, enum irqchip_type type)
 	};
 
 	switch (type) {
+	case IRQCHIP_GICV2M:
+		msi_compatible = "arm,gic-v2m-frame";
+		/* fall-through */
 	case IRQCHIP_GICV2:
 		compatible = "arm,cortex-a15-gic";
 		reg_prop[2] = cpu_to_fdt64(ARM_GIC_CPUI_BASE);
diff --git a/arm/gicv2m.c b/arm/gicv2m.c
new file mode 100644
index 000000000000..d7e6398a13a8
--- /dev/null
+++ b/arm/gicv2m.c
@@ -0,0 +1,153 @@
+#include <errno.h>
+#include <stdlib.h>
+
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#include "arm-common/gic.h"
+
+#define GICV2M_MSI_TYPER	0x008
+#define GICV2M_MSI_SETSPI	0x040
+#define GICV2M_MSI_IIDR		0xfcc
+
+#define GICV2M_SPI_MASK		0x3ff
+#define GICV2M_MSI_TYPER_VAL(start, nr)	\
+	(((start) & GICV2M_SPI_MASK) << 16 | ((nr) & GICV2M_SPI_MASK))
+
+struct gicv2m_chip {
+	int	first_spi;
+	int	num_spis;
+	int	*spis;
+	u64	base;
+	u64	size;
+};
+
+static struct gicv2m_chip v2m;
+
+/*
+ * MSI routing is setup lazily, when the guest writes the MSI tables. The guest
+ * writes which SPI is associated to an MSI vector into the message data field.
+ * The IRQ code notifies us of any change to MSI routing via this callback.
+ * Store the MSI->SPI translation for later.
+ *
+ * Data is the GIC interrupt ID, that includes SGIs and PPIs. SGIs at 0-15, PPIs
+ * are 16-31 and SPIs are 32-1019. What we're saving for later is the MSI's GSI
+ * number, a logical ID used by KVM for routing. The GSI of an SPI is implicitly
+ * defined by KVM to be its pin number (SPI index), and the GSI of an MSI is
+ * allocated by kvmtool.
+ */
+static int gicv2m_update_routing(struct kvm *kvm,
+				 struct kvm_irq_routing_entry *entry)
+{
+	int spi;
+
+	if (entry->type != KVM_IRQ_ROUTING_MSI)
+		return -EINVAL;
+
+	if (!entry->u.msi.address_hi && !entry->u.msi.address_lo)
+		return 0;
+
+	spi = entry->u.msi.data & GICV2M_SPI_MASK;
+	if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) {
+		pr_err("invalid SPI number %d", spi);
+		return -EINVAL;
+	}
+
+	v2m.spis[spi - v2m.first_spi] = entry->gsi;
+
+	return 0;
+}
+
+/*
+ * Find SPI bound to the given MSI and return the associated GSI.
+ */
+static int gicv2m_translate_gsi(struct kvm *kvm, u32 gsi)
+{
+	int i;
+
+	for (i = 0; i < v2m.num_spis; i++) {
+		if (v2m.spis[i] == (int)gsi)
+			return i + v2m.first_spi - KVM_IRQ_OFFSET;
+	}
+
+	/* Not an MSI */
+	return gsi;
+}
+
+static bool gicv2m_can_signal_msi(struct kvm *kvm)
+{
+	return true;
+}
+
+/*
+ * Instead of setting up MSI routes, virtual devices can also trigger them
+ * manually (like a direct write to MSI_SETSPI). In this case, trigger the SPI
+ * directly.
+ */
+static int gicv2m_signal_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+	int spi = msi->data & GICV2M_SPI_MASK;
+
+	if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) {
+		pr_err("invalid SPI number %d", spi);
+		return -EINVAL;
+	}
+
+	kvm__irq_trigger(kvm, spi);
+	return 0;
+}
+
+static struct msi_routing_ops gicv2m_routing = {
+	.update_route	= gicv2m_update_routing,
+	.translate_gsi	= gicv2m_translate_gsi,
+	.can_signal_msi	= gicv2m_can_signal_msi,
+	.signal_msi	= gicv2m_signal_msi,
+};
+
+static void gicv2m_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+				  u32 len, u8 is_write, void *ptr)
+{
+	if (is_write)
+		return;
+
+	addr -= v2m.base;
+
+	switch (addr) {
+		case GICV2M_MSI_TYPER:
+			*(u32 *)data = GICV2M_MSI_TYPER_VAL(v2m.first_spi,
+							    v2m.num_spis);
+			break;
+		case GICV2M_MSI_IIDR:
+			*(u32 *)data = 0x0;
+			break;
+	}
+}
+
+int gic__create_gicv2m_frame(struct kvm *kvm, u64 base)
+{
+	int i;
+	int irq = irq__alloc_line();
+
+	v2m = (struct gicv2m_chip) {
+		.first_spi	= irq,	/* Includes GIC_SPI_IRQ_BASE */
+		.num_spis	= 64,	/* arbitrary */
+		.base		= base,
+		.size		= KVM_VGIC_V2M_SIZE,
+	};
+
+	v2m.spis = calloc(v2m.num_spis, sizeof(int));
+	if (!v2m.spis)
+		return -ENOMEM;
+
+	v2m.spis[0] = -1;
+	for (i = 1; i < v2m.num_spis; i++) {
+		irq__alloc_line();
+		v2m.spis[i] = -1;
+	}
+
+	msi_routing_ops = &gicv2m_routing;
+
+	return kvm__register_mmio(kvm, base, KVM_VGIC_V2M_SIZE, false,
+				  gicv2m_mmio_callback, kvm);
+}
diff --git a/arm/include/arm-common/gic.h b/arm/include/arm-common/gic.h
index 0c279aca8a5e..560fea2a2c5a 100644
--- a/arm/include/arm-common/gic.h
+++ b/arm/include/arm-common/gic.h
@@ -23,6 +23,7 @@
 
 enum irqchip_type {
 	IRQCHIP_GICV2,
+	IRQCHIP_GICV2M,
 	IRQCHIP_GICV3,
 	IRQCHIP_GICV3_ITS,
 };
@@ -39,4 +40,6 @@ void gic__del_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd);
 #define irq__add_irqfd gic__add_irqfd
 #define irq__del_irqfd gic__del_irqfd
 
+int gic__create_gicv2m_frame(struct kvm *kvm, u64 msi_frame_addr);
+
 #endif /* ARM_COMMON__GIC_H */
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index f18b2c88fa79..6a196f1852de 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -28,7 +28,7 @@ int irqchip_parser(const struct option *opt, const char *arg, int unset);
 		    "Force virtio devices to use PCI as their default "		\
 		    "transport"),						\
         OPT_CALLBACK('\0', "irqchip", &(cfg)->irqchip,				\
-		     "[gicv2|gicv3|gicv3-its]",					\
+		     "[gicv2|gicv2m|gicv3|gicv3-its]",				\
 		     "Type of interrupt controller to emulate in the guest",	\
 		     irqchip_parser, NULL),
 
diff --git a/include/kvm/irq.h b/include/kvm/irq.h
index b24385b13f66..530ce3f9133d 100644
--- a/include/kvm/irq.h
+++ b/include/kvm/irq.h
@@ -11,6 +11,14 @@
 
 struct kvm;
 
+struct msi_routing_ops {
+	int (*update_route)(struct kvm *kvm, struct kvm_irq_routing_entry *);
+	bool (*can_signal_msi)(struct kvm *kvm);
+	int (*signal_msi)(struct kvm *kvm, struct kvm_msi *msi);
+	int (*translate_gsi)(struct kvm *kvm, u32 gsi);
+};
+
+extern struct msi_routing_ops *msi_routing_ops;
 extern struct kvm_irq_routing *irq_routing;
 extern int next_gsi;
 
@@ -24,6 +32,9 @@ int irq__allocate_routing_entry(void);
 int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg, u32 device_id);
 void irq__update_msix_route(struct kvm *kvm, u32 gsi, struct msi_msg *msg);
 
+bool irq__can_signal_msi(struct kvm *kvm);
+int irq__signal_msi(struct kvm *kvm, struct kvm_msi *msi);
+
 /*
  * The function takes two eventfd arguments, trigger_fd and resample_fd. If
  * resample_fd is <= 0, resampling is disabled and the IRQ is edge-triggered
diff --git a/irq.c b/irq.c
index 25fa572761fa..cdcf99233baa 100644
--- a/irq.c
+++ b/irq.c
@@ -13,6 +13,9 @@ static int allocated_gsis = 0;
 
 int next_gsi;
 
+struct msi_routing_ops irq__default_routing_ops;
+struct msi_routing_ops *msi_routing_ops = &irq__default_routing_ops;
+
 struct kvm_irq_routing *irq_routing = NULL;
 
 int irq__alloc_line(void)
@@ -66,9 +69,42 @@ static bool check_for_irq_routing(struct kvm *kvm)
 	return has_irq_routing > 0;
 }
 
+static int irq__update_msix_routes(struct kvm *kvm,
+				   struct kvm_irq_routing_entry *entry)
+{
+	return ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
+}
+
+static bool irq__default_can_signal_msi(struct kvm *kvm)
+{
+	return kvm__supports_extension(kvm, KVM_CAP_SIGNAL_MSI);
+}
+
+static int irq__default_signal_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+	return ioctl(kvm->vm_fd, KVM_SIGNAL_MSI, msi);
+}
+
+struct msi_routing_ops irq__default_routing_ops = {
+	.update_route	= irq__update_msix_routes,
+	.signal_msi	= irq__default_signal_msi,
+	.can_signal_msi	= irq__default_can_signal_msi,
+};
+
+bool irq__can_signal_msi(struct kvm *kvm)
+{
+	return msi_routing_ops->can_signal_msi(kvm);
+}
+
+int irq__signal_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+	return msi_routing_ops->signal_msi(kvm, msi);
+}
+
 int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg, u32 device_id)
 {
 	int r;
+	struct kvm_irq_routing_entry *entry;
 
 	if (!check_for_irq_routing(kvm))
 		return -ENXIO;
@@ -77,22 +113,23 @@ int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg, u32 device_id)
 	if (r)
 		return r;
 
-	irq_routing->entries[irq_routing->nr] =
-		(struct kvm_irq_routing_entry) {
-			.gsi = next_gsi,
-			.type = KVM_IRQ_ROUTING_MSI,
-			.u.msi.address_hi = msg->address_hi,
-			.u.msi.address_lo = msg->address_lo,
-			.u.msi.data = msg->data,
-		};
+	entry = &irq_routing->entries[irq_routing->nr];
+	*entry = (struct kvm_irq_routing_entry) {
+		.gsi = next_gsi,
+		.type = KVM_IRQ_ROUTING_MSI,
+		.u.msi.address_hi = msg->address_hi,
+		.u.msi.address_lo = msg->address_lo,
+		.u.msi.data = msg->data,
+	};
 
 	if (kvm->msix_needs_devid) {
-		irq_routing->entries[irq_routing->nr].flags = KVM_MSI_VALID_DEVID;
-		irq_routing->entries[irq_routing->nr].u.msi.devid = device_id;
+		entry->flags = KVM_MSI_VALID_DEVID;
+		entry->u.msi.devid = device_id;
 	}
+
 	irq_routing->nr++;
 
-	r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
+	r = msi_routing_ops->update_route(kvm, entry);
 	if (r)
 		return r;
 
@@ -129,7 +166,7 @@ void irq__update_msix_route(struct kvm *kvm, u32 gsi, struct msi_msg *msg)
 	if (!changed)
 		return;
 
-	if (ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing) == -1)
+	if (msi_routing_ops->update_route(kvm, &irq_routing->entries[i]))
 		die_perror("KVM_SET_GSI_ROUTING");
 }
 
@@ -143,6 +180,10 @@ int irq__common_add_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd,
 		.resamplefd	= resample_fd,
 	};
 
+	/* If we emulate MSI routing, translate the MSI to the corresponding IRQ */
+	if (msi_routing_ops->translate_gsi)
+		irqfd.gsi = msi_routing_ops->translate_gsi(kvm, gsi);
+
 	return ioctl(kvm->vm_fd, KVM_IRQFD, &irqfd);
 }
 
@@ -154,6 +195,9 @@ void irq__common_del_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd)
 		.flags		= KVM_IRQFD_FLAG_DEASSIGN,
 	};
 
+	if (msi_routing_ops->translate_gsi)
+		irqfd.gsi = msi_routing_ops->translate_gsi(kvm, gsi);
+
 	ioctl(kvm->vm_fd, KVM_IRQFD, &irqfd);
 }
 
diff --git a/virtio/pci.c b/virtio/pci.c
index 46473b00029b..4ce111108100 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -350,7 +350,7 @@ static void virtio_pci__signal_msi(struct kvm *kvm, struct virtio_pci *vpci,
 		msi.devid = vpci->dev_hdr.dev_num << 3;
 	}
 
-	ioctl(kvm->vm_fd, KVM_SIGNAL_MSI, &msi);
+	irq__signal_msi(kvm, &msi);
 }
 
 int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
@@ -488,7 +488,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | PCI_IO_SIZE);
 	vpci->config_vector = 0;
 
-	if (kvm__supports_extension(kvm, KVM_CAP_SIGNAL_MSI))
+	if (irq__can_signal_msi(kvm))
 		vpci->features |= VIRTIO_PCI_F_SIGNAL_MSI;
 
 	r = device__register(&vpci->dev_hdr);
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH kvmtool 0/2] Add GICv2m support
  2017-11-03 11:38 [PATCH kvmtool 0/2] Add GICv2m support Jean-Philippe Brucker
  2017-11-03 11:38 ` [PATCH kvmtool 1/2] Prevent segfault when kvm_pause is called too early Jean-Philippe Brucker
  2017-11-03 11:38 ` [PATCH kvmtool 2/2] Add GICv2m support Jean-Philippe Brucker
@ 2017-11-03 13:46 ` Marc Zyngier
  2 siblings, 0 replies; 6+ messages in thread
From: Marc Zyngier @ 2017-11-03 13:46 UTC (permalink / raw)
  To: Jean-Philippe Brucker, kvm
  Cc: kvmarm, andre.przywara, punit.agrawal, will.deacon

On 03/11/17 11:38, Jean-Philippe Brucker wrote:
> GICv2m is an extension to GICv2 defined in the Server Base System
> Architecture (SBSA) [1], allowing pre-GICv3 platforms to support MSIs.
> 
> Presenting GICv2m frames to the guest can be useful for testing PCI
> pass-through on platforms that have a GICv2m, for example AMD Seattle.
> Otherwise they are forced to use legacy INTx.
> 
> This series adds a GICv2m frame to kvmtool, which is basically an MMIO
> register telling the guest which SPIs (Shared Peripheral Interrupts) are
> reserved for MSIs. When configuring MSI vectors, the guest writes the
> desired SPI number into the MSI data field. Then in kvmtool we create
> the IRQFD routes such that they inject the given SPI.
> 
> [1] https://developer.arm.com/products/architecture/a-profile/docs/den0029/latest/server-base-system-architecture
> 
> Jean-Philippe Brucker (2):
>   Prevent segfault when kvm_pause is called too early
>   Add GICv2m support
> 
>  Makefile                                 |   2 +-
>  arm/aarch32/include/asm/kvm.h            |   2 +
>  arm/aarch64/include/asm/kvm.h            |   2 +
>  arm/gic.c                                |  13 +++
>  arm/gicv2m.c                             | 153 +++++++++++++++++++++++++++++++
>  arm/include/arm-common/gic.h             |   3 +
>  arm/include/arm-common/kvm-config-arch.h |   2 +-
>  include/kvm/irq.h                        |  11 +++
>  irq.c                                    |  68 +++++++++++---
>  kvm.c                                    |   2 +-
>  virtio/pci.c                             |   4 +-
>  11 files changed, 245 insertions(+), 17 deletions(-)
>  create mode 100644 arm/gicv2m.c
> 

Thanks for putting this together. For both patches:

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH kvmtool 2/2] Add GICv2m support
  2017-11-03 11:38 ` [PATCH kvmtool 2/2] Add GICv2m support Jean-Philippe Brucker
@ 2017-11-03 14:27   ` Andre Przywara
  2017-11-03 15:03     ` Jean-Philippe Brucker
  0 siblings, 1 reply; 6+ messages in thread
From: Andre Przywara @ 2017-11-03 14:27 UTC (permalink / raw)
  To: Jean-Philippe Brucker, kvm
  Cc: marc.zyngier, punit.agrawal, will.deacon, kvmarm

Hi,

good stuff, thanks for doing this!

On 03/11/17 11:38, Jean-Philippe Brucker wrote:
> GICv2m is a small extension to the GICv2 architecture, specified in the
> Server Base System Architecture (SBSA). It adds a set of register to
> converts MSIs into SPIs, effectively enabling MSI support for pre-GICv3
> platforms.

I was wondering if it would be worth to split this up, and introduce the
msi_routing_ops in a separate patch first, possibly even the changes to
pci.c.

> Implement a GICv2m emulation entirely in userspace. Add a thin translation
> layer in irq.c to catch the MSI->SPI routing setup of the guest, and then
> transform irqfd injection of MSI into the associated SPI. There shouldn't
> be any significant runtime overhead compared to gicv3-its.

As others have pointed out already, these patches seem to rely on some
other patches.
However by ignoring the two hunks in non-yet-existing functions in irq.c
and adding #include <stdbool.h> to include/kvm/irq.h I could compile and
run it on a Juno.

> The device can be enabled by passing "--irqchip gicv2m" to kvmtool.

Might be worth to mention that for actually using MSIs in general one
needs "--force-pci" on the command line as well.

Given the compile fixes mentioned above, this boots with MSIs on my
Juno. Testing 32 bit in a minute.

Cheers,
Andre.

> 
> Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
> ---
>  Makefile                                 |   2 +-
>  arm/aarch32/include/asm/kvm.h            |   2 +
>  arm/aarch64/include/asm/kvm.h            |   2 +
>  arm/gic.c                                |  13 +++
>  arm/gicv2m.c                             | 153 +++++++++++++++++++++++++++++++
>  arm/include/arm-common/gic.h             |   3 +
>  arm/include/arm-common/kvm-config-arch.h |   2 +-
>  include/kvm/irq.h                        |  11 +++
>  irq.c                                    |  68 +++++++++++---
>  virtio/pci.c                             |   4 +-
>  10 files changed, 244 insertions(+), 16 deletions(-)
>  create mode 100644 arm/gicv2m.c
> 
> diff --git a/Makefile b/Makefile
> index 6414b5853947..93dc0673571d 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -153,7 +153,7 @@ ifeq ($(ARCH), powerpc)
>  endif
>  
>  # ARM
> -OBJS_ARM_COMMON		:= arm/fdt.o arm/gic.o arm/ioport.o \
> +OBJS_ARM_COMMON		:= arm/fdt.o arm/gic.o arm/gicv2m.o arm/ioport.o \
>  			   arm/kvm.o arm/kvm-cpu.o arm/pci.o arm/timer.o \
>  			   arm/pmu.o
>  HDRS_ARM_COMMON		:= arm/include
> diff --git a/arm/aarch32/include/asm/kvm.h b/arm/aarch32/include/asm/kvm.h
> index 6ebd3e6a1fd1..022066730dc7 100644
> --- a/arm/aarch32/include/asm/kvm.h
> +++ b/arm/aarch32/include/asm/kvm.h
> @@ -84,6 +84,8 @@ struct kvm_regs {
>  #define KVM_VGIC_V2_DIST_SIZE		0x1000
>  #define KVM_VGIC_V2_CPU_SIZE		0x2000
>  
> +#define KVM_VGIC_V2M_SIZE		0x1000
> +
>  /* Supported VGICv3 address types  */
>  #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
>  #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
> diff --git a/arm/aarch64/include/asm/kvm.h b/arm/aarch64/include/asm/kvm.h
> index c2860358ae3e..7d14507bd329 100644
> --- a/arm/aarch64/include/asm/kvm.h
> +++ b/arm/aarch64/include/asm/kvm.h
> @@ -84,6 +84,8 @@ struct kvm_regs {
>  #define KVM_VGIC_V2_DIST_SIZE		0x1000
>  #define KVM_VGIC_V2_CPU_SIZE		0x2000
>  
> +#define KVM_VGIC_V2M_SIZE		0x1000
> +
>  /* Supported VGICv3 address types  */
>  #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
>  #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
> diff --git a/arm/gic.c b/arm/gic.c
> index e53f932e28c3..46cfa245e590 100644
> --- a/arm/gic.c
> +++ b/arm/gic.c
> @@ -32,6 +32,8 @@ int irqchip_parser(const struct option *opt, const char *arg, int unset)
>  
>  	if (!strcmp(arg, "gicv2")) {
>  		*type = IRQCHIP_GICV2;
> +	} else if (!strcmp(arg, "gicv2m")) {
> +		*type = IRQCHIP_GICV2M;
>  	} else if (!strcmp(arg, "gicv3")) {
>  		*type = IRQCHIP_GICV3;
>  	} else if (!strcmp(arg, "gicv3-its")) {
> @@ -134,6 +136,8 @@ static int gic__create_msi_frame(struct kvm *kvm, enum irqchip_type type,
>  				 u64 msi_frame_addr)
>  {
>  	switch (type) {
> +	case IRQCHIP_GICV2M:
> +		return gic__create_gicv2m_frame(kvm, msi_frame_addr);
>  	case IRQCHIP_GICV3_ITS:
>  		return gic__create_its_frame(kvm, msi_frame_addr);
>  	default:	/* No MSI frame needed */
> @@ -165,6 +169,7 @@ static int gic__create_device(struct kvm *kvm, enum irqchip_type type)
>  	};
>  
>  	switch (type) {
> +	case IRQCHIP_GICV2M:
>  	case IRQCHIP_GICV2:
>  		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V2;
>  		dist_attr.attr  = KVM_VGIC_V2_ADDR_TYPE_DIST;
> @@ -183,6 +188,7 @@ static int gic__create_device(struct kvm *kvm, enum irqchip_type type)
>  	gic_fd = gic_device.fd;
>  
>  	switch (type) {
> +	case IRQCHIP_GICV2M:
>  	case IRQCHIP_GICV2:
>  		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &cpu_if_attr);
>  		break;
> @@ -243,6 +249,10 @@ int gic__create(struct kvm *kvm, enum irqchip_type type)
>  	int err;
>  
>  	switch (type) {
> +	case IRQCHIP_GICV2M:
> +		gic_msi_size = KVM_VGIC_V2M_SIZE;
> +		gic_msi_base = ARM_GIC_DIST_BASE - gic_msi_size;
> +		break;
>  	case IRQCHIP_GICV2:
>  		break;
>  	case IRQCHIP_GICV3_ITS:
> @@ -325,6 +335,9 @@ void gic__generate_fdt_nodes(void *fdt, enum irqchip_type type)
>  	};
>  
>  	switch (type) {
> +	case IRQCHIP_GICV2M:
> +		msi_compatible = "arm,gic-v2m-frame";
> +		/* fall-through */
>  	case IRQCHIP_GICV2:
>  		compatible = "arm,cortex-a15-gic";
>  		reg_prop[2] = cpu_to_fdt64(ARM_GIC_CPUI_BASE);
> diff --git a/arm/gicv2m.c b/arm/gicv2m.c
> new file mode 100644
> index 000000000000..d7e6398a13a8
> --- /dev/null
> +++ b/arm/gicv2m.c
> @@ -0,0 +1,153 @@
> +#include <errno.h>
> +#include <stdlib.h>
> +
> +#include "kvm/irq.h"
> +#include "kvm/kvm.h"
> +#include "kvm/util.h"
> +
> +#include "arm-common/gic.h"
> +
> +#define GICV2M_MSI_TYPER	0x008
> +#define GICV2M_MSI_SETSPI	0x040
> +#define GICV2M_MSI_IIDR		0xfcc
> +
> +#define GICV2M_SPI_MASK		0x3ff
> +#define GICV2M_MSI_TYPER_VAL(start, nr)	\
> +	(((start) & GICV2M_SPI_MASK) << 16 | ((nr) & GICV2M_SPI_MASK))
> +
> +struct gicv2m_chip {
> +	int	first_spi;
> +	int	num_spis;
> +	int	*spis;
> +	u64	base;
> +	u64	size;
> +};
> +
> +static struct gicv2m_chip v2m;
> +
> +/*
> + * MSI routing is setup lazily, when the guest writes the MSI tables. The guest
> + * writes which SPI is associated to an MSI vector into the message data field.
> + * The IRQ code notifies us of any change to MSI routing via this callback.
> + * Store the MSI->SPI translation for later.
> + *
> + * Data is the GIC interrupt ID, that includes SGIs and PPIs. SGIs at 0-15, PPIs
> + * are 16-31 and SPIs are 32-1019. What we're saving for later is the MSI's GSI
> + * number, a logical ID used by KVM for routing. The GSI of an SPI is implicitly
> + * defined by KVM to be its pin number (SPI index), and the GSI of an MSI is
> + * allocated by kvmtool.
> + */
> +static int gicv2m_update_routing(struct kvm *kvm,
> +				 struct kvm_irq_routing_entry *entry)
> +{
> +	int spi;
> +
> +	if (entry->type != KVM_IRQ_ROUTING_MSI)
> +		return -EINVAL;
> +
> +	if (!entry->u.msi.address_hi && !entry->u.msi.address_lo)
> +		return 0;
> +
> +	spi = entry->u.msi.data & GICV2M_SPI_MASK;
> +	if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) {
> +		pr_err("invalid SPI number %d", spi);
> +		return -EINVAL;
> +	}
> +
> +	v2m.spis[spi - v2m.first_spi] = entry->gsi;
> +
> +	return 0;
> +}
> +
> +/*
> + * Find SPI bound to the given MSI and return the associated GSI.
> + */
> +static int gicv2m_translate_gsi(struct kvm *kvm, u32 gsi)
> +{
> +	int i;
> +
> +	for (i = 0; i < v2m.num_spis; i++) {
> +		if (v2m.spis[i] == (int)gsi)
> +			return i + v2m.first_spi - KVM_IRQ_OFFSET;
> +	}
> +
> +	/* Not an MSI */
> +	return gsi;
> +}
> +
> +static bool gicv2m_can_signal_msi(struct kvm *kvm)
> +{
> +	return true;
> +}
> +
> +/*
> + * Instead of setting up MSI routes, virtual devices can also trigger them
> + * manually (like a direct write to MSI_SETSPI). In this case, trigger the SPI
> + * directly.
> + */
> +static int gicv2m_signal_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	int spi = msi->data & GICV2M_SPI_MASK;
> +
> +	if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) {
> +		pr_err("invalid SPI number %d", spi);
> +		return -EINVAL;
> +	}
> +
> +	kvm__irq_trigger(kvm, spi);
> +	return 0;
> +}
> +
> +static struct msi_routing_ops gicv2m_routing = {
> +	.update_route	= gicv2m_update_routing,
> +	.translate_gsi	= gicv2m_translate_gsi,
> +	.can_signal_msi	= gicv2m_can_signal_msi,
> +	.signal_msi	= gicv2m_signal_msi,
> +};
> +
> +static void gicv2m_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> +				  u32 len, u8 is_write, void *ptr)
> +{
> +	if (is_write)
> +		return;
> +
> +	addr -= v2m.base;
> +
> +	switch (addr) {
> +		case GICV2M_MSI_TYPER:
> +			*(u32 *)data = GICV2M_MSI_TYPER_VAL(v2m.first_spi,
> +							    v2m.num_spis);
> +			break;
> +		case GICV2M_MSI_IIDR:
> +			*(u32 *)data = 0x0;
> +			break;
> +	}
> +}
> +
> +int gic__create_gicv2m_frame(struct kvm *kvm, u64 base)
> +{
> +	int i;
> +	int irq = irq__alloc_line();
> +
> +	v2m = (struct gicv2m_chip) {
> +		.first_spi	= irq,	/* Includes GIC_SPI_IRQ_BASE */
> +		.num_spis	= 64,	/* arbitrary */
> +		.base		= base,
> +		.size		= KVM_VGIC_V2M_SIZE,
> +	};
> +
> +	v2m.spis = calloc(v2m.num_spis, sizeof(int));
> +	if (!v2m.spis)
> +		return -ENOMEM;
> +
> +	v2m.spis[0] = -1;
> +	for (i = 1; i < v2m.num_spis; i++) {
> +		irq__alloc_line();
> +		v2m.spis[i] = -1;
> +	}
> +
> +	msi_routing_ops = &gicv2m_routing;
> +
> +	return kvm__register_mmio(kvm, base, KVM_VGIC_V2M_SIZE, false,
> +				  gicv2m_mmio_callback, kvm);
> +}
> diff --git a/arm/include/arm-common/gic.h b/arm/include/arm-common/gic.h
> index 0c279aca8a5e..560fea2a2c5a 100644
> --- a/arm/include/arm-common/gic.h
> +++ b/arm/include/arm-common/gic.h
> @@ -23,6 +23,7 @@
>  
>  enum irqchip_type {
>  	IRQCHIP_GICV2,
> +	IRQCHIP_GICV2M,
>  	IRQCHIP_GICV3,
>  	IRQCHIP_GICV3_ITS,
>  };
> @@ -39,4 +40,6 @@ void gic__del_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd);
>  #define irq__add_irqfd gic__add_irqfd
>  #define irq__del_irqfd gic__del_irqfd
>  
> +int gic__create_gicv2m_frame(struct kvm *kvm, u64 msi_frame_addr);
> +
>  #endif /* ARM_COMMON__GIC_H */
> diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
> index f18b2c88fa79..6a196f1852de 100644
> --- a/arm/include/arm-common/kvm-config-arch.h
> +++ b/arm/include/arm-common/kvm-config-arch.h
> @@ -28,7 +28,7 @@ int irqchip_parser(const struct option *opt, const char *arg, int unset);
>  		    "Force virtio devices to use PCI as their default "		\
>  		    "transport"),						\
>          OPT_CALLBACK('\0', "irqchip", &(cfg)->irqchip,				\
> -		     "[gicv2|gicv3|gicv3-its]",					\
> +		     "[gicv2|gicv2m|gicv3|gicv3-its]",				\
>  		     "Type of interrupt controller to emulate in the guest",	\
>  		     irqchip_parser, NULL),
>  
> diff --git a/include/kvm/irq.h b/include/kvm/irq.h
> index b24385b13f66..530ce3f9133d 100644
> --- a/include/kvm/irq.h
> +++ b/include/kvm/irq.h
> @@ -11,6 +11,14 @@
>  
>  struct kvm;
>  
> +struct msi_routing_ops {
> +	int (*update_route)(struct kvm *kvm, struct kvm_irq_routing_entry *);
> +	bool (*can_signal_msi)(struct kvm *kvm);
> +	int (*signal_msi)(struct kvm *kvm, struct kvm_msi *msi);
> +	int (*translate_gsi)(struct kvm *kvm, u32 gsi);
> +};
> +
> +extern struct msi_routing_ops *msi_routing_ops;
>  extern struct kvm_irq_routing *irq_routing;
>  extern int next_gsi;
>  
> @@ -24,6 +32,9 @@ int irq__allocate_routing_entry(void);
>  int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg, u32 device_id);
>  void irq__update_msix_route(struct kvm *kvm, u32 gsi, struct msi_msg *msg);
>  
> +bool irq__can_signal_msi(struct kvm *kvm);
> +int irq__signal_msi(struct kvm *kvm, struct kvm_msi *msi);
> +
>  /*
>   * The function takes two eventfd arguments, trigger_fd and resample_fd. If
>   * resample_fd is <= 0, resampling is disabled and the IRQ is edge-triggered
> diff --git a/irq.c b/irq.c
> index 25fa572761fa..cdcf99233baa 100644
> --- a/irq.c
> +++ b/irq.c
> @@ -13,6 +13,9 @@ static int allocated_gsis = 0;
>  
>  int next_gsi;
>  
> +struct msi_routing_ops irq__default_routing_ops;
> +struct msi_routing_ops *msi_routing_ops = &irq__default_routing_ops;
> +
>  struct kvm_irq_routing *irq_routing = NULL;
>  
>  int irq__alloc_line(void)
> @@ -66,9 +69,42 @@ static bool check_for_irq_routing(struct kvm *kvm)
>  	return has_irq_routing > 0;
>  }
>  
> +static int irq__update_msix_routes(struct kvm *kvm,
> +				   struct kvm_irq_routing_entry *entry)
> +{
> +	return ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
> +}
> +
> +static bool irq__default_can_signal_msi(struct kvm *kvm)
> +{
> +	return kvm__supports_extension(kvm, KVM_CAP_SIGNAL_MSI);
> +}
> +
> +static int irq__default_signal_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	return ioctl(kvm->vm_fd, KVM_SIGNAL_MSI, msi);
> +}
> +
> +struct msi_routing_ops irq__default_routing_ops = {
> +	.update_route	= irq__update_msix_routes,
> +	.signal_msi	= irq__default_signal_msi,
> +	.can_signal_msi	= irq__default_can_signal_msi,
> +};
> +
> +bool irq__can_signal_msi(struct kvm *kvm)
> +{
> +	return msi_routing_ops->can_signal_msi(kvm);
> +}
> +
> +int irq__signal_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	return msi_routing_ops->signal_msi(kvm, msi);
> +}
> +
>  int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg, u32 device_id)
>  {
>  	int r;
> +	struct kvm_irq_routing_entry *entry;
>  
>  	if (!check_for_irq_routing(kvm))
>  		return -ENXIO;
> @@ -77,22 +113,23 @@ int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg, u32 device_id)
>  	if (r)
>  		return r;
>  
> -	irq_routing->entries[irq_routing->nr] =
> -		(struct kvm_irq_routing_entry) {
> -			.gsi = next_gsi,
> -			.type = KVM_IRQ_ROUTING_MSI,
> -			.u.msi.address_hi = msg->address_hi,
> -			.u.msi.address_lo = msg->address_lo,
> -			.u.msi.data = msg->data,
> -		};
> +	entry = &irq_routing->entries[irq_routing->nr];
> +	*entry = (struct kvm_irq_routing_entry) {
> +		.gsi = next_gsi,
> +		.type = KVM_IRQ_ROUTING_MSI,
> +		.u.msi.address_hi = msg->address_hi,
> +		.u.msi.address_lo = msg->address_lo,
> +		.u.msi.data = msg->data,
> +	};
>  
>  	if (kvm->msix_needs_devid) {
> -		irq_routing->entries[irq_routing->nr].flags = KVM_MSI_VALID_DEVID;
> -		irq_routing->entries[irq_routing->nr].u.msi.devid = device_id;
> +		entry->flags = KVM_MSI_VALID_DEVID;
> +		entry->u.msi.devid = device_id;
>  	}
> +
>  	irq_routing->nr++;
>  
> -	r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
> +	r = msi_routing_ops->update_route(kvm, entry);
>  	if (r)
>  		return r;
>  
> @@ -129,7 +166,7 @@ void irq__update_msix_route(struct kvm *kvm, u32 gsi, struct msi_msg *msg)
>  	if (!changed)
>  		return;
>  
> -	if (ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing) == -1)
> +	if (msi_routing_ops->update_route(kvm, &irq_routing->entries[i]))
>  		die_perror("KVM_SET_GSI_ROUTING");
>  }
>  
> @@ -143,6 +180,10 @@ int irq__common_add_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd,
>  		.resamplefd	= resample_fd,
>  	};
>  
> +	/* If we emulate MSI routing, translate the MSI to the corresponding IRQ */
> +	if (msi_routing_ops->translate_gsi)
> +		irqfd.gsi = msi_routing_ops->translate_gsi(kvm, gsi);
> +
>  	return ioctl(kvm->vm_fd, KVM_IRQFD, &irqfd);
>  }
>  
> @@ -154,6 +195,9 @@ void irq__common_del_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd)
>  		.flags		= KVM_IRQFD_FLAG_DEASSIGN,
>  	};
>  
> +	if (msi_routing_ops->translate_gsi)
> +		irqfd.gsi = msi_routing_ops->translate_gsi(kvm, gsi);
> +
>  	ioctl(kvm->vm_fd, KVM_IRQFD, &irqfd);
>  }
>  
> diff --git a/virtio/pci.c b/virtio/pci.c
> index 46473b00029b..4ce111108100 100644
> --- a/virtio/pci.c
> +++ b/virtio/pci.c
> @@ -350,7 +350,7 @@ static void virtio_pci__signal_msi(struct kvm *kvm, struct virtio_pci *vpci,
>  		msi.devid = vpci->dev_hdr.dev_num << 3;
>  	}
>  
> -	ioctl(kvm->vm_fd, KVM_SIGNAL_MSI, &msi);
> +	irq__signal_msi(kvm, &msi);
>  }
>  
>  int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
> @@ -488,7 +488,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
>  	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | PCI_IO_SIZE);
>  	vpci->config_vector = 0;
>  
> -	if (kvm__supports_extension(kvm, KVM_CAP_SIGNAL_MSI))
> +	if (irq__can_signal_msi(kvm))
>  		vpci->features |= VIRTIO_PCI_F_SIGNAL_MSI;
>  
>  	r = device__register(&vpci->dev_hdr);
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH kvmtool 2/2] Add GICv2m support
  2017-11-03 14:27   ` Andre Przywara
@ 2017-11-03 15:03     ` Jean-Philippe Brucker
  0 siblings, 0 replies; 6+ messages in thread
From: Jean-Philippe Brucker @ 2017-11-03 15:03 UTC (permalink / raw)
  To: Andre Przywara, kvm; +Cc: kvmarm, Marc Zyngier, Punit Agrawal, Will Deacon

On 03/11/17 14:27, Andre Przywara wrote:
> Hi,
> 
> good stuff, thanks for doing this!
> 
> On 03/11/17 11:38, Jean-Philippe Brucker wrote:
>> GICv2m is a small extension to the GICv2 architecture, specified in the
>> Server Base System Architecture (SBSA). It adds a set of register to
>> converts MSIs into SPIs, effectively enabling MSI support for pre-GICv3
>> platforms.
> 
> I was wondering if it would be worth to split this up, and introduce the
> msi_routing_ops in a separate patch first, possibly even the changes to
> pci.c.
> 
>> Implement a GICv2m emulation entirely in userspace. Add a thin translation
>> layer in irq.c to catch the MSI->SPI routing setup of the guest, and then
>> transform irqfd injection of MSI into the associated SPI. There shouldn't
>> be any significant runtime overhead compared to gicv3-its.
> 
> As others have pointed out already, these patches seem to rely on some
> other patches.
> However by ignoring the two hunks in non-yet-existing functions in irq.c

Right, this was based on the VFIO series and a bit rushed, sorry about
that. A little more work is needed to support irqfd ("irq: add irqfd
helpers") and the combination GICv2m+force-pci+vhost, but it should be
ready soon enough.

Thanks,
Jean

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-11-03 15:01 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-03 11:38 [PATCH kvmtool 0/2] Add GICv2m support Jean-Philippe Brucker
2017-11-03 11:38 ` [PATCH kvmtool 1/2] Prevent segfault when kvm_pause is called too early Jean-Philippe Brucker
2017-11-03 11:38 ` [PATCH kvmtool 2/2] Add GICv2m support Jean-Philippe Brucker
2017-11-03 14:27   ` Andre Przywara
2017-11-03 15:03     ` Jean-Philippe Brucker
2017-11-03 13:46 ` [PATCH kvmtool 0/2] " Marc Zyngier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.