}
 
 struct ibv_device *
-mlx5_os_get_ibv_device(struct rte_pci_addr *addr)
+mlx5_os_get_ibv_device(const struct rte_pci_addr *addr)
 {
        int n;
        struct ibv_device **ibv_list = mlx5_glue->get_device_list(&n);
 
 
 __rte_internal
 struct ibv_device *
-mlx5_os_get_ibv_device(struct rte_pci_addr *addr);
+mlx5_os_get_ibv_device(const struct rte_pci_addr *addr);
+
+__rte_internal
+struct ibv_device *
+mlx5_os_get_ibv_dev(const struct rte_device *dev);
 
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
 
 #include <sys/mman.h>
 #include <inttypes.h>
 
+#include <rte_errno.h>
+#include <rte_bus_pci.h>
+
+#include "mlx5_common_utils.h"
+#include "mlx5_common_log.h"
+#include "mlx5_common_private.h"
 #include "mlx5_autoconf.h"
 #include <mlx5_glue.h>
 #include <mlx5_common.h>
 #include <mlx5_common_mr.h>
 
+struct ibv_device *
+mlx5_os_get_ibv_dev(const struct rte_device *dev)
+{
+       struct ibv_device *ibv = NULL;
+
+       if (mlx5_dev_is_pci(dev))
+               ibv = mlx5_os_get_ibv_device(&RTE_DEV_TO_PCI_CONST(dev)->addr);
+       if (ibv == NULL) {
+               rte_errno = ENODEV;
+               DRV_LOG(ERR, "Verbs device not found: %s", dev->name);
+       }
+       return ibv;
+}
+
 /**
  * Register mr. Given protection domain pointer, pointer to addr and length
  * register the memory region.
                memset(pmd_mr, 0, sizeof(*pmd_mr));
        }
 }
-
 
 
 #include <rte_errno.h>
 #include <rte_mempool.h>
+#include <rte_class.h>
+#include <rte_malloc.h>
 
 #include "mlx5_common.h"
 #include "mlx5_common_os.h"
 #include "mlx5_common_log.h"
 #include "mlx5_common_pci.h"
+#include "mlx5_common_private.h"
 
 uint8_t haswell_broadwell_cpu;
 
 
 RTE_LOG_REGISTER_DEFAULT(mlx5_common_logtype, NOTICE)
 
+/* Head of list of drivers. */
+static TAILQ_HEAD(mlx5_drivers, mlx5_class_driver) drivers_list =
+                               TAILQ_HEAD_INITIALIZER(drivers_list);
+
+/* Head of devices. */
+static TAILQ_HEAD(mlx5_devices, mlx5_common_device) devices_list =
+                               TAILQ_HEAD_INITIALIZER(devices_list);
+
+static const struct {
+       const char *name;
+       unsigned int drv_class;
+} mlx5_classes[] = {
+       { .name = "vdpa", .drv_class = MLX5_CLASS_VDPA },
+       { .name = "eth", .drv_class = MLX5_CLASS_ETH },
+       /* Keep class "net" for backward compatibility. */
+       { .name = "net", .drv_class = MLX5_CLASS_ETH },
+       { .name = "regex", .drv_class = MLX5_CLASS_REGEX },
+       { .name = "compress", .drv_class = MLX5_CLASS_COMPRESS },
+       { .name = "crypto", .drv_class = MLX5_CLASS_CRYPTO },
+};
+
+static int
+class_name_to_value(const char *class_name)
+{
+       unsigned int i;
+
+       for (i = 0; i < RTE_DIM(mlx5_classes); i++) {
+               if (strcmp(class_name, mlx5_classes[i].name) == 0)
+                       return mlx5_classes[i].drv_class;
+       }
+       return -EINVAL;
+}
+
+static struct mlx5_class_driver *
+driver_get(uint32_t class)
+{
+       struct mlx5_class_driver *driver;
+
+       TAILQ_FOREACH(driver, &drivers_list, next) {
+               if ((uint32_t)driver->drv_class == class)
+                       return driver;
+       }
+       return NULL;
+}
+
+static int
+devargs_class_handler(__rte_unused const char *key,
+                     const char *class_names, void *opaque)
+{
+       int *ret = opaque;
+       int class_val;
+       char *scratch;
+       char *found;
+       char *refstr = NULL;
+
+       *ret = 0;
+       scratch = strdup(class_names);
+       if (scratch == NULL) {
+               *ret = -ENOMEM;
+               return *ret;
+       }
+       found = strtok_r(scratch, ":", &refstr);
+       if (found == NULL)
+               /* Empty string. */
+               goto err;
+       do {
+               /* Extract each individual class name. Multiple
+                * classes can be supplied as class=net:regex:foo:bar.
+                */
+               class_val = class_name_to_value(found);
+               /* Check if its a valid class. */
+               if (class_val < 0) {
+                       *ret = -EINVAL;
+                       goto err;
+               }
+               *ret |= class_val;
+               found = strtok_r(NULL, ":", &refstr);
+       } while (found != NULL);
+err:
+       free(scratch);
+       if (*ret < 0)
+               DRV_LOG(ERR, "Invalid mlx5 class options: %s.\n", class_names);
+       return *ret;
+}
+
+static int
+parse_class_options(const struct rte_devargs *devargs)
+{
+       struct rte_kvargs *kvlist;
+       int ret = 0;
+
+       if (devargs == NULL)
+               return 0;
+       if (devargs->cls != NULL && devargs->cls->name != NULL)
+               /* Global syntax, only one class type. */
+               return class_name_to_value(devargs->cls->name);
+       /* Legacy devargs support multiple classes. */
+       kvlist = rte_kvargs_parse(devargs->args, NULL);
+       if (kvlist == NULL)
+               return 0;
+       rte_kvargs_process(kvlist, RTE_DEVARGS_KEY_CLASS,
+                          devargs_class_handler, &ret);
+       rte_kvargs_free(kvlist);
+       return ret;
+}
+
+static const unsigned int mlx5_class_invalid_combinations[] = {
+       MLX5_CLASS_ETH | MLX5_CLASS_VDPA,
+       /* New class combination should be added here. */
+};
+
+static int
+is_valid_class_combination(uint32_t user_classes)
+{
+       unsigned int i;
+
+       /* Verify if user specified unsupported combination. */
+       for (i = 0; i < RTE_DIM(mlx5_class_invalid_combinations); i++) {
+               if ((mlx5_class_invalid_combinations[i] & user_classes) ==
+                   mlx5_class_invalid_combinations[i])
+                       return -EINVAL;
+       }
+       /* Not found any invalid class combination. */
+       return 0;
+}
+
+static bool
+device_class_enabled(const struct mlx5_common_device *device, uint32_t class)
+{
+       return (device->classes_loaded & class) > 0;
+}
+
+static bool
+mlx5_bus_match(const struct mlx5_class_driver *drv,
+              const struct rte_device *dev)
+{
+       if (mlx5_dev_is_pci(dev))
+               return mlx5_dev_pci_match(drv, dev);
+       return true;
+}
+
+static struct mlx5_common_device *
+to_mlx5_device(const struct rte_device *rte_dev)
+{
+       struct mlx5_common_device *dev;
+
+       TAILQ_FOREACH(dev, &devices_list, next) {
+               if (rte_dev == dev->dev)
+                       return dev;
+       }
+       return NULL;
+}
+
+static void
+dev_release(struct mlx5_common_device *dev)
+{
+       TAILQ_REMOVE(&devices_list, dev, next);
+       rte_free(dev);
+}
+
+static int
+drivers_remove(struct mlx5_common_device *dev, uint32_t enabled_classes)
+{
+       struct mlx5_class_driver *driver;
+       int local_ret = -ENODEV;
+       unsigned int i = 0;
+       int ret = 0;
+
+       enabled_classes &= dev->classes_loaded;
+       while (enabled_classes) {
+               driver = driver_get(RTE_BIT64(i));
+               if (driver != NULL) {
+                       local_ret = driver->remove(dev->dev);
+                       if (local_ret == 0)
+                               dev->classes_loaded &= ~RTE_BIT64(i);
+                       else if (ret == 0)
+                               ret = local_ret;
+               }
+               enabled_classes &= ~RTE_BIT64(i);
+               i++;
+       }
+       if (local_ret != 0 && ret == 0)
+               ret = local_ret;
+       return ret;
+}
+
+static int
+drivers_probe(struct mlx5_common_device *dev, uint32_t user_classes)
+{
+       struct mlx5_class_driver *driver;
+       uint32_t enabled_classes = 0;
+       bool already_loaded;
+       int ret;
+
+       TAILQ_FOREACH(driver, &drivers_list, next) {
+               if ((driver->drv_class & user_classes) == 0)
+                       continue;
+               if (!mlx5_bus_match(driver, dev->dev))
+                       continue;
+               already_loaded = dev->classes_loaded & driver->drv_class;
+               if (already_loaded && driver->probe_again == 0) {
+                       DRV_LOG(ERR, "Device %s is already probed",
+                               dev->dev->name);
+                       ret = -EEXIST;
+                       goto probe_err;
+               }
+               ret = driver->probe(dev->dev);
+               if (ret < 0) {
+                       DRV_LOG(ERR, "Failed to load driver %s",
+                               driver->name);
+                       goto probe_err;
+               }
+               enabled_classes |= driver->drv_class;
+       }
+       dev->classes_loaded |= enabled_classes;
+       return 0;
+probe_err:
+       /* Only unload drivers which are enabled which were enabled
+        * in this probe instance.
+        */
+       drivers_remove(dev, enabled_classes);
+       return ret;
+}
+
+int
+mlx5_common_dev_probe(struct rte_device *eal_dev)
+{
+       struct mlx5_common_device *dev;
+       uint32_t classes = 0;
+       bool new_device = false;
+       int ret;
+
+       DRV_LOG(INFO, "probe device \"%s\".", eal_dev->name);
+       ret = parse_class_options(eal_dev->devargs);
+       if (ret < 0) {
+               DRV_LOG(ERR, "Unsupported mlx5 class type: %s",
+                       eal_dev->devargs->args);
+               return ret;
+       }
+       classes = ret;
+       if (classes == 0)
+               /* Default to net class. */
+               classes = MLX5_CLASS_ETH;
+       dev = to_mlx5_device(eal_dev);
+       if (!dev) {
+               dev = rte_zmalloc("mlx5_common_device", sizeof(*dev), 0);
+               if (!dev)
+                       return -ENOMEM;
+               dev->dev = eal_dev;
+               TAILQ_INSERT_HEAD(&devices_list, dev, next);
+               new_device = true;
+       } else {
+               /* Validate combination here. */
+               ret = is_valid_class_combination(classes |
+                                                dev->classes_loaded);
+               if (ret != 0) {
+                       DRV_LOG(ERR, "Unsupported mlx5 classes combination.");
+                       return ret;
+               }
+       }
+       ret = drivers_probe(dev, classes);
+       if (ret)
+               goto class_err;
+       return 0;
+class_err:
+       if (new_device)
+               dev_release(dev);
+       return ret;
+}
+
+int
+mlx5_common_dev_remove(struct rte_device *eal_dev)
+{
+       struct mlx5_common_device *dev;
+       int ret;
+
+       dev = to_mlx5_device(eal_dev);
+       if (!dev)
+               return -ENODEV;
+       /* Matching device found, cleanup and unload drivers. */
+       ret = drivers_remove(dev, dev->classes_loaded);
+       if (ret != 0)
+               dev_release(dev);
+       return ret;
+}
+
+int
+mlx5_common_dev_dma_map(struct rte_device *dev, void *addr, uint64_t iova,
+                       size_t len)
+{
+       struct mlx5_class_driver *driver = NULL;
+       struct mlx5_class_driver *temp;
+       struct mlx5_common_device *mdev;
+       int ret = -EINVAL;
+
+       mdev = to_mlx5_device(dev);
+       if (!mdev)
+               return -ENODEV;
+       TAILQ_FOREACH(driver, &drivers_list, next) {
+               if (!device_class_enabled(mdev, driver->drv_class) ||
+                   driver->dma_map == NULL)
+                       continue;
+               ret = driver->dma_map(dev, addr, iova, len);
+               if (ret)
+                       goto map_err;
+       }
+       return ret;
+map_err:
+       TAILQ_FOREACH(temp, &drivers_list, next) {
+               if (temp == driver)
+                       break;
+               if (device_class_enabled(mdev, temp->drv_class) &&
+                   temp->dma_map && temp->dma_unmap)
+                       temp->dma_unmap(dev, addr, iova, len);
+       }
+       return ret;
+}
+
+int
+mlx5_common_dev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova,
+                         size_t len)
+{
+       struct mlx5_class_driver *driver;
+       struct mlx5_common_device *mdev;
+       int local_ret = -EINVAL;
+       int ret = 0;
+
+       mdev = to_mlx5_device(dev);
+       if (!mdev)
+               return -ENODEV;
+       /* There is no unmap error recovery in current implementation. */
+       TAILQ_FOREACH_REVERSE(driver, &drivers_list, mlx5_drivers, next) {
+               if (!device_class_enabled(mdev, driver->drv_class) ||
+                   driver->dma_unmap == NULL)
+                       continue;
+               local_ret = driver->dma_unmap(dev, addr, iova, len);
+               if (local_ret && (ret == 0))
+                       ret = local_ret;
+       }
+       if (local_ret)
+               ret = local_ret;
+       return ret;
+}
+
+void
+mlx5_class_driver_register(struct mlx5_class_driver *driver)
+{
+       mlx5_common_driver_on_register_pci(driver);
+       TAILQ_INSERT_TAIL(&drivers_list, driver, next);
+}
+
+static void mlx5_common_driver_init(void)
+{
+       mlx5_common_pci_init();
+}
+
 static bool mlx5_common_initialized;
 
 /**
                return;
 
        mlx5_glue_constructor();
-       mlx5_common_pci_init();
+       mlx5_common_driver_init();
        mlx5_common_initialized = true;
 }
 
 exit:
        return uar;
 }
+
+RTE_PMD_EXPORT_NAME(mlx5_common_driver, __COUNTER__);
 
 __rte_internal
 void mlx5_common_init(void);
 
+/*
+ * Common Driver Interface
+ *
+ * ConnectX common driver supports multiple classes: net, vDPA, regex, crypto
+ * and compress devices. This layer enables creating such multiple classes
+ * on a single device by allowing to bind multiple class-specific device
+ * drivers to attach to the common driver.
+ *
+ * ------------  -------------  --------------  -----------------  ------------
+ * | mlx5 net |  | mlx5 vdpa |  | mlx5 regex |  | mlx5 compress |  | mlx5 ... |
+ * |  driver  |  |  driver   |  |   driver   |  |     driver    |  |  drivers |
+ * ------------  -------------  --------------  -----------------  ------------
+ *                               ||
+ *                        -----------------
+ *                        |     mlx5      |
+ *                        | common driver |
+ *                        -----------------
+ *                          |          |
+ *                 -----------        -----------------
+ *                 |   mlx5  |        |   mlx5        |
+ *                 | pci dev |        | auxiliary dev |
+ *                 -----------        -----------------
+ *
+ * - mlx5 PCI bus driver binds to mlx5 PCI devices defined by PCI ID table
+ *   of all related devices.
+ * - mlx5 class driver such as net, vDPA, regex defines its specific
+ *   PCI ID table and mlx5 bus driver probes matching class drivers.
+ * - mlx5 common driver is central place that validates supported
+ *   class combinations.
+ * - mlx5 common driver hides bus difference by resolving device address
+ *   from devargs, locating target RDMA device and probing with it.
+ */
+
+/**
+ * Initialization function for the driver called during device probing.
+ */
+typedef int (mlx5_class_driver_probe_t)(struct rte_device *dev);
+
+/**
+ * Uninitialization function for the driver called during hot-unplugging.
+ */
+typedef int (mlx5_class_driver_remove_t)(struct rte_device *dev);
+
+/**
+ * Driver-specific DMA mapping. After a successful call the device
+ * will be able to read/write from/to this segment.
+ *
+ * @param dev
+ *   Pointer to the device.
+ * @param addr
+ *   Starting virtual address of memory to be mapped.
+ * @param iova
+ *   Starting IOVA address of memory to be mapped.
+ * @param len
+ *   Length of memory segment being mapped.
+ * @return
+ *   - 0 On success.
+ *   - Negative value and rte_errno is set otherwise.
+ */
+typedef int (mlx5_class_driver_dma_map_t)(struct rte_device *dev, void *addr,
+                                         uint64_t iova, size_t len);
+
+/**
+ * Driver-specific DMA un-mapping. After a successful call the device
+ * will not be able to read/write from/to this segment.
+ *
+ * @param dev
+ *   Pointer to the device.
+ * @param addr
+ *   Starting virtual address of memory to be unmapped.
+ * @param iova
+ *   Starting IOVA address of memory to be unmapped.
+ * @param len
+ *   Length of memory segment being unmapped.
+ * @return
+ *   - 0 On success.
+ *   - Negative value and rte_errno is set otherwise.
+ */
+typedef int (mlx5_class_driver_dma_unmap_t)(struct rte_device *dev, void *addr,
+                                           uint64_t iova, size_t len);
+
+/** Device already probed can be probed again to check for new ports. */
+#define MLX5_DRV_PROBE_AGAIN 0x0004
+
+/**
+ * A structure describing a mlx5 common class driver.
+ */
+struct mlx5_class_driver {
+       TAILQ_ENTRY(mlx5_class_driver) next;
+       enum mlx5_class drv_class;            /**< Class of this driver. */
+       const char *name;                     /**< Driver name. */
+       mlx5_class_driver_probe_t *probe;     /**< Device probe function. */
+       mlx5_class_driver_remove_t *remove;   /**< Device remove function. */
+       mlx5_class_driver_dma_map_t *dma_map; /**< Device DMA map function. */
+       mlx5_class_driver_dma_unmap_t *dma_unmap;
+       /**< Device DMA unmap function. */
+       const struct rte_pci_id *id_table;    /**< ID table, NULL terminated. */
+       uint32_t probe_again:1;
+       /**< Device already probed can be probed again to check new device. */
+       uint32_t intr_lsc:1; /**< Supports link state interrupt. */
+       uint32_t intr_rmv:1; /**< Supports device remove interrupt. */
+};
+
+/**
+ * Register a mlx5 device driver.
+ *
+ * @param driver
+ *   A pointer to a mlx5_driver structure describing the driver
+ *   to be registered.
+ */
+__rte_internal
+void
+mlx5_class_driver_register(struct mlx5_class_driver *driver);
+
+/**
+ * Test device is a PCI bus device.
+ *
+ * @param dev
+ *   Pointer to device.
+ *
+ * @return
+ *   - True on device devargs is a PCI bus device.
+ *   - False otherwise.
+ */
+__rte_internal
+bool
+mlx5_dev_is_pci(const struct rte_device *dev);
+
 #endif /* RTE_PMD_MLX5_COMMON_H_ */
 
  */
 
 #include <stdlib.h>
