[dpdk-dev,v6,5/8] eal: introduce bus scan and probe in EAL

Message ID 1484581107-2025-6-git-send-email-shreyansh.jain@nxp.com (mailing list archive)
State Superseded, archived
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel compilation success Compilation OK

Commit Message

Shreyansh Jain Jan. 16, 2017, 3:38 p.m. UTC
  Each bus implementation defines their own callbacks for scanning bus
and probing devices available on the bus. Enable EAL to call bus specific
scan and probe functions during DPDK initialization.

Existing PCI scan/probe continues to exist. It will removed in subsequent
patches.

Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
---
 lib/librte_eal/bsdapp/eal/eal.c                 |  8 +++
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 11 ++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  2 +
 lib/librte_eal/common/eal_common_bus.c          | 41 +++++++++++++++
 lib/librte_eal/common/eal_common_pci.c          | 33 ++++++++++++
 lib/librte_eal/common/include/rte_bus.h         | 39 ++++++++++++++
 lib/librte_eal/common/include/rte_pci.h         | 68 +++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal.c               |  8 +++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 15 ++++++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  2 +
 10 files changed, 227 insertions(+)
  

Comments

Ferruh Yigit Jan. 16, 2017, 7:58 p.m. UTC | #1
On 1/16/2017 3:38 PM, Shreyansh Jain wrote:
> Each bus implementation defines their own callbacks for scanning bus
> and probing devices available on the bus. Enable EAL to call bus specific
> scan and probe functions during DPDK initialization.
> 
> Existing PCI scan/probe continues to exist. It will removed in subsequent
> patches.
> 
> Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>

<...>

> +/* Scan all the buses for registering devices */
> +int
> +rte_bus_scan(void)

I hesitate to make this kind of (not really functional) comments in this
stage of the release, but please feel free to ignore them as your wish.

Previous patch is (4/8) for adding bus scan support, so why not this
function (also .map and .h file part of it) added in prev patch?

And if there is a specific patch for scan, probe can be another one?

