@@ -502,6 +502,25 @@ pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
return NULL;
}
+static struct rte_device *
+pci_find_device_by_name(const struct rte_device *start,
+ rte_dev_cmp_name_t cmp_name,
+ const void *data)
+{
+ struct rte_pci_device *dev;
+
+ FOREACH_DEVICE_ON_PCIBUS(dev) {
+ if (start && &dev->device == start) {
+ start = NULL; /* starting point found */
+ continue;
+ }
+ if (cmp_name(dev->device.name, data) == 0)
+ return &dev->device;
+ }
+
+ return NULL;
+}
+
static int
pci_plug(struct rte_device *dev)
{
@@ -528,6 +547,7 @@ struct rte_pci_bus rte_pci_bus = {
.scan = rte_pci_scan,
.probe = rte_pci_probe,
.find_device = pci_find_device,
+ .find_device_by_name = pci_find_device_by_name,
.plug = pci_plug,
.unplug = pci_unplug,
.parse = pci_parse,
@@ -323,6 +323,25 @@ vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
return NULL;
}
+
+static struct rte_device *
+vdev_find_device_by_name(const struct rte_device *start,
+ rte_dev_cmp_name_t cmp_name,
+ const void *data)
+{
+ struct rte_vdev_device *dev;
+
+ TAILQ_FOREACH(dev, &vdev_device_list, next) {
+ if (start && &dev->device == start) {
+ start = NULL;
+ continue;
+ }
+ if (cmp_name(dev->device.name, data) == 0)
+ return &dev->device;
+ }
+ return NULL;
+}
+
static int
vdev_plug(struct rte_device *dev)
{
@@ -339,6 +358,7 @@ static struct rte_bus rte_vdev_bus = {
.scan = vdev_scan,
.probe = vdev_probe,
.find_device = vdev_find_device,
+ .find_device_by_name = vdev_find_device_by_name,
.plug = vdev_plug,
.unplug = vdev_unplug,
.parse = vdev_parse,
@@ -51,6 +51,7 @@ rte_bus_register(struct rte_bus *bus)
RTE_VERIFY(bus->scan);
RTE_VERIFY(bus->probe);
RTE_VERIFY(bus->find_device);
+ RTE_VERIFY(bus->find_device_by_name);
/* Buses supporting driver plug also require unplug. */
RTE_VERIFY(!bus->plug || bus->unplug);
@@ -170,6 +171,14 @@ cmp_rte_device(const struct rte_device *dev1, const void *_dev2)
}
static int
+cmp_rte_device_name(const char *dev_name1, const void *_dev_name2)
+{
+ const char *dev_name2 = _dev_name2;
+
+ return strcmp(dev_name1, dev_name2);
+}
+
+static int
bus_find_device(const struct rte_bus *bus, const void *_dev)
{
struct rte_device *dev;
@@ -178,6 +187,25 @@ bus_find_device(const struct rte_bus *bus, const void *_dev)
return dev == NULL;
}
+static struct rte_device *
+bus_find_device_by_name(const struct rte_bus *bus, const void *_dev_name)
+{
+ struct rte_device *dev;
+
+ dev = bus->find_device_by_name(NULL, cmp_rte_device_name, _dev_name);
+ return dev;
+}
+
+struct rte_device *
+
+rte_bus_find_device(const struct rte_bus *bus, const void *_dev_name)
+{
+ struct rte_device *dev;
+
+ dev = bus_find_device_by_name(bus, _dev_name);
+ return dev;
+}
+
struct rte_bus *
rte_bus_find_by_device(const struct rte_device *dev)
{
@@ -122,6 +122,34 @@ typedef struct rte_device *
const void *data);
/**
+ * Device iterator to find a device on a bus.
+ *
+ * This function returns an rte_device if one of those held by the bus
+ * matches the data passed as parameter.
+ *
+ * If the comparison function returns zero this function should stop iterating
+ * over any more devices. To continue a search the device of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param cmp
+ * the device name comparison function.
+ *
+ * @param data
+ * Data to compare each device against.
+ *
+ * @param start
+ * starting point for the iteration
+ *
+ * @return
+ * The first device matching the data, NULL if none exists.
+ */
+typedef struct rte_device *
+(*rte_bus_find_device_by_name_t)(const struct rte_device *start,
+ rte_dev_cmp_name_t cmp,
+ const void *data);
+
+
+/**
* Implementation specific probe function which is responsible for linking
* devices on that bus with applicable drivers.
*
@@ -206,6 +234,8 @@ struct rte_bus {
rte_bus_scan_t scan; /**< Scan for devices attached to bus */
rte_bus_probe_t probe; /**< Probe devices on bus */
rte_bus_find_device_t find_device; /**< Find a device on the bus */
+ rte_bus_find_device_by_name_t find_device_by_name;
+ /**< Find a device on the bus */
rte_bus_plug_t plug; /**< Probe single device for drivers */
rte_bus_unplug_t unplug; /**< Remove single device from driver */
rte_bus_parse_t parse; /**< Parse a device name */
@@ -306,6 +336,12 @@ struct rte_bus *rte_bus_find(const struct rte_bus *start, rte_bus_cmp_t cmp,
struct rte_bus *rte_bus_find_by_device(const struct rte_device *dev);
/**
+ * Find the registered bus for a particular device.
+ */
+struct rte_device *rte_bus_find_device(const struct rte_bus *bus,
+ const void *dev_name);
+
+/**
* Find the registered bus for a given name.
*/
struct rte_bus *rte_bus_find_by_name(const char *busname);
@@ -53,10 +53,28 @@ extern "C" {
#include <exec-env/rte_dev.h>
+#define RTE_EAL_UEV_MSG_LEN 4096
+#define RTE_EAL_UEV_MSG_ELEM_LEN 128
+
+enum rte_dev_state {
+ RTE_DEV_UNDEFINED, /**< unknown device state */
+ RTE_DEV_FAULT, /**< device fault or error */
+ RTE_DEV_PARSED, /**< device have been parsed on bus*/
+ RTE_DEV_PROBED, /**< devcie have been probed driver */
+};
+
+enum uev_subsystem {
+ UEV_SUBSYSTEM_UIO,
+ UEV_SUBSYSTEM_VFIO,
+ UEV_SUBSYSTEM_PCI,
+ UEV_SUBSYSTEM_MAX
+};
+
enum uev_monitor_netlink_group {
UEV_MONITOR_KERNEL,
UEV_MONITOR_UDEV,
};
+
/**
* The device event type.
*/
@@ -204,6 +222,7 @@ struct rte_device {
const struct rte_driver *driver;/**< Associated driver */
int numa_node; /**< NUMA node connection */
struct rte_devargs *devargs; /**< Device user arguments */
+ enum rte_dev_state state; /**< Device state */
/** User application callbacks for device event */
struct rte_eal_dev_cb_list uev_cbs;
};
@@ -288,6 +307,8 @@ int rte_eal_hotplug_remove(const char *busname, const char *devname);
*/
typedef int (*rte_dev_cmp_t)(const struct rte_device *dev, const void *data);
+typedef int (*rte_dev_cmp_name_t)(const char *dev_name, const void *data);
+
#define RTE_PMD_EXPORT_NAME_ARRAY(n, idx) n##idx[]
#define RTE_PMD_EXPORT_NAME(name, idx) \
@@ -79,10 +79,126 @@ dev_monitor_enable(int netlink_fd)
return -1;
}
+static void
+dev_uev_parse(const char *buf, struct rte_eal_uevent *event)
+{
+ char action[RTE_EAL_UEV_MSG_ELEM_LEN];
+ char subsystem[RTE_EAL_UEV_MSG_ELEM_LEN];
+ char dev_path[RTE_EAL_UEV_MSG_ELEM_LEN];
+ char pci_slot_name[RTE_EAL_UEV_MSG_ELEM_LEN];
+ int i = 0;
+
+ memset(action, 0, RTE_EAL_UEV_MSG_ELEM_LEN);
+ memset(subsystem, 0, RTE_EAL_UEV_MSG_ELEM_LEN);
+ memset(dev_path, 0, RTE_EAL_UEV_MSG_ELEM_LEN);
+ memset(pci_slot_name, 0, RTE_EAL_UEV_MSG_ELEM_LEN);
+
+ while (i < RTE_EAL_UEV_MSG_LEN) {
+ for (; i < RTE_EAL_UEV_MSG_LEN; i++) {
+ if (*buf)
+ break;
+ buf++;
+ }
+ if (!strncmp(buf, "libudev", 7)) {
+ buf += 7;
+ i += 7;
+ event->group = UEV_MONITOR_UDEV;
+ }
+ if (!strncmp(buf, "ACTION=", 7)) {
+ buf += 7;
+ i += 7;
+ snprintf(action, sizeof(action), "%s", buf);
+ } else if (!strncmp(buf, "DEVPATH=", 8)) {
+ buf += 8;
+ i += 8;
+ snprintf(dev_path, sizeof(dev_path), "%s", buf);
+ } else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
+ buf += 10;
+ i += 10;
+ snprintf(subsystem, sizeof(subsystem), "%s", buf);
+ } else if (!strncmp(buf, "PCI_SLOT_NAME=", 14)) {
+ buf += 14;
+ i += 14;
+ snprintf(pci_slot_name, sizeof(subsystem), "%s", buf);
+ event->devname = pci_slot_name;
+ }
+ for (; i < RTE_EAL_UEV_MSG_LEN; i++) {
+ if (*buf == '\0')
+ break;
+ buf++;
+ }
+ }
+
+ if (!strncmp(subsystem, "pci", 3))
+ event->subsystem = UEV_SUBSYSTEM_PCI;
+ if (!strncmp(action, "add", 3))
+ event->type = RTE_DEV_EVENT_ADD;
+ if (!strncmp(action, "remove", 6))
+ event->type = RTE_DEV_EVENT_REMOVE;
+ event->devname = pci_slot_name;
+}
+
static int
-dev_uev_process(__rte_unused struct epoll_event *events, __rte_unused int nfds)
+dev_uev_receive(int fd, struct rte_eal_uevent *uevent)
{
- /* TODO: device uevent processing */
+ int ret;
+ char buf[RTE_EAL_UEV_MSG_LEN];
+
+ memset(uevent, 0, sizeof(struct rte_eal_uevent));
+ memset(buf, 0, RTE_EAL_UEV_MSG_LEN);
+
+ ret = recv(fd, buf, RTE_EAL_UEV_MSG_LEN - 1, MSG_DONTWAIT);
+ if (ret < 0) {
+ RTE_LOG(ERR, EAL,
+ "Socket read error(%d): %s\n",
+ errno, strerror(errno));
+ return -1;
+ } else if (ret == 0)
+ /* connection closed */
+ return -1;
+
+ dev_uev_parse(buf, uevent);
+
+ return 0;
+}
+
+static int
+dev_uev_process(struct epoll_event *events, int nfds)
+{
+ struct rte_bus *bus;
+ struct rte_device *dev;
+ struct rte_eal_uevent uevent;
+ int i;
+
+ for (i = 0; i < nfds; i++) {
+ /**
+ * check device uevent from kernel side, no need to check
+ * uevent from udev.
+ */
+ if ((dev_uev_receive(events[i].data.fd, &uevent)) ||
+ (uevent.group == UEV_MONITOR_UDEV))
+ return 0;
+
+ /* default handle all pci devcie when is being hot plug */
+ if (uevent.subsystem == UEV_SUBSYSTEM_PCI) {
+ bus = rte_bus_find_by_name("pci");
+ dev = rte_bus_find_device(bus, uevent.devname);
+ if (uevent.type == RTE_DEV_EVENT_REMOVE) {
+
+ if ((!dev) || dev->state == RTE_DEV_UNDEFINED)
+ return 0;
+ return(_rte_dev_callback_process(dev,
+ RTE_DEV_EVENT_REMOVE,
+ NULL));
+ } else if (uevent.type == RTE_DEV_EVENT_ADD) {
+ if (dev == NULL) {
+ return(_rte_dev_callback_process(NULL,
+ RTE_DEV_EVENT_ADD,
+ uevent.devname));
+ }
+ }
+ }
+ }
return 0;
}