[dpdk-dev] [PATCH v7 4/9] eal/bus: support for scanning of bus

Shreyansh Jain shreyansh.jain at nxp.com
Tue Jan 17 11:09:29 CET 2017


Scan for bus discovers the devices available on the bus and adds them
to a bus specific device list. Each bus mandatorily implements this
method.

Test cases for Bus are also updated by this patch.

Signed-off-by: Shreyansh Jain <shreyansh.jain at nxp.com>
---
 app/test/test_bus.c                     | 175 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/eal_common_bus.c  |   2 +
 lib/librte_eal/common/include/rte_bus.h |  18 ++++
 3 files changed, 195 insertions(+)

diff --git a/app/test/test_bus.c b/app/test/test_bus.c
index 9680bac..0b6d011 100644
--- a/app/test/test_bus.c
+++ b/app/test/test_bus.c
@@ -106,10 +106,26 @@ struct dummy_bus_map {
 struct rte_bus_list orig_bus_list =
 	TAILQ_HEAD_INITIALIZER(orig_bus_list);
 
+/* Forward declarations for callbacks from bus */
+
+/* Bus A
+ * Scan would register devA1 and devA2 to bus
+ */
+static int scan_fn_for_busA(void);
+
+/* Bus B
+ * Scan would register devB1 and devB2 to bus
+ */
+static int scan_fn_for_busB(void);
+
+/* generic implementations wrapped around by above declarations */
+static int generic_scan_fn(struct rte_bus *bus);
+
 struct dummy_bus busA = {
 	.name = "busA_impl", /* busA */
 	.bus = {
 		.name = "busA",
+		.scan = scan_fn_for_busA,
 	},
 };
 
@@ -117,6 +133,7 @@ struct dummy_bus busB = {
 	.name = "busB_impl", /* busB */
 	.bus = {
 		.name = "busB",
+		.scan = scan_fn_for_busB,
 	},
 };
 
@@ -226,9 +243,81 @@ dump_device_tree(void)
 	printf("------>8-------\n");
 }
 
+/* @internal
+ * Move over the bus_map and find the entry matching the bus object
+ * passed as argument.
+ * For each device in that bus_map list, register.
+ *
+ * @param bus
+ *	bus to scan againt test entry
+ * @return
+ *	0 for successful scan, even if no devices are found
+ *	!0 for any error in scanning (like, invalid bus)
+ */
+static int
+generic_scan_fn(struct rte_bus *bus)
+{
+	int i = 0;
+	struct dummy_device *ddev = NULL;
+	struct dummy_bus_map *dbmap = NULL;
+	struct dummy_bus *db = NULL;
+
+	if (!bus)
+		return -1;
+
+	/* Extract the device tree node using the bus passed */
+	for (i = 0; bus_map[i].name; i++) {
+		if (!strcmp(bus_map[i].name, bus->name)) {
+			dbmap = &bus_map[i];
+			break;
+		}
+	}
+
+	if (!dbmap)
+		return -1;
+
+	db = dbmap->dbus;
+
+	/* For all the devices in the device tree (bus_map), add device */
+	for (i = 0; dbmap->ddevices[i]; i++) {
+		ddev = dbmap->ddevices[i];
+		TAILQ_INSERT_TAIL(&db->device_list, ddev, next);
+		ddev->dev.bus = bus;
+	}
+
+	return 0;
+}
+
+int
+scan_fn_for_busA(void) {
+	struct dummy_bus_map *dbm;
+
+	dbm = &bus_map[0];
+	while (dbm) {
+		if (strcmp(dbm->name, "busA") == 0)
+			return generic_scan_fn(&dbm->dbus->bus);
+		dbm++;
+	}
+	return 1;
+}
+
+int
+scan_fn_for_busB(void) {
+	struct dummy_bus_map *dbm;
+
+	dbm = &bus_map[0];
+	while (dbm) {
+		if (strcmp(dbm->name, "busB") == 0)
+			return generic_scan_fn(&dbm->dbus->bus);
+		dbm++;
+	}
+	return 1;
+}
+
 static int
 test_bus_setup(void)
 {
+	int i = 0;
 	struct rte_bus *bus_p = NULL;
 
 	/* Preserve the original bus list before executing test */
@@ -238,6 +327,13 @@ test_bus_setup(void)
 		TAILQ_INSERT_TAIL(&orig_bus_list, bus_p, next);
 	}
 
