[dpdk-dev] [RFC PATCH 3/6] bus: add bus driver layer

Shreyansh Jain shreyansh.jain at nxp.com
Thu Nov 17 06:30:02 CET 2016


A bus is managed using a 'bus driver'. This patch introduces a sample
PCI bus driver which essentially is the scan and match implementation for
PCI.

There are multiple possible alternatives to where such a driver can be
kept within the DPDK code:
1. librte_bus
 - For each type of bus, there would a file like 'eal_xxx_bus' which would
   then be bound with the eal library.
 - Within this way, another possibility was librte_bus_xxx.

2. Within the drivers/* folder:
 - drivers/bus, parallel to drivers/net and drivers/crypto
 - This way, each bus implmentation would be within the drivers/* area and
   a new implementation would only mean adding a new set of files and
   corresponding changes to the Makefiles.

3. Problem with (3) is that the naming is misleading. drivers/net and
   drivers/crypto are essentially two functionalities rather than drivers.
   Putting driver/bus parallel to these would be misleading in literal
   terms.
   Another possibility is to keep the drivers parallel to 'drivers' folder
   in root of DPDK.
   This is the implementation preferred in this patch.
   A new bus would mean adding a new folder structure within 'bus' -
   including distinction between linuxapp and bsdapp.

In all the three cases, the bus drivers would be instantiated using a
constructor similar to RTE_PMD_REGISTER_XXX. OR, specifically in case of
(2), it would be a priority based constructor.
(__attribute__((contructor(XX))) to assure that buses are loaded before
the drivers are loaded.

Further, as of now the 'pci_bus.c' only shows the scan and dump hooks.
rte_bus also includes hooks for 'dump'ing all devices on the bus and
'find_dev' for finding a device given its rte_device. Each of these
'optional' implementation are more like helpers but have implementation
which is specific to the bus. Hooks for finding a device can be used for
hotplugging (searching before adding a new device, removing existing).
Similarly, 'dump' is a way to represent device information in bus specific
way.

Missing/Grey areas:
 - A lot of PCI specific code is still in EAL - for example mapping. These
   can be moved into bus. Mapping of memory should be a bus property.
 - PMDINFOGEN symbol support for bus - this patch doesn't take care of
   that
 - there would be multiple lists for each bus. Would those be shared
   across various libraries, internal or external, which can be associated
   with DPDK? Should a tailq registration like method be used?

Pending work:
 - The integration of bus/* with librte_eal is not complete. There might
   be symbol issues.
 - Notification support for drivers over a bus doesn't exist yet. Probably
   that needs to be integrated with interrupt handling - no work on this
   has been done yet.

Signed-off-by: Shreyansh Jain <shreyansh.jain at nxp.com>
---
 bus/Makefile               |  36 ++++
 bus/pci/Makefile           |  37 ++++
 bus/pci/linuxapp/pci_bus.c | 418 +++++++++++++++++++++++++++++++++++++++++++++
 bus/pci/linuxapp/pci_bus.h |  55 ++++++
 4 files changed, 546 insertions(+)
 create mode 100644 bus/Makefile
 create mode 100644 bus/pci/Makefile
 create mode 100644 bus/pci/linuxapp/pci_bus.c
 create mode 100644 bus/pci/linuxapp/pci_bus.h

diff --git a/bus/Makefile b/bus/Makefile
new file mode 100644
index 0000000..cfa548c
--- /dev/null
+++ b/bus/Makefile
@@ -0,0 +1,36 @@
+#   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 $(RTE_SDK)/mk/rte.vars.mk
+
+DIRS-y += pci
+
+include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/bus/pci/Makefile b/bus/pci/Makefile
new file mode 100644
index 0000000..fb6cc44
--- /dev/null
+++ b/bus/pci/Makefile
@@ -0,0 +1,37 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   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 Intel Corporation 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 $(RTE_SDK)/mk/rte.vars.mk
+
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += linuxapp
+DIRS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += bsdapp
+
+include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/bus/pci/linuxapp/pci_bus.c b/bus/pci/linuxapp/pci_bus.c
new file mode 100644
index 0000000..b61cb0a
--- /dev/null
+++ b/bus/pci/linuxapp/pci_bus.c
@@ -0,0 +1,418 @@
+/*-
+ *   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 <string.h>
+#include <dirent.h>
+
+#include <rte_log.h>
+#include <rte_bus.h>
+#include <rte_pci.h>
+#include <rte_eal_memconfig.h>
+#include <rte_malloc.h>
+#include <rte_devargs.h>
+#include <rte_memcpy.h>
+
+#include "eal_filesystem.h"
+#include "eal_private.h"
+#include "eal_pci_init.h"
+
+
+
+/**
+ * Default PCI matching function called duing probe for drivers
+ *
+ * @param drv
+ *	The PCI driver handle
+ * @param dev
+ *	The PCI device handle
+ * @return
+ *	0 for successful match
+ *	!0 for unsuccessful match
+ */
+int rte_eal_pci_match_default(struct rte_pci_driver *drv,
+			      struct rte_pci_device *dev);
+
+
+/*
+ * split up a pci address into its constituent parts.
+ */
+static int
+parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
+		      uint8_t *bus, uint8_t *devid, uint8_t *function)
+{
+	/* first split on ':' */
+	union splitaddr {
+		struct {
+			char *domain;
+			char *bus;
+			char *devid;
+			char *function;
+		};
+		char *str[PCI_FMT_NVAL];
+		/* last element-separator is "." not ":" */
+	} splitaddr;
+
+	char *buf_copy = strndup(buf, bufsize);
+	if (buf_copy == NULL)
+		return -1;
+
+	if (rte_strsplit(buf_copy, bufsize, splitaddr.str, PCI_FMT_NVAL, ':')
+			!= PCI_FMT_NVAL - 1)
+		goto error;
+	/* final split is on '.' between devid and function */
+	splitaddr.function = strchr(splitaddr.devid,'.');
+	if (splitaddr.function == NULL)
+		goto error;
+	*splitaddr.function++ = '\0';
+
+	/* now convert to int values */
+	errno = 0;
+	*domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
+	*bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
+	*devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
+	*function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
+	if (errno != 0)
+		goto error;
+
+	free(buf_copy); /* free the copy made with strdup */
+	return 0;
+error:
+	free(buf_copy);
+	return -1;
+}
+
+/* parse the "resource" sysfs file */
+static int
+pci_parse_sysfs_resource(const char *filename,
+			 struct rte_pci_device *dev)
+{
+	FILE *f;
+	char buf[BUFSIZ];
+	int i;
+	uint64_t phys_addr, end_addr, flags;
+
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		RTE_LOG(ERR, EAL, "Cannot open sysfs resource\n");
+		return -1;
+	}
+
+	for (i = 0; i<PCI_MAX_RESOURCE; i++) {
+
+		if (fgets(buf, sizeof(buf), f) == NULL) {
+			RTE_LOG(ERR, EAL,
+				"%s(): cannot read resource\n", __func__);
+			goto error;
+		}
+		if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
+				&end_addr, &flags) < 0)
+			goto error;
+
+		if (flags & IORESOURCE_MEM) {
+			dev->mem_resource[i].phys_addr = phys_addr;
+			dev->mem_resource[i].len = end_addr - phys_addr + 1;
+			/* not mapped for now */
+			dev->mem_resource[i].addr = NULL;
+		}
+	}
+	fclose(f);
+	return 0;
+
+error:
+	fclose(f);
+	return -1;
+}
+
+/* Scan one pci sysfs entry, and fill the devices list from it. */
+static int
+pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,uint8_t devid,
+	     uint8_t function)
+{
+	char filename[PATH_MAX];
+	unsigned long tmp;
+	struct rte_pci_device *pci_dev;
+	struct rte_bus *pci_bus;
+	struct rte_device *dev;
+	char driver[PATH_MAX];
+	int ret;
+
+	/* Get the PCI bus for device; It it doesn't exist, can't continue */
+	pci_bus = rte_eal_get_bus(PCI_BUS_NAME);
+	if (!pci_bus) {
+		RTE_LOG(ERR, EAL, "Unable to get PCI bus.\n");
+		return -1;
+	}
+
+	pci_dev = malloc(sizeof(*pci_dev));
+	if (pci_dev == NULL)
+		return -1;
+
+	memset(pci_dev, 0, sizeof(*pci_dev));
+	pci_dev->addr.domain = domain;
+	pci_dev->addr.bus = bus;
+	pci_dev->addr.devid = devid;
+	pci_dev->addr.function = function;
+
+	/* Set Bus */
+	pci_dev->device->bus = pci_bus;
+
+	/* get vendor id */
+	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
+	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
+		free(pci_dev);
+		return -1;
+	}
+	pci_dev->id.vendor_id = (uint16_t)tmp;
+
+	/* get device id */
+	snprintf(filename, sizeof(filename), "%s/device", dirname);
+	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
+		free(pci_dev);
+		return -1;
+	}
+	pci_dev->id.device_id = (uint16_t)tmp;
+
+	/* get subsystem_vendor id */
+	snprintf(filename, sizeof(filename), "%s/subsystem_vendor",
+		 dirname);
+	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
+		free(pci_dev);
+		return -1;
+	}
+	pci_dev->id.subsystem_vendor_id = (uint16_t)tmp;
+
+	/* get subsystem_device id */
+	snprintf(filename, sizeof(filename), "%s/subsystem_device",
+		 dirname);
+	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
+		free(pci_dev);
+		return -1;
+	}
+	pci_dev->id.subsystem_device_id = (uint16_t)tmp;
+
+	/* get class_id */
+	snprintf(filename, sizeof(filename), "%s/class",
+		 dirname);
+	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
+		free(pci_dev);
+		return -1;
+	}
+	/* the least 24 bits are valid: class, subclass, program interface */
+	pci_dev->id.class_id = (uint32_t)tmp & RTE_CLASS_ANY_ID;
+
+	/* get max_vfs */
+	pci_dev->max_vfs = 0;
+	snprintf(filename, sizeof(filename), "%s/max_vfs", dirname);
+	if (!access(filename, F_OK) &&
+	    eal_parse_sysfs_value(filename, &tmp) == 0)
+		pci_dev->max_vfs = (uint16_t)tmp;
+	else {
+		/* for non igb_uio driver, need kernel version >= 3.8 */
+		snprintf(filename, sizeof(filename),
+			 "%s/sriov_numvfs", dirname);
+		if (!access(filename, F_OK) &&
+		    eal_parse_sysfs_value(filename, &tmp) == 0)
+			pci_dev->max_vfs = (uint16_t)tmp;
+	}
+
+	/* get numa node */
+	snprintf(filename, sizeof(filename), "%s/numa_node",
+		 dirname);
+	if (access(filename, R_OK) != 0) {
+		/* if no NUMA support, set default to 0 */
+		pci_dev->device.numa_node = 0;
+	} else {
+		if (eal_parse_sysfs_value(filename, &tmp) < 0) {
+			free(pci_dev);
+			return -1;
+		}
+		pci_dev->device.numa_node = tmp;
+	}
+
+	/* parse resources */
+	snprintf(filename, sizeof(filename), "%s/resource", dirname);
+	if (pci_parse_sysfs_resource(filename, pci_dev) < 0) {
+		RTE_LOG(ERR, EAL, "%s(): cannot parse resource\n", __func__);
+		free(pci_dev);
+		return -1;
+	}
+
+	/* parse driver */
+	snprintf(filename, sizeof(filename), "%s/driver", dirname);
+	ret = pci_get_kernel_driver_by_path(filename, driver);
+	if (ret < 0) {
+		RTE_LOG(ERR, EAL, "Fail to get kernel driver\n");
+		free(pci_dev);
+		return -1;
+	}
+
+	if (!ret) {
+		if (!strcmp(driver, "vfio-pci"))
+			pci_dev->kdrv = RTE_KDRV_VFIO;
+		else if (!strcmp(driver, "igb_uio"))
+			pci_dev->kdrv = RTE_KDRV_IGB_UIO;
+		else if (!strcmp(driver, "uio_pci_generic"))
+			pci_dev->kdrv = RTE_KDRV_UIO_GENERIC;
+		else
+			pci_dev->kdrv = RTE_KDRV_UNKNOWN;
+	} else
+		pci_dev->kdrv = RTE_KDRV_NONE;
+
+	/* device is valid, add in list (sorted) */
+	if (TAILQ_EMPTY(&pci_bus->device_list)) {
+		rte_eal_bus_add_device(pci_bus, dev->device);
+	} else {
+		struct rte_device *dev2 = NULL;
+		struct rte_pci_device *pci_dev2;
+		int ret;
+
+		TAILQ_FOREACH(dev2, &pci_bus->device_list, next) {
+			pci_dev2 = container_of(dev2, struct rte_pci_device,
+						device);
+
+			ret = rte_eal_compare_pci_addr(&pci_dev->addr,
+						       &pci_dev2->addr);
+			if (ret > 0)
+				continue;
+
+			if (ret < 0) {
+				/* TODO Pending: 'before' handler for
+				 * bus->device_list
+				 */
+				rte_eal_bus_add_device(pci_bus,
+						       pci_dev2->device);
+			} else { /* already registered */
+				pci_dev2->kdrv = pci_dev->kdrv;
+				pci_dev2->max_vfs = pci_dev->max_vfs;
+				memmove(pci_dev2->mem_resource,
+					pci_dev->mem_resource,
+					sizeof(pci_dev->mem_resource));
+				free(pci_dev);
+			}
+			return 0;
+		}
+		rte_eal_device_insert(&pci_dev->device);
+		TAILQ_INSERT_TAIL(&pci_device_list, pci_dev, next);
+	}
+
+	return 0;
+}
+
+/* Default PCI match implementation */
+int
+pci_bus_match(struct rte_pci_driver *drv,
+			  struct rte_pci_device *dev)
+{
+	int ret = 1;
+	const struct rte_pci_id *id_table;
+
+	for (id_table = drv->id_table; id_table->vendor_id != 0; id_table++) {
+
+		/* check if device's identifiers match the driver's ones */
+		if (id_table->vendor_id != dev->id.vendor_id &&
+				id_table->vendor_id != PCI_ANY_ID)
+			continue;
+		if (id_table->device_id != dev->id.device_id &&
+				id_table->device_id != PCI_ANY_ID)
+			continue;
+		if (id_table->subsystem_vendor_id !=
+		    dev->id.subsystem_vendor_id &&
+		    id_table->subsystem_vendor_id != PCI_ANY_ID)
+			continue;
+		if (id_table->subsystem_device_id !=
+		    dev->id.subsystem_device_id &&
+		    id_table->subsystem_device_id != PCI_ANY_ID)
+			continue;
+		if (id_table->class_id != dev->id.class_id &&
+				id_table->class_id != RTE_CLASS_ANY_ID)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	/* Returning a >0 value as <0 is considered error by caller */
+	return ret;
+}
+
+/*
+ * Scan the content of the PCI bus, and the devices in the devices
+ * list
+ */
+int
+pci_bus_scan(void)
+{
+	struct dirent *e;
+	DIR *dir;
+	char dirname[PATH_MAX];
+	uint16_t domain;
+	uint8_t bus, devid, function;
+
+	/* for debug purposes, PCI can be disabled */
+	if (internal_config.no_pci)
+		return 0;
+
+	dir = opendir(pci_get_sysfs_path());
+	if (dir == NULL) {
+		RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n",
+			__func__, strerror(errno));
+		return -1;
+	}
+
+	while ((e = readdir(dir)) != NULL) {
+		if (e->d_name[0] == '.')
+			continue;
+
+		if (parse_pci_addr_format(e->d_name, sizeof(e->d_name),
+				&domain, &bus, &devid, &function) != 0)
+			continue;
+
+		snprintf(dirname, sizeof(dirname), "%s/%s",
+				pci_get_sysfs_path(), e->d_name);
+		if (pci_scan_one(dirname, domain, bus, devid, function) < 0)
+			goto error;
+	}
+	closedir(dir);
+	return 0;
+
+error:
+	closedir(dir);
+	return -1;
+}
+
+struct rte_bus pci_bus = {
+	.scan = pci_bus_scan,
+	.match = pci_bus_match,
+	.dump = NULL,
+};
+
+RTE_PMD_REGISTER_BUS("pci_bus", pci_bus);
diff --git a/bus/pci/linuxapp/pci_bus.h b/bus/pci/linuxapp/pci_bus.h
new file mode 100644
index 0000000..580fa36
--- /dev/null
+++ b/bus/pci/linuxapp/pci_bus.h
@@ -0,0 +1,55 @@
+/*-
+ *   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.
+ */
+
+/**
+ * Default PCI matching function called duing probe for drivers
+ *
+ * @param drv
+ *	The PCI driver handle
+ * @param dev
+ *	The PCI device handle
+ * @return
+ *	0 for successful match
+ *	!0 for unsuccessful match
+ */
+int bus_pci_match(struct rte_pci_driver *drv,
+		  struct rte_pci_device *dev);
+
+/**
+* Scan the content of the PCI bus, and the devices in the devices
+* list
+*
+* @return
+*  0 on success, negative on error
+*/
+int bus_pci_scan(void);
-- 
2.7.4



More information about the dev mailing list