9ae3a8
From acd0e88a7222dac83caf4d507a1bfce7cd0ea734 Mon Sep 17 00:00:00 2001
9ae3a8
From: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Date: Fri, 29 Sep 2017 21:45:14 +0200
9ae3a8
Subject: [PATCH 09/27] vfio: Add sysfsdev property for pci & platform
9ae3a8
9ae3a8
RH-Author: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Message-id: <20170929214514.16765.36252.stgit@gimli.home>
9ae3a8
Patchwork-id: 76768
9ae3a8
O-Subject: [RHEL-7.5 qemu-kvm PATCH 09/16] vfio: Add sysfsdev property for pci & platform
9ae3a8
Bugzilla: 1494181
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Auger Eric <eric.auger@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
Upstream: 7df9381b7aa56c897e344f3bfe43bf5848bbd3e0
9ae3a8
RHEL: Dropped platform
9ae3a8
9ae3a8
vfio-pci currently requires a host= parameter, which comes in the
9ae3a8
form of a PCI address in [domain:]<bus:slot.function> notation.  We
9ae3a8
expect to find a matching entry in sysfs for that under
9ae3a8
/sys/bus/pci/devices/.  vfio-platform takes a similar approach, but
9ae3a8
defines the host= parameter to be a string, which can be matched
9ae3a8
directly under /sys/bus/platform/devices/.  On the PCI side, we have
9ae3a8
some interest in using vfio to expose vGPU devices.  These are not
9ae3a8
actual discrete PCI devices, so they don't have a compatible host PCI
9ae3a8
bus address or a device link where QEMU wants to look for it.  There's
9ae3a8
also really no requirement that vfio can only be used to expose
9ae3a8
physical devices, a new vfio bus and iommu driver could expose a
9ae3a8
completely emulated device.  To fit within the vfio framework, it
9ae3a8
would need a kernel struct device and associated IOMMU group, but
9ae3a8
those are easy constraints to manage.
9ae3a8
9ae3a8
To support such devices, which would include vGPUs, that honor the
9ae3a8
VFIO PCI programming API, but are not necessarily backed by a unique
9ae3a8
PCI address, add support for specifying any device in sysfs.  The
9ae3a8
vfio API already has support for probing the device type to ensure
9ae3a8
compatibility with either vfio-pci or vfio-platform.
9ae3a8
9ae3a8
With this, a vfio-pci device could either be specified as:
9ae3a8
9ae3a8
-device vfio-pci,host=02:00.0
9ae3a8
9ae3a8
or
9ae3a8
9ae3a8
-device vfio-pci,sysfsdev=/sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0
9ae3a8
9ae3a8
or even
9ae3a8
9ae3a8
-device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:02:00.0
9ae3a8
9ae3a8
When vGPU support comes along, this might look something more like:
9ae3a8
9ae3a8
-device vfio-pci,sysfsdev=/sys/devices/virtual/intel-vgpu/vgpu0@0000:00:02.0
9ae3a8
9ae3a8
NB - This is only a made up example path
9ae3a8
9ae3a8
The same change is made for vfio-platform, specifying sysfsdev has
9ae3a8
precedence over the old host option.
9ae3a8
9ae3a8
Tested-by: Eric Auger <eric.auger@linaro.org>
9ae3a8
Reviewed-by: Eric Auger <eric.auger@linaro.org>
9ae3a8
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/misc/vfio.c | 131 ++++++++++++++++++++++++---------------------------------
9ae3a8
 1 file changed, 54 insertions(+), 77 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
