@@ -94,7 +94,7 @@ SRCS-y += test_cycles.c
SRCS-y += test_spinlock.c
SRCS-y += test_memory.c
SRCS-y += test_memzone.c
-
+SRCS-y += test_bus.c
SRCS-y += test_ring.c
SRCS-y += test_ring_perf.c
SRCS-y += test_pmd_perf.c
@@ -236,6 +236,8 @@ int commands_init(void);
int test_pci(void);
int test_pci_run;
+int test_bus(void);
+
int test_mp_secondary(void);
int test_set_rxtx_conf(cmdline_fixed_string_t mode);
new file mode 100644
@@ -0,0 +1,424 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 NXP.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of NXP nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_bus.h>
+#include <rte_devargs.h>
+
+#include "test.h"
+#include "resource.h"
+
+/* Visualizing following bus-device-driver model for test
+ *
+ * ===.===========.===========.=========,= busA
+ * | | . |
+ * devA1 devA2 . '____CPU_
+ * `-----------`-------> driverA |
+ * '
+ * ===.===========.===========.=========|= busB
+ * | | .
+ * devB1 devB2 .
+ * `-----------`-------> driverB
+ *
+ */
+
+#define MAX_DEVICES_ON_BUS 10
+#define MAX_DRIVERS_ON_BUS 10
+
+/* A structure representing a ethernet/crypto device, embedding
+ * the rte_device.
+ */
+struct dummy_device {
+ const char *name;
+ struct rte_device dev;
+};
+
+/* Structure representing a Bus with devices attached to it, and drivers
+ * for those devices
+ */
+struct dummy_bus {
+ const char *name;
+ struct rte_bus *bus;
+ struct rte_driver *drivers[MAX_DRIVERS_ON_BUS];
+ struct dummy_device *devices[MAX_DEVICES_ON_BUS];
+};
+
+struct rte_bus_list orig_bus_list =
+ TAILQ_HEAD_INITIALIZER(orig_bus_list);
+
+struct rte_bus busA = {
+ .name = "busA", /* "busA" */
+};
+
+struct rte_bus busB = {
+ .name = "busB", /* "busB */
+};
+
+struct rte_driver driverA = {
+ .name = "driverA",
+};
+
+struct dummy_device devA1 = {
+ .name = "devA1",
+ .dev = {
+ .bus = NULL,
+ .driver = NULL,
+ }
+};
+
+struct dummy_device devA2 = {
+ .name = "devA2",
+ .dev = {
+ .bus = NULL,
+ .driver = NULL,
+ }
+};
+
+struct rte_driver driverB = {
+ .name = "driverB",
+};
+
+struct dummy_device devB1 = {
+ .name = "devB1",
+ .dev = {
+ .bus = NULL,
+ .driver = NULL,
+ }
+};
+
+struct dummy_device devB2 = {
+ .name = "devB2",
+ .dev = {
+ .bus = NULL,
+ .driver = NULL,
+ }
+};
+
+struct dummy_bus dummy_buses[] = {
+ {
+ .name = "busA",
+ .bus = &busA,
+ .drivers = {&driverA, NULL},
+ .devices = {&devA1, &devA2, NULL},
+ },
+ {
+ .name = "busB",
+ .bus = &busB,
+ .drivers = {&driverB, NULL},
+ .devices = {&devB1, &devB2, NULL},
+ },
+ {NULL, NULL, {NULL,}, {NULL,}, },
+};
+
+/* @internal
+ * Dump the device tree
+ */
+static void
+dump_device_tree(void)
+{
+ int i;
+ struct dummy_bus *db;
+ struct rte_bus *bus;
+ struct rte_driver *drv;
+ struct rte_device *dev;
+
+ printf("------>8-------\n");
+ printf("Device Tree:\n");
+ for (i = 0; dummy_buses[i].name; i++) {
+ db = &dummy_buses[i];
+
+ bus = rte_eal_bus_get(db->name);
+ if (!bus)
+ return;
+
+ printf(" Bus: %s\n", bus->name);
+
+ printf(" Drivers on bus:\n");
+ TAILQ_FOREACH(drv, &bus->driver_list, next) {
+ printf(" %s\n", drv->name);
+ }
+
+ printf(" Devices on bus:\n");
+ TAILQ_FOREACH(dev, &bus->device_list, next) {
+ printf(" Addr: %p\n", dev);
+ if (dev->driver)
+ printf(" Driver = %s\n", dev->driver->name);
+ else
+ printf(" Driver = None\n");
+ }
+ }
+ printf("------>8-------\n");
+}
+
+static int
+test_bus_setup(void)
+{
+ struct rte_bus *bus_p = NULL;
+
+ /* Preserve the original bus list before executing test */
+ while (!TAILQ_EMPTY(&rte_bus_list)) {
+ bus_p = TAILQ_FIRST(&rte_bus_list);
+ TAILQ_REMOVE(&rte_bus_list, bus_p, next);
+ TAILQ_INSERT_TAIL(&orig_bus_list, bus_p, next);
+ }
+
+ return 0;
+}
+
+static int
+test_bus_cleanup(void)
+{
+ struct rte_bus *bus_p = NULL;
+
+ /* Cleanup rte_bus_list before restoring entries */
+ while (!TAILQ_EMPTY(&rte_bus_list)) {
+ bus_p = TAILQ_FIRST(&rte_bus_list);
+ rte_eal_bus_unregister(bus_p);
+ TAILQ_REMOVE(&rte_bus_list, bus_p, next);
+ }
+
+ bus_p = NULL;
+ /* Restore original entries */
+ while (!TAILQ_EMPTY(&orig_bus_list)) {
+ bus_p = TAILQ_FIRST(&orig_bus_list);
+ TAILQ_REMOVE(&orig_bus_list, bus_p, next);
+ TAILQ_INSERT_TAIL(&rte_bus_list, bus_p, next);
+ }
+
+ dump_device_tree();
+ return 0;
+}
+
+
+static int
+test_bus_registration(void)
+{
+ int i;
+ int ret;
+ struct rte_bus *bus = NULL;
+
+ for (i = 0; dummy_buses[i].name != NULL; i++) {
+ bus = dummy_buses[i].bus;
+ rte_eal_bus_register(bus);
+ printf("Registered Bus %s\n", dummy_buses[i].name);
+ }
+
+ /* Verify that all buses have been successfully registered */
+ i = 0;
+ TAILQ_FOREACH(bus, &rte_bus_list, next) {
+ /* Or, if the name of the bus is NULL */
+ if (!bus->name) {
+ /* Incorrect entry in list */
+ printf("Incorrect bus registered.\n");
+ return -1;
+ }
+
+ /* Or, if the bus name doesn't match that of dummy_buses */
+ ret = strcmp(bus->name, dummy_buses[i].name);
+ if (ret) {
+ /* Bus name doesn't match */
+ printf("Unable to correctly register bus (%s).\n",
+ dummy_buses[i].name);
+ return -1;
+ }
+ i++;
+ }
+
+ /* Current value of dummy_buses[i] should be the NULL entry */
+ if (dummy_buses[i].name != NULL) {
+ printf("Not all buses were registered. For e.g. (%s)\n",
+ dummy_buses[i].name);
+ return -1;
+ }
+
+ printf("Buses registered are:\n");
+ rte_eal_bus_dump(stdout);
+
+ return 0;
+}
+
+static int
+test_bus_unregistration(void)
+{
+ int i;
+ struct rte_bus *bus = NULL;
+
+ for (i = 0; dummy_buses[i].name != NULL; i++) {
+ bus = rte_eal_bus_get(dummy_buses[i].name);
+ if (bus) {
+ printf("Unregistering bus: '%s'\n", bus->name);
+ rte_eal_bus_unregister(bus);
+ }
+ }
+
+ if (!TAILQ_EMPTY(&rte_bus_list)) {
+ /* Unable to unregister all dummy buses */
+ printf("Unable to unregister all buses\n");
+ return -1;
+ }
+
+ printf("All buses have been unregistered.\n");
+ dump_device_tree();
+ return 0;
+}
+
+/* Positive case: For each driver in dummy_buses, perform
+ * registration
+ */
+static int
+test_driver_registration_on_bus(void)
+{
+ int i, j;
+ struct rte_bus *bus = NULL;
+ struct rte_driver *drv, *drv2;
+
+ /* For each bus on the dummy_buses list:
+ * 1. get the bus reference
+ * 2. register all drivers from dummy_buses
+ */
+ for (i = 0; dummy_buses[i].name; i++) {
+ bus = rte_eal_bus_get(dummy_buses[i].name);
+ if (!bus) {
+ printf("Unable to find bus (%s)\n",
+ dummy_buses[i].name);
+ return -1;
+ }
+
+ /* For bus 'bus', register all drivers */
+ for (j = 0; dummy_buses[i].drivers[j]; j++) {
+ drv = dummy_buses[i].drivers[j];
+ rte_eal_bus_add_driver(bus, drv);
+ }
+ }
+
+ /* Drivers have been registered. Verify by parsing the list */
+ drv = NULL;
+ for (i = 0; dummy_buses[i].name; i++) {
+ bus = rte_eal_bus_get(dummy_buses[i].name);
+ if (!bus) {
+ printf("Unable to find bus (%s)\n",
+ dummy_buses[i].name);
+ return -1;
+ }
+
+ j = 0;
+ TAILQ_FOREACH(drv, &bus->driver_list, next) {
+ drv2 = dummy_buses[i].drivers[j++];
+ if (strcmp(drv2->name, drv->name)) {
+ printf("Incorrectly registered drivers."
+ " Expected: %s; Available: %s\n",
+ drv2->name, drv->name);
+ return -1;
+ }
+ }
+ }
+
+ printf("Driver registration test successful.\n");
+ dump_device_tree();
+
+ return 0;
+}
+
+static int
+test_driver_unregistration_on_bus(void)
+{
+ int i;
+ struct rte_bus *bus = NULL;
+ struct rte_driver *drv;
+
+ for (i = 0; dummy_buses[i].name; i++) {
+ bus = rte_eal_bus_get(dummy_buses[i].name);
+ if (!bus) {
+ printf("Unable to find bus (%s)\n",
+ dummy_buses[i].name);
+ return -1;
+ }
+
+ /* For bus 'bus', unregister all drivers */
+ TAILQ_FOREACH(drv, &bus->driver_list, next) {
+ rte_eal_bus_remove_driver(drv);
+ }
+ }
+
+ /* Verifying that all drivers have been removed */
+ for (i = 0; dummy_buses[i].name; i++) {
+ bus = rte_eal_bus_get(dummy_buses[i].name);
+
+ if (!TAILQ_EMPTY(&bus->driver_list)) {
+ printf("Unable to remove all drivers on bus (%s)\n",
+ bus->name);
+ return -1;
+ }
+ }
+
+ printf("Unregistration of drivers on all buses is successful.\n");
+ /* All devices from all buses have been removed */
+ dump_device_tree();
+ return 0;
+
+}
+
+int
+test_bus(void)
+{
+ /* Make necessary arrangements before starting test */
+ if (test_bus_setup())
+ return -1;
+
+ if (test_bus_registration())
+ return -1;
+
+ /* Assuming that buses are already registered, register drivers
+ * with them.
+ */
+ if (test_driver_registration_on_bus())
+ return -1;
+
+ if (test_driver_unregistration_on_bus())
+ return -1;
+
+ if (test_bus_unregistration())
+ return -1;
+
+ /* Restore the original environment/settings */
+ if (test_bus_cleanup())
+ return -1;
+
+ return 0;
+}
+
+REGISTER_TEST_COMMAND(bus_autotest, test_bus);