|
|
5d360b |
From bbd8cc516329f84b70d38a75820f36f2ecd0abda Mon Sep 17 00:00:00 2001
|
|
|
5d360b |
From: Alex Williamson <alex.williamson@redhat.com>
|
|
|
5d360b |
Date: Fri, 29 Sep 2017 21:46:14 +0200
|
|
|
5d360b |
Subject: [PATCH 15/27] vfio: Enable sparse mmap capability
|
|
|
5d360b |
|
|
|
5d360b |
RH-Author: Alex Williamson <alex.williamson@redhat.com>
|
|
|
5d360b |
Message-id: <20170929214614.16765.48627.stgit@gimli.home>
|
|
|
5d360b |
Patchwork-id: 76773
|
|
|
5d360b |
O-Subject: [RHEL-7.5 qemu-kvm PATCH 15/16] vfio: Enable sparse mmap capability
|
|
|
5d360b |
Bugzilla: 1494181
|
|
|
5d360b |
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
5d360b |
RH-Acked-by: Auger Eric <eric.auger@redhat.com>
|
|
|
5d360b |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
5d360b |
|
|
|
5d360b |
Upstream: b53b0f696b10828f6393155f44a352c019e673fd
|
|
|
5d360b |
RHEL: Roll in required linux-headers update
|
|
|
5d360b |
|
|
|
5d360b |
The sparse mmap capability in a vfio region info allows vfio to tell
|
|
|
5d360b |
us which sub-areas of a region may be mmap'd. Thus rather than
|
|
|
5d360b |
assuming a single mmap covers the entire region and later frobbing it
|
|
|
5d360b |
ourselves for things like the PCI MSI-X vector table, we can read that
|
|
|
5d360b |
directly from vfio.
|
|
|
5d360b |
|
|
|
5d360b |
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
|
|
|
5d360b |
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
5d360b |
Tested-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
5d360b |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
5d360b |
---
|
|
|
5d360b |
hw/misc/vfio.c | 67 +++++++++++++++++++++++++++++++++++++++++++---
|
|
|
5d360b |
linux-headers/linux/vfio.h | 53 +++++++++++++++++++++++++++++++++++-
|
|
|
5d360b |
trace-events | 2 ++
|
|
|
5d360b |
3 files changed, 117 insertions(+), 5 deletions(-)
|
|
|
5d360b |
|
|
|
5d360b |
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
|
|
|
5d360b |
index d634531..a27698b 100644
|
|
|
5d360b |
--- a/hw/misc/vfio.c
|
|
|
5d360b |
+++ b/hw/misc/vfio.c
|
|
|
5d360b |
@@ -2602,6 +2602,54 @@ static void vfio_unmap_bar(VFIOPCIDevice *vdev, int nr)
|
|
|
5d360b |
vfio_region_finalize(&bar->region);
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
+static struct vfio_info_cap_header *
|
|
|
5d360b |
+vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id)
|
|
|
5d360b |
+{
|
|
|
5d360b |
+ struct vfio_info_cap_header *hdr;
|
|
|
5d360b |
+ void *ptr = info;
|
|
|
5d360b |
+
|
|
|
5d360b |
+ if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS)) {
|
|
|
5d360b |
+ return NULL;
|
|
|
5d360b |
+ }
|
|
|
5d360b |
+
|
|
|
5d360b |
+ for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) {
|
|
|
5d360b |
+ if (hdr->id == id) {
|
|
|
5d360b |
+ return hdr;
|
|
|
5d360b |
+ }
|
|
|
5d360b |
+ }
|
|
|
5d360b |
+
|
|
|
5d360b |
+ return NULL;
|
|
|
5d360b |
+}
|
|
|
5d360b |
+
|
|
|
5d360b |
+static void vfio_setup_region_sparse_mmaps(VFIORegion *region,
|
|
|
5d360b |
+ struct vfio_region_info *info)
|
|
|
5d360b |
+{
|
|
|
5d360b |
+ struct vfio_info_cap_header *hdr;
|
|
|
5d360b |
+ struct vfio_region_info_cap_sparse_mmap *sparse;
|
|
|
5d360b |
+ int i;
|
|
|
5d360b |
+
|
|
|
5d360b |
+ hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP);
|
|
|
5d360b |
+ if (!hdr) {
|
|
|
5d360b |
+ return;
|
|
|
5d360b |
+ }
|
|
|
5d360b |
+
|
|
|
5d360b |
+ sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header);
|
|
|
5d360b |
+
|
|
|
5d360b |
+ trace_vfio_region_sparse_mmap_header(region->vbasedev->name,
|
|
|
5d360b |
+ region->nr, sparse->nr_areas);
|
|
|
5d360b |
+
|
|
|
5d360b |
+ region->nr_mmaps = sparse->nr_areas;
|
|
|
5d360b |
+ region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
|
|
|
5d360b |
+
|
|
|
5d360b |
+ for (i = 0; i < region->nr_mmaps; i++) {
|
|
|
5d360b |
+ region->mmaps[i].offset = sparse->areas[i].offset;
|
|
|
5d360b |
+ region->mmaps[i].size = sparse->areas[i].size;
|
|
|
5d360b |
+ trace_vfio_region_sparse_mmap_entry(i, region->mmaps[i].offset,
|
|
|
5d360b |
+ region->mmaps[i].offset +
|
|
|
5d360b |
+ region->mmaps[i].size);
|
|
|
5d360b |
+ }
|
|
|
5d360b |
+}
|
|
|
5d360b |
+
|
|
|
5d360b |
static int vfio_region_setup(Object *obj, VFIODevice *vbasedev,
|
|
|
5d360b |
VFIORegion *region, int index, const char *name)
|
|
|
5d360b |
{
|
|
|
5d360b |
@@ -2628,11 +2676,14 @@ static int vfio_region_setup(Object *obj, VFIODevice *vbasedev,
|
|
|
5d360b |
region->flags & VFIO_REGION_INFO_FLAG_MMAP &&
|
|
|
5d360b |
!(region->size & ~TARGET_PAGE_MASK)) {
|
|
|
5d360b |
|
|
|
5d360b |
- region->nr_mmaps = 1;
|
|
|
5d360b |
- region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
|
|
|
5d360b |
+ vfio_setup_region_sparse_mmaps(region, info);
|
|
|
5d360b |
|
|
|
5d360b |
- region->mmaps[0].offset = 0;
|
|
|
5d360b |
- region->mmaps[0].size = region->size;
|
|
|
5d360b |
+ if (!region->nr_mmaps) {
|
|
|
5d360b |
+ region->nr_mmaps = 1;
|
|
|
5d360b |
+ region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
|
|
|
5d360b |
+ region->mmaps[0].offset = 0;
|
|
|
5d360b |
+ region->mmaps[0].size = region->size;
|
|
|
5d360b |
+ }
|
|
|
5d360b |
}
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
@@ -3796,6 +3847,7 @@ static int vfio_get_region_info(VFIODevice *vbasedev, int index,
|
|
|
5d360b |
*info = g_malloc0(argsz);
|
|
|
5d360b |
|
|
|
5d360b |
(*info)->index = index;
|
|
|
5d360b |
+retry:
|
|
|
5d360b |
(*info)->argsz = argsz;
|
|
|
5d360b |
|
|
|
5d360b |
if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) {
|
|
|
5d360b |
@@ -3803,6 +3855,13 @@ static int vfio_get_region_info(VFIODevice *vbasedev, int index,
|
|
|
5d360b |
return -errno;
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
+ if ((*info)->argsz > argsz) {
|
|
|
5d360b |
+ argsz = (*info)->argsz;
|
|
|
5d360b |
+ *info = g_realloc(*info, argsz);
|
|
|
5d360b |
+
|
|
|
5d360b |
+ goto retry;
|
|
|
5d360b |
+ }
|
|
|
5d360b |
+
|
|
|
5d360b |
return 0;
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
|
|
|
5d360b |
index d197fd4..8995a34 100644
|
|
|
5d360b |
--- a/linux-headers/linux/vfio.h
|
|
|
5d360b |
+++ b/linux-headers/linux/vfio.h
|
|
|
5d360b |
@@ -38,6 +38,33 @@
|
|
|
5d360b |
#define VFIO_TYPE (';')
|
|
|
5d360b |
#define VFIO_BASE 100
|
|
|
5d360b |
|
|
|
5d360b |
+/*
|
|
|
5d360b |
+ * For extension of INFO ioctls, VFIO makes use of a capability chain
|
|
|
5d360b |
+ * designed after PCI/e capabilities. A flag bit indicates whether
|
|
|
5d360b |
+ * this capability chain is supported and a field defined in the fixed
|
|
|
5d360b |
+ * structure defines the offset of the first capability in the chain.
|
|
|
5d360b |
+ * This field is only valid when the corresponding bit in the flags
|
|
|
5d360b |
+ * bitmap is set. This offset field is relative to the start of the
|
|
|
5d360b |
+ * INFO buffer, as is the next field within each capability header.
|
|
|
5d360b |
+ * The id within the header is a shared address space per INFO ioctl,
|
|
|
5d360b |
+ * while the version field is specific to the capability id. The
|
|
|
5d360b |
+ * contents following the header are specific to the capability id.
|
|
|
5d360b |
+ */
|
|
|
5d360b |
+struct vfio_info_cap_header {
|
|
|
5d360b |
+ __u16 id; /* Identifies capability */
|
|
|
5d360b |
+ __u16 version; /* Version specific to the capability ID */
|
|
|
5d360b |
+ __u32 next; /* Offset of next capability */
|
|
|
5d360b |
+};
|
|
|
5d360b |
+
|
|
|
5d360b |
+/*
|
|
|
5d360b |
+ * Callers of INFO ioctls passing insufficiently sized buffers will see
|
|
|
5d360b |
+ * the capability chain flag bit set, a zero value for the first capability
|
|
|
5d360b |
+ * offset (if available within the provided argsz), and argsz will be
|
|
|
5d360b |
+ * updated to report the necessary buffer size. For compatibility, the
|
|
|
5d360b |
+ * INFO ioctl will not report error in this case, but the capability chain
|
|
|
5d360b |
+ * will not be available.
|
|
|
5d360b |
+ */
|
|
|
5d360b |
+
|
|
|
5d360b |
/* -------- IOCTLs for VFIO file descriptor (/dev/vfio/vfio) -------- */
|
|
|
5d360b |
|
|
|
5d360b |
/**
|
|
|
5d360b |
@@ -171,13 +198,37 @@ struct vfio_region_info {
|
|
|
5d360b |
#define VFIO_REGION_INFO_FLAG_READ (1 << 0) /* Region supports read */
|
|
|
5d360b |
#define VFIO_REGION_INFO_FLAG_WRITE (1 << 1) /* Region supports write */
|
|
|
5d360b |
#define VFIO_REGION_INFO_FLAG_MMAP (1 << 2) /* Region supports mmap */
|
|
|
5d360b |
+#define VFIO_REGION_INFO_FLAG_CAPS (1 << 3) /* Info supports caps */
|
|
|
5d360b |
__u32 index; /* Region index */
|
|
|
5d360b |
- __u32 resv; /* Reserved for alignment */
|
|
|
5d360b |
+ __u32 cap_offset; /* Offset within info struct of first cap */
|
|
|
5d360b |
__u64 size; /* Region size (bytes) */
|
|
|
5d360b |
__u64 offset; /* Region offset from start of device fd */
|
|
|
5d360b |
};
|
|
|
5d360b |
#define VFIO_DEVICE_GET_REGION_INFO _IO(VFIO_TYPE, VFIO_BASE + 8)
|
|
|
5d360b |
|
|
|
5d360b |
+/*
|
|
|
5d360b |
+ * The sparse mmap capability allows finer granularity of specifying areas
|
|
|
5d360b |
+ * within a region with mmap support. When specified, the user should only
|
|
|
5d360b |
+ * mmap the offset ranges specified by the areas array. mmaps outside of the
|
|
|
5d360b |
+ * areas specified may fail (such as the range covering a PCI MSI-X table) or
|
|
|
5d360b |
+ * may result in improper device behavior.
|
|
|
5d360b |
+ *
|
|
|
5d360b |
+ * The structures below define version 1 of this capability.
|
|
|
5d360b |
+ */
|
|
|
5d360b |
+#define VFIO_REGION_INFO_CAP_SPARSE_MMAP 1
|
|
|
5d360b |
+
|
|
|
5d360b |
+struct vfio_region_sparse_mmap_area {
|
|
|
5d360b |
+ __u64 offset; /* Offset of mmap'able area within region */
|
|
|
5d360b |
+ __u64 size; /* Size of mmap'able area */
|
|
|
5d360b |
+};
|
|
|
5d360b |
+
|
|
|
5d360b |
+struct vfio_region_info_cap_sparse_mmap {
|
|
|
5d360b |
+ struct vfio_info_cap_header header;
|
|
|
5d360b |
+ __u32 nr_areas;
|
|
|
5d360b |
+ __u32 reserved;
|
|
|
5d360b |
+ struct vfio_region_sparse_mmap_area areas[];
|
|
|
5d360b |
+};
|
|
|
5d360b |
+
|
|
|
5d360b |
/**
|
|
|
5d360b |
* VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9,
|
|
|
5d360b |
* struct vfio_irq_info)
|
|
|
5d360b |
diff --git a/trace-events b/trace-events
|
|
|
5d360b |
index cc62b0b..fa2618d 100644
|
|
|
5d360b |
--- a/trace-events
|
|
|
5d360b |
+++ b/trace-events
|
|
|
5d360b |
@@ -1164,3 +1164,5 @@ vfio_region_mmap(const char *name, unsigned long offset, unsigned long end) "Reg
|
|
|
5d360b |
vfio_region_exit(const char *name, int index) "Device %s, region %d"
|
|
|
5d360b |
vfio_region_finalize(const char *name, int index) "Device %s, region %d"
|
|
|
5d360b |
vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps enabled: %d"
|
|
|
5d360b |
+vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries"
|
|
|
5d360b |
+vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]"
|
|
|
5d360b |
--
|
|
|
5d360b |
1.8.3.1
|
|
|
5d360b |
|