From mboxrd@z Thu Jan 1 00:00:00 1970 From: Shreyansh Jain Subject: [PATCH v7 7/9] test: update bus and pci unit test cases Date: Tue, 17 Jan 2017 15:39:32 +0530 Message-ID: <1484647774-28984-8-git-send-email-shreyansh.jain@nxp.com> References: <1484581107-2025-1-git-send-email-shreyansh.jain@nxp.com> <1484647774-28984-1-git-send-email-shreyansh.jain@nxp.com> Mime-Version: 1.0 Content-Type: text/plain Cc: , , Shreyansh Jain To: Return-path: Received: from NAM03-DM3-obe.outbound.protection.outlook.com (mail-dm3nam03on0052.outbound.protection.outlook.com [104.47.41.52]) by dpdk.org (Postfix) with ESMTP id 0E7BE2BA2 for ; Tue, 17 Jan 2017 11:06:31 +0100 (CET) In-Reply-To: <1484647774-28984-1-git-send-email-shreyansh.jain@nxp.com> List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Signed-off-by: Shreyansh Jain --- 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 #include +#include #include #include #include +#include #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