The parent device needs to report the generic stuff about the supported
mediated devices types, like device API, available instances, and
description which might hold some useful data about supported
resolutions for the type given, framebuffer size, etc. Unfortunately,
these are not standardized yet to be considered for separate elements.
Signed-off-by: Erik Skultety <eskultet(a)redhat.com>
---
src/conf/node_device_conf.h | 2 +
src/node_device/node_device_udev.c | 115 +++++++++++++++++++++++++++++++++++++
2 files changed, 117 insertions(+)
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index b7db35dd50..d521dd9a4c 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -166,6 +166,8 @@ struct _virNodeDevCapPCIDev {
int numa_node;
virPCIEDeviceInfoPtr pci_express;
int hdrType; /* enum virPCIHeaderType or -1 */
+ virNodeDevCapMdevPtr *mdevs;
+ size_t nmdevs;
};
typedef struct _virNodeDevCapUSBDev virNodeDevCapUSBDev;
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index dbbd8e5d06..be031fa5a8 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -324,6 +324,115 @@ udevTranslatePCIIds(unsigned int vendor,
return 0;
}
+#define MDEV_GET_SYSFS_ATTR(attr, cb, ...) \
+ do { \
+ if (virAsprintf(&attrpath, "%s/%s", relpath, #attr) < 0)
\
+ goto cleanup; \
+ \
+ if (cb(device, attrpath, __VA_ARGS__) < 0) \
+ goto cleanup; \
+ } while (0) \
+
+
+static int
+udevGetMdevCaps(struct udev_device *device,
+ const char *sysfspath,
+ virNodeDevCapMdevPtr mdev)
+{
+ int ret = -1;
+ char *attrpath = NULL; /* relative path to the actual sysfs attribute */
+ const char *devpath = NULL; /* base sysfs path as reported by udev */
+ const char *relpath = NULL; /* diff between @sysfspath and @devpath */
+ char *tmp = NULL;
+
+
+ /* UDEV doesn't report attributes under subdirectories but can query them
+ * if specified as relative paths to the device's base path,
+ * e.g. /sys/devices/../0000:00:01.0/ is the device's base path as udev
+ * reports it, but we're interested in attributes under
+ * /sys/devices/../0000:00:01.0/mdev_supported_types/<type>/. So, let's
+ * strip the common part of the path and let udev chew the relative bit.
+ */
+ devpath = udev_device_get_syspath(device);
+ relpath = sysfspath + strlen(devpath);
+
+ /* When calling from the mdev child device, @sysfspath is a symbolic link
+ * to the actual mdev type (rather than a physical path), so we need to
+ * resolve it in order to get the type's name.
+ */
+ if (virFileResolveLink(sysfspath, &tmp) < 0)
+ goto cleanup;
+
+ if (VIR_STRDUP(mdev->type, last_component(tmp)) < 0)
+ goto cleanup;
+
+ MDEV_GET_SYSFS_ATTR(name, udevGetStringSysfsAttr,
+ &mdev->name);
+ MDEV_GET_SYSFS_ATTR(description, udevGetStringSysfsAttr,
+ &mdev->description);
+ MDEV_GET_SYSFS_ATTR(device_api, udevGetStringSysfsAttr,
+ &mdev->device_api);
+ MDEV_GET_SYSFS_ATTR(available_instances, udevGetUintSysfsAttr,
+ &mdev->available_instances, 10);
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(attrpath);
+ VIR_FREE(tmp);
+ return ret;
+}
+#undef MDEV_GET_SYSFS_ATTR
+
+
+static int
+udevPCIGetMdevCaps(struct udev_device *device,
+ virNodeDevCapPCIDevPtr pcidata)
+{
+ int ret = -1;
+ DIR *dir = NULL;
+ struct dirent *entry;
+ char *path = NULL;
+ char *tmppath = NULL;
+ virNodeDevCapMdevPtr mdev = NULL;
+
+ if (virAsprintf(&path, "%s/mdev_supported_types",
+ udev_device_get_syspath(device)) < 0)
+ return -1;
+
+ if ((ret = virDirOpenIfExists(&dir, path)) <= 0)
+ goto cleanup;
+
+ if (VIR_ALLOC(pcidata->mdevs) < 0)
+ goto cleanup;
+
+ /* since udev doesn't provide means to list other than top-level
+ * attributes, we need to scan the subdirectories ourselves
+ */
+ while ((ret = virDirRead(dir, &entry, path)) > 0) {
+ if (VIR_ALLOC(mdev) < 0)
+ goto cleanup;
+
+ if (virAsprintf(&tmppath, "%s/%s", path, entry->d_name) < 0)
+ goto cleanup;
+
+ if (udevGetMdevCaps(device, tmppath, mdev) < 0)
+ goto cleanup;
+
+ if (VIR_APPEND_ELEMENT(pcidata->mdevs, pcidata->nmdevs, mdev) < 0)
+ goto cleanup;
+
+ VIR_FREE(tmppath);
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_DIR_CLOSE(dir);
+ VIR_FREE(path);
+ VIR_FREE(tmppath);
+ virNodeDevCapMdevFree(mdev);
+ return ret;
+}
+
static int
udevProcessPCI(struct udev_device *device,
@@ -412,6 +521,12 @@ udevProcessPCI(struct udev_device *device,
}
}
+ /* check whether the device is mediated devices framework capable, if so,
+ * process it
+ */
+ if (udevPCIGetMdevCaps(device, pci_dev) < 0)
+ goto cleanup;
+
ret = 0;
cleanup:
--
2.12.2