[dpdk-dev] [PATCH v8 7/9] test: update bus and pci unit test cases

Shreyansh Jain shreyansh.jain at nxp.com
Tue Jan 17 14:37:42 CET 2017


Signed-off-by: Shreyansh Jain <shreyansh.jain at nxp.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit at intel.com>
---
 app/test/test_bus.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++
 app/test/test_pci.c | 164 ++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 266 insertions(+), 50 deletions(-)

diff --git a/app/test/test_bus.c b/app/test/test_bus.c
index 0b6d011..ef7fa89 100644
--- a/app/test/test_bus.c
+++ b/app/test/test_bus.c
@@ -120,12 +120,15 @@ static int scan_fn_for_busB(void);
 
 /* generic implementations wrapped around by above declarations */
 static int generic_scan_fn(struct rte_bus *bus);
+static int generic_probe_fn(void);
+static int dummy_match_fn(struct rte_driver *drv, struct rte_device *dev);
 
 struct dummy_bus busA = {
 	.name = "busA_impl", /* busA */
 	.bus = {
 		.name = "busA",
 		.scan = scan_fn_for_busA,
+		.probe = generic_probe_fn,
 	},
 };
 
@@ -134,6 +137,7 @@ struct dummy_bus busB = {
 	.bus = {
 		.name = "busB",
 		.scan = scan_fn_for_busB,
+		.probe = generic_probe_fn,
 	},
 };
 
@@ -288,6 +292,46 @@ generic_scan_fn(struct rte_bus *bus)
 	return 0;
 }
 
+/* @internal
+ * Obtain bus from driver object. Match the address of rte_device object
+ * with all the devices associated with that bus.
+ *
+ * Being a test function, all this does is validate that device object
+ * provided is available on the same bus to which driver is registered.
+ *
+ * @param drv
+ *	driver to match with
+ * @param dev
+ *	device object
+ * @return
+ *	0 for successful match
+ *	!0 for failed match
+ */
+static int
+dummy_match_fn(struct rte_driver *drv __rte_unused, struct rte_device *dev)
+{
+	struct rte_bus *bus;
+	struct dummy_device *ddev = NULL;
+	struct dummy_device *ddev_as_arg;
+	struct dummy_bus *dbus = NULL;
+
+	/* Match is based entirely on address of 'dev' and 'dev_p' extracted
+	 * from bus->device_list.
+	 */
+
+	/* a driver is registered with the bus *before* the scan. */
+	bus = dev->bus;
+	dbus = container_of(bus, struct dummy_bus, bus);
+	ddev_as_arg = container_of(dev, struct dummy_device, dev);
+
+	TAILQ_FOREACH(ddev, &dbus->device_list, next) {
+		if (ddev == ddev_as_arg)
+			return 0;
+	}
+
+	return 1;
+}
+
 int
 scan_fn_for_busA(void) {
 	struct dummy_bus_map *dbm;
@@ -504,6 +548,110 @@ test_bus_scan(void)
 	return 0;
 }
 
