[RFC,v2,5/5] bus/pci: add mdev support
diff mbox series

Message ID 20190715075214.16616-6-tiwei.bie@intel.com
State New
Delegated to: Thomas Monjalon
Headers show
Series
  • Add mdev (Mediated device) support in DPDK
Related show

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail Compilation issues

Commit Message

Tiwei Bie July 15, 2019, 7:52 a.m. UTC
This patch adds the mdev (Mediated device) support in PCI bus
driver. With this patch, the PCI bus driver will be able to scan
and probe the mediated PCI devices (i.e. the Mediated devices
whose device API is "vfio-pci") in the system.

There are several things different between physical PCI devices
and mediated PCI devices:

- Mediated PCI devices have to be accessed through VFIO API;
- The regions in mediated PCI devices may not be mmap-able,
  and drivers need to call read/write function to access them
  in this case;
- Mediated PCI devices use UUID as device address;

Signed-off-by: Cunming Liang <cunming.liang@intel.com>
Signed-off-by: Tiwei Bie <tiwei.bie@intel.com>
---
 drivers/bus/pci/linux/Makefile        |   1 +
 drivers/bus/pci/linux/pci.c           |  30 +++-
 drivers/bus/pci/linux/pci_init.h      |  15 +-
 drivers/bus/pci/linux/pci_vfio.c      | 104 ++++++++++--
 drivers/bus/pci/linux/pci_vfio_mdev.c | 236 ++++++++++++++++++++++++++
 drivers/bus/pci/meson.build           |   3 +-
 drivers/bus/pci/pci_common.c          |  29 ++--
 drivers/bus/pci/rte_bus_pci.h         |  17 +-
 lib/librte_eal/linux/eal/eal.c        |  17 +-
 9 files changed, 404 insertions(+), 48 deletions(-)
 create mode 100644 drivers/bus/pci/linux/pci_vfio_mdev.c

Patch
diff mbox series

diff --git a/drivers/bus/pci/linux/Makefile b/drivers/bus/pci/linux/Makefile
index 90404468b..c17ab2484 100644
--- a/drivers/bus/pci/linux/Makefile
+++ b/drivers/bus/pci/linux/Makefile
@@ -4,3 +4,4 @@ 
 SRCS += pci.c
 SRCS += pci_uio.c
 SRCS += pci_vfio.c
+SRCS += pci_vfio_mdev.c
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index bdfc8c5ff..5be898803 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -31,7 +31,7 @@ 
 
 extern struct rte_pci_bus rte_pci_bus;
 
