Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1335845 > unrolled thread
| Started by | Alex Williamson <alex.williamson@redhat.com> |
|---|---|
| First post | 2016-02-16 22:10 +0100 |
| Last post | 2016-02-16 22:10 +0100 |
| Articles | 4 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v3 00/10] vfio: capability chains, sparse mmaps, device specific regions, IGD support Alex Williamson <alex.williamson@redhat.com> - 2016-02-16 22:10 +0100
[PATCH v3 05/10] vfio: Define device specific region type capability Alex Williamson <alex.williamson@redhat.com> - 2016-02-16 22:10 +0100
[PATCH v3 06/10] vfio/pci: Add infrastructure for additional device specific regions Alex Williamson <alex.williamson@redhat.com> - 2016-02-16 22:10 +0100
[PATCH v3 09/10] vfio/pci: Intel IGD host and LCP bridge config space access Alex Williamson <alex.williamson@redhat.com> - 2016-02-16 22:10 +0100
| From | Alex Williamson <alex.williamson@redhat.com> |
|---|---|
| Date | 2016-02-16 22:10 +0100 |
| Subject | [PATCH v3 00/10] vfio: capability chains, sparse mmaps, device specific regions, IGD support |
| Message-ID | <r2V2F-4T4-3@gated-at.bofh.it> |
v3:
Dropped GMCH and BDSM clearing and protection from the kernel. The
more I thought about this, clearing these registers isn't really
vfio's responsibility. It doesn't protect the host, it's only a
feeble attempt to prevent the device from stomping on user memory.
But any DMA capable device has the ability to do that, the user needs
to know how to drive it or shouldn't be touching it. This isn't gone
completely, QEMU just needs to do it.
NB, the ASL Storage register still needs protection because unlike the
above two, it's a read-write scratch register. Giving the user the
ability to write directly to it makes for a one-time use device. So
we still virtualize that in the kernel.
Rebased to v4.5-rc4.
v2:
v2 includes more IGD support. Read only access to the host bridge
and LPC bridge config space is provided to allow configuration of
emulated devices for VM use cases. We also try to hide the stolen
memory window from the user. This probably needs additional work as
I'd prefer not to need to update the code for every new graphics chip.
Perhaps we should instead blacklist anything pre-SandyBridge, identify
SandyBridge specifically, and hope that anything unknown after that
uses the gen8+ register layout. Additionally since IGD doesn't have
a real ROM BAR, but does typically have its vBIOS in shadow ROM space,
expose that as if it were a ROM BAR. This series should be used in
conjunction with:
Subject: [PATCH] pci: Wait for up to an additional 1000ms after FLR reset
for use on laptops.
v1:
We have a number of cases were we want to extend the vfio API to
provide further details in the vfio INFO ioctls. For instance we take
it as implicit that we can't mmap over MSI-X vector tables of a BAR,
but we'd prefer to have the API define that explicitly as a sparse
mmap capable region. We have some devices that need additional
regions, but we don't want to "burn" a region index for something
specific to a single device. We also have the ongoing problem of
describing valid IOVA ranges for an IOMMU. This series doesn't solve
every case of those problems, but it solves some and gives us the vfio
level API to solve the others.
To do this we use capability chains, much like they're used in PCI.
A flag bit in the INFO ioctl structure tells us whether a capability
chain is present and new fields are defined to provide the buffer
index of the first capability. Each capability provides the start
index of the next capability along with an identifier and version of
itself. The existing argsz field of is used to convey to the user the
necessary buffer size to retrieve all of the capabilities. A few
helpers in the vfio core simplifies the mechanics of adding
capabilities for the bus and iommu drivers to make use of.
The sparse mmap capability solves the problem of regions which can
only be partially mmaped, such as when an MSI-X table is present.
This is also expected to be useful for vGPU support should a device
have a mix of direct access and emulated access within the same
region.
The device specific region capability allows us to easily add new
regions that are device specific. Included here is the IGD OpRegion,
which is a host memory region exclusively for the configuration and
use of Intel graphics devices, but is not part of the device in the
PCI sense. There are potentially other regions we can expose on this
device to further facilitate use of it.
I particularly welcome feedback on how we identify device specific
regions. Here I've used a type and sub-type field where I've defined
one bit of the type field to identify a vendor specific type with a
mask to identify the vendor. In the Opregion case here, that defines
an 8086 set of sub-types where I've simply defined sub-type 1 as an
IGD OpRegion. We could of course get the vendor from the device
itself, but this method might promote code re-use if we eventually
have multiple vendors using regions for the same purpose. At least
that's my thinking.
Appreciate feedback. Thanks,
Alex
---
Alex Williamson (10):
vfio: Define capability chains
vfio: Add capability chain helpers
vfio: Define sparse mmap capability for regions
vfio/pci: Include sparse mmap capability for MSI-X table regions
vfio: Define device specific region type capability
vfio/pci: Add infrastructure for additional device specific regions
vfio/pci: Enable virtual register in PCI config space
vfio/pci: Intel IGD OpRegion support
vfio/pci: Intel IGD host and LCP bridge config space access
vfio/pci: Expose shadow ROM as PCI option ROM
drivers/vfio/pci/Kconfig | 4 +
drivers/vfio/pci/Makefile | 1
drivers/vfio/pci/vfio_pci.c | 176 +++++++++++++++++++++-
drivers/vfio/pci/vfio_pci_config.c | 45 +++++-
drivers/vfio/pci/vfio_pci_igd.c | 280 +++++++++++++++++++++++++++++++++++
drivers/vfio/pci/vfio_pci_private.h | 39 +++++
drivers/vfio/pci/vfio_pci_rdwr.c | 9 +
drivers/vfio/vfio.c | 54 +++++++
include/linux/vfio.h | 11 +
include/uapi/linux/vfio.h | 92 +++++++++++-
10 files changed, 692 insertions(+), 19 deletions(-)
create mode 100644 drivers/vfio/pci/vfio_pci_igd.c
[toc] | [next] | [standalone]
| From | Alex Williamson <alex.williamson@redhat.com> |
|---|---|
| Date | 2016-02-16 22:10 +0100 |
| Subject | [PATCH v3 05/10] vfio: Define device specific region type capability |
| Message-ID | <r2V2G-4T4-25@gated-at.bofh.it> |
| In reply to | #1335845 |
To this point vfio has only provided an interface to the user that
allows them to determine the number of regions and specifics about
each region. What the region represents is left to the vfio bus
driver. vfio-pci chooses to use fixed indexes for fixed resources,
index 0 is BAR0, 1 is BAR1,... 7 is config space, etc. This works
pretty well since all PCI devices have these regions, even if they
don't necessarily populate all of them. Then we start to add things
like VGA, which only certain device even support. We added this the
same way, but now we've wasted a region index, and due to our offset
implementation the corresponding address space, for all devices.
Rather than continuing that process, let's try to make regions self
describing by including a capability that defines their type. For
vfio-pci we'll make the current VFIO_PCI_NUM_REGIONS fixed, defining
the end of the static indexes and the beginning of self describing
regions.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---
include/uapi/linux/vfio.h | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index fde7b1e..1c37a0e 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -252,6 +252,34 @@ struct vfio_region_info_cap_sparse_mmap {
struct vfio_region_sparse_mmap_area areas[];
};
+/*
+ * The device specific type capability allows regions unique to a specific
+ * device or class of devices to be exposed. This helps solve the problem for
+ * vfio bus drivers of defining which region indexes correspond to which region
+ * on the device, without needing to resort to static indexes, as done by
+ * vfio-pci. For instance, if we were to go back in time, we might remove
+ * VFIO_PCI_VGA_REGION_INDEX and let vfio-pci simply define that all indexes
+ * greater than or equal to VFIO_PCI_NUM_REGIONS are device specific and we'd
+ * make a "VGA" device specific type to describe the VGA access space. This
+ * means that non-VGA devices wouldn't need to waste this index, and thus the
+ * address space associated with it due to implementation of device file
+ * descriptor offsets in vfio-pci.
+ *
+ * The current implementation is now part of the user ABI, so we can't use this
+ * for VGA, but there are other upcoming use cases, such as opregions for Intel
+ * IGD devices and framebuffers for vGPU devices. We missed VGA, but we'll
+ * use this for future additions.
+ *
+ * The structure below defines version 1 of this capability.
+ */
+#define VFIO_REGION_INFO_CAP_TYPE 2
+
+struct vfio_region_info_cap_type {
+ struct vfio_info_cap_header header;
+ __u32 type; /* global per bus driver */
+ __u32 subtype; /* type specific */
+};
+
/**
* VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9,
* struct vfio_irq_info)
@@ -387,7 +415,8 @@ enum {
* between described ranges are unimplemented.
*/
VFIO_PCI_VGA_REGION_INDEX,
- VFIO_PCI_NUM_REGIONS
+ VFIO_PCI_NUM_REGIONS = 9 /* Fixed user ABI, region indexes >=9 use */
+ /* device specific cap to define content. */
};
enum {
[toc] | [prev] | [next] | [standalone]
| From | Alex Williamson <alex.williamson@redhat.com> |
|---|---|
| Date | 2016-02-16 22:10 +0100 |
| Subject | [PATCH v3 06/10] vfio/pci: Add infrastructure for additional device specific regions |
| Message-ID | <r2V2G-4T4-29@gated-at.bofh.it> |
| In reply to | #1335845 |
Add support for additional regions with indexes started after the
already defined fixed regions. Device specific code can register
these regions with the new vfio_pci_register_dev_region() function.
The ops structure per region currently only includes read/write
access and a release function, allowing automatic cleanup when the
device is closed. mmap support is only missing here because it's
not needed by the first user queued for this support.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---
drivers/vfio/pci/vfio_pci.c | 81 +++++++++++++++++++++++++++++++++--
drivers/vfio/pci/vfio_pci_private.h | 27 ++++++++++++
2 files changed, 103 insertions(+), 5 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 4682207..813a2e6 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -175,7 +175,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
static void vfio_pci_disable(struct vfio_pci_device *vdev)
{
struct pci_dev *pdev = vdev->pdev;
- int bar;
+ int i, bar;
/* Stop the device from further DMA */
pci_clear_master(pdev);
@@ -186,6 +186,13 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
vdev->virq_disabled = false;
+ for (i = 0; i < vdev->num_regions; i++)
+ vdev->region[i].ops->release(vdev, &vdev->region[i]);
+
+ vdev->num_regions = 0;
+ kfree(vdev->region);
+ vdev->region = NULL; /* don't krealloc a freed pointer */
+
vfio_config_free(vdev);
for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
@@ -463,6 +470,51 @@ static int msix_sparse_mmap_cap(struct vfio_pci_device *vdev,
return 0;
}
+static int region_type_cap(struct vfio_pci_device *vdev,
+ struct vfio_info_cap *caps,
+ unsigned int type, unsigned int subtype)
+{
+ struct vfio_info_cap_header *header;
+ struct vfio_region_info_cap_type *cap;
+
+ header = vfio_info_cap_add(caps, sizeof(*cap),
+ VFIO_REGION_INFO_CAP_TYPE, 1);
+ if (IS_ERR(header))
+ return PTR_ERR(header);
+
+ cap = container_of(header, struct vfio_region_info_cap_type, header);
+ cap->type = type;
+ cap->subtype = subtype;
+
+ return 0;
+}
+
+int vfio_pci_register_dev_region(struct vfio_pci_device *vdev,
+ unsigned int type, unsigned int subtype,
+ const struct vfio_pci_regops *ops,
+ size_t size, u32 flags, void *data)
+{
+ struct vfio_pci_region *region;
+
+ region = krealloc(vdev->region,
+ (vdev->num_regions + 1) * sizeof(*region),
+ GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+
+ vdev->region = region;
+ vdev->region[vdev->num_regions].type = type;
+ vdev->region[vdev->num_regions].subtype = subtype;
+ vdev->region[vdev->num_regions].ops = ops;
+ vdev->region[vdev->num_regions].size = size;
+ vdev->region[vdev->num_regions].flags = flags;
+ vdev->region[vdev->num_regions].data = data;
+
+ vdev->num_regions++;
+
+ return 0;
+}
+
static long vfio_pci_ioctl(void *device_data,
unsigned int cmd, unsigned long arg)
{
@@ -485,7 +537,7 @@ static long vfio_pci_ioctl(void *device_data,
if (vdev->reset_works)
info.flags |= VFIO_DEVICE_FLAGS_RESET;
- info.num_regions = VFIO_PCI_NUM_REGIONS;
+ info.num_regions = VFIO_PCI_NUM_REGIONS + vdev->num_regions;
info.num_irqs = VFIO_PCI_NUM_IRQS;
return copy_to_user((void __user *)arg, &info, minsz);
@@ -494,7 +546,7 @@ static long vfio_pci_ioctl(void *device_data,
struct pci_dev *pdev = vdev->pdev;
struct vfio_region_info info;
struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
- int ret;
+ int i, ret;
minsz = offsetofend(struct vfio_region_info, offset);
@@ -568,7 +620,21 @@ static long vfio_pci_ioctl(void *device_data,
break;
default:
- return -EINVAL;
+ if (info.index >=
+ VFIO_PCI_NUM_REGIONS + vdev->num_regions)
+ return -EINVAL;
+
+ i = info.index - VFIO_PCI_NUM_REGIONS;
+
+ info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.size = vdev->region[i].size;
+ info.flags = vdev->region[i].flags;
+
+ ret = region_type_cap(vdev, &caps,
+ vdev->region[i].type,
+ vdev->region[i].subtype);
+ if (ret)
+ return ret;
}
if (caps.size) {
@@ -866,7 +932,7 @@ static ssize_t vfio_pci_rw(void *device_data, char __user *buf,
unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
struct vfio_pci_device *vdev = device_data;
- if (index >= VFIO_PCI_NUM_REGIONS)
+ if (index >= VFIO_PCI_NUM_REGIONS + vdev->num_regions)
return -EINVAL;
switch (index) {
@@ -883,6 +949,10 @@ static ssize_t vfio_pci_rw(void *device_data, char __user *buf,
case VFIO_PCI_VGA_REGION_INDEX:
return vfio_pci_vga_rw(vdev, buf, count, ppos, iswrite);
+ default:
+ index -= VFIO_PCI_NUM_REGIONS;
+ return vdev->region[index].ops->rw(vdev, buf,
+ count, ppos, iswrite);
}
return -EINVAL;
@@ -1065,6 +1135,7 @@ static void vfio_pci_remove(struct pci_dev *pdev)
return;
vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev);
+ kfree(vdev->region);
kfree(vdev);
if (vfio_pci_is_vga(pdev)) {
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index 0e7394f..0710bda 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -14,6 +14,7 @@
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/irqbypass.h>
+#include <linux/types.h>
#ifndef VFIO_PCI_PRIVATE_H
#define VFIO_PCI_PRIVATE_H
@@ -33,6 +34,25 @@ struct vfio_pci_irq_ctx {
struct irq_bypass_producer producer;
};
+struct vfio_pci_device;
+struct vfio_pci_region;
+
+struct vfio_pci_regops {
+ size_t (*rw)(struct vfio_pci_device *vdev, char __user *buf,
+ size_t count, loff_t *ppos, bool iswrite);
+ void (*release)(struct vfio_pci_device *vdev,
+ struct vfio_pci_region *region);
+};
+
+struct vfio_pci_region {
+ u32 type;
+ u32 subtype;
+ const struct vfio_pci_regops *ops;
+ void *data;
+ size_t size;
+ u32 flags;
+};
+
struct vfio_pci_device {
struct pci_dev *pdev;
void __iomem *barmap[PCI_STD_RESOURCE_END + 1];
@@ -45,6 +65,8 @@ struct vfio_pci_device {
struct vfio_pci_irq_ctx *ctx;
int num_ctx;
int irq_type;
+ int num_regions;
+ struct vfio_pci_region *region;
u8 msi_qmax;
u8 msix_bar;
u16 msix_size;
@@ -91,4 +113,9 @@ extern void vfio_pci_uninit_perm_bits(void);
extern int vfio_config_init(struct vfio_pci_device *vdev);
extern void vfio_config_free(struct vfio_pci_device *vdev);
+
+extern int vfio_pci_register_dev_region(struct vfio_pci_device *vdev,
+ unsigned int type, unsigned int subtype,
+ const struct vfio_pci_regops *ops,
+ size_t size, u32 flags, void *data);
#endif /* VFIO_PCI_PRIVATE_H */
[toc] | [prev] | [next] | [standalone]
| From | Alex Williamson <alex.williamson@redhat.com> |
|---|---|
| Date | 2016-02-16 22:10 +0100 |
| Subject | [PATCH v3 09/10] vfio/pci: Intel IGD host and LCP bridge config space access |
| Message-ID | <r2V2H-4T4-31@gated-at.bofh.it> |
| In reply to | #1335845 |
Provide read-only access to PCI config space of the PCI host bridge
and LPC bridge through device specific regions. This may be used to
configure a VM with matching register contents to satisfy driver
requirements. Providing this through the vfio file descriptor removes
an additional userspace requirement for access through pci-sysfs and
removes the CAP_SYS_ADMIN requirement that doesn't appear to apply to
the specific devices we're accessing.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---
drivers/vfio/pci/vfio_pci.c | 15 ++-
drivers/vfio/pci/vfio_pci_igd.c | 171 +++++++++++++++++++++++++++++++++++
drivers/vfio/pci/vfio_pci_private.h | 4 -
include/uapi/linux/vfio.h | 3 +
4 files changed, 186 insertions(+), 7 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index cb2624d..74a3752 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -111,6 +111,7 @@ static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
}
static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev);
+static void vfio_pci_disable(struct vfio_pci_device *vdev);
static int vfio_pci_enable(struct vfio_pci_device *vdev)
{
@@ -170,10 +171,16 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
vdev->has_vga = true;
- if (vfio_pci_is_vga(pdev) && pdev->vendor == PCI_VENDOR_ID_INTEL) {
- if (vfio_pci_igd_opregion_init(vdev) == 0)
- dev_info(&pdev->dev,
- "Intel IGD OpRegion support enabled\n");
+ if (vfio_pci_is_vga(pdev) &&
+ pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ IS_ENABLED(CONFIG_VFIO_PCI_IGD)) {
+ ret = vfio_pci_igd_init(vdev);
+ if (ret) {
+ dev_warn(&vdev->pdev->dev,
+ "Failed to setup Intel IGD regions\n");
+ vfio_pci_disable(vdev);
+ return ret;
+ }
}
return 0;
diff --git a/drivers/vfio/pci/vfio_pci_igd.c b/drivers/vfio/pci/vfio_pci_igd.c
index 3b6a6f7..6394b16 100644
--- a/drivers/vfio/pci/vfio_pci_igd.c
+++ b/drivers/vfio/pci/vfio_pci_igd.c
@@ -55,7 +55,7 @@ static const struct vfio_pci_regops vfio_pci_igd_regops = {
.release = vfio_pci_igd_release,
};
-int vfio_pci_igd_opregion_init(struct vfio_pci_device *vdev)
+static int vfio_pci_igd_opregion_init(struct vfio_pci_device *vdev)
{
__le32 *dwordp = (__le32 *)(vdev->vconfig + OPREGION_PCI_ADDR);
u32 addr, size;
@@ -109,3 +109,172 @@ int vfio_pci_igd_opregion_init(struct vfio_pci_device *vdev)
return ret;
}
+
+static size_t vfio_pci_igd_cfg_rw(struct vfio_pci_device *vdev,
+ char __user *buf, size_t count, loff_t *ppos,
+ bool iswrite)
+{
+ unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) - VFIO_PCI_NUM_REGIONS;
+ struct pci_dev *pdev = vdev->region[i].data;
+ loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+ size_t size;
+ int ret;
+
+ if (pos >= vdev->region[i].size || iswrite)
+ return -EINVAL;
+
+ size = count = min(count, (size_t)(vdev->region[i].size - pos));
+
+ if ((pos & 1) && size) {
+ u8 val;
+
+ ret = pci_user_read_config_byte(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ if (copy_to_user(buf + count - size, &val, 1))
+ return -EFAULT;
+
+ pos++;
+ size--;
+ }
+
+ if ((pos & 3) && size > 2) {
+ u16 val;
+
+ ret = pci_user_read_config_word(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ val = cpu_to_le16(val);
+ if (copy_to_user(buf + count - size, &val, 2))
+ return -EFAULT;
+
+ pos += 2;
+ size -= 2;
+ }
+
+ while (size > 3) {
+ u32 val;
+
+ ret = pci_user_read_config_dword(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ val = cpu_to_le32(val);
+ if (copy_to_user(buf + count - size, &val, 4))
+ return -EFAULT;
+
+ pos += 4;
+ size -= 4;
+ }
+
+ while (size >= 2) {
+ u16 val;
+
+ ret = pci_user_read_config_word(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ val = cpu_to_le16(val);
+ if (copy_to_user(buf + count - size, &val, 2))
+ return -EFAULT;
+
+ pos += 2;
+ size -= 2;
+ }
+
+ while (size) {
+ u8 val;
+
+ ret = pci_user_read_config_byte(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ if (copy_to_user(buf + count - size, &val, 1))
+ return -EFAULT;
+
+ pos++;
+ size--;
+ }
+
+ *ppos += count;
+
+ return count;
+}
+
+static void vfio_pci_igd_cfg_release(struct vfio_pci_device *vdev,
+ struct vfio_pci_region *region)
+{
+ struct pci_dev *pdev = region->data;
+
+ pci_dev_put(pdev);
+}
+
+static const struct vfio_pci_regops vfio_pci_igd_cfg_regops = {
+ .rw = vfio_pci_igd_cfg_rw,
+ .release = vfio_pci_igd_cfg_release,
+};
+
+static int vfio_pci_igd_cfg_init(struct vfio_pci_device *vdev)
+{
+ struct pci_dev *host_bridge, *lpc_bridge;
+ int ret;
+
+ host_bridge = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
+ if (!host_bridge)
+ return -ENODEV;
+
+ if (host_bridge->vendor != PCI_VENDOR_ID_INTEL ||
+ host_bridge->class != (PCI_CLASS_BRIDGE_HOST << 8)) {
+ pci_dev_put(host_bridge);
+ return -EINVAL;
+ }
+
+ ret = vfio_pci_register_dev_region(vdev,
+ PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
+ VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG,
+ &vfio_pci_igd_cfg_regops, host_bridge->cfg_size,
+ VFIO_REGION_INFO_FLAG_READ, host_bridge);
+ if (ret) {
+ pci_dev_put(host_bridge);
+ return ret;
+ }
+
+ lpc_bridge = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x1f, 0));
+ if (!lpc_bridge)
+ return -ENODEV;
+
+ if (lpc_bridge->vendor != PCI_VENDOR_ID_INTEL ||
+ lpc_bridge->class != (PCI_CLASS_BRIDGE_ISA << 8)) {
+ pci_dev_put(lpc_bridge);
+ return -EINVAL;
+ }
+
+ ret = vfio_pci_register_dev_region(vdev,
+ PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
+ VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG,
+ &vfio_pci_igd_cfg_regops, lpc_bridge->cfg_size,
+ VFIO_REGION_INFO_FLAG_READ, lpc_bridge);
+ if (ret) {
+ pci_dev_put(lpc_bridge);
+ return ret;
+ }
+
+ return 0;
+}
+
+int vfio_pci_igd_init(struct vfio_pci_device *vdev)
+{
+ int ret;
+
+ ret = vfio_pci_igd_opregion_init(vdev);
+ if (ret)
+ return ret;
+
+ ret = vfio_pci_igd_cfg_init(vdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index 19f7699..8a7d546 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -123,9 +123,9 @@ extern int vfio_pci_register_dev_region(struct vfio_pci_device *vdev,
const struct vfio_pci_regops *ops,
size_t size, u32 flags, void *data);
#ifdef CONFIG_VFIO_PCI_IGD
-extern int vfio_pci_igd_opregion_init(struct vfio_pci_device *vdev);
+extern int vfio_pci_igd_init(struct vfio_pci_device *vdev);
#else
-static inline int vfio_pci_igd_opregion_init(struct vfio_pci_device *vdev)
+static inline int vfio_pci_igd_init(struct vfio_pci_device *vdev)
{
return -ENODEV;
}
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index e622982..255a211 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -283,7 +283,10 @@ struct vfio_region_info_cap_type {
#define VFIO_REGION_TYPE_PCI_VENDOR_TYPE (1 << 31)
#define VFIO_REGION_TYPE_PCI_VENDOR_MASK (0xffff)
+/* 8086 Vendor sub-types */
#define VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION (1)
+#define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2)
+#define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3)
/**
* VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9,
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web