9ae3a8
index 0d88313..64d4dc7 100644
9ae3a8
--- a/hw/misc/vfio.c
9ae3a8
+++ b/hw/misc/vfio.c
9ae3a8
@@ -187,6 +187,7 @@ typedef struct VFIODeviceOps VFIODeviceOps;
9ae3a8
 typedef struct VFIODevice {
9ae3a8
     QLIST_ENTRY(VFIODevice) next;
9ae3a8
     struct VFIOGroup *group;
9ae3a8
+    char *sysfsdev;
9ae3a8
     char *name;
9ae3a8
     int fd;
9ae3a8
     int type;
9ae3a8
@@ -1288,12 +1289,8 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
9ae3a8
     if (vdev->pdev.romfile || !vdev->pdev.rom_bar) {
9ae3a8
         /* Since pci handles romfile, just print a message and return */
9ae3a8
         if (vfio_blacklist_opt_rom(vdev) && vdev->pdev.romfile) {
9ae3a8
-            error_printf("Warning : Device at %04x:%02x:%02x.%x "
9ae3a8
-                         "is known to cause system instability issues during "
9ae3a8
-                         "option rom execution. "
9ae3a8
-                         "Proceeding anyway since user specified romfile\n",
9ae3a8
-                         vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
-                         vdev->host.function);
9ae3a8
+            error_printf("Warning : Device at %s is known to cause system instability issues during option rom execution. Proceeding anyway since user specified romfile\n",
9ae3a8
+                         vdev->vbasedev.name);
9ae3a8
         }
9ae3a8
         return;
9ae3a8
     }
9ae3a8
@@ -1306,9 +1303,7 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
9ae3a8
         pwrite(fd, &size, 4, offset) != 4 ||
9ae3a8
         pread(fd, &size, 4, offset) != 4 ||
9ae3a8
         pwrite(fd, &orig, 4, offset) != 4) {
9ae3a8
-        error_report("%s(%04x:%02x:%02x.%x) failed: %m",
9ae3a8
-                     __func__, vdev->host.domain, vdev->host.bus,
9ae3a8
-                     vdev->host.slot, vdev->host.function);
9ae3a8
+        error_report("%s(%s) failed: %m", __func__, vdev->vbasedev.name);
9ae3a8
         return;
9ae3a8
     }
9ae3a8
 
9ae3a8
@@ -1320,29 +1315,18 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
9ae3a8
 
9ae3a8
     if (vfio_blacklist_opt_rom(vdev)) {
9ae3a8
         if (dev->opts && qemu_opt_get(dev->opts, "rombar")) {
9ae3a8
-            error_printf("Warning : Device at %04x:%02x:%02x.%x "
9ae3a8
-                         "is known to cause system instability issues during "
9ae3a8
-                         "option rom execution. "
9ae3a8
-                         "Proceeding anyway since user specified non zero value for "
9ae3a8
-                         "rombar\n",
9ae3a8
-                         vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
-                         vdev->host.function);
9ae3a8
+            error_printf("Warning : Device at %s is known to cause system instability issues during option rom execution. Proceeding anyway since user specified non zero value for rombar\n",
9ae3a8
+                         vdev->vbasedev.name);
9ae3a8
         } else {
9ae3a8
-            error_printf("Warning : Rom loading for device at "
9ae3a8
-                         "%04x:%02x:%02x.%x has been disabled due to "
9ae3a8
-                         "system instability issues. "
9ae3a8
-                         "Specify rombar=1 or romfile to force\n",
9ae3a8
-                         vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
-                         vdev->host.function);
9ae3a8
+            error_printf("Warning : Rom loading for device at %s has been disabled due to system instability issues. Specify rombar=1 or romfile to force\n",
9ae3a8
+                         vdev->vbasedev.name);
9ae3a8
             return;
9ae3a8
         }
9ae3a8
     }
9ae3a8
 
9ae3a8
     DPRINTF("%s ROM size 0x%x\n", vdev->vbasedev.name, size);
9ae3a8
 
9ae3a8
-    snprintf(name, sizeof(name), "vfio[%04x:%02x:%02x.%x].rom",
9ae3a8
-             vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
-             vdev->host.function);
9ae3a8
+    snprintf(name, sizeof(name), "vfio[%s].rom", vdev->vbasedev.name);
9ae3a8
 
9ae3a8
     memory_region_init_io(&vdev->pdev.rom,
9ae3a8
                           &vfio_rom_ops, vdev, name, size);
9ae3a8
@@ -2112,9 +2096,8 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
9ae3a8
         ret = pread(vdev->vbasedev.fd, &phys_val, len,
9ae3a8
                     vdev->config_offset + addr);
