* [Qemu-devel] [RFC v2 1/4] Add EXEC_FLAG to VFIO DMA mappings
2014-05-11 17:13 [Qemu-devel] [RFC v2 0/4] AMBA platform device passthrough Alvise Rigo
@ 2014-05-11 17:13 ` Alvise Rigo
2014-05-23 8:40 ` Eric Auger
2014-05-11 17:13 ` [Qemu-devel] [RFC v2 2/4] Add AMBA devices support to VFIO Alvise Rigo
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Alvise Rigo @ 2014-05-11 17:13 UTC (permalink / raw)
To: qemu-devel, a.motakis, eric.auger, kim.phillips
Cc: Andrew Jones, Alexey Kardashevskiy, Michael Tokarev, Alvise Rigo,
Alex Williamson, Paolo Bonzini, tech
The flag is mandatory for the ARM SMMU so we always add it if the MMIO
handles it.
Signed-off-by: Alvise Rigo <a.rigo@virtualopensystems.com>
---
hw/vfio/common.c | 9 +++++++++
hw/vfio/vfio-common.h | 1 +
| 2 ++
3 files changed, 12 insertions(+)
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 9d1f723..a805c5d 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -107,6 +107,11 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova,
map.flags |= VFIO_DMA_MAP_FLAG_WRITE;
}
+ /* add exec flag */
+ if (container->iommu_data.has_exec_cap) {
+ map.flags |= VFIO_DMA_MAP_FLAG_EXEC;
+ }
+
/*
* Try the mapping, if it fails with EBUSY, unmap the region and try
* again. This shouldn't be necessary, but we sometimes see it in
@@ -352,6 +357,10 @@ static int vfio_connect_container(VFIOGroup *group)
return -errno;
}
+ if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_IOMMU_PROT_EXEC)) {
+ container->iommu_data.has_exec_cap = true;
+ }
+
container->iommu_data.type1.listener = vfio_memory_listener;
container->iommu_data.release = vfio_listener_release;
diff --git a/hw/vfio/vfio-common.h b/hw/vfio/vfio-common.h
index 21148ef..1abbd1a 100644
--- a/hw/vfio/vfio-common.h
+++ b/hw/vfio/vfio-common.h
@@ -35,6 +35,7 @@ typedef struct VFIOContainer {
union {
VFIOType1 type1;
};
+ bool has_exec_cap; /* support of exec capability by the IOMMU */
void (*release)(struct VFIOContainer *);
} iommu_data;
QLIST_HEAD(, VFIOGroup) group_list;
--git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index 17c58e0..95a02c5 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -24,6 +24,7 @@
#define VFIO_TYPE1_IOMMU 1
#define VFIO_SPAPR_TCE_IOMMU 2
+#define VFIO_IOMMU_PROT_EXEC 5
/*
* The IOCTL interface is designed for extensibility by embedding the
* structure length (argsz) and flags into structures passed between
@@ -392,6 +393,7 @@ struct vfio_iommu_type1_dma_map {
__u32 flags;
#define VFIO_DMA_MAP_FLAG_READ (1 << 0) /* readable from device */
#define VFIO_DMA_MAP_FLAG_WRITE (1 << 1) /* writable from device */
+#define VFIO_DMA_MAP_FLAG_EXEC (1 << 2) /* executable from device */
__u64 vaddr; /* Process virtual address */
__u64 iova; /* IO virtual address */
__u64 size; /* Size of mapping (bytes) */
--
1.9.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [RFC v2 2/4] Add AMBA devices support to VFIO
2014-05-11 17:13 [Qemu-devel] [RFC v2 0/4] AMBA platform device passthrough Alvise Rigo
2014-05-11 17:13 ` [Qemu-devel] [RFC v2 1/4] Add EXEC_FLAG to VFIO DMA mappings Alvise Rigo
@ 2014-05-11 17:13 ` Alvise Rigo
2014-05-11 17:13 ` [Qemu-devel] [RFC v2 3/4] MemoryRegion with EOI callbacks for VFIO Platform devices Alvise Rigo
2014-05-11 17:13 ` [Qemu-devel] [RFC v2 4/4] Always use eventfd as notifying mechanism Alvise Rigo
3 siblings, 0 replies; 6+ messages in thread
From: Alvise Rigo @ 2014-05-11 17:13 UTC (permalink / raw)
To: qemu-devel, a.motakis, eric.auger, kim.phillips
Cc: Peter Maydell, tech, Alvise Rigo
The impossibility to add more then one compatibility property to the
device tree node was not permitting to bind AMBA devices.
Now we can add an arbitrary number of compatibility property values divided by
the character ";".
If the compatibility string contains the substring "arm,primecell", a
clock property will be added to the device tree node in order to allow the AMBA
bus code to probe the device.
Signed-off-by: Alvise Rigo <a.rigo@virtualopensystems.com>
---
hw/arm/virt.c | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 1fb66ef..dadf5f0 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -344,6 +344,8 @@ static int vfio_init_func(QemuOpts *opts, void *opaque)
size_t size;
int i;
uint32_t *irq_attr;
+ bool is_amba = false;
+ int compat_str_len;
if (!driver) {
qerror_report(QERR_MISSING_PARAMETER, "driver");
@@ -369,12 +371,31 @@ static int vfio_init_func(QemuOpts *opts, void *opaque)
/*
* process compatibility property string passed by end-user
- * replaces / by ,
- * currently a single property compatibility value is supported!
+ * replaces / by , and ; by NUL character
*/
corrected_compat = g_strdup(*pcompat);
- char *slash = strchr(corrected_compat, '/');
- *slash = ',';
+ /*
+ * the total length of the string has to include also the last
+ * NUL char.
+ */
+ compat_str_len = strlen(corrected_compat) + 1;
+
+ char *str_ptr = corrected_compat;
+ while ((str_ptr = strchr(str_ptr, '/')) != NULL) {
+ *str_ptr = ',';
+ }
+
+ /* check if is an AMBA device */
+ str_ptr = corrected_compat;
+ if (strstr(str_ptr, "arm,primecell") != NULL) {
+ is_amba = true;
+ }
+
+ /* substitute ";" with the NUL char */
+ str_ptr = corrected_compat;
+ while ((str_ptr = strchr(str_ptr, ';')) != NULL) {
+ *str_ptr = '\0';
+ }
sysbus_mmio_map(s, 0, vbi->avail_vfio_base);
@@ -383,11 +404,19 @@ static int vfio_init_func(QemuOpts *opts, void *opaque)
qemu_fdt_add_subnode(vbi->fdt, nodename);
qemu_fdt_setprop(vbi->fdt, nodename, "compatible",
- corrected_compat, strlen(corrected_compat));
+ corrected_compat, compat_str_len);
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename,
"reg", 2, vbi->avail_vfio_base, 2, size);
+ if (is_amba) {
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks",
+ vbi->clock_phandle);
+ char clock_names[] = "apb_pclk";
+ qemu_fdt_setprop(vbi->fdt, nodename, "clock-names", clock_names,
+ sizeof(clock_names));
+ }
+
irq_attr = g_malloc0(num_irqs*3*sizeof(uint32_t));
for (i = 0; i < num_irqs; i++) {
sysbus_connect_irq(s, i, vbi->pic[irq_start+i]);
--
1.9.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [RFC v2 3/4] MemoryRegion with EOI callbacks for VFIO Platform devices
2014-05-11 17:13 [Qemu-devel] [RFC v2 0/4] AMBA platform device passthrough Alvise Rigo
2014-05-11 17:13 ` [Qemu-devel] [RFC v2 1/4] Add EXEC_FLAG to VFIO DMA mappings Alvise Rigo
2014-05-11 17:13 ` [Qemu-devel] [RFC v2 2/4] Add AMBA devices support to VFIO Alvise Rigo
@ 2014-05-11 17:13 ` Alvise Rigo
2014-05-11 17:13 ` [Qemu-devel] [RFC v2 4/4] Always use eventfd as notifying mechanism Alvise Rigo
3 siblings, 0 replies; 6+ messages in thread
From: Alvise Rigo @ 2014-05-11 17:13 UTC (permalink / raw)
To: qemu-devel, a.motakis, eric.auger, kim.phillips
Cc: Alex Williamson, tech, Alvise Rigo
The user can specify the location of the memory region (register) used
by the guest driver to clear the pending interrupt; if enabled, this
mechanism will overlap to the default one (timer based).
The region is provided as command line property "intclr-region" of the
vfio-platform device. The property is a string "region_index;offset;size" where:
region_index: is the index of the memory region where the register
lives,
offset: offset of the register in the region,
size: size of the register.
example:
-device vfio-platform,...,intclr-region="0;0x2c;4"
Signed-off-by: Alvise Rigo <a.rigo@virtualopensystems.com>
---
hw/vfio/platform.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 89 insertions(+), 2 deletions(-)
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index c4a4286..ec6a29e 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -40,6 +40,7 @@
#include "vfio-common.h"
+/*#define DEBUG_VFIO 1*/
#ifdef DEBUG_VFIO
#define DPRINTF(fmt, ...) \
do { fprintf(stderr, "vfio: %s: " fmt, __func__, ## __VA_ARGS__); } \
@@ -56,6 +57,11 @@
#define TYPE_VFIO_PLATFORM "vfio-platform"
+struct intclr_region {
+ hwaddr offset;
+ hwaddr size;
+};
+
typedef struct VFIORegion {
off_t fd_offset; /* offset of region within device fd */
int fd; /* device fd, allows us to pass VFIORegion as opaque data */
@@ -65,6 +71,7 @@ typedef struct VFIORegion {
size_t size;
uint32_t flags; /* VFIO region flags (rd/wr/mmap) */
uint8_t nr; /* cache the region number for debug */
+ struct intclr_region intclr_reg;
} VFIORegion;
@@ -99,6 +106,8 @@ typedef struct VFIODevice {
QLIST_ENTRY(VFIODevice) next;
struct VFIOGroup *group;
QLIST_HEAD(, VFIOINTp) intp_list;
+ char *intclr_region_str; /* clear interrupt region string */
+ bool has_intclr_region;
} VFIODevice;
@@ -120,6 +129,48 @@ void vfio_get_props(SysBusDevice *s, char **pname,
*psize = vdev->regions[0].size;
}
+static int parse_clrint_string(const char *intclr_str, uint32_t *id_reg,
+ hwaddr *off_reg, uint64_t *size_reg)
+{
+ char *str_ptr = g_strdup(intclr_str);
+ char *idx, *off, *size;
+
+ if (strlen(intclr_str) < 5) {
+ return -1;
+ }
+
+ idx = str_ptr;
+ str_ptr = strchr(str_ptr, ';');
+ if (!str_ptr || idx == str_ptr) {
+ return -1;
+ }
+ *str_ptr = '\0';
+
+ off = ++str_ptr;
+ str_ptr = strchr(str_ptr, ';');
+ if (!str_ptr || off == str_ptr) {
+ return -1;
+ }
+ *str_ptr = '\0';
+
+ size = ++str_ptr;
+ if (!*size) {
+ return -1;
+ }
+
+ *id_reg = strtol(idx, NULL, 10);
+ *off_reg = strtol(off, NULL, 0);
+ *size_reg = strtol(size, NULL, 10);
+
+ if (errno == EINVAL || errno == ERANGE) {
+ return -1;
+ }
+
+ DPRINTF("intclr region - id: %u offset: 0x%"HWADDR_PRIx" size: %"PRIx64"\n",
+ *id_reg, *off_reg, *size_reg);
+ return 0;
+}
+
static void vfio_disable_irqindex(VFIODevice *vdev, int index)
{
struct vfio_irq_set irq_set = {
@@ -397,6 +448,8 @@ static void vfio_region_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
VFIORegion *region = opaque;
+ VFIODevice *vdev = NULL;
+
union {
uint8_t byte;
uint16_t word;
@@ -427,13 +480,22 @@ static void vfio_region_write(void *opaque, hwaddr addr,
DPRINTF("(region %d, addr=0x%"HWADDR_PRIx", data= 0x%"PRIx64", %d)\n",
region->nr, addr, data, size);
- vfio_irq_eoi(container_of(region, VFIODevice, regions[region->nr]));
+ vdev = container_of(region, VFIODevice, regions[region->nr]);
+ struct intclr_region *intr = ®ion->intclr_reg;
+ /* If an interrupt clear region has been specified we clear the pending
+ * intterrupts only when the memory accesse is inside the region.
+ * */
+ if ((addr >= intr->offset && addr + size <= intr->offset + intr->size)
+ || !vdev->has_intclr_region) {
+ vfio_irq_eoi(vdev);
+ }
}
static uint64_t vfio_region_read(void *opaque, hwaddr addr, unsigned size)
{
VFIORegion *region = opaque;
+ VFIODevice *vdev = NULL;
union {
uint8_t byte;
uint16_t word;
@@ -466,7 +528,10 @@ static uint64_t vfio_region_read(void *opaque, hwaddr addr, unsigned size)
DPRINTF("(region %d, addr= 0x%"HWADDR_PRIx", data=%d) = 0x%"PRIx64"\n",
region->nr, addr, size, data);
- vfio_irq_eoi(container_of(region, VFIODevice, regions[region->nr]));
+ vdev = container_of(region, VFIODevice, regions[region->nr]);
+ if (!vdev->has_intclr_region) {
+ vfio_irq_eoi(vdev);
+ }
return data;
}
@@ -669,6 +734,17 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
}
}
+ hwaddr intclr_off = 0;
+ uint64_t intclr_size = 0;
+ uint32_t id = 0;
+ if (vdev->intclr_region_str) {
+ ret = parse_clrint_string(vdev->intclr_region_str, &id, &intclr_off,
+ &intclr_size);
+ } else {
+ ret = -1;
+ }
+ vdev->has_intclr_region = (!ret) ? true : false;
+
ret = vfio_get_device(group, path, vdev);
if (ret) {
error_report("vfio: failed to get device %s", path);
@@ -678,6 +754,16 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
for (i = 0; i < vdev->num_regions; i++) {
vfio_map_region(vdev, i);
+
+ if (id == i && vdev->has_intclr_region) {
+ struct intclr_region *intclr_reg = NULL;
+
+ intclr_reg = &(vdev->regions[i].intclr_reg);
+
+ intclr_reg->offset = intclr_off;
+ intclr_reg->size = intclr_size;
+ }
+
sysbus_init_mmio(sbdev, &vdev->regions[i].mem);
}
}
@@ -729,6 +815,7 @@ typedef struct VFIOPlatformDeviceClass {
static Property vfio_platform_dev_properties[] = {
DEFINE_PROP_STRING("vfio_device", VFIODevice, name),
DEFINE_PROP_STRING("compat", VFIODevice, compat),
+DEFINE_PROP_STRING("intclr-region", VFIODevice, intclr_region_str),
DEFINE_PROP_UINT32("mmap-timeout-ms", VFIODevice, mmap_timeout, 1100),
DEFINE_PROP_END_OF_LIST(),
};
--
1.9.1
^ permalink raw reply related [flat|nested] 6+ messages in thread