-static int
+int
 pci_get_kernel_driver_by_path(const char *filename, char *dri_name,
 			      size_t len)
 {
@@ -71,7 +71,7 @@  rte_pci_map_device(struct rte_pci_device *dev)
 	switch (dev->kdrv) {
 	case RTE_KDRV_VFIO:
 #ifdef VFIO_PRESENT
-		if (pci_vfio_is_enabled())
+		if (pci_vfio_is_enabled(dev))
 			ret = pci_vfio_map_resource(dev);
 #endif
 		break;
@@ -100,7 +100,7 @@  rte_pci_unmap_device(struct rte_pci_device *dev)
 	switch (dev->kdrv) {
 	case RTE_KDRV_VFIO:
 #ifdef VFIO_PRESENT
-		if (pci_vfio_is_enabled())
+		if (pci_vfio_is_enabled(dev))
 			pci_vfio_unmap_resource(dev);
 #endif
 		break;
@@ -348,6 +348,15 @@  pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 		int ret;
 
 		TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) {
+			/*
+			 * Insert physical PCI devices before all mediated
+			 * PCI devices.
+			 */
+			if (dev2->is_mdev) {
+				rte_pci_insert_device(dev2, dev);
+				return 0;
+			}
+
 			ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr);
 			if (ret > 0)
 				continue;
@@ -471,8 +480,14 @@  rte_pci_scan(void)
 		return 0;
 
 #ifdef VFIO_PRESENT
-	if (!pci_vfio_is_enabled())
-		RTE_LOG(DEBUG, EAL, "VFIO PCI modules not loaded\n");
+	if (!rte_vfio_is_enabled("vfio_pci"))
+		RTE_LOG(DEBUG, EAL, "VFIO PCI module not loaded\n");
+
+	if (!rte_vfio_is_enabled("vfio_mdev"))
+		RTE_LOG(DEBUG, EAL, "VFIO MDEV module not loaded\n");
+
+	if (pci_scan_mdev() != 0)
+		return -1;
 #endif
 
 	dir = opendir(rte_pci_get_sysfs_path());
@@ -788,7 +803,7 @@  rte_pci_ioport_map(struct rte_pci_device *dev, int bar,
 	switch (dev->kdrv) {
 #ifdef VFIO_PRESENT
 	case RTE_KDRV_VFIO:
-		if (pci_vfio_is_enabled())
+		if (pci_vfio_is_enabled(dev))
 			ret = pci_vfio_ioport_map(dev, bar, p);
 		break;
 #endif
@@ -877,8 +892,7 @@  rte_pci_ioport_unmap(struct rte_pci_ioport *p)
 	switch (p->dev->kdrv) {
 #ifdef VFIO_PRESENT
 	case RTE_KDRV_VFIO:
-		if (pci_vfio_is_enabled())
-			ret = pci_vfio_ioport_unmap(p);
+		ret = -1;
 		break;
 #endif
 	case RTE_KDRV_IGB_UIO:
diff --git a/drivers/bus/pci/linux/pci_init.h b/drivers/bus/pci/linux/pci_init.h
index 158a16977..12739ba51 100644
--- a/drivers/bus/pci/linux/pci_init.h
+++ b/drivers/bus/pci/linux/pci_init.h
@@ -17,6 +17,9 @@ 
 extern void *pci_map_addr;
 void *pci_find_max_end_va(void);
 
+int pci_get_kernel_driver_by_path(const char *filename, char *dri_name,
+				  size_t len);
+
 /* parse one line of the "resource" sysfs file (note that the 'line'
  * string is modified)
  */
@@ -91,7 +94,17 @@  int pci_vfio_ioport_unmap(struct rte_pci_ioport *p);
 int pci_vfio_map_resource(struct rte_pci_device *dev);
 int pci_vfio_unmap_resource(struct rte_pci_device *dev);
 
-int pci_vfio_is_enabled(void);
+int pci_vfio_is_enabled(struct rte_pci_device *dev);
+
+int pci_vfio_fill_regions(struct rte_pci_device *dev, int vfio_dev_fd,
+			  struct vfio_device_info *device_info);
+
+int pci_vfio_get_pci_id(struct rte_pci_device *dev, int vfio_dev_fd,
+			struct rte_pci_id *pci_id);
+
+const char *pci_mdev_get_sysfs_path(void);
+
+int pci_scan_mdev(void);
 
 #endif
 
diff --git a/drivers/bus/pci/linux/pci_vfio.c b/drivers/bus/pci/linux/pci_vfio.c
index 204698be0..7cea57ff9 100644
--- a/drivers/bus/pci/linux/pci_vfio.c
+++ b/drivers/bus/pci/linux/pci_vfio.c
@@ -21,6 +21,7 @@ 
 #include <rte_bus.h>
 #include <rte_spinlock.h>
 #include <rte_tailq.h>
+#include <rte_uuid.h>
 
 #include "eal_filesystem.h"
 
@@ -696,7 +697,7 @@  pci_vfio_msix_is_mappable(int vfio_dev_fd, int msix_region)
 	return ret;
 }
 
-static int
+int
 pci_vfio_fill_regions(struct rte_pci_device *dev, int vfio_dev_fd,
 		      struct vfio_device_info *device_info)
 {
@@ -731,6 +732,7 @@  pci_vfio_map_resource_primary(struct rte_pci_device *dev)
 	struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
 	struct vfio_region_info *reg = NULL;
 	char pci_addr[PATH_MAX] = {0};
+	const char *sysfs_base;
 	int vfio_dev_fd;
 	struct rte_pci_addr *loc = &dev->addr;
 	int i, ret;
@@ -746,10 +748,16 @@  pci_vfio_map_resource_primary(struct rte_pci_device *dev)
 #endif
 
 	/* store PCI address string */
-	snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
+	if (dev->is_mdev) {
+		sysfs_base = pci_mdev_get_sysfs_path();
+		rte_uuid_unparse(dev->uuid, pci_addr, sizeof(pci_addr));
+	} else {
+		sysfs_base = rte_pci_get_sysfs_path();
+		snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
 			loc->domain, loc->bus, loc->devid, loc->function);
+	}
 
-	ret = rte_vfio_setup_device(rte_pci_get_sysfs_path(), pci_addr,
+	ret = rte_vfio_setup_device(sysfs_base, pci_addr,
 					&vfio_dev_fd, &device_info);
 	if (ret)
 		return ret;
@@ -889,6 +897,7 @@  pci_vfio_map_resource_secondary(struct rte_pci_device *dev)
 {
 	struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
 	char pci_addr[PATH_MAX] = {0};
+	const char *sysfs_base;
 	int vfio_dev_fd;
 	struct rte_pci_addr *loc = &dev->addr;
 	int i, ret;
@@ -904,8 +913,14 @@  pci_vfio_map_resource_secondary(struct rte_pci_device *dev)
 #endif
 
 	/* store PCI address string */
-	snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
+	if (dev->is_mdev) {
+		sysfs_base = pci_mdev_get_sysfs_path();
+		rte_uuid_unparse(dev->uuid, pci_addr, sizeof(pci_addr));
+	} else {
+		sysfs_base = rte_pci_get_sysfs_path();
+		snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
 			loc->domain, loc->bus, loc->devid, loc->function);
+	}
 
 	/* if we're in a secondary process, just find our tailq entry */
 	TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
@@ -921,7 +936,7 @@  pci_vfio_map_resource_secondary(struct rte_pci_device *dev)
 		return -1;
 	}
 
-	ret = rte_vfio_setup_device(rte_pci_get_sysfs_path(), pci_addr,
+	ret = rte_vfio_setup_device(sysfs_base, pci_addr,
 					&vfio_dev_fd, &device_info);
 	if (ret)
 		return ret;
@@ -1011,6 +1026,7 @@  find_and_unmap_vfio_resource(struct mapped_pci_res_list *vfio_res_list,
 static int
 pci_vfio_unmap_resource_primary(struct rte_pci_device *dev)
 {
+	const char *sysfs_base;
 	char pci_addr[PATH_MAX] = {0};
 	struct rte_pci_addr *loc = &dev->addr;
 	struct mapped_pci_resource *vfio_res = NULL;
@@ -1018,8 +1034,14 @@  pci_vfio_unmap_resource_primary(struct rte_pci_device *dev)
 	int ret;
 
 	/* store PCI address string */
-	snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
+	if (dev->is_mdev) {
+		sysfs_base = pci_mdev_get_sysfs_path();
+		rte_uuid_unparse(dev->uuid, pci_addr, sizeof(pci_addr));
+	} else {
+		sysfs_base = rte_pci_get_sysfs_path();
+		snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
 			loc->domain, loc->bus, loc->devid, loc->function);
+	}
 
 #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
 	ret = pci_vfio_disable_notifier(dev);
@@ -1041,7 +1063,7 @@  pci_vfio_unmap_resource_primary(struct rte_pci_device *dev)
 		return -1;
 	}
 
-	ret = rte_vfio_release_device(rte_pci_get_sysfs_path(), pci_addr,
+	ret = rte_vfio_release_device(sysfs_base, pci_addr,
 				  dev->intr_handle.vfio_dev_fd);
 	if (ret < 0) {
 		RTE_LOG(ERR, EAL,
@@ -1068,6 +1090,7 @@  pci_vfio_unmap_resource_primary(struct rte_pci_device *dev)
 static int
 pci_vfio_unmap_resource_secondary(struct rte_pci_device *dev)
 {
+	const char *sysfs_base;
 	char pci_addr[PATH_MAX] = {0};
 	struct rte_pci_addr *loc = &dev->addr;
 	struct mapped_pci_resource *vfio_res = NULL;
@@ -1075,10 +1098,16 @@  pci_vfio_unmap_resource_secondary(struct rte_pci_device *dev)
 	int ret;
 
 	/* store PCI address string */
-	snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
+	if (dev->is_mdev) {
+		sysfs_base = pci_mdev_get_sysfs_path();
+		rte_uuid_unparse(dev->uuid, pci_addr, sizeof(pci_addr));
+	} else {
+		sysfs_base = rte_pci_get_sysfs_path();
+		snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
 			loc->domain, loc->bus, loc->devid, loc->function);
+	}
 
-	ret = rte_vfio_release_device(rte_pci_get_sysfs_path(), pci_addr,
+	ret = rte_vfio_release_device(sysfs_base, pci_addr,
 				  dev->intr_handle.vfio_dev_fd);
 	if (ret < 0) {
 		RTE_LOG(ERR, EAL,
@@ -1201,8 +1230,61 @@  pci_vfio_mmio_write(const struct rte_pci_device *dev, int bar,
 }
 
 int
-pci_vfio_is_enabled(void)
+pci_vfio_is_enabled(struct rte_pci_device *dev)
 {
-	return rte_vfio_is_enabled("vfio_pci");
+	return rte_vfio_is_enabled(dev->is_mdev ? "vfio_mdev" : "vfio_pci");
 }
+
+int
+pci_vfio_get_pci_id(struct rte_pci_device *dev, int vfio_dev_fd,
+		    struct rte_pci_id *pci_id)
+{
+	uint64_t size, offset;
+	int class;
+
+	if (pci_vfio_get_region(dev, VFIO_PCI_CONFIG_REGION_INDEX,
+				&size, &offset) != 0) {
+		RTE_LOG(DEBUG, EAL, "Cannot get offset of CONFIG region.\n");
+		return -1;
+	}
+
+	/* vendor_id */
+	if (pread64(vfio_dev_fd, &pci_id->vendor_id, sizeof(uint16_t),
+		    offset + PCI_VENDOR_ID) != sizeof(uint16_t)) {
+		RTE_LOG(DEBUG, EAL, "Cannot read VendorID from PCI config space\n");
+		return -1;
+	}
+
+	/* device_id */
+	if (pread64(vfio_dev_fd, &pci_id->device_id, sizeof(uint16_t),
+		    offset + PCI_DEVICE_ID) != sizeof(uint16_t)) {
+		RTE_LOG(DEBUG, EAL, "Cannot read DeviceID from PCI config space\n");
+		return -1;
+	}
+
+	/* subsystem_vendor_id */
+	if (pread64(vfio_dev_fd, &pci_id->subsystem_vendor_id, sizeof(uint16_t),
+		    offset + PCI_SUBSYSTEM_VENDOR_ID) != sizeof(uint16_t)) {
+		RTE_LOG(DEBUG, EAL, "Cannot read SubVendorID from PCI config space\n");
+		return -1;
+	}
+
+	/* subsystem_device_id */
+	if (pread64(vfio_dev_fd, &pci_id->subsystem_device_id, sizeof(uint16_t),
+		    offset + PCI_SUBSYSTEM_ID) != sizeof(uint16_t)) {
+		RTE_LOG(DEBUG, EAL, "Cannot read SubDeviceID from PCI config space\n");
+		return -1;
+	}
+
+	/* class_id */
+	if (pread64(vfio_dev_fd, &class, sizeof(uint32_t),
+		    offset + PCI_CLASS_REVISION) != sizeof(uint32_t)) {
+		RTE_LOG(DEBUG, EAL, "Cannot read ClassID from PCI config space\n");
+		return -1;
+	}
+	pci_id->class_id = class >> 8;
+
+	return 0;
+}
+
 #endif
diff --git a/drivers/bus/pci/linux/pci_vfio_mdev.c b/drivers/bus/pci/linux/pci_vfio_mdev.c
new file mode 100644
index 000000000..dab7e9b35
--- /dev/null
+++ b/drivers/bus/pci/linux/pci_vfio_mdev.c
@@ -0,0 +1,236 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/pci_regs.h>
+
+#include <rte_log.h>
+#include <rte_pci.h>
+#include <rte_eal_memconfig.h>
+#include <rte_malloc.h>
+#include <rte_devargs.h>
+#include <rte_memcpy.h>
+#include <rte_vfio.h>
+#include <rte_uuid.h>
+
+#include "eal_private.h"
+#include "eal_filesystem.h"
+
+#include "private.h"
+#include "pci_init.h"
+
+#ifdef VFIO_PRESENT
+
+extern struct rte_pci_bus rte_pci_bus;
+
+#define SYSFS_MDEV_DEVICES "/sys/bus/mdev/devices"
+
+const char *pci_mdev_get_sysfs_path(void)
+{
+	const char *path = NULL;
+
+	path = getenv("SYSFS_MDEV_DEVICES");
+	if (path == NULL)
+		return SYSFS_MDEV_DEVICES;
+
+	return path;
+}
+
+static int
+is_pci_device(const char *dirname)
+{
+	char device_api[PATH_MAX];
+	char filename[PATH_MAX];
+	char *ptr;
+
+	/* get device_api */
+	snprintf(filename, sizeof(filename), "%s/mdev_type/device_api",
+		 dirname);
+
+	if (rte_eal_parse_sysfs_str(filename, device_api,
+				    sizeof(device_api)) < 0) {
+		return -1;
+	}
+
+	ptr = strchr(device_api, '\n');
+	if (ptr != NULL)
+		*ptr = '\0';
+
+	return strcmp(device_api, "vfio-pci") == 0;
+}
+
+static int
+pci_scan_one_mdev(const char *dirname, const rte_uuid_t addr)
+{
+	struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
+	char name[RTE_UUID_STRLEN];
+	char filename[PATH_MAX];
+	char path[PATH_MAX];
+	char driver[PATH_MAX];
+	char *ptr;
+	struct rte_pci_device_internal *pdev;
+	struct rte_pci_device *dev;
+	bool need_release = false;
+	const char *sysfs_base;
+	unsigned long tmp;
+	int vfio_dev_fd;
+	int ret;
+
+	sysfs_base = pci_mdev_get_sysfs_path();
+
+	pdev = malloc(sizeof(*pdev));
+	if (pdev == NULL)
+		return -1;
+
+	memset(pdev, 0, sizeof(*pdev));
+
+	dev = &pdev->device;
+	dev->device.bus = &rte_pci_bus.bus;
+	rte_uuid_unparse(addr, name, sizeof(name));
+
+	/* parse driver */
+	snprintf(filename, sizeof(filename), "%s/driver", dirname);
+	ret = pci_get_kernel_driver_by_path(filename, driver, sizeof(driver));
+	if (ret < 0) {
+		RTE_LOG(DEBUG, EAL, "%s: failed to get kernel driver\n", name);
+		goto err;
+	}
+
+	if (ret != 0 || strcmp(driver, "vfio_mdev") != 0) {
+		RTE_LOG(DEBUG, EAL, "%s: unsupported mdev driver\n", name);
+		goto err;
+	}
+
+	dev->kdrv = RTE_KDRV_VFIO;
+
+	dev->is_mdev = 1;
+	rte_uuid_copy(dev->uuid, addr);
+
+	snprintf(filename, sizeof(filename), "%s/%s", sysfs_base, name);
+
+	/* Get the path of the parent device. */
+	if (realpath(filename, path) == NULL) {
+		RTE_LOG(DEBUG, EAL, "%s: failed to get parent device\n", name);
+		goto err;
+	}
+
+	ptr = strrchr(path, '/');
+	if (ptr == NULL) {
+		RTE_LOG(DEBUG, EAL, "%s: failed to parse parent device\n",
+			name);
+		goto err;
+	}
+	*ptr = '\0';
+
+	/* get numa node, default to 0 if not present */
+	snprintf(filename, sizeof(filename), "%s/numa_node", path);
+
+	if (access(filename, F_OK) != -1) {
+		if (eal_parse_sysfs_value(filename, &tmp) == 0)
+			dev->device.numa_node = tmp;
+		else
+			dev->device.numa_node = -1;
+	} else {
+		dev->device.numa_node = 0;
+	}
+
+	pci_name_set(dev);
+
+	if (rte_vfio_setup_device(sysfs_base, name, &vfio_dev_fd,
+				  &device_info) != 0) {
+		RTE_LOG(DEBUG, EAL, "%s: failed to setup device\n", name);
+		goto err;
+	}
+
+	need_release = true;
+
+	if (pci_vfio_fill_regions(dev, vfio_dev_fd, &device_info) != 0) {
+		RTE_LOG(DEBUG, EAL, "%s: failed to get regions\n", name);
+		goto err;
+	}
+
+	if (pci_vfio_get_pci_id(dev, vfio_dev_fd, &dev->id) != 0) {
+		RTE_LOG(DEBUG, EAL, "%s: failed to access the device\n", name);
+		goto err;
+	}
+
+	/* device is valid, add to the list (sorted) */
+	if (TAILQ_EMPTY(&rte_pci_bus.device_list)) {
+		rte_pci_add_device(dev);
+	} else {
+		struct rte_pci_device *dev2;
+		int ret;
+
+		TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) {
+			/*
+			 * Insert mediated PCI devices after all physical
+			 * PCI devices.
+			 */
+			if (!dev2->is_mdev)
+				continue;
+			ret = rte_uuid_compare(dev->uuid, dev2->uuid);
+			if (ret > 0)
+				continue;
+			if (ret < 0)
+				rte_pci_insert_device(dev2, dev);
+			else /* already registered */
+				free(pdev);
+			return 0;
+		}
+
+		rte_pci_add_device(dev);
+	}
+
+	return 0;
+
+err:
+	if (need_release)
+		rte_vfio_release_device(sysfs_base, name, vfio_dev_fd);
+	free(pdev);
+	return 1;
+}
+
+int
+pci_scan_mdev(void)
+{
+	struct dirent *e;
+	DIR *dir;
+	char dirname[PATH_MAX];
+	rte_uuid_t addr;
+
+	dir = opendir(pci_mdev_get_sysfs_path());
+	if (dir == NULL) {
+		RTE_LOG(DEBUG, EAL, "%s(): opendir failed: %s\n",
+			__func__, strerror(errno));
+		return 0;
+	}
+
+	while ((e = readdir(dir)) != NULL) {
+		if (e->d_name[0] == '.')
+			continue;
+
+		if (rte_uuid_parse(e->d_name, addr) != 0)
+			continue;
+
+		snprintf(dirname, sizeof(dirname), "%s/%s",
+			 pci_mdev_get_sysfs_path(), e->d_name);
+
+		if (!is_pci_device(dirname))
+			continue;
+
+		if (pci_scan_one_mdev(dirname, addr) < 0)
+			goto error;
+	}
+	closedir(dir);
+	return 0;
+
+error:
+	closedir(dir);
+	return -1;
+}
+
+#endif /* VFIO_PRESENT */
diff --git a/drivers/bus/pci/meson.build b/drivers/bus/pci/meson.build
index a312ecc03..890b7bda0 100644
--- a/drivers/bus/pci/meson.build
+++ b/drivers/bus/pci/meson.build
@@ -11,7 +11,8 @@  sources = files('pci_common.c',
 if is_linux
 	sources += files('linux/pci.c',
 			'linux/pci_uio.c',
-			'linux/pci_vfio.c')
+			'linux/pci_vfio.c',
+			'linux/pci_vfio_mdev.c')
 	includes += include_directories('linux')
 else
 	sources += files('bsd/pci.c')
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 8b9deca8b..ec314cb07 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -25,6 +25,7 @@ 
 #include <rte_common.h>
 #include <rte_devargs.h>
 #include <rte_vfio.h>
+#include <rte_uuid.h>
 
 #include "private.h"
 
@@ -61,8 +62,10 @@  pci_name_set(struct rte_pci_device *dev)
 	struct rte_devargs *devargs;
 
 	/* Each device has its internal, canonical name set. */
-	rte_pci_device_name(&dev->addr,
-			dev->name, sizeof(dev->name));
+	if (dev->is_mdev)
+		rte_uuid_unparse(dev->uuid, dev->name, sizeof(dev->name));
+	else
+		rte_pci_device_name(&dev->addr, dev->name, sizeof(dev->name));
 	devargs = pci_devargs_lookup(dev);
 	dev->device.devargs = devargs;
 	/* In blacklist mode, if the device is not blacklisted, no
@@ -124,21 +127,17 @@  rte_pci_probe_one_driver(struct rte_pci_driver *dr,
 {
 	int ret;
 	bool already_probed;
-	struct rte_pci_addr *loc;
 
 	if ((dr == NULL) || (dev == NULL))
 		return -EINVAL;
 
-	loc = &dev->addr;
-
 	/* The device is not blacklisted; Check if driver supports it */
 	if (!rte_pci_match(dr, dev))
 		/* Match of device and driver failed */
 		return 1;
 
-	RTE_LOG(INFO, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
-			loc->domain, loc->bus, loc->devid, loc->function,
-			dev->device.numa_node);
+	RTE_LOG(INFO, EAL, "PCI device %s on NUMA socket %i\n",
+		dev->name, dev->device.numa_node);
 
 	/* no initialization when blacklisted, return without error */
 	if (dev->device.devargs != NULL &&
@@ -208,7 +207,6 @@  rte_pci_probe_one_driver(struct rte_pci_driver *dr,
 static int
 rte_pci_detach_dev(struct rte_pci_device *dev)
 {
-	struct rte_pci_addr *loc;
 	struct rte_pci_driver *dr;
 	int ret = 0;
 
@@ -216,11 +214,9 @@  rte_pci_detach_dev(struct rte_pci_device *dev)
 		return -EINVAL;
 
 	dr = dev->driver;
-	loc = &dev->addr;
 
-	RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
-			loc->domain, loc->bus, loc->devid,
-			loc->function, dev->device.numa_node);
+	RTE_LOG(DEBUG, EAL, "PCI device %s on NUMA socket %i\n",
+		dev->name, dev->device.numa_node);
 
 	RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n", dev->id.vendor_id,
 			dev->id.device_id, dr->driver.name);
@@ -297,10 +293,9 @@  rte_pci_probe(void)
 			ret = pci_probe_all_drivers(dev);
 		if (ret < 0) {
 			if (ret != -EEXIST) {
-				RTE_LOG(ERR, EAL, "Requested device "
-					PCI_PRI_FMT " cannot be used\n",
-					dev->addr.domain, dev->addr.bus,
-					dev->addr.devid, dev->addr.function);
+				RTE_LOG(ERR, EAL,
+					"Requested device %s cannot be used\n",
+					dev->name);
 				rte_errno = errno;
 				failed++;
 			}
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 86527b421..47e669e9c 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -51,13 +51,26 @@  TAILQ_HEAD(rte_pci_driver_list, rte_pci_driver);
 
 struct rte_devargs;
 
+/*
+ * NOTE: we can't include rte_uuid.h directly due to the conflicts
+ *      introduced by stdbool.h
+ */
+typedef unsigned char rte_uuid_t[16];
+
+/* It's RTE_UUID_STRLEN, which is bigger than PCI_PRI_STR_SIZE. */
+#define RTE_PCI_NAME_LEN		(36 + 1)
+
 /**
  * A structure describing a PCI device.
  */
 struct rte_pci_device {
 	TAILQ_ENTRY(rte_pci_device) next;   /**< Next probed PCI device. */
 	struct rte_device device;           /**< Inherit core device */
-	struct rte_pci_addr addr;           /**< PCI location. */
+	union {
+		struct rte_pci_addr addr;   /**< PCI location. */
+		rte_uuid_t uuid;            /**< Mdev location. */
+	};
+	uint8_t is_mdev;                    /**< True for mediated PCI device */
 	struct rte_pci_id id;               /**< PCI ID. */
 	struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE];
 					    /**< PCI Memory Resource */
@@ -65,7 +78,7 @@  struct rte_pci_device {
 	struct rte_pci_driver *driver;      /**< PCI driver used in probing */
 	uint16_t max_vfs;                   /**< sriov enable if not zero */
 	enum rte_kernel_driver kdrv;        /**< Kernel driver passthrough */
-	char name[PCI_PRI_STR_SIZE+1];      /**< PCI location (ASCII) */
+	char name[RTE_PCI_NAME_LEN];        /**< PCI/Mdev location (ASCII) */
 	struct rte_intr_handle vfio_req_intr_handle;
 				/**< Handler of VFIO request interrupt */
 };
diff --git a/lib/librte_eal/linux/eal/eal.c b/lib/librte_eal/linux/eal/eal.c
index 44bad45d3..942148180 100644
--- a/lib/librte_eal/linux/eal/eal.c
+++ b/lib/librte_eal/linux/eal/eal.c
@@ -1068,6 +1068,15 @@  rte_eal_init(int argc, char **argv)
 		return -1;
 	}
 
+#ifdef VFIO_PRESENT
+	if (rte_eal_vfio_setup() < 0) {
+		rte_eal_init_alert("Cannot init VFIO");
+		rte_errno = EAGAIN;
+		rte_atomic32_clear(&run_once);
+		return -1;
+	}
+#endif
+
 	if (rte_bus_scan()) {
 		rte_eal_init_alert("Cannot scan the buses for devices");
 		rte_errno = ENODEV;
@@ -1151,14 +1160,6 @@  rte_eal_init(int argc, char **argv)
 		return -1;
 	}
 
-#ifdef VFIO_PRESENT
-	if (rte_eal_vfio_setup() < 0) {
-		rte_eal_init_alert("Cannot init VFIO");
-		rte_errno = EAGAIN;
-		rte_atomic32_clear(&run_once);
-		return -1;
-	}
-#endif
 	/* in secondary processes, memory init may allocate additional fbarrays
 	 * not present in primary processes, so to avoid any potential issues,
 	 * initialize memzones first.