9ae3a8
         if (ret != len) {
9ae3a8
-            error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",
9ae3a8
-                         __func__, vdev->host.domain, vdev->host.bus,
9ae3a8
-                         vdev->host.slot, vdev->host.function, addr, len);
9ae3a8
+            error_report("%s(%s, 0x%x, 0x%x) failed: %m",
9ae3a8
+                         __func__, vdev->vbasedev.name, addr, len);
9ae3a8
             return -errno;
9ae3a8
         }
9ae3a8
         phys_val = le32_to_cpu(phys_val);
9ae3a8
@@ -2140,9 +2123,8 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
9ae3a8
     /* Write everything to VFIO, let it filter out what we can't write */
9ae3a8
     if (pwrite(vdev->vbasedev.fd, &val_le, len, vdev->config_offset + addr)
9ae3a8
                 != len) {
9ae3a8
-        error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m",
9ae3a8
-                     __func__, vdev->host.domain, vdev->host.bus,
9ae3a8
-                     vdev->host.slot, vdev->host.function, addr, val, len);
9ae3a8
+        error_report("%s(%s, 0x%x, 0x%x, 0x%x) failed: %m",
9ae3a8
+                     __func__, vdev->vbasedev.name, addr, val, len);
9ae3a8
     }
9ae3a8
 
9ae3a8
     /* MSI/MSI-X Enabling/Disabling */
9ae3a8
@@ -2610,9 +2592,7 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr)
9ae3a8
         return;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    snprintf(name, sizeof(name), "VFIO %04x:%02x:%02x.%x BAR %d",
9ae3a8
-             vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
-             vdev->host.function, nr);
9ae3a8
+    snprintf(name, sizeof(name), "VFIO %s BAR %d", vdev->vbasedev.name, nr);
9ae3a8
 
9ae3a8
     /* Determine what type of BAR this is for registration */
9ae3a8
     ret = pread(vdev->vbasedev.fd, &pci_bar, sizeof(pci_bar),
9ae3a8
@@ -2946,9 +2926,8 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos)
9ae3a8
     }
9ae3a8
 
9ae3a8
     if (ret < 0) {
9ae3a8
-        error_report("vfio: %04x:%02x:%02x.%x Error adding PCI capability "
9ae3a8
-                     "0x%x[0x%x]@0x%x: %d", vdev->host.domain,
9ae3a8
-                     vdev->host.bus, vdev->host.slot, vdev->host.function,
9ae3a8
+        error_report("vfio: %s Error adding PCI capability "
9ae3a8
+                     "0x%x[0x%x]@0x%x: %d", vdev->vbasedev.name,
9ae3a8
                      cap_id, size, pos, ret);
9ae3a8
         return ret;
9ae3a8
     }
9ae3a8
@@ -3010,11 +2989,14 @@ static void vfio_pci_post_reset(VFIOPCIDevice *vdev)
9ae3a8
     vfio_enable_intx(vdev);
9ae3a8
 }
9ae3a8
 
9ae3a8
-static bool vfio_pci_host_match(PCIHostDeviceAddress *host1,
9ae3a8
-                                PCIHostDeviceAddress *host2)
9ae3a8
+static bool vfio_pci_host_match(PCIHostDeviceAddress *addr, const char *name)
9ae3a8
 {
9ae3a8
-    return (host1->domain == host2->domain && host1->bus == host2->bus &&
9ae3a8
-            host1->slot == host2->slot && host1->function == host2->function);
9ae3a8
+    char tmp[13];
9ae3a8
+
9ae3a8
+    sprintf(tmp, "%04x:%02x:%02x.%1x", addr->domain,
9ae3a8
+            addr->bus, addr->slot, addr->function);
9ae3a8
+
9ae3a8
+    return (strcmp(tmp, name) == 0);
9ae3a8
 }
9ae3a8
 
9ae3a8
 static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