+
 #include <rte_malloc.h>
+#include <rte_devargs.h>
+#include <rte_errno.h>
 #include <rte_class.h>
 
 #include "mlx5_common_log.h"
 #include "mlx5_common_pci.h"
+#include "mlx5_common_private.h"
+
+static struct rte_pci_driver mlx5_common_pci_driver;
+
+/********** Legacy PCI bus driver, to be removed ********/
 
 struct mlx5_pci_device {
        struct rte_pci_device *pci_dev;
  *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
 static int
-mlx5_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
-                     struct rte_pci_device *pci_dev)
+mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+              struct rte_pci_device *pci_dev)
 {
        struct mlx5_pci_device *dev;
        uint32_t user_classes = 0;
  *   0 on success, the function cannot fail.
  */
 static int
-mlx5_common_pci_remove(struct rte_pci_device *pci_dev)
+mlx5_pci_remove(struct rte_pci_device *pci_dev)
 {
        struct mlx5_pci_device *dev;
        int ret;
 }
 
 static int
-mlx5_common_pci_dma_map(struct rte_pci_device *pci_dev, void *addr,
-                       uint64_t iova, size_t len)
+mlx5_pci_dma_map(struct rte_pci_device *pci_dev, void *addr,
+                uint64_t iova, size_t len)
 {
        struct mlx5_pci_driver *driver = NULL;
        struct mlx5_pci_driver *temp;
 }
 
 static int
-mlx5_common_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr,
-                         uint64_t iova, size_t len)
+mlx5_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr,
+                  uint64_t iova, size_t len)
 {
        struct mlx5_pci_driver *driver;
        struct mlx5_pci_device *dev;
        .driver = {
                .name = MLX5_PCI_DRIVER_NAME,
        },
-       .probe = mlx5_common_pci_probe,
-       .remove = mlx5_common_pci_remove,
-       .dma_map = mlx5_common_pci_dma_map,
-       .dma_unmap = mlx5_common_pci_dma_unmap,
+       .probe = mlx5_pci_probe,
+       .remove = mlx5_pci_remove,
+       .dma_map = mlx5_pci_dma_map,
+       .dma_unmap = mlx5_pci_dma_unmap,
 };
 
 static int
        updated_table = calloc(num_ids, sizeof(*updated_table));
        if (!updated_table)
                return -ENOMEM;