+	/* Initialize the bus lists */
+	for (i = 0; bus_map[i].name; i++) {
+		TAILQ_INIT(&bus_map[i].dbus->device_list);
+		TAILQ_INIT(&bus_map[i].dbus->driver_list);
+	}
+
+	dump_device_tree();
 	return 0;
 }
 
@@ -336,6 +432,79 @@ test_bus_unregistration(void)
 	return 0;
 }
 
+static int
+test_device_unregistration_on_bus(void)
+{
+	int i;
+	struct rte_bus *bus = NULL;
+	struct dummy_device *ddev;
+	struct dummy_bus *dbus;
+
+	for (i = 0; bus_map[i].name; i++) {
+		bus = &(bus_map[i].dbus->bus);
+		if (!bus) {
+			printf("Unable to find bus (%s)\n",
+			       bus_map[i].name);
+			return -1;
+		}
+
+		dbus = container_of(bus, struct dummy_bus, bus);
+		/* For bus 'bus', unregister all devices */
+		TAILQ_FOREACH(ddev, &dbus->device_list, next) {
+			TAILQ_REMOVE(&dbus->device_list, ddev, next);
+		}
+	}
+
+	for (i = 0; bus_map[i].name; i++) {
+		bus = &(bus_map[i].dbus->bus);
+		dbus = container_of(bus, struct dummy_bus, bus);
+
+		if (!TAILQ_EMPTY(&dbus->device_list)) {
+			printf("Unable to remove all devices on bus (%s)\n",
+			       bus->name);
+			return -1;
+		}
+	}
+
+	/* All devices from all buses have been removed */
+	printf("All devices on all buses unregistered.\n");
+	dump_device_tree();
+
+	return 0;
+}
+
+/* @internal
+ * For each bus registered, call the scan function to identify devices
+ * on the bus.
+ *
+ * @param void
+ * @return
+ *	0 for successful scan
+ *	!0 for unsuccessful scan
+ *
+ */
+static int
+test_bus_scan(void)
+{
+	int ret;
+	struct rte_bus *bus;
+
+	TAILQ_FOREACH(bus, &rte_bus_list, next) {
+		/* Call the scan function for each bus */
+		ret = bus->scan();
+		if (ret) {
+			printf("Scan of buses failed.\n");
+			return -1;
+		}
+	}
+
+	printf("Scan of all buses completed.\n");
+	dump_device_tree();
+
+	return 0;
+}
+
+
 int
 test_bus(void)
 {
@@ -346,6 +515,12 @@ test_bus(void)
 	if (test_bus_registration())
 		return -1;
 
+	if (test_bus_scan())
+		return -1;
+
+	if (test_device_unregistration_on_bus())
+		return -1;
+
 	if (test_bus_unregistration())
 		return -1;
 
diff --git a/lib/librte_eal/common/eal_common_bus.c b/lib/librte_eal/common/eal_common_bus.c
index c891392..35baff8 100644
--- a/lib/librte_eal/common/eal_common_bus.c
+++ b/lib/librte_eal/common/eal_common_bus.c
@@ -51,6 +51,8 @@ rte_bus_register(struct rte_bus *bus)
 {
 	RTE_VERIFY(bus);
 	RTE_VERIFY(bus->name && strlen(bus->name));
+	/* A bus should mandatorily have the scan implemented */
+	RTE_VERIFY(bus->scan);
 
 	TAILQ_INSERT_TAIL(&rte_bus_list, bus, next);
 	RTE_LOG(INFO, EAL, "Registered [%s] bus.\n", bus->name);
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index fe0f69d..152451c 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -60,11 +60,29 @@ TAILQ_HEAD(rte_bus_list, rte_bus);
 extern struct rte_bus_list rte_bus_list;
 
 /**
+ * Bus specific scan for devices attached on the bus.
+ * For each bus object, the scan would be reponsible for finding devices and
+ * adding them to its private device list.
+ *
+ * A bus should mandatorily implement this method.
+ *
+ * Generic bus object passed only as a helper for implementation to find
+ * their respective registered bus object. Implementations can choose not
+ * to use this variable.
+ *
+ * @return
+ *	0 for successful scan
+ *	!0 (<0) for unsuccessful scan with error value
+ */
+typedef int (*rte_bus_scan_t)(void);
+
+/**
  * A structure describing a generic bus.
  */
 struct rte_bus {
 	TAILQ_ENTRY(rte_bus) next;   /**< Next bus object in linked list */
 	const char *name;            /**< Name of the bus */
+	rte_bus_scan_t scan;         /**< Scan for devices attached to bus */
 };
 
 /**
-- 
2.7.4



More information about the dev mailing list