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);