> +{
> +	int ret;
> +	struct rte_bus *bus = NULL;
> +
> +	TAILQ_FOREACH(bus, &rte_bus_list, next) {
> +		ret = bus->scan();
> +		if (ret) {
> +			RTE_LOG(ERR, EAL, "Scan for (%s) bus failed.\n",
> +				bus->name);
> +			/* Error in scanning any bus stops the EAL init. */
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}

<...>

> diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
> index 0d799be..35da451 100644
<...>
> +
> +/* Add a PCI device to PCI Bus */
> +void
> +rte_eal_pci_add_device(struct rte_pci_bus *pci_bus,
> +		       struct rte_pci_device *pci_dev)

I think more generic approach from previous version was better
(rte_eal_bus_add_device()), but I guess they sacrificed for less
modification.

> +{
> +	TAILQ_INSERT_TAIL(&pci_bus->device_list, pci_dev, next);
> +	/* Update Bus references */
> +	pci_dev->device.bus = &pci_bus->bus;
> +}
> +

<...>

>  
> +/**
> + * Structure describing the PCI bus
> + */
> +struct rte_pci_bus {
> +	struct rte_bus bus;               /**< Inherit the generic class */
> +	struct rte_pci_device_list device_list;  /**< List of PCI devices */
> +	struct rte_pci_driver_list driver_list;  /**< List of PCI drivers */

Why bus device/driver lists moved from rte_bus? Each bus will need this?
Is it to change as less code as possible?

<...>

> +
> +/**
> + * Insert a PCI device in the PCI Bus at a particular location in the device
> + * list. It also updates the PCI Bus reference of the new devices to be
> + * inserted.

Minor issue in document compilation:

- warning: argument 'pci_dev' of command @param is not found

- parameter 'new_pci_dev' not documented

Similar warnings exists for rte_eal_pci_remove_device() too.

Also following in rte_bus_scan(void) and rte_bus_probe(void)
- warning: argument 'void' of command @param is not found

> + *
> + * @param exist_pci_dev
> + *	Existing PCI device in PCI Bus
> + * @param pci_dev
> + *	PCI device to be added before exist_pci_dev
> + * @return void
> + */
> +void rte_eal_pci_insert_device(struct rte_pci_device *exist_pci_dev,
> +			       struct rte_pci_device *new_pci_dev);
> +

<...>
  
Shreyansh Jain Jan. 17, 2017, 5:03 a.m. UTC | #2
On Tuesday 17 January 2017 01:28 AM, Ferruh Yigit wrote:
> On 1/16/2017 3:38 PM, Shreyansh Jain wrote:
>> Each bus implementation defines their own callbacks for scanning bus
>> and probing devices available on the bus. Enable EAL to call bus specific
>> scan and probe functions during DPDK initialization.
>>
>> Existing PCI scan/probe continues to exist. It will removed in subsequent
>> patches.
>>
>> Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
>
> <...>
>
>> +/* Scan all the buses for registering devices */
>> +int
>> +rte_bus_scan(void)
>
> I hesitate to make this kind of (not really functional) comments in this
> stage of the release, but please feel free to ignore them as your wish.

No issues - any review comment is welcome.

>
> Previous patch is (4/8) for adding bus scan support, so why not this
> function (also .map and .h file part of it) added in prev patch?

Maybe I didn't get your point well, but this is my take:

4/8 is for introducing the scan callbacks into the Bus layer. There is 
no work done for EAL yet in 4/8.

This patch, 5/8, adds functions (not callbacks) and modifications to EAL 
for plugging the bus (with its scan/probe) into EAL.

>
> And if there is a specific patch for scan, probe can be another one?

I agree with this.

>
>> +{
>> +	int ret;
>> +	struct rte_bus *bus = NULL;
>> +
>> +	TAILQ_FOREACH(bus, &rte_bus_list, next) {
>> +		ret = bus->scan();
>> +		if (ret) {
>> +			RTE_LOG(ERR, EAL, "Scan for (%s) bus failed.\n",
>> +				bus->name);
>> +			/* Error in scanning any bus stops the EAL init. */
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>
> <...>
>
>> diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
>> index 0d799be..35da451 100644
> <...>
>> +
>> +/* Add a PCI device to PCI Bus */
>> +void
>> +rte_eal_pci_add_device(struct rte_pci_bus *pci_bus,
>> +		       struct rte_pci_device *pci_dev)
>
> I think more generic approach from previous version was better
> (rte_eal_bus_add_device()), but I guess they sacrificed for less
> modification.

There was a lot of offline discussions after the reviews were posted 
until v5. From the gist of it, I gathered that smaller 'specific' 
changes are preferred as compared to complete generic approach without 
an upfront usecase.

Also, this change became irrelevant once I moved out the device/driver 
lists from rte_bus to rte_xxx_bus. This is inline with existing model of 
(rte_pci_device->rte_device, rte_pci_driver->rte_driver, 
rte_pci_bus->rte_bus) and having pci_device_list/pci_driver_list private 
to PCI itself.

I guess what is going to happen is that in near future when buses start 
moving to drivers/bus/*, this kind of generic layer would come in.

>
>> +{
>> +	TAILQ_INSERT_TAIL(&pci_bus->device_list, pci_dev, next);
>> +	/* Update Bus references */
>> +	pci_dev->device.bus = &pci_bus->bus;
>> +}
>> +
>
> <...>
>
>>
>> +/**
>> + * Structure describing the PCI bus
>> + */
>> +struct rte_pci_bus {
>> +	struct rte_bus bus;               /**< Inherit the generic class */
>> +	struct rte_pci_device_list device_list;  /**< List of PCI devices */
>> +	struct rte_pci_driver_list driver_list;  /**< List of PCI drivers */
>
> Why bus device/driver lists moved from rte_bus? Each bus will need this?
> Is it to change as less code as possible?

Yes, to move towards a minimal change.
Also, in sync with existing 'pci_device_list/pci_driver_list'.

>
> <...>
>
>> +
>> +/**
>> + * Insert a PCI device in the PCI Bus at a particular location in the device
>> + * list. It also updates the PCI Bus reference of the new devices to be
>> + * inserted.
>
> Minor issue in document compilation:
>
> - warning: argument 'pci_dev' of command @param is not found
>
> - parameter 'new_pci_dev' not documented
>
> Similar warnings exists for rte_eal_pci_remove_device() too.
>
> Also following in rte_bus_scan(void) and rte_bus_probe(void)
> - warning: argument 'void' of command @param is not found

I will fix and post v7 very shortly.

>
>> + *
>> + * @param exist_pci_dev
>> + *	Existing PCI device in PCI Bus
>> + * @param pci_dev
>> + *	PCI device to be added before exist_pci_dev
>> + * @return void
>> + */
>> +void rte_eal_pci_insert_device(struct rte_pci_device *exist_pci_dev,
>> +			       struct rte_pci_device *new_pci_dev);
>> +
>
> <...>
>
>
  
Shreyansh Jain Jan. 17, 2017, 10:13 a.m. UTC | #3
Just an update on things fixed/updated in v7 against these comments:

On Tuesday 17 January 2017 01:28 AM, Ferruh Yigit wrote:
> On 1/16/2017 3:38 PM, Shreyansh Jain wrote:
>> Each bus implementation defines their own callbacks for scanning bus
>> and probing devices available on the bus. Enable EAL to call bus specific
>> scan and probe functions during DPDK initialization.
>>
>> Existing PCI scan/probe continues to exist. It will removed in subsequent
>> patches.
>>
>> Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
>
> <...>
>
>> +/* Scan all the buses for registering devices */
>> +int
>> +rte_bus_scan(void)
>
> I hesitate to make this kind of (not really functional) comments in this
> stage of the release, but please feel free to ignore them as your wish.
>
> Previous patch is (4/8) for adding bus scan support, so why not this
> function (also .map and .h file part of it) added in prev patch?
>
> And if there is a specific patch for scan, probe can be another one?

v7 Contains a split patch for introducing probe handler and introducing
scan and probe in EAL.

>
>> +{
>> +	int ret;
>> +	struct rte_bus *bus = NULL;
>> +
>> +	TAILQ_FOREACH(bus, &rte_bus_list, next) {
>> +		ret = bus->scan();
>> +		if (ret) {
>> +			RTE_LOG(ERR, EAL, "Scan for (%s) bus failed.\n",
>> +				bus->name);
>> +			/* Error in scanning any bus stops the EAL init. */
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>
> <...>
>
>> diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
>> index 0d799be..35da451 100644
> <...>
>> +
>> +/* Add a PCI device to PCI Bus */
>> +void
>> +rte_eal_pci_add_device(struct rte_pci_bus *pci_bus,
>> +		       struct rte_pci_device *pci_dev)
>
> I think more generic approach from previous version was better
> (rte_eal_bus_add_device()), but I guess they sacrificed for less
> modification.
>
>> +{
>> +	TAILQ_INSERT_TAIL(&pci_bus->device_list, pci_dev, next);
>> +	/* Update Bus references */
>> +	pci_dev->device.bus = &pci_bus->bus;
>> +}
>> +
>
> <...>
>
>>
>> +/**
>> + * Structure describing the PCI bus
>> + */
>> +struct rte_pci_bus {
>> +	struct rte_bus bus;               /**< Inherit the generic class */
>> +	struct rte_pci_device_list device_list;  /**< List of PCI devices */
>> +	struct rte_pci_driver_list driver_list;  /**< List of PCI drivers */
>
> Why bus device/driver lists moved from rte_bus? Each bus will need this?
> Is it to change as less code as possible?
>
> <...>
>
>> +
>> +/**
>> + * Insert a PCI device in the PCI Bus at a particular location in the device
>> + * list. It also updates the PCI Bus reference of the new devices to be
>> + * inserted.
>
> Minor issue in document compilation:
>
> - warning: argument 'pci_dev' of command @param is not found
>
> - parameter 'new_pci_dev' not documented
>
> Similar warnings exists for rte_eal_pci_remove_device() too.
>
> Also following in rte_bus_scan(void) and rte_bus_probe(void)
> - warning: argument 'void' of command @param is not found

Pushed v7 to ML. 'make doc' is not reporting any warn/error now.
Thanks for pointing it out.

>
>> + *
>> + * @param exist_pci_dev
>> + *	Existing PCI device in PCI Bus
>> + * @param pci_dev
>> + *	PCI device to be added before exist_pci_dev
>> + * @return void
>> + */
>> +void rte_eal_pci_insert_device(struct rte_pci_device *exist_pci_dev,
>> +			       struct rte_pci_device *new_pci_dev);
>> +
>
> <...>
>
>
  
Thomas Monjalon Jan. 17, 2017, 11:04 p.m. UTC | #4
2017-01-17 10:33, Shreyansh Jain:
> On Tuesday 17 January 2017 01:28 AM, Ferruh Yigit wrote:
> > On 1/16/2017 3:38 PM, Shreyansh Jain wrote:
> >> +/* Add a PCI device to PCI Bus */
> >> +void
> >> +rte_eal_pci_add_device(struct rte_pci_bus *pci_bus,
> >> +                   struct rte_pci_device *pci_dev)
> >
> > I think more generic approach from previous version was better
> > (rte_eal_bus_add_device()), but I guess they sacrificed for less
> > modification.
> 
> There was a lot of offline discussions after the reviews were posted 
> until v5. From the gist of it, I gathered that smaller 'specific' 
> changes are preferred as compared to complete generic approach without 
> an upfront usecase.

Yes I discussed (a lot) this approach with Shreyansh.

> Also, this change became irrelevant once I moved out the device/driver 
> lists from rte_bus to rte_xxx_bus. This is inline with existing model of 
> (rte_pci_device->rte_device, rte_pci_driver->rte_driver, 
> rte_pci_bus->rte_bus) and having pci_device_list/pci_driver_list private 
> to PCI itself.
> 
> I guess what is going to happen is that in near future when buses start 
> moving to drivers/bus/*, this kind of generic layer would come in.

I think there will be no use case requiring a unique list of all rte_device(s).
Being generic and wrapping stuff with abstract classes is not always a benefit.
That's why, this version is more focused on specialized objects.

Experience with this layering will tell us wether it is a good design or not.
  

Patch

diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 2206277..a584447 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -64,6 +64,7 @@ 
 #include <rte_string_fns.h>
 #include <rte_cpuflags.h>
 #include <rte_interrupts.h>
+#include <rte_bus.h>
 #include <rte_pci.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
@@ -577,6 +578,9 @@  rte_eal_init(int argc, char **argv)
 		rte_config.master_lcore, thread_id, cpuset,
 		ret == 0 ? "" : "...");
 
+	if (rte_bus_scan())
+		rte_panic("Cannot scan the buses for devices\n");
+
 	RTE_LCORE_FOREACH_SLAVE(i) {
 
 		/*
@@ -613,6 +617,10 @@  rte_eal_init(int argc, char **argv)
 	if (rte_eal_pci_probe())
 		rte_panic("Cannot probe PCI\n");
 
+	/* Probe all the buses and devices/drivers on them */
+	if (rte_bus_probe())
+		rte_panic("Cannot probe devices\n");
+
 	if (rte_eal_dev_init() < 0)
 		rte_panic("Cannot init pmd devices\n");
 
diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 3a5c315..48bfe24 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -673,3 +673,14 @@  rte_eal_pci_init(void)
 	}
 	return 0;
 }
+
+struct rte_pci_bus rte_pci_bus = {
+	.bus = {
+		.scan = rte_eal_pci_scan,
+		.probe = rte_eal_pci_probe,
+	},
+	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
+	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
+};
+
+RTE_REGISTER_BUS(PCI_BUS_NAME, rte_pci_bus.bus);
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index c015889..c43140c 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -182,6 +182,8 @@  DPDK_17.02 {
 	rte_bus_dump;
 	rte_bus_register;
 	rte_bus_unregister;
+	rte_bus_probe;
+	rte_bus_scan;
 	rte_pci_match;
 
 } DPDK_16.11;
diff --git a/lib/librte_eal/common/eal_common_bus.c b/lib/librte_eal/common/eal_common_bus.c
index 35baff8..9c91ca6 100644
--- a/lib/librte_eal/common/eal_common_bus.c
+++ b/lib/librte_eal/common/eal_common_bus.c
@@ -53,6 +53,7 @@  rte_bus_register(struct rte_bus *bus)
 	RTE_VERIFY(bus->name && strlen(bus->name));
 	/* A bus should mandatorily have the scan implemented */
 	RTE_VERIFY(bus->scan);
+	RTE_VERIFY(bus->probe);
 
 	TAILQ_INSERT_TAIL(&rte_bus_list, bus, next);
 	RTE_LOG(INFO, EAL, "Registered [%s] bus.\n", bus->name);
@@ -66,6 +67,46 @@  rte_bus_unregister(struct rte_bus *bus)
 	RTE_LOG(INFO, EAL, "Unregistered [%s] bus.\n", bus->name);
 }
 
+/* Scan all the buses for registering devices */
+int
+rte_bus_scan(void)
+{
+	int ret;
+	struct rte_bus *bus = NULL;
+
+	TAILQ_FOREACH(bus, &rte_bus_list, next) {
+		ret = bus->scan();
+		if (ret) {
+			RTE_LOG(ERR, EAL, "Scan for (%s) bus failed.\n",
+				bus->name);
+			/* Error in scanning any bus stops the EAL init. */
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/* Call bus specific probe */
+int
+rte_bus_probe(void)
+{
+	int ret;
+	struct rte_bus *bus;
+
+	/* For each bus registered with EAL */
+	TAILQ_FOREACH(bus, &rte_bus_list, next) {
+		ret = bus->probe();
+		if (ret) {
+			RTE_LOG(ERR, EAL, "Bus (%s) probe failed.\n",
+				bus->name);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 /* dump one bus info */
 static int
 bus_dump_one(FILE *f, struct rte_bus *bus)
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 0d799be..35da451 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -71,6 +71,7 @@ 
 
 #include <rte_interrupts.h>
 #include <rte_log.h>
+#include <rte_bus.h>
 #include <rte_pci.h>
 #include <rte_per_lcore.h>
 #include <rte_memory.h>
@@ -508,3 +509,35 @@  rte_eal_pci_unregister(struct rte_pci_driver *driver)
 	rte_eal_driver_unregister(&driver->driver);
 	TAILQ_REMOVE(&pci_driver_list, driver, next);
 }
+
+/* Add a PCI device to PCI Bus */
+void
+rte_eal_pci_add_device(struct rte_pci_bus *pci_bus,
+		       struct rte_pci_device *pci_dev)
+{
+	TAILQ_INSERT_TAIL(&pci_bus->device_list, pci_dev, next);
+	/* Update Bus references */
+	pci_dev->device.bus = &pci_bus->bus;
+}
+
+/* Insert a PCI device into a predefined position in PCI bus */
+void
+rte_eal_pci_insert_device(struct rte_pci_device *exist_pci_dev,
+			  struct rte_pci_device *new_pci_dev)
+{
+	TAILQ_INSERT_BEFORE(exist_pci_dev, new_pci_dev, next);
+	/* Update Bus references */
+	new_pci_dev->device.bus = exist_pci_dev->device.bus;
+}
+
+/* Remove a PCI device from PCI bus */
+void
+rte_eal_pci_remove_device(struct rte_pci_device *pci_dev)
+{
+	struct rte_pci_bus *pci_bus;
+
+	pci_bus = container_of(pci_dev->device.bus, struct rte_pci_bus, bus);
+	TAILQ_REMOVE(&pci_bus->device_list, pci_dev, next);
+	/* Update Bus references */
+	pci_dev->device.bus = NULL;
+}
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 152451c..f1d4c2c 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -77,12 +77,30 @@  extern struct rte_bus_list rte_bus_list;
 typedef int (*rte_bus_scan_t)(void);
 
 /**
+ * Implementation specific probe function which is responsible for linking
+ * devices on that bus with applicable drivers.
+ *
+ * This is called while iterating over each registered bus. Bus object is
+ * passed along assuming this is wrapped around (embedded) by Implementation
+ * specific bus object.
+ *
+ * @param bus
+ *	Generic bus object which was registered with EAL
+ *
+ * @return
+ *	0 for successful probe
+ *	!0 for any error while probing
+ */
+typedef int (*rte_bus_probe_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 */
+	rte_bus_probe_t probe;       /**< Probe devices on bus */
 };
 
 /**
@@ -104,6 +122,27 @@  void rte_bus_register(struct rte_bus *bus);
 void rte_bus_unregister(struct rte_bus *bus);
 
 /**
+ * Scan all the buses attached to the framework.
+ *
+ * @param void
+ * @return
+ *	0 in case of success in scanning all buses
+ *	!0 in case of failure to scan
+ */
+int rte_bus_scan(void);
+
+/**
+ * For each device on the bus, perform a driver 'match' and call the
+ * bus's probe for device initialization.
+ *
+ * @param void
+ * @return
+ *	0 for successful match/probe
+ *	!0 otherwise
+ */
+int rte_bus_probe(void);
+
+/**
  * Dump information of all the buses registered with EAL.
  *
  * @param f
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 6c9ec39..a52b390 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -85,6 +85,7 @@  extern "C" {
 #include <rte_debug.h>
 #include <rte_interrupts.h>
 #include <rte_dev.h>
+#include <rte_bus.h>
 
 TAILQ_HEAD(pci_device_list, rte_pci_device); /**< PCI devices in D-linked Q. */
 TAILQ_HEAD(pci_driver_list, rte_pci_driver); /**< PCI drivers in D-linked Q. */
@@ -111,6 +112,25 @@  const char *pci_get_sysfs_path(void);
 /** Maximum number of PCI resources. */
 #define PCI_MAX_RESOURCE 6
 
+/** Name of PCI Bus */
+#define PCI_BUS_NAME "PCI"
+
+/* Forward declarations */
+struct rte_pci_device;
+struct rte_pci_driver;
+
+/** List of PCI devices */
+TAILQ_HEAD(rte_pci_device_list, rte_pci_device);
+/** List of PCI drivers */
+TAILQ_HEAD(rte_pci_driver_list, rte_pci_driver);
+
+/* PCI Bus iterators */
+#define FOREACH_DEVICE_ON_PCIBUS(p)	\
+		TAILQ_FOREACH(p, &(rte_pci_bus.device_list), next)
+
+#define FOREACH_DRIVER_ON_PCIBUS(p)	\
+		TAILQ_FOREACH(p, &(rte_pci_bus.driver_list), next)
+
 /**
  * A structure describing an ID for a PCI driver. Each driver provides a
  * table of these IDs for each device that it supports.
@@ -206,12 +226,22 @@  typedef int (pci_remove_t)(struct rte_pci_device *);
 struct rte_pci_driver {
 	TAILQ_ENTRY(rte_pci_driver) next;       /**< Next in list. */
 	struct rte_driver driver;               /**< Inherit core driver. */
+	struct rte_pci_bus *pci_bus;            /**< PCI bus reference */
 	pci_probe_t *probe;                     /**< Device Probe function. */
 	pci_remove_t *remove;                   /**< Device Remove function. */
 	const struct rte_pci_id *id_table;	/**< ID table, NULL terminated. */
 	uint32_t drv_flags;                     /**< Flags contolling handling of device. */
 };
 
+/**
+ * Structure describing the PCI bus
+ */
+struct rte_pci_bus {
+	struct rte_bus bus;               /**< Inherit the generic class */
+	struct rte_pci_device_list device_list;  /**< List of PCI devices */
+	struct rte_pci_driver_list driver_list;  /**< List of PCI drivers */
+};
+
 /** Device needs PCI BAR mapping (done with either IGB_UIO or VFIO) */
 #define RTE_PCI_DRV_NEED_MAPPING 0x0001
 /** Device driver supports link state interrupt */
@@ -523,6 +553,44 @@  RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
 void rte_eal_pci_unregister(struct rte_pci_driver *driver);
 
 /**
+ * Add a PCI device to the PCI Bus (append to PCI Device list). This function
+ * also updates the bus references of the PCI Device (and the generic device
+ * object embedded within.
+ *
+ * @param pci_bus
+ *	PCI Bus reference to which device is to be added
+ * @param pci_dev
+ *	PCI device to add
+ * @return void
+ */
+void rte_eal_pci_add_device(struct rte_pci_bus *pci_bus,
+			    struct rte_pci_device *pci_dev);
+
+/**
+ * Insert a PCI device in the PCI Bus at a particular location in the device
+ * list. It also updates the PCI Bus reference of the new devices to be
+ * inserted.
+ *
+ * @param exist_pci_dev
+ *	Existing PCI device in PCI Bus
+ * @param pci_dev
+ *	PCI device to be added before exist_pci_dev
+ * @return void
+ */
+void rte_eal_pci_insert_device(struct rte_pci_device *exist_pci_dev,
+			       struct rte_pci_device *new_pci_dev);
+
+/**
+ * Remove a PCI device from the PCI Bus. This sets to NULL the bus references
+ * in the PCI device object as well as the generic device object.
+ *
+ * @param pci_dev
+ *	PCI device to be removed from PCI Bus
+ * @return void
+ */
+void rte_eal_pci_remove_device(struct rte_pci_device *pci_device);
+
+/**
  * Read PCI config space.
  *
  * @param device
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 16dd5b9..f77ff5c 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -69,6 +69,7 @@ 
 #include <rte_string_fns.h>
 #include <rte_cpuflags.h>
 #include <rte_interrupts.h>
+#include <rte_bus.h>
 #include <rte_pci.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
@@ -844,6 +845,9 @@  rte_eal_init(int argc, char **argv)
 	if (rte_eal_intr_init() < 0)
 		rte_panic("Cannot init interrupt-handling thread\n");
 
+	if (rte_bus_scan())
+		rte_panic("Cannot scan the buses for devices\n");
+
 	RTE_LCORE_FOREACH_SLAVE(i) {
 
 		/*
@@ -884,6 +888,10 @@  rte_eal_init(int argc, char **argv)
 	if (rte_eal_pci_probe())
 		rte_panic("Cannot probe PCI\n");
 
+	/* Probe all the buses and devices/drivers on them */
+	if (rte_bus_probe())
+		rte_panic("Cannot probe devices\n");
+
 	if (rte_eal_dev_init() < 0)
 		rte_panic("Cannot init pmd devices\n");
 
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index e2fc219..300064d 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -35,6 +35,7 @@ 
 #include <dirent.h>
 
 #include <rte_log.h>
+#include <rte_bus.h>
 #include <rte_pci.h>
 #include <rte_eal_memconfig.h>
 #include <rte_malloc.h>
@@ -54,6 +55,9 @@ 
  * IGB_UIO driver (or doesn't initialize, if the device wasn't bound to it).
  */
 
+/* Forward declaration of PCI bus */
+struct rte_pci_bus rte_pci_bus;
+
 static int
 pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
 {
@@ -723,3 +727,14 @@  rte_eal_pci_init(void)
 
 	return 0;
 }
+
+struct rte_pci_bus rte_pci_bus = {
+	.bus = {
+		.scan = rte_eal_pci_scan,
+		.probe = rte_eal_pci_probe,
+	},
+	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
+	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
+};
+
+RTE_REGISTER_BUS(PCI_BUS_NAME, rte_pci_bus.bus);
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 5ed2589..6f047c5 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -186,6 +186,8 @@  DPDK_17.02 {
 	rte_bus_dump;
 	rte_bus_register;
 	rte_bus_unregister;
+	rte_bus_probe;
+	rte_bus_scan;
 	rte_pci_match;
 
 } DPDK_16.11;