+/*
+ *
+ */
+static int
+generic_probe_fn(void)
+{
+	int ret = 0;
+	int i, j;
+	struct rte_driver *drv;
+	struct rte_device *dev;
+	struct dummy_bus *dbus = NULL;
+	struct dummy_device *ddev = NULL;
+	struct dummy_driver *ddrv = NULL;
+
+	/* In case of this test:
+	 * 1. for each bus in rte_bus_list
+	 * 2.  for each device on that bus (bus specific->device_list)
+	 * 3.   for each driver on that bus (bus specific->driver_list)
+	 * 4.    call match
+	 * 5.    link driver and device
+	 * 6. Verify the linkage.
+	 */
+	for (i = 0; bus_map[i].name; i++) {
+		/* get bus pointer from bus_map itself */
+		dbus = bus_map[i].dbus;
+
+		/* Looping over all scanned devices */
+		TAILQ_FOREACH(ddev, &dbus->device_list, next) {
+			/* There is a list of drivers within dummy_bus_map.
+			 * In case of PMDs, this would be driver registration
+			 * APIs/list
+			 */
+			for (j = 0; bus_map[i].ddrivers[j]; j++) {
+				ddrv = bus_map[i].ddrivers[j];
+
+				drv = &ddrv->drv;
+				dev = &ddev->dev;
+				ret = dummy_match_fn(drv, dev);
+				if (!ret) {
+					/* As match is generic, it always
+					 * results in dev->drv pointing to
+					 * first driver entry in bus_map[i]
+					 */
+					dev->driver = drv;
+					dev->bus = &dbus->bus;
+				}
+				/* Else, continue */
+			}
+		}
+	}
+
+	/* Verify the linkage. All devices belonging to a bus_map[i]
+	 * should have same driver (first driver entry of bus_map[i])
+	 */
+	for (i = 0; bus_map[i].name; i++) {
+		ddrv = bus_map[i].ddrivers[0];
+		drv = &ddrv->drv;
+
+		for (j = 0; bus_map[i].ddevices[j]; j++) {
+			ddev = bus_map[i].ddevices[j];
+			dev = &ddev->dev;
+			if (dev->driver != drv) {
+				printf("Incorrect driver<->device linkage.\n");
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* @internal
+ * Function to perform 'probe' and link devices and drivers on a bus.
+ * This would work over all the buses registered, and all devices and drivers
+ * registered with it - call match on each pair.
+ *
+ * @param void
+ * @return
+ *	0 for successful probe
+ *	!0 for failure in probe
+ *
+ */
+static int
+test_probe_on_bus(void)
+{
+	int ret = 0;
+	int i;
+	struct dummy_bus *dbus;
+	struct rte_bus *bus;
+
+	for (i = 0; bus_map[i].name; i++) {
+		/* get bus pointer from bus_map itself */
+		dbus = bus_map[i].dbus;
+		bus = &dbus->bus;
+		ret = bus->probe();
+		if (ret)
+			printf("Probe for %s failed.\n", bus_map[i].name);
+	}
+
+	printf("Probe on all buses successful.\n");
+	dump_device_tree();
+
+	return 0;
+}
 
 int
 test_bus(void)
@@ -518,6 +666,10 @@ test_bus(void)
 	if (test_bus_scan())
 		return -1;
 
+	/* Now that the devices and drivers are registered, perform probe */
+	if (test_probe_on_bus())
+		return -1;
+
 	if (test_device_unregistration_on_bus())
 		return -1;
 
diff --git a/app/test/test_pci.c b/app/test/test_pci.c
index cda186d..09261cc 100644
--- a/app/test/test_pci.c
+++ b/app/test/test_pci.c
@@ -38,9 +38,11 @@
 #include <sys/queue.h>
 
 #include <rte_interrupts.h>
+#include <rte_bus.h>
 #include <rte_pci.h>
 #include <rte_ethdev.h>
 #include <rte_devargs.h>
+#include <rte_tailq.h>
 
 #include "test.h"
 #include "resource.h"
@@ -61,10 +63,31 @@
 
 int test_pci_run = 0; /* value checked by the multiprocess test */
 static unsigned pci_dev_count;
+struct test_pci_bus;
+static struct test_pci_bus *pci_bus; /* global reference to a Test PCI bus */
+
+/** List of PCI devices */
+TAILQ_HEAD(test_pci_device_list, rte_pci_device);
+/** List of PCI drivers */
+TAILQ_HEAD(test_pci_driver_list, rte_pci_driver);
 
 static int my_driver_init(struct rte_pci_driver *dr,
 			  struct rte_pci_device *dev);
 
+struct test_pci_bus {
+	struct rte_bus bus;
+	struct test_pci_device_list test_device_list;
+	struct test_pci_driver_list test_driver_list;
+};
+
+struct test_pci_bus test_pci_bus = {
+	.bus = {
+		.name = "test_pci_bus",
+		.scan = rte_eal_pci_scan,
+		.probe = rte_eal_pci_probe,
+	},
+};
+
 /* IXGBE NICS */
 struct rte_pci_id my_driver_id[] = {
 	{RTE_PCI_DEVICE(0x0001, 0x1234)},
@@ -79,7 +102,7 @@ struct rte_pci_id my_driver_id2[] = {
 
 struct rte_pci_driver my_driver = {
 	.driver = {
-		.name = "test_driver"
+		.name = "test_driver",
 	},
 	.probe = my_driver_init,
 	.id_table = my_driver_id,
@@ -88,7 +111,7 @@ struct rte_pci_driver my_driver = {
 
 struct rte_pci_driver my_driver2 = {
 	.driver = {
-		.name = "test_driver2"
+		.name = "test_driver2",
 	},
 	.probe = my_driver_init,
 	.id_table = my_driver_id2,
@@ -108,6 +131,55 @@ my_driver_init(__attribute__((unused)) struct rte_pci_driver *dr,
 	return 0;
 }
 
+/* dump devices on the bus */
+static void
+do_pci_device_dump(FILE *f)
+{
+	int i;
+	struct rte_pci_device *dev = NULL;
+
+	TAILQ_FOREACH(dev, &test_pci_bus.test_device_list, next) {
+
+		fprintf(f, PCI_PRI_FMT, dev->addr.domain, dev->addr.bus,
+		       dev->addr.devid, dev->addr.function);
+		fprintf(f, " - vendor:%x device:%x\n", dev->id.vendor_id,
+		       dev->id.device_id);
+
+		for (i = 0; i != sizeof(dev->mem_resource) /
+			sizeof(dev->mem_resource[0]); i++) {
+			fprintf(f, "   %16.16"PRIx64" %16.16"PRIx64"\n",
+				dev->mem_resource[i].phys_addr,
+				dev->mem_resource[i].len);
+		}
+	}
+}
+
+/* Dummy implementation for rte_eal_pci_probe() over test_pci_bus */
+static int
+do_pci_bus_probe(void)
+{
+	int ret;
+	struct rte_pci_device *device;
+	struct rte_pci_driver *driver;
+
+	TAILQ_FOREACH(device, &test_pci_bus.test_device_list, next) {
+		TAILQ_FOREACH(driver, &test_pci_bus.test_driver_list, next) {
+			ret = rte_pci_match(driver, device);
+			if (!ret) {
+				if (!driver->probe)
+					continue;
+
+				device->driver = driver;
+				ret = driver->probe(driver, device);
+				if (ret != 0)
+					return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static void
 blacklist_all_devices(void)
 {
@@ -115,7 +187,7 @@ blacklist_all_devices(void)
 	unsigned i = 0;
 	char pci_addr_str[16];
 
-	TAILQ_FOREACH(dev, &pci_device_list, next) {
+	TAILQ_FOREACH(dev, &(test_pci_bus.test_device_list), next) {
 		snprintf(pci_addr_str, sizeof(pci_addr_str), PCI_PRI_FMT,
 			dev->addr.domain, dev->addr.bus, dev->addr.devid,
 			dev->addr.function);
@@ -142,19 +214,11 @@ static void free_devargs_list(void)
 	}
 }
 
-/* backup real devices & drivers (not used for testing) */
-struct pci_driver_list real_pci_driver_list =
-	TAILQ_HEAD_INITIALIZER(real_pci_driver_list);
-struct pci_device_list real_pci_device_list =
-	TAILQ_HEAD_INITIALIZER(real_pci_device_list);
-
 REGISTER_LINKED_RESOURCE(test_pci_sysfs);
 
 static int
 test_pci_setup(void)
 {
-	struct rte_pci_device *dev;
-	struct rte_pci_driver *dr;
 	const struct resource *r;
 	int ret;
 
@@ -167,22 +231,22 @@ test_pci_setup(void)
 	ret = setenv("SYSFS_PCI_DEVICES", "test_pci_sysfs/bus/pci/devices", 1);
 	TEST_ASSERT_SUCCESS(ret, "failed to setenv");
 
-	/* Unregister original devices & drivers lists */
-	while (!TAILQ_EMPTY(&pci_driver_list)) {
-		dr = TAILQ_FIRST(&pci_driver_list);
-		rte_eal_pci_unregister(dr);
-		TAILQ_INSERT_TAIL(&real_pci_driver_list, dr, next);
-	}
+	TAILQ_INIT(&test_pci_bus.test_device_list);
+	TAILQ_INIT(&test_pci_bus.test_driver_list);
 
-	while (!TAILQ_EMPTY(&pci_device_list)) {
-		dev = TAILQ_FIRST(&pci_device_list);
-		TAILQ_REMOVE(&pci_device_list, dev, next);
-		TAILQ_INSERT_TAIL(&real_pci_device_list, dev, next);
-	}
+	/* Create a new Bus called 'test_pci_bus' */
+	/* Bus doesn't exist; Create the test bus */
+	printf("Creating a Test PCI bus\n");
+	rte_bus_register(&test_pci_bus.bus);
+	pci_bus = &test_pci_bus;
+
+	printf("Scan for Test devices and add to bus\n");
+	ret = pci_bus->bus.scan();
 
-	ret = rte_eal_pci_scan();
 	TEST_ASSERT_SUCCESS(ret, "failed to scan PCI bus");
-	rte_eal_pci_dump(stdout);
+
+	printf("Dump of all devices scanned:\n");
+	do_pci_device_dump(stdout);
 
 	return 0;
 }
@@ -190,10 +254,11 @@ test_pci_setup(void)
 static int
 test_pci_cleanup(void)
 {
-	struct rte_pci_device *dev;
-	struct rte_pci_driver *dr;
+	struct rte_pci_device *dev = NULL;
+	struct rte_pci_driver *dr = NULL;
 	const struct resource *r;
 	int ret;
+	void *temp;
 
 	unsetenv("SYSFS_PCI_DEVICES");
 
@@ -203,28 +268,23 @@ test_pci_cleanup(void)
 	ret = resource_rm_by_tar(r);
 	TEST_ASSERT_SUCCESS(ret, "Failed to delete resource %s", r->name);
 
+	TEST_ASSERT_NOT_NULL(pci_bus, "Invalid bus specified");
+
 	/*
 	 * FIXME: there is no API in DPDK to free a rte_pci_device so we
 	 * cannot free the devices in the right way. Let's assume that we
 	 * don't care for tests.
 	 */
-	while (!TAILQ_EMPTY(&pci_device_list)) {
-		dev = TAILQ_FIRST(&pci_device_list);
-		TAILQ_REMOVE(&pci_device_list, dev, next);
+	TAILQ_FOREACH_SAFE(dev, &(test_pci_bus.test_device_list), next, temp) {
+		TAILQ_REMOVE(&(test_pci_bus.test_device_list), dev, next);
+		dev->driver = NULL;
 	}
 
-	/* Restore original devices & drivers lists */
-	while (!TAILQ_EMPTY(&real_pci_driver_list)) {
-		dr = TAILQ_FIRST(&real_pci_driver_list);
-		TAILQ_REMOVE(&real_pci_driver_list, dr, next);
-		rte_eal_pci_register(dr);
+	TAILQ_FOREACH_SAFE(dr, &(test_pci_bus.test_driver_list), next, temp) {
+		TAILQ_REMOVE(&(test_pci_bus.test_driver_list), dr, next);
 	}
 
-	while (!TAILQ_EMPTY(&real_pci_device_list)) {
-		dev = TAILQ_FIRST(&real_pci_device_list);
-		TAILQ_REMOVE(&real_pci_device_list, dev, next);
-		TAILQ_INSERT_TAIL(&pci_device_list, dev, next);
-	}
+	rte_bus_unregister(&pci_bus->bus);
 
 	return 0;
 }
@@ -234,16 +294,19 @@ test_pci_blacklist(void)
 {
 	struct rte_devargs_list save_devargs_list;
 
-	printf("Dump all devices\n");
-	TEST_ASSERT(TAILQ_EMPTY(&pci_driver_list),
-			"pci_driver_list not empty");
+	TEST_ASSERT_NOT_NULL(pci_bus, "Invalid bus specified");
 
-	rte_eal_pci_register(&my_driver);
-	rte_eal_pci_register(&my_driver2);
+	TEST_ASSERT(TAILQ_EMPTY(&test_pci_bus.test_driver_list),
+		    "PCI Driver list not empty");
+
+	/* Add test drivers to Bus */
+	TAILQ_INSERT_TAIL(&test_pci_bus.test_driver_list, &my_driver, next);
+	TAILQ_INSERT_TAIL(&test_pci_bus.test_driver_list, &my_driver2, next);
 
 	pci_dev_count = 0;
-	printf("Scan bus\n");
-	rte_eal_pci_probe();
+
+	printf("Probe the Test Bus\n");
+	do_pci_bus_probe();
 
 	if (pci_dev_count == 0) {
 		printf("no device detected\n");
@@ -257,8 +320,8 @@ test_pci_blacklist(void)
 	blacklist_all_devices();
 
 	pci_dev_count = 0;
-	printf("Scan bus with all devices blacklisted\n");
-	rte_eal_pci_probe();
+	printf("Probe bus with all devices blacklisted\n");
+	do_pci_bus_probe();
 
 	free_devargs_list();
 	devargs_list = save_devargs_list;
@@ -270,8 +333,9 @@ test_pci_blacklist(void)
 
 	test_pci_run = 1;
 
-	rte_eal_pci_unregister(&my_driver);
-	rte_eal_pci_unregister(&my_driver2);
+	/* Clear the test drivers added to Test Bus */
+	TAILQ_REMOVE(&(test_pci_bus.test_driver_list), &my_driver, next);
+	TAILQ_REMOVE(&(test_pci_bus.test_driver_list), &my_driver2, next);
 
 	return 0;
 }
-- 
2.7.4



More information about the dev mailing list