@@ -672,3 +672,10 @@ rte_pci_ioport_unmap(struct rte_pci_ioport *p)
return ret;
}
+
+int
+rte_pci_dev_bind_driver(const char *dev_name, const char *drv_type)
+{
+ return -1;
+}
+
@@ -859,3 +859,56 @@ rte_pci_ioport_unmap(struct rte_pci_ioport *p)
return ret;
}
+
+int
+rte_pci_dev_bind_driver(const char *dev_name, const char *drv_type)
+{
+ char drv_bind_path[1024];
+ char drv_override_path[1024]; /* contains the /dev/uioX */
+ int drv_override_fd;
+ int drv_bind_fd;
+
+ RTE_SET_USED(drv_type);
+
+ snprintf(drv_override_path, sizeof(drv_override_path),
+ "/sys/bus/pci/devices/%s/driver_override", dev_name);
+
+ /* specify the driver for a device by writing to driver_override */
+ drv_override_fd = open(drv_override_path, O_WRONLY);
+ if (drv_override_fd < 0) {
+ RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
+ drv_override_path, strerror(errno));
+ goto err;
+ }
+
+ if (write(drv_override_fd, drv_type, sizeof(drv_type)) < 0) {
+ RTE_LOG(ERR, EAL,
+ "Error: bind failed - Cannot write "
+ "driver %s to device %s\n", drv_type, dev_name);
+ goto err;
+ }
+
+ close(drv_override_fd);
+
+ snprintf(drv_bind_path, sizeof(drv_bind_path),
+ "/sys/bus/pci/drivers/%s/bind", drv_type);
+
+ /* do the bind by writing device to the specific driver */
+ drv_bind_fd = open(drv_bind_path, O_WRONLY | O_APPEND);
+ if (drv_bind_fd < 0) {
+ RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
+ drv_bind_path, strerror(errno));
+ goto err;
+ }
+
+ if (write(drv_bind_fd, dev_name, sizeof(dev_name)) < 0)
+ goto err;
+
+ close(drv_bind_fd);
+ return 0;
+err:
+ close(drv_override_fd);
+ close(drv_bind_fd);
+ return -1;
+}
+
@@ -574,6 +574,7 @@ struct rte_pci_bus rte_pci_bus = {
.parse = pci_parse,
.get_iommu_class = rte_pci_get_iommu_class,
.remap_device = pci_remap_device,
+ .bind_driver = rte_pci_dev_bind_driver,
},
.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
@@ -344,6 +344,20 @@ void rte_pci_ioport_read(struct rte_pci_ioport *p,
void rte_pci_ioport_write(struct rte_pci_ioport *p,
const void *data, size_t len, off_t offset);
+/**
+ * It can be used to bind a device to a specific type of driver.
+ *
+ * @param dev_name
+ * The device name.
+ * @param drv_type
+ * The specific driver's type.
+ *
+ * @return
+ * - On success, zero.
+ * - On failure, a negative value.
+ */
+int rte_pci_dev_bind_driver(const char *dev_name, const char *drv_type);
+
#ifdef __cplusplus
}
#endif
@@ -349,6 +349,14 @@ vdev_remap_device(struct rte_device *dev)
}
static int
+vdev_bind_driver(const char *dev_name, const char *drv_type)
+{
+ RTE_SET_USED(dev_name);
+ RTE_SET_USED(drv_type);
+ return 0;
+}
+
+static int
vdev_plug(struct rte_device *dev)
{
return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
@@ -369,6 +377,7 @@ static struct rte_bus rte_vdev_bus = {
.unplug = vdev_unplug,
.parse = vdev_parse,
.remap_device = vdev_remap_device,
+ .bind_driver = vdev_bind_driver,
};
RTE_REGISTER_BUS(vdev, rte_vdev_bus);
@@ -55,6 +55,7 @@ rte_bus_register(struct rte_bus *bus)
/* Buses supporting driver plug also require unplug. */
RTE_VERIFY(!bus->plug || bus->unplug);
RTE_VERIFY(bus->remap_device);
+ RTE_VERIFY(bus->bind_driver);
TAILQ_INSERT_TAIL(&rte_bus_list, bus, next);
RTE_LOG(DEBUG, EAL, "Registered [%s] bus.\n", bus->name);
@@ -212,6 +212,23 @@ typedef int (*rte_bus_parse_t)(const char *name, void *addr);
typedef int (*rte_bus_remap_device_t)(struct rte_device *dev);
/**
+ * Implementation specific bind driver function which is responsible for bind
+ * a explicit type of driver with a devices on that bus.
+ *
+ * @param dev_name
+ * device textual description.
+ *
+ * @param drv_type
+ * driver type textual description.
+ *
+ * @return
+ * 0 on success.
+ * !0 on error.
+ */
+typedef int (*rte_bus_bind_driver_t)(const char *dev_name,
+ const char *drv_type);
+
+/**
* Bus scan policies
*/
enum rte_bus_scan_mode {
@@ -256,6 +273,7 @@ struct rte_bus {
rte_bus_unplug_t unplug; /**< Remove single device from driver */
rte_bus_parse_t parse; /**< Parse a device name */
rte_bus_remap_device_t remap_device; /**< remap a device */
+ rte_bus_bind_driver_t bind_driver; /**< bind a driver for bus device */
struct rte_bus_conf conf; /**< Bus configuration */
rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
};
@@ -207,6 +207,13 @@ dev_uev_process(struct epoll_event *events, int nfds)
NULL));
} else if (uevent.type == RTE_DEV_EVENT_ADD) {
if (dev == NULL) {
+ /**
+ * bind the driver to the device
+ * before user's add processing
+ */
+ bus->bind_driver(
+ uevent.devname,
+ "igb_uio");
return(_rte_dev_callback_process(NULL,
RTE_DEV_EVENT_ADD,
uevent.devname));