-       if (TAILQ_EMPTY(&drv_list)) {
+       if (old_table == NULL) {
                /* Copy the first driver's ID table. */
                for (id_iter = driver_id_table; id_iter->vendor_id != 0;
                     id_iter++, i++)
        /* Terminate table with empty entry. */
        updated_table[i].vendor_id = 0;
        mlx5_pci_driver.id_table = updated_table;
+       mlx5_common_pci_driver.id_table = updated_table;
        mlx5_pci_id_table = updated_table;
        if (old_table)
                free(old_table);
        TAILQ_INSERT_TAIL(&drv_list, driver, next);
 }
 
+/********** New common PCI bus driver ********/
+
+bool
+mlx5_dev_is_pci(const struct rte_device *dev)
+{
+       return strcmp(dev->bus->name, "pci") == 0;
+}
+
+bool
+mlx5_dev_pci_match(const struct mlx5_class_driver *drv,
+                  const struct rte_device *dev)
+{
+       const struct rte_pci_device *pci_dev;
+       const struct rte_pci_id *id_table;
+
+       if (!mlx5_dev_is_pci(dev))
+               return false;
+       pci_dev = RTE_DEV_TO_PCI_CONST(dev);
+       for (id_table = drv->id_table; id_table->vendor_id != 0;
+            id_table++) {
+               /* Check if device's ids match the class driver's ids. */
+               if (id_table->vendor_id != pci_dev->id.vendor_id &&
+                   id_table->vendor_id != RTE_PCI_ANY_ID)
+                       continue;
+               if (id_table->device_id != pci_dev->id.device_id &&
+                   id_table->device_id != RTE_PCI_ANY_ID)
+                       continue;
+               if (id_table->subsystem_vendor_id !=
+                   pci_dev->id.subsystem_vendor_id &&
+                   id_table->subsystem_vendor_id != RTE_PCI_ANY_ID)
+                       continue;
+               if (id_table->subsystem_device_id !=
+                   pci_dev->id.subsystem_device_id &&
+                   id_table->subsystem_device_id != RTE_PCI_ANY_ID)
+                       continue;
+               if (id_table->class_id != pci_dev->id.class_id &&
+                   id_table->class_id != RTE_CLASS_ANY_ID)
+                       continue;
+               return true;
+       }
+       return false;
+}
+
+static int
+mlx5_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+                     struct rte_pci_device *pci_dev)
+{
+       return mlx5_common_dev_probe(&pci_dev->device);
+}
+
+static int
+mlx5_common_pci_remove(struct rte_pci_device *pci_dev)
+{
+       return mlx5_common_dev_remove(&pci_dev->device);
+}
+
+static int
+mlx5_common_pci_dma_map(struct rte_pci_device *pci_dev, void *addr,
+                       uint64_t iova, size_t len)
+{
+       return mlx5_common_dev_dma_map(&pci_dev->device, addr, iova, len);
+}
+
+static int
+mlx5_common_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr,
+                         uint64_t iova, size_t len)
+{
+       return mlx5_common_dev_dma_unmap(&pci_dev->device, addr, iova, len);
+}
+
+void
+mlx5_common_driver_on_register_pci(struct mlx5_class_driver *driver)
+{
+       if (driver->id_table != NULL) {
+               if (pci_ids_table_update(driver->id_table) != 0)
+                       return;
+       }
+       if (driver->probe_again)
+               mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_PROBE_AGAIN;
+       if (driver->intr_lsc)
+               mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_LSC;
+       if (driver->intr_rmv)
+               mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_RMV;
+}
+
+static struct rte_pci_driver mlx5_common_pci_driver = {
+       .driver = {
+                  .name = MLX5_PCI_DRIVER_NAME,
+       },
+       .probe = mlx5_common_pci_probe,
+       .remove = mlx5_common_pci_remove,
+       .dma_map = mlx5_common_pci_dma_map,
+       .dma_unmap = mlx5_common_pci_dma_unmap,
+};
+
 void mlx5_common_pci_init(void)
 {
        const struct rte_pci_id empty_table[] = {
         */
        if (mlx5_pci_id_table == NULL && pci_ids_table_update(empty_table))
                return;
-       rte_pci_register(&mlx5_pci_driver);
+       rte_pci_register(&mlx5_common_pci_driver);
 }
 
 RTE_FINI(mlx5_common_pci_finish)
                /* Constructor doesn't register with PCI bus if it failed
                 * to build the table.
                 */
-               rte_pci_unregister(&mlx5_pci_driver);
+               rte_pci_unregister(&mlx5_common_pci_driver);
                free(mlx5_pci_id_table);
        }
 }
