Re: [PATCH v8 10/30] PCI: Introduce pci_host_bridge_list to manage host bridges
From: Yinghai Lu
Date: Thu Mar 26 2015 - 12:32:13 EST
On Mon, Mar 23, 2015 at 8:34 PM, Yijing Wang <wangyijing@xxxxxxxxxx> wrote:
> Introduce pci_host_bridge_list to manage pci host
> bridges in system, this make us have the ability
> to check whether the new host would conflict with
> existing one. Then we could remove bus alreay exist
> check in __pci_create_root_bus().
Can we use bus_type instead?
Then we can use bus_find_device for the host_bridge enumeration.
Please refer the patches that I sent out couple years ago.
Thanks
Yinghai
Subject: [PATCH] PCI: Add dummy bus_type for pci_host_bridge
Need to use it for looping registered host_bridges, and kill
pci_root_buses list later.
Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
---
drivers/pci/pci-driver.c | 10 ++++++++++
drivers/pci/probe.c | 1 +
include/linux/pci.h | 2 ++
3 files changed, 13 insertions(+)
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -735,6 +735,7 @@ enum pcie_bus_config_types {
extern enum pcie_bus_config_types pcie_bus_config;
+extern struct bus_type pci_host_bridge_bus_type;
extern struct bus_type pci_bus_type;
/* Do NOT directly access these two variables, unless you are arch-specific PCI
@@ -808,6 +809,7 @@ void pci_stop_root_bus(struct pci_bus *b
void pci_remove_root_bus(struct pci_bus *bus);
void pci_setup_cardbus(struct pci_bus *bus);
void pci_sort_breadthfirst(void);
+#define dev_is_pci_host_bridge(d) ((d)->bus == &pci_host_bridge_bus_type)
#define dev_is_pci(d) ((d)->bus == &pci_bus_type)
#define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false))
#define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf(to_pci_dev(d)) : 0))
Index: linux-2.6/drivers/pci/pci-driver.c
===================================================================
--- linux-2.6.orig/drivers/pci/pci-driver.c
+++ linux-2.6/drivers/pci/pci-driver.c
@@ -1408,6 +1408,16 @@ struct bus_type pci_bus_type = {
};
EXPORT_SYMBOL(pci_bus_type);
+struct bus_type pci_host_bridge_bus_type = {
+ .name = "pci_host_bridge",
+};
+
+static int __init pci_host_bridge_driver_init(void)
+{
+ return bus_register(&pci_host_bridge_bus_type);
+}
+postcore_initcall(pci_host_bridge_driver_init);
+
static int __init pci_driver_init(void)
{
return bus_register(&pci_bus_type);
Index: linux-2.6/drivers/pci/probe.c
===================================================================
--- linux-2.6.orig/drivers/pci/probe.c
+++ linux-2.6/drivers/pci/probe.c
@@ -1949,6 +1949,7 @@ struct pci_bus *pci_create_root_bus(stru
goto err_out;
bridge->dev.parent = parent;
+ bridge->dev.bus = &pci_host_bridge_bus_type;
bridge->dev.release = pci_release_host_bridge_dev;
dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
error = pcibios_root_bridge_prepare(bridge);
Subject: [PATCH] PCI: Add for_each_pci_host_bridge() and pci_get_next_host_bridge
Now we have pci_root_buses list, and there is lots of iteration with
list_of_each of it, that is not safe after we add pci root bus hotplug
support after booting stage.
Also pci_find_next_bus is pretty misleading name, and it is only finding
next root bus instead of regular pci bus.
Add pci_get_next_host_bridge and use bus_find_device in driver core to
iterate host bridge and the same time get root bus.
In folllowing patches will replace searching root bus with searching host_bridge.
after using with that host-bridge, will need to call put device to release
reference if break early from the loop.
After those replacing, we even could kill pci_root_buses list.
-v2: fixes compiling error when CONFIG_PCI is not defined that Fengguang found.
Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
---
drivers/pci/search.c | 24 ++++++++++++++++++++++++
include/linux/pci.h | 9 +++++++++
2 files changed, 33 insertions(+)
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -409,6 +409,8 @@ struct pci_host_bridge {
};
#define to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev)
+#define for_each_pci_host_bridge(d) while ((d = pci_get_next_host_bridge(d)) != NULL)
+
void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
void (*release_fn)(struct pci_host_bridge *),
void *release_data);
@@ -831,6 +833,7 @@ int pci_find_ht_capability(struct pci_de
int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
+struct pci_host_bridge *pci_get_next_host_bridge(struct pci_host_bridge *from);
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
struct pci_dev *from);
struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
@@ -1447,6 +1450,12 @@ static inline int pci_domain_nr(struct p
static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
+static inline struct pci_host_bridge *pci_get_next_host_bridge(
+ struct pci_host_bridge *host_bridge)
+{
+ return NULL;
+}
+
#define dev_is_pci(d) (false)
#define dev_is_pf(d) (false)
#define dev_num_vf(d) (0)
Index: linux-2.6/drivers/pci/search.c
===================================================================
--- linux-2.6.orig/drivers/pci/search.c
+++ linux-2.6/drivers/pci/search.c
@@ -231,6 +231,30 @@ struct pci_dev *pci_get_domain_bus_and_s
}
EXPORT_SYMBOL(pci_get_domain_bus_and_slot);
+static int match_pci_host_bridge(struct device *dev, void *data)
+{
+ return 1;
+}
+
+struct pci_host_bridge *pci_get_next_host_bridge(struct pci_host_bridge *from)
+{
+ struct device *dev;
+ struct device *dev_start = NULL;
+ struct pci_host_bridge *bridge = NULL;
+
+ WARN_ON(in_interrupt());
+ if (from)
+ dev_start = &from->dev;
+ dev = bus_find_device(&pci_host_bridge_bus_type, dev_start, NULL,
+ match_pci_host_bridge);
+ if (dev)
+ bridge = to_pci_host_bridge(dev);
+ if (from)
+ put_device(&from->dev);
+ return bridge;
+}
+EXPORT_SYMBOL_GPL(pci_get_next_host_bridge);
+
static int match_pci_dev_by_id(struct device *dev, void *data)
{
struct pci_dev *pdev = to_pci_dev(dev);