9ae3a8
@@ -3040,9 +3022,8 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
9ae3a8
     if (ret && errno != ENOSPC) {
9ae3a8
         ret = -errno;
9ae3a8
         if (!vdev->has_pm_reset) {
9ae3a8
-            error_report("vfio: Cannot reset device %04x:%02x:%02x.%x, "
9ae3a8
-                         "no available reset mechanism.", vdev->host.domain,
9ae3a8
-                         vdev->host.bus, vdev->host.slot, vdev->host.function);
9ae3a8
+            error_report("vfio: Cannot reset device %s, "
9ae3a8
+                         "no available reset mechanism.", vdev->vbasedev.name);
9ae3a8
         }
9ae3a8
         goto out_single;
9ae3a8
     }
9ae3a8
@@ -3075,7 +3056,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
9ae3a8
         DPRINTF("\t%04x:%02x:%02x.%x group %d\n", host.domain,
9ae3a8
                 host.bus, host.slot, host.function, devices[i].group_id);
9ae3a8
 
9ae3a8
-        if (vfio_pci_host_match(&host, &vdev->host)) {
9ae3a8
+        if (vfio_pci_host_match(&host, vdev->vbasedev.name)) {
9ae3a8
             continue;
9ae3a8
         }
9ae3a8
 
9ae3a8
@@ -3101,7 +3082,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
9ae3a8
                 continue;
9ae3a8
             }
9ae3a8
             tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
9ae3a8
-            if (vfio_pci_host_match(&host, &tmp->host)) {
9ae3a8
+            if (vfio_pci_host_match(&host, tmp->vbasedev.name)) {
9ae3a8
                 if (single) {
9ae3a8
                     DPRINTF("vfio: found another in-use device "
9ae3a8
                             "%s\n", tmp->vbasedev.name);
9ae3a8
@@ -3165,7 +3146,7 @@ out:
9ae3a8
         host.slot = PCI_SLOT(devices[i].devfn);
9ae3a8
         host.function = PCI_FUNC(devices[i].devfn);
9ae3a8
 
9ae3a8
-        if (vfio_pci_host_match(&host, &vdev->host)) {
9ae3a8
+        if (vfio_pci_host_match(&host, vdev->vbasedev.name)) {
9ae3a8
             continue;
9ae3a8
         }
9ae3a8
 
9ae3a8
@@ -3184,7 +3165,7 @@ out:
9ae3a8
                 continue;
9ae3a8
             }
9ae3a8
             tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
9ae3a8
-            if (vfio_pci_host_match(&host, &tmp->host)) {
9ae3a8
+            if (vfio_pci_host_match(&host, tmp->vbasedev.name)) {
9ae3a8
                 vfio_pci_post_reset(tmp);
9ae3a8
                 break;
9ae3a8
             }
9ae3a8
@@ -3683,10 +3664,7 @@ static void vfio_err_notifier_handler(void *opaque)
9ae3a8
      * guest to contain the error.
9ae3a8
      */
9ae3a8
 
9ae3a8
-    error_report("%s(%04x:%02x:%02x.%x) Unrecoverable error detected.  "
9ae3a8
-                 "Please collect any data possible and then kill the guest",
9ae3a8
-                 __func__, vdev->host.domain, vdev->host.bus,
9ae3a8
-                 vdev->host.slot, vdev->host.function);
9ae3a8
+    error_report("%s(%s) Unrecoverable error detected. Please collect any data possible and then kill the guest", __func__, vdev->vbasedev.name);
9ae3a8
 
9ae3a8
     vm_stop(RUN_STATE_INTERNAL_ERROR);
9ae3a8
 }
9ae3a8
@@ -3867,7 +3845,7 @@ static int vfio_initfn(PCIDevice *pdev)
9ae3a8
     VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
9ae3a8
     VFIODevice *vbasedev_iter;
9ae3a8
     VFIOGroup *group;
9ae3a8
-    char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name;
9ae3a8
+    char *tmp, group_path[PATH_MAX], *group_name;
9ae3a8
     ssize_t len;
9ae3a8
     struct stat st;
9ae3a8
     int groupid;
9ae3a8
@@ -3885,36 +3863,37 @@ static int vfio_initfn(PCIDevice *pdev)
9ae3a8
         return -1;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    /* Check that the host device exists */
9ae3a8
-    snprintf(path, sizeof(path),
9ae3a8
-             "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
9ae3a8
-             vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
-             vdev->host.function);
9ae3a8
-    if (stat(path, &st) < 0) {
9ae3a8
-        error_report("vfio: error: no such host device: %s", path);
9ae3a8
+    if (!vdev->vbasedev.sysfsdev) {
9ae3a8
+        vdev->vbasedev.sysfsdev =
9ae3a8
+            g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x",
9ae3a8
+                            vdev->host.domain, vdev->host.bus,
9ae3a8
+                            vdev->host.slot, vdev->host.function);
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
9ae3a8
+        error_report("vfio: error: no such host device: %s",
9ae3a8
+                     vdev->vbasedev.sysfsdev);
9ae3a8
         return -errno;
9ae3a8
     }
9ae3a8
 
9ae3a8
+    vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev));
9ae3a8
     vdev->vbasedev.ops = &vfio_pci_ops;
9ae3a8
-
9ae3a8
     vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
9ae3a8
-    vdev->vbasedev.name = g_strdup_printf("%04x:%02x:%02x.%01x",
9ae3a8
-                                          vdev->host.domain, vdev->host.bus,
9ae3a8
-                                          vdev->host.slot, vdev->host.function);
9ae3a8
 
9ae3a8
-    strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
9ae3a8
+    tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev);
9ae3a8
+    len = readlink(tmp, group_path, sizeof(group_path));
9ae3a8
+    g_free(tmp);
9ae3a8
 