+
 RTE_PMD_EXPORT_NAME(mlx5_common_pci, __COUNTER__);
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2021 Mellanox Technologies, Ltd
+ */
+
+#ifndef MLX5_COMMON_PRIVATE_H
+#define MLX5_COMMON_PRIVATE_H
+
+#include <rte_pci.h>
+
+#include "mlx5_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Common bus driver: */
+
+struct mlx5_common_device {
+       struct rte_device *dev;
+       TAILQ_ENTRY(mlx5_common_device) next;
+       uint32_t classes_loaded;
+};
+
+int mlx5_common_dev_probe(struct rte_device *eal_dev);
+int mlx5_common_dev_remove(struct rte_device *eal_dev);
+int mlx5_common_dev_dma_map(struct rte_device *dev, void *addr, uint64_t iova,
+                           size_t len);
+int mlx5_common_dev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova,
+                             size_t len);
+
+/* Common PCI bus driver: */
+
+void mlx5_common_driver_on_register_pci(struct mlx5_class_driver *driver);
+bool mlx5_dev_pci_match(const struct mlx5_class_driver *drv,
+                       const struct rte_device *dev);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* MLX5_COMMON_PRIVATE_H */
 
 #ifndef RTE_PMD_MLX5_COMMON_UTILS_H_
 #define RTE_PMD_MLX5_COMMON_UTILS_H_
 
+#include <rte_rwlock.h>
+
 #include "mlx5_common.h"
 
 /************************ mlx5 list *****************************/
 
 
        haswell_broadwell_cpu;
 
+       mlx5_class_driver_register;
+
        mlx5_common_init;
 
        mlx5_common_verbs_reg_mr; # WINDOWS_NO_EXPORT
 
        mlx5_create_mr_ext;
 
+       mlx5_dev_is_pci;
        mlx5_dev_to_pci_addr; # WINDOWS_NO_EXPORT
 
        mlx5_devx_alloc_uar; # WINDOWS_NO_EXPORT
        mlx5_os_alloc_pd;
        mlx5_os_dealloc_pd;
        mlx5_os_dereg_mr;
+       mlx5_os_get_ibv_dev; # WINDOWS_NO_EXPORT
        mlx5_os_get_ibv_device; # WINDOWS_NO_EXPORT
        mlx5_os_reg_mr;
        mlx5_os_umem_dereg;