vfio/pci: Enable virtual register in PCI config space
authorAlex Williamson <alex.williamson@redhat.com>
Mon, 22 Feb 2016 23:02:41 +0000 (16:02 -0700)
committerAlex Williamson <alex.williamson@redhat.com>
Mon, 22 Feb 2016 23:10:09 +0000 (16:10 -0700)
Typically config space for a device is mapped out into capability
specific handlers and unassigned space.  The latter allows direct
read/write access to config space.  Sometimes we know about registers
living in this void space and would like an easy way to virtualize
them, similar to how BAR registers are managed.  To do this, create
one more pseudo (fake) PCI capability to be handled as purely virtual
space.  Reads and writes are serviced entirely from virtual config
space.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
drivers/vfio/pci/vfio_pci_config.c
drivers/vfio/pci/vfio_pci_private.h

index fe2b470d7ec6b33c8fd75ffbfccb1168a6975ca2..88dc646c01448bcd5656ed5f17c9b487a0c5f49b 100644 (file)
@@ -33,9 +33,8 @@
 
 #define PCI_CFG_SPACE_SIZE     256
 
-/* Useful "pseudo" capabilities */
+/* Fake capability ID for standard config space */
 #define PCI_CAP_ID_BASIC       0
-#define PCI_CAP_ID_INVALID     0xFF
 
 #define is_bar(offset) \
        ((offset >= PCI_BASE_ADDRESS_0 && offset < PCI_BASE_ADDRESS_5 + 4) || \
@@ -301,6 +300,23 @@ static int vfio_raw_config_read(struct vfio_pci_device *vdev, int pos,
        return count;
 }
 
+/* Virt access uses only virtualization */
+static int vfio_virt_config_write(struct vfio_pci_device *vdev, int pos,
+                                 int count, struct perm_bits *perm,
+                                 int offset, __le32 val)
+{
+       memcpy(vdev->vconfig + pos, &val, count);
+       return count;
+}
+
+static int vfio_virt_config_read(struct vfio_pci_device *vdev, int pos,
+                                int count, struct perm_bits *perm,
+                                int offset, __le32 *val)
+{
+       memcpy(val, vdev->vconfig + pos, count);
+       return count;
+}
+
 /* Default capability regions to read-only, no-virtualization */
 static struct perm_bits cap_perms[PCI_CAP_ID_MAX + 1] = {
        [0 ... PCI_CAP_ID_MAX] = { .readfn = vfio_direct_config_read }
@@ -319,6 +335,11 @@ static struct perm_bits unassigned_perms = {
        .writefn = vfio_raw_config_write
 };
 
+static struct perm_bits virt_perms = {
+       .readfn = vfio_virt_config_read,
+       .writefn = vfio_virt_config_write
+};
+
 static void free_perm_bits(struct perm_bits *perm)
 {
        kfree(perm->virt);
@@ -1332,6 +1353,8 @@ static int vfio_cap_init(struct vfio_pci_device *vdev)
                                pos + i, map[pos + i], cap);
                }
 
+               BUILD_BUG_ON(PCI_CAP_ID_MAX >= PCI_CAP_ID_INVALID_VIRT);
+
                memset(map + pos, cap, len);
                ret = vfio_fill_vconfig_bytes(vdev, pos, len);
                if (ret)
@@ -1419,9 +1442,9 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
                /*
                 * Even though ecap is 2 bytes, we're currently a long way
                 * from exceeding 1 byte capabilities.  If we ever make it
-                * up to 0xFF we'll need to up this to a two-byte, byte map.
+                * up to 0xFE we'll need to up this to a two-byte, byte map.
                 */
-               BUILD_BUG_ON(PCI_EXT_CAP_ID_MAX >= PCI_CAP_ID_INVALID);
+               BUILD_BUG_ON(PCI_EXT_CAP_ID_MAX >= PCI_CAP_ID_INVALID_VIRT);
 
                memset(map + epos, ecap, len);
                ret = vfio_fill_vconfig_bytes(vdev, epos, len);
@@ -1597,6 +1620,9 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_device *vdev, char __user *buf,
        if (cap_id == PCI_CAP_ID_INVALID) {
                perm = &unassigned_perms;
                cap_start = *ppos;
+       } else if (cap_id == PCI_CAP_ID_INVALID_VIRT) {
+               perm = &virt_perms;
+               cap_start = *ppos;
        } else {
                if (*ppos >= PCI_CFG_SPACE_SIZE) {
                        WARN_ON(cap_id > PCI_EXT_CAP_ID_MAX);
index 0710bda5ae2c2e103e266e806dbb066fca320a16..b1e403235feb29f9a02a6f7ede3e9ac5e7ea56a8 100644 (file)
 #define VFIO_PCI_INDEX_TO_OFFSET(index)        ((u64)(index) << VFIO_PCI_OFFSET_SHIFT)
 #define VFIO_PCI_OFFSET_MASK   (((u64)(1) << VFIO_PCI_OFFSET_SHIFT) - 1)
 
+/* Special capability IDs predefined access */
+#define PCI_CAP_ID_INVALID             0xFF    /* default raw access */
+#define PCI_CAP_ID_INVALID_VIRT                0xFE    /* default virt access */
+
 struct vfio_pci_irq_ctx {
        struct eventfd_ctx      *trigger;
        struct virqfd           *unmask;