9ae3a8
-    len = readlink(path, iommu_group_path, sizeof(path));
9ae3a8
-    if (len <= 0 || len >= sizeof(path)) {
9ae3a8
+    if (len <= 0 || len >= sizeof(group_path)) {
9ae3a8
         error_report("vfio: error no iommu_group for device");
9ae3a8
         return len < 0 ? -errno : -ENAMETOOLONG;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    iommu_group_path[len] = 0;
9ae3a8
-    group_name = basename(iommu_group_path);
9ae3a8
+    group_path[len] = 0;
9ae3a8
 
9ae3a8
+    group_name = basename(group_path);
9ae3a8
     if (sscanf(group_name, "%d", &groupid) != 1) {
9ae3a8
-        error_report("vfio: error reading %s: %m", path);
9ae3a8
+        error_report("vfio: error reading %s: %m", group_path);
9ae3a8
         return -errno;
9ae3a8
     }
9ae3a8
 
9ae3a8
@@ -3926,21 +3905,18 @@ static int vfio_initfn(PCIDevice *pdev)
9ae3a8
         return -ENOENT;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    snprintf(path, sizeof(path), "%04x:%02x:%02x.%01x",
9ae3a8
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
-            vdev->host.function);
9ae3a8
-
9ae3a8
     QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
9ae3a8
         if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) {
9ae3a8
-            error_report("vfio: error: device %s is already attached", path);
9ae3a8
+            error_report("vfio: error: device %s is already attached",
9ae3a8
+                         vdev->vbasedev.name);
9ae3a8
             vfio_put_group(group);
9ae3a8
             return -EBUSY;
9ae3a8
         }
9ae3a8
     }
9ae3a8
 
9ae3a8
-    ret = vfio_get_device(group, path, vdev);
9ae3a8
+    ret = vfio_get_device(group, vdev->vbasedev.name, vdev);
9ae3a8
     if (ret) {
9ae3a8
-        error_report("vfio: failed to get device %s", path);
9ae3a8
+        error_report("vfio: failed to get device %s", vdev->vbasedev.name);
9ae3a8
         vfio_put_group(group);
9ae3a8
         return ret;
9ae3a8
     }
9ae3a8
@@ -4086,6 +4062,7 @@ post_reset:
9ae3a8
 
9ae3a8
 static Property vfio_pci_dev_properties[] = {
9ae3a8
     DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host),
9ae3a8
+    DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev),
9ae3a8
     DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice,
9ae3a8
                        intx.mmap_timeout, 1100),
9ae3a8
     DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features,
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8