v8->v9:
Add Thierry's Acked-by and Tested-by.
Fix the building error for powerpc found by Daniel.
Change pci_host_assign_domain_nr() to static.
v7->v8:
Fix some cross building errors found by kbuild test.
Drop the rename patch for find_pci_host_bridge().
v6->v7:
Drop previous patch which combined the domain and bus in one argument.
Make the pci_host_bridge hold the default busn resource, so we could
check whether new host busn resource is conflict with existing ones.
Move pci_host_assign_domain_nr() to drivers/pci/host-bridge.c
Other changes suggested by Bjorn and Suravee.
v5->v6:
Fix cross building errors found by kbuild test.
Export busn_resource to Xen pcifront driver.
v4->v5:
Fix some code style issues and rename some functions suggested by Bjorn.
Fix some code flaw(Eg. call pci_bus_add_devices() before resources claim
or lack the return checking).
v3->v4:
Fix the rebase issue.
v2->v3:
Rebase this series on v4.0-rc1.
v1->v2:
Split pci_host_bridge_list into a new patch, remove .phb_probe_mode
and rework powerpc .phb_of_scan_bus() for simpilicty suggested by
Arnd. Refresh some patch description log, and add a new patch to fix
build warning in ia64.
This series is based on Bjorn's pci/enumeration branch.
You could pull it from https://github.com/YijingWang/linux-pci.git enumer9
Now in kernel, we scan pci bus use the following ways:
1. pci_scan_bus.
parent = NULL, default io/mem/bus resources
call pci_bus_add_devices()
2. pci_scan_bus_parented() + pci_bus_add_devices()
default io/mem/bus resources, only used by xen
3. pci_scan_root_bus() + pci_bus_add_devices()
4. pci_create_root_bus() + pci_scan_child_bus() + pci_bus_add_devices()
5. pci_create_root_bus() + xx_of_scan_bus() + pci_bus_add_devices()
And we have a lot of arch specific pci_domain_nr() and other platform
specific weak function like pcibios_root_bridge_prepare().
After applied this series, we have following scan interfaces:
1. pci_scan_bus()
parent = NULL, default io/mem/bus resources.
for legacy pci scan
2. pci_scan_root_bus()
for callers provide its own parent and io/mem/bus resources
but no platform specific pci_host_bridge operations
3. pci_scan_host_bridge()
for callers provide its own parent and io/mem/bus resources
Arnd Bergmann (1):
xen/PCI: Don't use deprecated function pci_scan_bus_parented()
Yijing Wang (29):
PCI: Remove deprecated pci_scan_bus_parented()
PCI: Save domain in pci_host_bridge
PCI: Move pci_bus_assign_domain_nr() declaration into
drivers/pci/pci.h
PCI: Introduce pci_host_assign_domain_nr() to assign domain
PCI: Separate pci_host_bridge creation out of pci_create_root_bus()
PCI: Add default bus resource in pci_host_bridge
PCI: Update pci_host_bridge bus resource
PCI: Introduce pci_host_first_busnr() function
PCI: Introduce pci_host_bridge_list to manage host bridges
PCI: Save sysdata in pci_host_bridge drvdata
powerpc/PCI: Rename pcibios_root_bridge_prepare() to
pcibios_set_root_bus_speed()
PCI: Move pcibios_root_bridge_prepare() to pci_create_host_bridge()
PCI: Introduce pci_host_bridge_ops to support host specific
operations
PCI: Introduce new scan function pci_scan_host_bridge()
PCI: Introduce pci_bus_child_max_busnr()
x86/PCI: Refine pci_acpi_scan_root() with generic pci_host_bridge
ia64/PCI: Refine pci_acpi_scan_root() with generic pci_host_bridge
powerpc/pci: Use pci_scan_host_bridge() for simplicity
PCI: Remove pcibios_root_bridge_prepare() and
pcibos_set_root_bus_speed()
sparc/PCI: Use pci_scan_host_bridge() for simplicity
parisc/PCI: Use pci_scan_root_bus() for simplicity
PCI/mvebu: Use pci_common_init_dev() to simplify code
PCI/tegra: Remove redundant tegra_pcie_scan_bus()
PCI/designware: Use pci_scan_root_bus() for simplicity
PCI/xgene: Use pci_scan_root_bus() instead of pci_create_root_bus()
PCI: Rename __pci_create_root_bus() to pci_create_root_bus()
PCI: Remove platform specific pci_domain_nr()
PCI: Remove pci_bus_assign_domain_nr()
PCI: Clean up CONFIG_PCI_DOMAINS_GENERIC
arch/alpha/include/asm/pci.h | 2 -
arch/alpha/kernel/pci.c | 4 +-
arch/alpha/kernel/sys_nautilus.c | 2 +-
arch/arm/Kconfig | 3 -
arch/arm/kernel/bios32.c | 2 +-
arch/arm/mach-dove/pcie.c | 2 +-
arch/arm/mach-iop13xx/pci.c | 4 +-
arch/arm/mach-mv78xx0/pcie.c | 2 +-
arch/arm/mach-orion5x/pci.c | 4 +-
arch/arm64/Kconfig | 3 -
arch/frv/mb93090-mb00/pci-vdk.c | 3 +-
arch/ia64/include/asm/pci.h | 1 -
arch/ia64/pci/pci.c | 34 +++--
arch/ia64/sn/kernel/io_init.c | 4 +-
arch/m68k/coldfire/pci.c | 2 +-
arch/microblaze/pci/pci-common.c | 15 +--
arch/mips/include/asm/pci.h | 2 -
arch/mips/pci/pci.c | 4 +-
arch/mn10300/unit-asb2305/pci.c | 3 +-
arch/powerpc/include/asm/machdep.h | 2 +-
arch/powerpc/kernel/pci-common.c | 79 ++++++------
arch/powerpc/platforms/pseries/pci.c | 8 +-
arch/powerpc/platforms/pseries/pseries.h | 2 +-
arch/powerpc/platforms/pseries/setup.c | 2 +-
arch/s390/pci/pci.c | 10 +-
arch/sh/drivers/pci/pci.c | 4 +-
arch/sh/include/asm/pci.h | 2 -
arch/sparc/kernel/leon_pci.c | 2 +-
arch/sparc/kernel/pci.c | 45 +++----
arch/sparc/kernel/pcic.c | 2 +-
arch/tile/include/asm/pci.h | 2 -
arch/tile/kernel/pci.c | 4 +-
arch/tile/kernel/pci_gx.c | 4 +-
arch/unicore32/kernel/pci.c | 2 +-
arch/x86/include/asm/pci.h | 6 -
arch/x86/pci/acpi.c | 37 +++---
arch/x86/pci/common.c | 2 +-
arch/xtensa/kernel/pci.c | 2 +-
drivers/parisc/dino.c | 6 +-
drivers/parisc/lba_pci.c | 4 +-
drivers/pci/host-bridge.c | 202 ++++++++++++++++++++++++++++
drivers/pci/host/pci-mvebu.c | 18 +---
drivers/pci/host/pci-tegra.c | 16 ---
drivers/pci/host/pci-versatile.c | 3 +-
drivers/pci/host/pci-xgene.c | 3 +-
drivers/pci/host/pcie-designware.c | 4 +-
drivers/pci/host/pcie-xilinx.c | 2 +-
drivers/pci/hotplug/acpiphp_glue.c | 29 +----
drivers/pci/hotplug/ibmphp_core.c | 2 +-
drivers/pci/pci.c | 85 ++++---------
drivers/pci/pci.h | 15 ++
drivers/pci/probe.c | 212 ++++++++++++------------------
drivers/pci/xen-pcifront.c | 16 ++-
include/linux/pci.h | 46 +++----
54 files changed, 517 insertions(+), 459 deletions(-)
Save platform specific sysdata in pci_host_bridge
drvdata, host bridge specific operation need to
access it before the pci bus creation.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 3 ++-
drivers/pci/pci.h | 2 +-
drivers/pci/probe.c | 20 ++++++++++----------
3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index dffb345..98047c6 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -63,7 +63,7 @@ static bool pci_host_busn_res_overlap(
struct pci_host_bridge *pci_create_host_bridge(
struct device *parent, int domain, int bus,
- struct list_head *resources)
+ void *sysdata, struct list_head *resources)
{
int error;
struct pci_host_bridge *host, *tmp;
@@ -101,6 +101,7 @@ struct pci_host_bridge *pci_create_host_bridge(
mutex_unlock(&pci_host_mutex);
host->dev.release = pci_release_host_bridge_dev;
+ dev_set_drvdata(&host->dev, sysdata);
dev_set_name(&host->dev, "pci%04x:%02x",
host->domain, bus);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 886d72f..aa8dff6 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -335,7 +335,7 @@ static inline void pci_host_assign_domain_nr(struct pci_host_bridge *host)
#endif
struct pci_host_bridge *pci_create_host_bridge(struct device *parent,
- int domain, int bus, struct list_head *resources);
+ int domain, int bus, void *sysdata, struct list_head *resources);
void pci_free_host_bridge(struct pci_host_bridge *host);
static inline int pci_host_first_busnr(struct pci_host_bridge *host)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 8517d1b..0ac2bf6 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1865,8 +1865,7 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
}
static struct pci_bus *__pci_create_root_bus(
- struct pci_host_bridge *bridge, struct pci_ops *ops,
- void *sysdata)
+ struct pci_host_bridge *bridge, struct pci_ops *ops)
{
int error;
struct pci_bus *b;
@@ -1882,7 +1881,7 @@ static struct pci_bus *__pci_create_root_bus(
if (!b)
return NULL;
- b->sysdata = sysdata;
+ b->sysdata = dev_get_drvdata(&bridge->dev);
b->ops = ops;
b->number = b->busn_res.start =
pci_host_first_busnr(bridge);
@@ -1956,11 +1955,12 @@ struct pci_bus *pci_create_root_bus(struct device *parent,
{
struct pci_host_bridge *host;
- host = pci_create_host_bridge(parent, domain, bus, resources);
+ host = pci_create_host_bridge(parent, domain, bus,
+ sysdata, resources);
if (!host)
return NULL;
- host->bus = __pci_create_root_bus(host, ops, sysdata);
+ host->bus = __pci_create_root_bus(host, ops);
if (!host->bus)
pci_free_host_bridge(host);
@@ -2037,13 +2037,12 @@ void pci_bus_release_busn_res(struct pci_bus *b)
}
static struct pci_bus *__pci_scan_root_bus(
- struct pci_host_bridge *host, struct pci_ops *ops,
- void *sysdata)
+ struct pci_host_bridge *host, struct pci_ops *ops)
{
struct pci_bus *b;
int max;
- b = __pci_create_root_bus(host, ops, sysdata);
+ b = __pci_create_root_bus(host, ops);
if (!b)
return NULL;
@@ -2064,11 +2063,12 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
{
struct pci_host_bridge *host;
- host = pci_create_host_bridge(parent, domain, bus, resources);
+ host = pci_create_host_bridge(parent, domain, bus,
+ sysdata, resources);
if (!host)
return NULL;
- host->bus = __pci_scan_root_bus(host, ops, sysdata);
+ host->bus = __pci_scan_root_bus(host, ops);
if (!host->bus)
pci_free_host_bridge(host);
--
1.7.1
From: Arnd Bergmann <[email protected]>
Use pci_scan_root_bus() instead of deprecated function
pci_scan_bus_parented().
Signed-off-by: Arnd Bergmann <[email protected]>
Signed-off-by: Yijing Wang <[email protected]>
CC: Konrad Rzeszutek Wilk <[email protected]>
CC: [email protected]
---
drivers/pci/xen-pcifront.c | 16 +++++++++++++---
1 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index b1ffebe..a69e529 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -446,9 +446,15 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
unsigned int domain, unsigned int bus)
{
struct pci_bus *b;
+ LIST_HEAD(resources);
struct pcifront_sd *sd = NULL;
struct pci_bus_entry *bus_entry = NULL;
int err = 0;
+ static struct resource busn_res = {
+ .start = 0,
+ .end = 255,
+ .flags = IORESOURCE_BUS,
+ };
#ifndef CONFIG_PCI_DOMAINS
if (domain != 0) {
@@ -470,17 +476,21 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
err = -ENOMEM;
goto err_out;
}
+ pci_add_resource(&resources, &ioport_resource);
+ pci_add_resource(&resources, &iomem_resource);
+ pci_add_resource(&resources, &busn_res);
pcifront_init_sd(sd, domain, bus, pdev);
pci_lock_rescan_remove();
- b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
- &pcifront_bus_ops, sd);
+ b = pci_scan_root_bus(&pdev->xdev->dev, bus,
+ &pcifront_bus_ops, sd, &resources);
if (!b) {
dev_err(&pdev->xdev->dev,
"Error creating PCI Frontend Bus!\n");
err = -ENOMEM;
pci_unlock_rescan_remove();
+ pci_free_resource_list(&resources);
goto err_out;
}
@@ -488,7 +498,7 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
list_add(&bus_entry->list, &pdev->root_buses);
- /* pci_scan_bus_parented skips devices which do not have a have
+ /* pci_scan_root_bus skips devices which do not have a
* devfn==0. The pcifront_scan_bus enumerates all devfn. */
err = pcifront_scan_bus(pdev, domain, bus, b);
--
1.7.1
No one uses pci_scan_bus_parented() any more,
remove it.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/probe.c | 19 -------------------
include/linux/pci.h | 2 --
2 files changed, 0 insertions(+), 21 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 8ef0375..699a238 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2091,25 +2091,6 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
}
EXPORT_SYMBOL(pci_scan_root_bus);
-/* Deprecated; use pci_scan_root_bus() instead */
-struct pci_bus *pci_scan_bus_parented(struct device *parent,
- int bus, struct pci_ops *ops, void *sysdata)
-{
- LIST_HEAD(resources);
- struct pci_bus *b;
-
- pci_add_resource(&resources, &ioport_resource);
- pci_add_resource(&resources, &iomem_resource);
- pci_add_resource(&resources, &busn_resource);
- b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
- if (b)
- pci_scan_child_bus(b);
- else
- pci_free_resource_list(&resources);
- return b;
-}
-EXPORT_SYMBOL(pci_scan_bus_parented);
-
struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
void *sysdata)
{
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 211e9da..36effb8 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -769,8 +769,6 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
void pcibios_scan_specific_bus(int busn);
struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
-struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata);
struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata,
--
1.7.1
Save domain in pci_host_bridge, so we could get domain
from pci_host_bridge, and at the end of series, we could
clean up the arch specific pci_domain_nr(). For arm,
we pass -1 as the domain number, we would update the
domain number in core by pci_bus_assign_domain_nr().
Signed-off-by: Yijing Wang <[email protected]>
---
arch/alpha/kernel/pci.c | 4 ++--
arch/alpha/kernel/sys_nautilus.c | 2 +-
arch/arm/kernel/bios32.c | 2 +-
arch/arm/mach-dove/pcie.c | 2 +-
arch/arm/mach-iop13xx/pci.c | 4 ++--
arch/arm/mach-mv78xx0/pcie.c | 2 +-
arch/arm/mach-orion5x/pci.c | 4 ++--
arch/frv/mb93090-mb00/pci-vdk.c | 3 ++-
arch/ia64/pci/pci.c | 4 ++--
arch/ia64/sn/kernel/io_init.c | 4 ++--
arch/m68k/coldfire/pci.c | 2 +-
arch/microblaze/pci/pci-common.c | 4 ++--
arch/mips/pci/pci.c | 4 ++--
arch/mn10300/unit-asb2305/pci.c | 3 ++-
arch/powerpc/kernel/pci-common.c | 4 ++--
arch/s390/pci/pci.c | 4 ++--
arch/sh/drivers/pci/pci.c | 4 ++--
arch/sparc/kernel/leon_pci.c | 2 +-
arch/sparc/kernel/pci.c | 4 ++--
arch/sparc/kernel/pcic.c | 2 +-
arch/tile/kernel/pci.c | 4 ++--
arch/tile/kernel/pci_gx.c | 4 ++--
arch/unicore32/kernel/pci.c | 2 +-
arch/x86/pci/acpi.c | 4 ++--
arch/x86/pci/common.c | 2 +-
arch/xtensa/kernel/pci.c | 2 +-
drivers/parisc/dino.c | 2 +-
drivers/parisc/lba_pci.c | 2 +-
drivers/pci/host/pci-mvebu.c | 2 +-
drivers/pci/host/pci-tegra.c | 4 ++--
drivers/pci/host/pci-versatile.c | 3 ++-
drivers/pci/host/pci-xgene.c | 2 +-
drivers/pci/host/pcie-designware.c | 2 +-
drivers/pci/host/pcie-xilinx.c | 2 +-
drivers/pci/hotplug/ibmphp_core.c | 2 +-
drivers/pci/probe.c | 21 +++++++++++++--------
drivers/pci/xen-pcifront.c | 2 +-
include/linux/pci.h | 8 +++++---
38 files changed, 72 insertions(+), 62 deletions(-)
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 82f738e..2b0bce9 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -336,8 +336,8 @@ common_init_pci(void)
pci_add_resource_offset(&resources, hose->mem_space,
hose->mem_space->start);
- bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
- hose, &resources);
+ bus = pci_scan_root_bus(NULL, hose->index, next_busno,
+ alpha_mv.pci_ops, hose, &resources);
if (!bus)
continue;
hose->bus = bus;
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 700686d..9614e4e 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -206,7 +206,7 @@ nautilus_init_pci(void)
unsigned long memtop = max_low_pfn << PAGE_SHIFT;
/* Scan our single hose. */
- bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
+ bus = pci_scan_bus(hose->index, 0, alpha_mv.pci_ops, hose);
if (!bus)
return;
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index ab19b7c..fec2c90 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -486,7 +486,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
if (hw->scan)
sys->bus = hw->scan(nr, sys);
else
- sys->bus = pci_scan_root_bus(parent, sys->busnr,
+ sys->bus = pci_scan_root_bus(parent, -1, sys->busnr,
hw->ops, sys, &sys->resources);
if (!sys->bus)
diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
index 91fe971..a379287 100644
--- a/arch/arm/mach-dove/pcie.c
+++ b/arch/arm/mach-dove/pcie.c
@@ -160,7 +160,7 @@ dove_pcie_scan_bus(int nr, struct pci_sys_data *sys)
return NULL;
}
- return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
+ return pci_scan_root_bus(NULL, -1, sys->busnr, &pcie_ops, sys,
&sys->resources);
}
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 9082b84..bc4ba7e 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -535,12 +535,12 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys)
while(time_before(jiffies, atux_trhfa_timeout))
udelay(100);
- bus = pci_bus_atux = pci_scan_root_bus(NULL, sys->busnr,
+ bus = pci_bus_atux = pci_scan_root_bus(NULL, -1, sys->busnr,
&iop13xx_atux_ops,
sys, &sys->resources);
break;
case IOP13XX_INIT_ATU_ATUE:
- bus = pci_bus_atue = pci_scan_root_bus(NULL, sys->busnr,
+ bus = pci_bus_atue = pci_scan_root_bus(NULL, -1, sys->busnr,
&iop13xx_atue_ops,
sys, &sys->resources);
break;
diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c
index 097ea4c..4010a95 100644
--- a/arch/arm/mach-mv78xx0/pcie.c
+++ b/arch/arm/mach-mv78xx0/pcie.c
@@ -202,7 +202,7 @@ mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys)
return NULL;
}
- return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
+ return pci_scan_root_bus(NULL, -1, sys->busnr, &pcie_ops, sys,
&sys->resources);
}
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index b02f394..83898cc 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -558,11 +558,11 @@ int __init orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys)
struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys)
{
if (nr == 0)
- return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
+ return pci_scan_root_bus(NULL, -1, sys->busnr, &pcie_ops, sys,
&sys->resources);
if (nr == 1 && !orion5x_pci_disabled)
- return pci_scan_root_bus(NULL, sys->busnr, &pci_ops, sys,
+ return pci_scan_root_bus(NULL, -1, sys->busnr, &pci_ops, sys,
&sys->resources);
BUG();
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
index f211839..719fb75 100644
--- a/arch/frv/mb93090-mb00/pci-vdk.c
+++ b/arch/frv/mb93090-mb00/pci-vdk.c
@@ -384,7 +384,8 @@ int __init pcibios_init(void)
printk("PCI: Probing PCI hardware\n");
pci_add_resource(&resources, &pci_ioport_resource);
pci_add_resource(&resources, &pci_iomem_resource);
- bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources);
+ bus = pci_scan_root_bus(NULL, 0, 0, pci_root_ops, NULL,
+ &resources);
pcibios_irq_init();
pcibios_fixup_irqs();
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 48cc657..c642bc8 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -465,8 +465,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
* should handle the case here, but it appears that IA64 hasn't
* such quirk. So we just ignore the case now.
*/
- pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
- &info->resources);
+ pbus = pci_create_root_bus(NULL, domain, bus, &pci_root_ops,
+ controller, &info->resources);
if (!pbus) {
pci_free_resource_list(&info->resources);
__release_pci_root_info(info);
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 1be65eb..d528814 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -266,8 +266,8 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
pci_add_resource_offset(&resources, &res[1],
prom_bussoft_ptr->bs_legacy_mem);
- bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller,
- &resources);
+ bus = pci_scan_root_bus(NULL, controller->segment, busnum,
+ &pci_root_ops, controller, &resources);
if (bus == NULL) {
kfree(res);
kfree(controller);
diff --git a/arch/m68k/coldfire/pci.c b/arch/m68k/coldfire/pci.c
index 821de92..63c0c2f 100644
--- a/arch/m68k/coldfire/pci.c
+++ b/arch/m68k/coldfire/pci.c
@@ -312,7 +312,7 @@ static int __init mcf_pci_init(void)
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(200));
- rootbus = pci_scan_bus(0, &mcf_pci_ops, NULL);
+ rootbus = pci_scan_bus(0, 0, &mcf_pci_ops, NULL);
if (!rootbus)
return -ENODEV;
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index ae838ed..d232c8a 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -1350,8 +1350,8 @@ static void pcibios_scan_phb(struct pci_controller *hose)
pcibios_setup_phb_resources(hose, &resources);
- bus = pci_scan_root_bus(hose->parent, hose->first_busno,
- hose->ops, hose, &resources);
+ bus = pci_scan_root_bus(hose->parent, hose->global_number,
+ hose->first_busno, hose->ops, hose, &resources);
if (bus == NULL) {
pr_err("Failed to create bus for PCI domain %04x\n",
hose->global_number);
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 8bb13a4..d6361d5 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -92,8 +92,8 @@ static void pcibios_scanbus(struct pci_controller *hose)
pci_add_resource_offset(&resources,
hose->mem_resource, hose->mem_offset);
pci_add_resource_offset(&resources, hose->io_resource, hose->io_offset);
- bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
- &resources);
+ bus = pci_scan_root_bus(NULL, hose->index, next_busno,
+ hose->pci_ops, hose, &resources);
hose->bus = bus;
need_domain_info = need_domain_info || hose->index;
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index 3dfe2d3..a298172 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -372,7 +372,8 @@ static int __init pcibios_init(void)
pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
- bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, &resources);
+ bus = pci_scan_root_bus(NULL, 0, 0, &pci_direct_ampci,
+ NULL, &resources);
if (!bus)
return 0;
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 2a525c9..9913f6c 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1612,8 +1612,8 @@ void pcibios_scan_phb(struct pci_controller *hose)
pci_add_resource(&resources, &hose->busn);
/* Create an empty bus for the toplevel */
- bus = pci_create_root_bus(hose->parent, hose->first_busno,
- hose->ops, hose, &resources);
+ bus = pci_create_root_bus(hose->parent, hose->global_number,
+ hose->first_busno, hose->ops, hose, &resources);
if (bus == NULL) {
pr_err("Failed to create bus for PCI domain %04x\n",
hose->global_number);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index a2a7391..7c5199b 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -770,8 +770,8 @@ static int zpci_scan_bus(struct zpci_dev *zdev)
if (ret)
return ret;
- zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
- zdev, &resources);
+ zdev->bus = pci_scan_root_bus(NULL, zdev->domain, ZPCI_BUS_NR,
+ &pci_root_ops, zdev, &resources);
if (!zdev->bus) {
zpci_cleanup_bus_resources(zdev);
return -EIO;
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index d5462b7..293249a 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -52,8 +52,8 @@ static void pcibios_scanbus(struct pci_channel *hose)
pci_add_resource_offset(&resources, res, offset);
}
- bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
- &resources);
+ bus = pci_scan_root_bus(NULL, hose->index, next_busno,
+ hose->pci_ops, hose, &resources);
hose->bus = bus;
need_domain_info = need_domain_info || hose->index;
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index 4371f72..36d702d 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -32,7 +32,7 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
info->busn.flags = IORESOURCE_BUS;
pci_add_resource(&resources, &info->busn);
- root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
+ root_bus = pci_scan_root_bus(&ofdev->dev, 0, 0, info->ops, info,
&resources);
if (!root_bus) {
pci_free_resource_list(&resources);
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 9e267ca..e40e456 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -667,8 +667,8 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
pbm->busn.end = pbm->pci_last_busno;
pbm->busn.flags = IORESOURCE_BUS;
pci_add_resource(&resources, &pbm->busn);
- bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
- pbm, &resources);
+ bus = pci_create_root_bus(parent, pbm->index, pbm->pci_first_busno,
+ pbm->pci_ops, pbm, &resources);
if (!bus) {
printk(KERN_ERR "Failed to create bus for %s\n",
node->full_name);
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 24384e1..7e86410 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -390,7 +390,7 @@ static void __init pcic_pbm_scan_bus(struct linux_pcic *pcic)
{
struct linux_pbm_info *pbm = &pcic->pbm;
- pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, &pcic_ops, pbm);
+ pbm->pci_bus = pci_scan_bus(0, pbm->pci_first_busno, &pcic_ops, pbm);
if (!pbm->pci_bus)
return;
diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
index 9475a74..6ae0871 100644
--- a/arch/tile/kernel/pci.c
+++ b/arch/tile/kernel/pci.c
@@ -306,8 +306,8 @@ int __init pcibios_init(void)
pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
- bus = pci_scan_root_bus(NULL, 0, controller->ops,
- controller, &resources);
+ bus = pci_scan_root_bus(NULL, controller->index, 0,
+ controller->ops, controller, &resources);
controller->root_bus = bus;
controller->last_busno = bus->busn_res.end;
}
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index b1df847..d47a698 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -881,8 +881,8 @@ int __init pcibios_init(void)
controller->mem_offset);
pci_add_resource(&resources, &controller->io_space);
controller->first_busno = next_busno;
- bus = pci_scan_root_bus(NULL, next_busno, controller->ops,
- controller, &resources);
+ bus = pci_scan_root_bus(NULL, controller->index, next_busno,
+ controller->ops, controller, &resources);
controller->root_bus = bus;
next_busno = bus->busn_res.end + 1;
}
diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index d45fa5f..ef9be16 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -258,7 +258,7 @@ static int __init pci_common_init(void)
pci_puv3_preinit();
- puv3_bus = pci_scan_bus(0, &pci_puv3_ops, NULL);
+ puv3_bus = pci_scan_bus(0, 0, &pci_puv3_ops, NULL);
if (!puv3_bus)
panic("PCI: unable to scan bus!");
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 6ac2738..d2655d5 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -425,8 +425,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
(u8)root->secondary.end, root->mcfg_addr))
- bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
- sd, &resources);
+ bus = pci_create_root_bus(NULL, domain, busnum,
+ &pci_root_ops, sd, &resources);
if (bus) {
pci_scan_child_bus(bus);
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 95a0ba7..9813266 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -486,7 +486,7 @@ void pcibios_scan_root(int busnum)
sd->node = x86_pci_root_bus_node(busnum);
x86_pci_root_bus_resources(busnum, &resources);
printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
- bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
+ bus = pci_scan_root_bus(NULL, 0, busnum, &pci_root_ops, sd, &resources);
if (!bus) {
pci_free_resource_list(&resources);
kfree(sd);
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index b848cc3..66da4c3 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -183,7 +183,7 @@ static int __init pcibios_init(void)
pci_ctrl->last_busno = 0xff;
INIT_LIST_HEAD(&resources);
pci_controller_apertures(pci_ctrl, &resources);
- bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno,
+ bus = pci_scan_root_bus(NULL, 0, pci_ctrl->first_busno,
pci_ctrl->ops, pci_ctrl, &resources);
if (!bus)
continue;
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index a0580af..f375252 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -986,7 +986,7 @@ static int __init dino_probe(struct parisc_device *dev)
** with configuration accessor functions.
*/
dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev,
- dino_current_bus, &dino_cfg_ops, NULL, &resources);
+ 0, dino_current_bus, &dino_cfg_ops, NULL, &resources);
if (!bus) {
printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
dev_name(&dev->dev), dino_current_bus);
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index dceb9dd..2949030 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1563,7 +1563,7 @@ lba_driver_probe(struct parisc_device *dev)
dev->dev.platform_data = lba_dev;
lba_bus = lba_dev->hba.hba_bus =
- pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start,
+ pci_create_root_bus(&dev->dev, 0, lba_dev->hba.bus_num.start,
cfg_ops, NULL, &resources);
if (!lba_bus) {
pci_free_resource_list(&resources);
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index 1309cfb..0cfc494 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -755,7 +755,7 @@ static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
struct mvebu_pcie *pcie = sys_to_pcie(sys);
struct pci_bus *bus;
- bus = pci_create_root_bus(&pcie->pdev->dev, sys->busnr,
+ bus = pci_create_root_bus(&pcie->pdev->dev, -1, sys->busnr,
&mvebu_pcie_ops, sys, &sys->resources);
if (!bus)
return NULL;
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 00e9272..94e9362 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -635,8 +635,8 @@ static struct pci_bus *tegra_pcie_scan_bus(int nr, struct pci_sys_data *sys)
struct tegra_pcie *pcie = sys_to_pcie(sys);
struct pci_bus *bus;
- bus = pci_create_root_bus(pcie->dev, sys->busnr, &tegra_pcie_ops, sys,
- &sys->resources);
+ bus = pci_create_root_bus(pcie->dev, -1, sys->busnr, &tegra_pcie_ops,
+ sys, &sys->resources);
if (!bus)
return NULL;
diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c
index e3a2450..58a22a9 100644
--- a/drivers/pci/host/pci-versatile.c
+++ b/drivers/pci/host/pci-versatile.c
@@ -208,7 +208,8 @@ static int versatile_pci_probe(struct platform_device *pdev)
pci_add_flags(PCI_ENABLE_PROC_DOMAINS);
pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC);
- bus = pci_scan_root_bus(&pdev->dev, 0, &pci_versatile_ops, &sys, &pci_res);
+ bus = pci_scan_root_bus(&pdev->dev, -1, 0, &pci_versatile_ops,
+ &sys, &pci_res);
if (!bus)
return -ENOMEM;
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
index aab5547..078e853 100644
--- a/drivers/pci/host/pci-xgene.c
+++ b/drivers/pci/host/pci-xgene.c
@@ -499,7 +499,7 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
if (ret)
return ret;
- bus = pci_create_root_bus(&pdev->dev, 0,
+ bus = pci_create_root_bus(&pdev->dev, -1, 0,
&xgene_pcie_ops, port, &res);
if (!bus)
return -ENOMEM;
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 1f4ea6f..93778b9 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -728,7 +728,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
struct pcie_port *pp = sys_to_pcie(sys);
pp->root_bus_nr = sys->busnr;
- bus = pci_create_root_bus(pp->dev, sys->busnr,
+ bus = pci_create_root_bus(pp->dev, -1, sys->busnr,
&dw_pcie_ops, sys, &sys->resources);
if (!bus)
return NULL;
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c
index f1a06a0..b5a72a5 100644
--- a/drivers/pci/host/pcie-xilinx.c
+++ b/drivers/pci/host/pcie-xilinx.c
@@ -647,7 +647,7 @@ static struct pci_bus *xilinx_pcie_scan_bus(int nr, struct pci_sys_data *sys)
struct pci_bus *bus;
port->root_busno = sys->busnr;
- bus = pci_scan_root_bus(port->dev, sys->busnr, &xilinx_pcie_ops,
+ bus = pci_scan_root_bus(port->dev, -1, sys->busnr, &xilinx_pcie_ops,
sys, &sys->resources);
return bus;
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 1530247..db6240e 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -765,7 +765,7 @@ static u8 bus_structure_fixup(u8 busno)
(l != 0x0000) && (l != 0xffff)) {
debug("%s - Inside bus_structure_fixup()\n",
__func__);
- b = pci_scan_bus(busno, ibmphp_pci_bus->ops, NULL);
+ b = pci_scan_bus(0, busno, ibmphp_pci_bus->ops, NULL);
if (!b)
continue;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 699a238..767f009 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1889,8 +1889,9 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
{
}
-struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata, struct list_head *resources)
+struct pci_bus *pci_create_root_bus(struct device *parent, int domain,
+ int bus, struct pci_ops *ops, void *sysdata,
+ struct list_head *resources)
{
int error;
struct pci_host_bridge *bridge;
@@ -1920,6 +1921,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
if (!bridge)
goto err_out;
+ bridge->domain = domain;
bridge->dev.parent = parent;
bridge->dev.release = pci_release_host_bridge_dev;
dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
@@ -2057,8 +2059,9 @@ void pci_bus_release_busn_res(struct pci_bus *b)
res, ret ? "can not be" : "is");
}
-struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata, struct list_head *resources)
+struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
+ int bus, struct pci_ops *ops, void *sysdata,
+ struct list_head *resources)
{
struct resource_entry *window;
bool found = false;
@@ -2071,7 +2074,8 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
break;
}
- b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
+ b = pci_create_root_bus(parent, domain, bus, ops,
+ sysdata, resources);
if (!b)
return NULL;
@@ -2091,8 +2095,8 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
}
EXPORT_SYMBOL(pci_scan_root_bus);
-struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
- void *sysdata)
+struct pci_bus *pci_scan_bus(int domain, int bus,
+ struct pci_ops *ops, void *sysdata)
{
LIST_HEAD(resources);
struct pci_bus *b;
@@ -2100,7 +2104,8 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
pci_add_resource(&resources, &busn_resource);
- b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
+ b = pci_create_root_bus(NULL, domain, bus, ops, sysdata,
+ &resources);
if (b) {
pci_scan_child_bus(b);
} else {
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index a69e529..830a31e 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -483,7 +483,7 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
pci_lock_rescan_remove();
- b = pci_scan_root_bus(&pdev->xdev->dev, bus,
+ b = pci_scan_root_bus(&pdev->xdev->dev, sd->domain, bus,
&pcifront_bus_ops, sd, &resources);
if (!b) {
dev_err(&pdev->xdev->dev,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 36effb8..2b575bc 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -401,6 +401,7 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
}
struct pci_host_bridge {
+ int domain;
struct device dev;
struct pci_bus *bus; /* root bus */
struct list_head windows; /* resource_entry */
@@ -769,14 +770,15 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
void pcibios_scan_specific_bus(int busn);
struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
-struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
-struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+struct pci_bus *pci_scan_bus(int domain, int bus, struct pci_ops *ops,
+ void *sysdata);
+struct pci_bus *pci_create_root_bus(struct device *parent, int domain, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources);
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
void pci_bus_release_busn_res(struct pci_bus *b);
-struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
+struct pci_bus *pci_scan_root_bus(struct device *parent, int domain, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources);
struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
--
1.7.1
pci_bus_assign_domain_nr() is only called in probe.c,
Move pci_bus_assign_domain_nr() declaration into
drivers/pci/pci.h.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/pci.h | 9 +++++++++
include/linux/pci.h | 6 ------
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4091f82..ba1bcce 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -321,4 +321,13 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
}
#endif
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
+#else
+static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
+ struct device *parent)
+{
+}
+#endif
+
#endif /* DRIVERS_PCI_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2b575bc..1542df8 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1327,12 +1327,6 @@ static inline int pci_domain_nr(struct pci_bus *bus)
{
return bus->domain_nr;
}
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
-#else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
- struct device *parent)
-{
-}
#endif
/* some architectures require additional setup to direct VGA traffic */
--
1.7.1
Introduce pci_host_assign_domain_nr() to assign domain
number for pci_host_bridge. In the later patch, we would
assign domain in pci_create_host_bridge, clean up the
pci_bus_assign_domain_nr() and move this function into
drivers/pci/host-bridge.c.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/pci.c | 21 ++++++++++++++++-----
drivers/pci/pci.h | 4 ++++
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 81f06e8..6677fac 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4501,10 +4501,10 @@ int pci_get_new_domain_nr(void)
}
#ifdef CONFIG_PCI_DOMAINS_GENERIC
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+static int pci_assign_domain_nr(struct device *dev)
{
static int use_dt_domains = -1;
- int domain = of_get_pci_domain_nr(parent->of_node);
+ int domain = of_get_pci_domain_nr(dev->of_node);
/*
* Check DT domain and use_dt_domains values.
@@ -4538,13 +4538,24 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
use_dt_domains = 0;
domain = pci_get_new_domain_nr();
} else {
- dev_err(parent, "Node %s has inconsistent \"linux,pci-domain\" property in DT\n",
- parent->of_node->full_name);
+ dev_err(dev, "Node %s has inconsistent \"linux,pci-domain\" property in DT\n",
+ dev->of_node->full_name);
domain = -1;
}
- bus->domain_nr = domain;
+ return domain;
+}
+
+void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+{
+ bus->domain_nr = pci_assign_domain_nr(parent);
}
+
+void pci_host_assign_domain_nr(struct pci_host_bridge *host)
+{
+ host->domain = pci_assign_domain_nr(host->dev.parent);
+}
+
#endif
#endif
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index ba1bcce..1d3d2d1 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -323,11 +323,15 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
#ifdef CONFIG_PCI_DOMAINS_GENERIC
void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
+void pci_host_assign_domain_nr(struct pci_host_bridge *host);
#else
static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
struct device *parent)
{
}
+static inline void pci_host_assign_domain_nr(struct pci_host_bridge *host)
+{
+}
#endif
#endif /* DRIVERS_PCI_H */
--
1.7.1
This patch separate pci_host_bridge creation out
of pci_create_root_bus(), and try to make a generic
pci_host_bridge, then we could make it hold host
bridge specific operations like
pcibios_root_bridge_prepare(). The changes are
transparent to platform host bridge drivers.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 52 +++++++++++++++++++++
drivers/pci/pci.h | 3 +
drivers/pci/probe.c | 113 +++++++++++++++++++++------------------------
3 files changed, 108 insertions(+), 60 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 39b2dbe..7d52a0a 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -8,6 +8,58 @@
#include "pci.h"
+static void pci_release_host_bridge_dev(struct device *dev)
+{
+ struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
+
+ if (bridge->release_fn)
+ bridge->release_fn(bridge);
+
+ pci_free_resource_list(&bridge->windows);
+ kfree(bridge);
+}
+
+struct pci_host_bridge *pci_create_host_bridge(
+ struct device *parent, int domain, int bus,
+ struct list_head *resources)
+{
+ int error;
+ struct pci_host_bridge *host;
+ struct resource_entry *window, *n;
+
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return NULL;
+
+ host->dev.parent = parent;
+ INIT_LIST_HEAD(&host->windows);
+ resource_list_for_each_entry_safe(window, n, resources)
+ list_move_tail(&window->node, &host->windows);
+ /*
+ * If support CONFIG_PCI_DOMAINS_GENERIC, use
+ * pci_host_assign_domain_nr() to update domain
+ * number.
+ */
+ host->domain = domain;
+ pci_host_assign_domain_nr(host);
+ host->dev.release = pci_release_host_bridge_dev;
+ dev_set_name(&host->dev, "pci%04x:%02x",
+ host->domain, bus);
+
+ error = device_register(&host->dev);
+ if (error) {
+ put_device(&host->dev);
+ return NULL;
+ }
+
+ return host;
+}
+
+void pci_free_host_bridge(struct pci_host_bridge *host)
+{
+ device_unregister(&host->dev);
+}
+
static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
{
while (bus->parent)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 1d3d2d1..8526790 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -334,4 +334,7 @@ static inline void pci_host_assign_domain_nr(struct pci_host_bridge *host)
}
#endif
+struct pci_host_bridge *pci_create_host_bridge(struct device *parent,
+ int domain, int bus, struct list_head *resources);
+void pci_free_host_bridge(struct pci_host_bridge *host);
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 767f009..9bc4784 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -502,31 +502,6 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)
return b;
}
-static void pci_release_host_bridge_dev(struct device *dev)
-{
- struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
-
- if (bridge->release_fn)
- bridge->release_fn(bridge);
-
- pci_free_resource_list(&bridge->windows);
-
- kfree(bridge);
-}
-
-static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
-{
- struct pci_host_bridge *bridge;
-
- bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
- if (!bridge)
- return NULL;
-
- INIT_LIST_HEAD(&bridge->windows);
- bridge->bus = b;
- return bridge;
-}
-
static const unsigned char pcix_bus_speed[] = {
PCI_SPEED_UNKNOWN, /* 0 */
PCI_SPEED_66MHz_PCIX, /* 1 */
@@ -1889,19 +1864,20 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
{
}
-struct pci_bus *pci_create_root_bus(struct device *parent, int domain,
- int bus, struct pci_ops *ops, void *sysdata,
- struct list_head *resources)
+static struct pci_bus *__pci_create_root_bus(int bus,
+ struct pci_host_bridge *bridge, struct pci_ops *ops,
+ void *sysdata)
{
int error;
- struct pci_host_bridge *bridge;
struct pci_bus *b, *b2;
- struct resource_entry *window, *n;
+ struct resource_entry *window;
+ struct device *parent;
struct resource *res;
resource_size_t offset;
char bus_addr[64];
char *fmt;
+ parent = bridge->dev.parent;
b = pci_alloc_bus(NULL);
if (!b)
return NULL;
@@ -1917,26 +1893,12 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int domain,
goto err_out;
}
- bridge = pci_alloc_host_bridge(b);
- if (!bridge)
- goto err_out;
-
- bridge->domain = domain;
- bridge->dev.parent = parent;
- bridge->dev.release = pci_release_host_bridge_dev;
- dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+ bridge->bus = b;
+ b->bridge = get_device(&bridge->dev);
error = pcibios_root_bridge_prepare(bridge);
- if (error) {
- kfree(bridge);
- goto err_out;
- }
+ if (error)
+ goto put_dev;
- error = device_register(&bridge->dev);
- if (error) {
- put_device(&bridge->dev);
- goto err_out;
- }
- b->bridge = get_device(&bridge->dev);
device_enable_async_suspend(b->bridge);
pci_set_bus_of_node(b);
@@ -1945,10 +1907,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int domain,
b->dev.class = &pcibus_class;
b->dev.parent = b->bridge;
- dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
+ dev_set_name(&b->dev, "%04x:%02x", bridge->domain, bus);
error = device_register(&b->dev);
if (error)
- goto class_dev_reg_err;
+ goto put_dev;
pcibios_add_bus(b);
@@ -1961,8 +1923,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int domain,
printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
/* Add initial resources to the bus */
- resource_list_for_each_entry_safe(window, n, resources) {
- list_move_tail(&window->node, &bridge->windows);
+ resource_list_for_each_entry(window, &bridge->windows) {
res = window->res;
offset = window->offset;
if (res->flags & IORESOURCE_BUS)
@@ -1988,14 +1949,30 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int domain,
return b;
-class_dev_reg_err:
+put_dev:
put_device(&bridge->dev);
- device_unregister(&bridge->dev);
err_out:
kfree(b);
return NULL;
}
+struct pci_bus *pci_create_root_bus(struct device *parent,
+ int domain, int bus, struct pci_ops *ops, void *sysdata,
+ struct list_head *resources)
+{
+ struct pci_host_bridge *host;
+
+ host = pci_create_host_bridge(parent, domain, bus, resources);
+ if (!host)
+ return NULL;
+
+ host->bus = __pci_create_root_bus(bus, host, ops, sysdata);
+ if (!host->bus)
+ pci_free_host_bridge(host);
+
+ return host->bus;
+}
+
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
{
struct resource *res = &b->busn_res;
@@ -2059,23 +2036,22 @@ void pci_bus_release_busn_res(struct pci_bus *b)
res, ret ? "can not be" : "is");
}
-struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
- int bus, struct pci_ops *ops, void *sysdata,
- struct list_head *resources)
+static struct pci_bus *__pci_scan_root_bus(int bus,
+ struct pci_host_bridge *host, struct pci_ops *ops,
+ void *sysdata)
{
struct resource_entry *window;
bool found = false;
struct pci_bus *b;
int max;
- resource_list_for_each_entry(window, resources)
+ resource_list_for_each_entry(window, &host->windows)
if (window->res->flags & IORESOURCE_BUS) {
found = true;
break;
}
- b = pci_create_root_bus(parent, domain, bus, ops,
- sysdata, resources);
+ b = __pci_create_root_bus(bus, host, ops, sysdata);
if (!b)
return NULL;
@@ -2093,6 +2069,23 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
return b;
}
+
+struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
+ int bus, struct pci_ops *ops, void *sysdata,
+ struct list_head *resources)
+{
+ struct pci_host_bridge *host;
+
+ host = pci_create_host_bridge(parent, domain, bus, resources);
+ if (!host)
+ return NULL;
+
+ host->bus = __pci_scan_root_bus(bus, host, ops, sysdata);
+ if (!host->bus)
+ pci_free_host_bridge(host);
+
+ return host->bus;
+}
EXPORT_SYMBOL(pci_scan_root_bus);
struct pci_bus *pci_scan_bus(int domain, int bus,
--
1.7.1
If there is no busn resource provided for pci_scan_root_bus(),
we would insert a default bus resource (root_bus_number, 255)
in root bus, and update the max bus number we found after
pci_scan_child_bus(). We also need to hold the default bus
resource in pci_host_bridge, then we could identify whether
the new pci host bridge conflict with existing one.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 20 ++++++++++++++++++++
drivers/pci/probe.c | 26 ++++++++++----------------
include/linux/pci.h | 2 ++
3 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 7d52a0a..ecc1a7c 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -19,6 +19,25 @@ static void pci_release_host_bridge_dev(struct device *dev)
kfree(bridge);
}
+static void pci_host_update_busn_res(
+ struct pci_host_bridge *host, int bus,
+ struct list_head *resources)
+{
+ struct resource_entry *window;
+
+ resource_list_for_each_entry(window, resources)
+ if (window->res->flags & IORESOURCE_BUS)
+ return;
+
+ pr_info(
+ "No busn resource found for pci%04x:%02x, will use [bus %02x-ff]\n",
+ host->domain, bus, bus);
+ host->busn_res.flags = IORESOURCE_BUS;
+ host->busn_res.start = bus;
+ host->busn_res.end = 255;
+ pci_add_resource(resources, &host->busn_res);
+}
+
struct pci_host_bridge *pci_create_host_bridge(
struct device *parent, int domain, int bus,
struct list_head *resources)
@@ -33,6 +52,7 @@ struct pci_host_bridge *pci_create_host_bridge(
host->dev.parent = parent;
INIT_LIST_HEAD(&host->windows);
+ pci_host_update_busn_res(host, bus, resources);
resource_list_for_each_entry_safe(window, n, resources)
list_move_tail(&window->node, &host->windows);
/*
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 9bc4784..d5a12d9 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2022,6 +2022,12 @@ int pci_bus_update_busn_res_end(struct pci_bus *b, int bus_max)
return ret;
}
+static void pci_host_update_busn_res_end(
+ struct pci_host_bridge *host, int max)
+{
+ host->busn_res.end = max;
+}
+
void pci_bus_release_busn_res(struct pci_bus *b)
{
struct resource *res = &b->busn_res;
@@ -2040,32 +2046,20 @@ static struct pci_bus *__pci_scan_root_bus(int bus,
struct pci_host_bridge *host, struct pci_ops *ops,
void *sysdata)
{
- struct resource_entry *window;
- bool found = false;
struct pci_bus *b;
int max;
- resource_list_for_each_entry(window, &host->windows)
- if (window->res->flags & IORESOURCE_BUS) {
- found = true;
- break;
- }
-
b = __pci_create_root_bus(bus, host, ops, sysdata);
if (!b)
return NULL;
- if (!found) {
- dev_info(&b->dev,
- "No busn resource found for root bus, will use [bus %02x-ff]\n",
- bus);
- pci_bus_insert_busn_res(b, bus, 255);
- }
-
max = pci_scan_child_bus(b);
- if (!found)
+ /* If default busn resource used, update the max bus number */
+ if (host->busn_res.flags & IORESOURCE_BUS) {
+ pci_host_update_busn_res_end(host, max);
pci_bus_update_busn_res_end(b, max);
+ }
return b;
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1542df8..f189dfb 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -404,6 +404,8 @@ struct pci_host_bridge {
int domain;
struct device dev;
struct pci_bus *bus; /* root bus */
+ /* we use default bus resource if no bus resource provided */
+ struct resource busn_res;
struct list_head windows; /* resource_entry */
void (*release_fn)(struct pci_host_bridge *);
void *release_data;
--
1.7.1
From: Yijing Wang <[email protected]>
Sometimes, the bus resource start number is not equal to
root bus number. For example, in pci_scan_bus(), we always
add the default bus resource which start bus number is 0,
but the root bus number callers given may != 0, so
we need to update pci_host_bridge bus resource, because we
would check whether host bridge bus resoruce is confict
in later patch.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index ecc1a7c..1a9834b 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -26,8 +26,11 @@ static void pci_host_update_busn_res(
struct resource_entry *window;
resource_list_for_each_entry(window, resources)
- if (window->res->flags & IORESOURCE_BUS)
+ if (window->res->flags & IORESOURCE_BUS) {
+ if (bus > window->res->start)
+ window->res->start = bus;
return;
+ }
pr_info(
"No busn resource found for pci%04x:%02x, will use [bus %02x-ff]\n",
--
1.7.1
Use it to get the first bus number of the bus
resource.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/pci.h | 11 +++++++++++
drivers/pci/probe.c | 19 ++++++++++---------
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 8526790..886d72f 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -337,4 +337,15 @@ static inline void pci_host_assign_domain_nr(struct pci_host_bridge *host)
struct pci_host_bridge *pci_create_host_bridge(struct device *parent,
int domain, int bus, struct list_head *resources);
void pci_free_host_bridge(struct pci_host_bridge *host);
+
+static inline int pci_host_first_busnr(struct pci_host_bridge *host)
+{
+ struct resource_entry *window;
+
+ resource_list_for_each_entry(window, &host->windows)
+ if (window->res->flags & IORESOURCE_BUS)
+ return window->res->start;
+ return -1;
+}
+
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index d5a12d9..25ac741 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1864,7 +1864,7 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
{
}
-static struct pci_bus *__pci_create_root_bus(int bus,
+static struct pci_bus *__pci_create_root_bus(
struct pci_host_bridge *bridge, struct pci_ops *ops,
void *sysdata)
{
@@ -1884,9 +1884,10 @@ static struct pci_bus *__pci_create_root_bus(int bus,
b->sysdata = sysdata;
b->ops = ops;
- b->number = b->busn_res.start = bus;
+ b->number = b->busn_res.start =
+ pci_host_first_busnr(bridge);
pci_bus_assign_domain_nr(b, parent);
- b2 = pci_find_bus(pci_domain_nr(b), bus);
+ b2 = pci_find_bus(pci_domain_nr(b), b->number);
if (b2) {
/* If we already got to this bus through a different bridge, ignore it */
dev_dbg(&b2->dev, "bus already known\n");
@@ -1907,7 +1908,7 @@ static struct pci_bus *__pci_create_root_bus(int bus,
b->dev.class = &pcibus_class;
b->dev.parent = b->bridge;
- dev_set_name(&b->dev, "%04x:%02x", bridge->domain, bus);
+ dev_set_name(&b->dev, "%04x:%02x", bridge->domain, b->number);
error = device_register(&b->dev);
if (error)
goto put_dev;
@@ -1927,7 +1928,7 @@ static struct pci_bus *__pci_create_root_bus(int bus,
res = window->res;
offset = window->offset;
if (res->flags & IORESOURCE_BUS)
- pci_bus_insert_busn_res(b, bus, res->end);
+ pci_bus_insert_busn_res(b, b->number, res->end);
else
pci_bus_add_resource(b, res, 0);
if (offset) {
@@ -1966,7 +1967,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent,
if (!host)
return NULL;
- host->bus = __pci_create_root_bus(bus, host, ops, sysdata);
+ host->bus = __pci_create_root_bus(host, ops, sysdata);
if (!host->bus)
pci_free_host_bridge(host);
@@ -2042,14 +2043,14 @@ void pci_bus_release_busn_res(struct pci_bus *b)
res, ret ? "can not be" : "is");
}
-static struct pci_bus *__pci_scan_root_bus(int bus,
+static struct pci_bus *__pci_scan_root_bus(
struct pci_host_bridge *host, struct pci_ops *ops,
void *sysdata)
{
struct pci_bus *b;
int max;
- b = __pci_create_root_bus(bus, host, ops, sysdata);
+ b = __pci_create_root_bus(host, ops, sysdata);
if (!b)
return NULL;
@@ -2074,7 +2075,7 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
if (!host)
return NULL;
- host->bus = __pci_scan_root_bus(bus, host, ops, sysdata);
+ host->bus = __pci_scan_root_bus(host, ops, sysdata);
if (!host->bus)
pci_free_host_bridge(host);
--
1.7.1
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().
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 41 ++++++++++++++++++++++++++++++++++++++++-
drivers/pci/probe.c | 9 +--------
include/linux/pci.h | 1 +
3 files changed, 42 insertions(+), 9 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 1a9834b..dffb345 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -8,6 +8,9 @@
#include "pci.h"
+static LIST_HEAD(pci_host_bridge_list);
+static DEFINE_MUTEX(pci_host_mutex);
+
static void pci_release_host_bridge_dev(struct device *dev)
{
struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
@@ -41,12 +44,29 @@ static void pci_host_update_busn_res(
pci_add_resource(resources, &host->busn_res);
}
+static bool pci_host_busn_res_overlap(
+ struct pci_host_bridge *new, struct pci_host_bridge *old)
+{
+ struct resource_entry *entry;
+ struct resource *res1 = NULL, *res2 = NULL;
+
+ resource_list_for_each_entry(entry, &old->windows)
+ if (entry->res->flags & IORESOURCE_BUS)
+ res1 = entry->res;
+
+ resource_list_for_each_entry(entry, &new->windows)
+ if (entry->res->flags & IORESOURCE_BUS)
+ res2 = entry->res;
+
+ return resource_overlaps(res1, res2);
+}
+
struct pci_host_bridge *pci_create_host_bridge(
struct device *parent, int domain, int bus,
struct list_head *resources)
{
int error;
- struct pci_host_bridge *host;
+ struct pci_host_bridge *host, *tmp;
struct resource_entry *window, *n;
host = kzalloc(sizeof(*host), GFP_KERNEL);
@@ -65,6 +85,21 @@ struct pci_host_bridge *pci_create_host_bridge(
*/
host->domain = domain;
pci_host_assign_domain_nr(host);
+ mutex_lock(&pci_host_mutex);
+ list_for_each_entry(tmp, &pci_host_bridge_list, list) {
+ if (tmp->domain == host->domain
+ && pci_host_busn_res_overlap(host, tmp)) {
+ pr_warn("pci host bridge pci%04x:%02x exist\n",
+ host->domain, bus);
+ mutex_unlock(&pci_host_mutex);
+ pci_free_resource_list(&host->windows);
+ kfree(host);
+ return NULL;
+ }
+ }
+ list_add_tail(&host->list, &pci_host_bridge_list);
+ mutex_unlock(&pci_host_mutex);
+
host->dev.release = pci_release_host_bridge_dev;
dev_set_name(&host->dev, "pci%04x:%02x",
host->domain, bus);
@@ -80,6 +115,10 @@ struct pci_host_bridge *pci_create_host_bridge(
void pci_free_host_bridge(struct pci_host_bridge *host)
{
+ mutex_lock(&pci_host_mutex);
+ list_del(&host->list);
+ mutex_unlock(&pci_host_mutex);
+
device_unregister(&host->dev);
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 25ac741..8517d1b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1869,7 +1869,7 @@ static struct pci_bus *__pci_create_root_bus(
void *sysdata)
{
int error;
- struct pci_bus *b, *b2;
+ struct pci_bus *b;
struct resource_entry *window;
struct device *parent;
struct resource *res;
@@ -1887,12 +1887,6 @@ static struct pci_bus *__pci_create_root_bus(
b->number = b->busn_res.start =
pci_host_first_busnr(bridge);
pci_bus_assign_domain_nr(b, parent);
- b2 = pci_find_bus(pci_domain_nr(b), b->number);
- if (b2) {
- /* If we already got to this bus through a different bridge, ignore it */
- dev_dbg(&b2->dev, "bus already known\n");
- goto err_out;
- }
bridge->bus = b;
b->bridge = get_device(&bridge->dev);
@@ -1952,7 +1946,6 @@ static struct pci_bus *__pci_create_root_bus(
put_dev:
put_device(&bridge->dev);
-err_out:
kfree(b);
return NULL;
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f189dfb..91cba01 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -407,6 +407,7 @@ struct pci_host_bridge {
/* we use default bus resource if no bus resource provided */
struct resource busn_res;
struct list_head windows; /* resource_entry */
+ struct list_head list;
void (*release_fn)(struct pci_host_bridge *);
void *release_data;
};
--
1.7.1
Save platform specific sysdata in pci_host_bridge
drvdata, host bridge specific operation need to
access it before the pci bus creation.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 3 ++-
drivers/pci/pci.h | 2 +-
drivers/pci/probe.c | 20 ++++++++++----------
3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index dffb345..98047c6 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -63,7 +63,7 @@ static bool pci_host_busn_res_overlap(
struct pci_host_bridge *pci_create_host_bridge(
struct device *parent, int domain, int bus,
- struct list_head *resources)
+ void *sysdata, struct list_head *resources)
{
int error;
struct pci_host_bridge *host, *tmp;
@@ -101,6 +101,7 @@ struct pci_host_bridge *pci_create_host_bridge(
mutex_unlock(&pci_host_mutex);
host->dev.release = pci_release_host_bridge_dev;
+ dev_set_drvdata(&host->dev, sysdata);
dev_set_name(&host->dev, "pci%04x:%02x",
host->domain, bus);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 886d72f..027fba0 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -335,7 +335,7 @@ static inline void pci_host_assign_domain_nr(struct pci_host_bridge *host)
#endif
struct pci_host_bridge *pci_create_host_bridge(struct device *parent,
- int domain, int bus, struct list_head *resources);
+ int domain, int bus, void *sysdata, struct list_head *resources);
void pci_free_host_bridge(struct pci_host_bridge *host);
static inline int pci_host_first_busnr(struct pci_host_bridge *host)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 8517d1b..0ac2bf6 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1865,8 +1865,7 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
}
static struct pci_bus *__pci_create_root_bus(
- struct pci_host_bridge *bridge, struct pci_ops *ops,
- void *sysdata)
+ struct pci_host_bridge *bridge, struct pci_ops *ops)
{
int error;
struct pci_bus *b;
@@ -1882,7 +1881,7 @@ static struct pci_bus *__pci_create_root_bus(
if (!b)
return NULL;
- b->sysdata = sysdata;
+ b->sysdata = dev_get_drvdata(&bridge->dev);
b->ops = ops;
b->number = b->busn_res.start =
pci_host_first_busnr(bridge);
@@ -1956,11 +1955,12 @@ struct pci_bus *pci_create_root_bus(struct device *parent,
{
struct pci_host_bridge *host;
- host = pci_create_host_bridge(parent, domain, bus, resources);
+ host = pci_create_host_bridge(parent, domain, bus,
+ sysdata, resources);
if (!host)
return NULL;
- host->bus = __pci_create_root_bus(host, ops, sysdata);
+ host->bus = __pci_create_root_bus(host, ops);
if (!host->bus)
pci_free_host_bridge(host);
@@ -2037,13 +2037,12 @@ void pci_bus_release_busn_res(struct pci_bus *b)
}
static struct pci_bus *__pci_scan_root_bus(
- struct pci_host_bridge *host, struct pci_ops *ops,
- void *sysdata)
+ struct pci_host_bridge *host, struct pci_ops *ops)
{
struct pci_bus *b;
int max;
- b = __pci_create_root_bus(host, ops, sysdata);
+ b = __pci_create_root_bus(host, ops);
if (!b)
return NULL;
@@ -2064,11 +2063,12 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
{
struct pci_host_bridge *host;
- host = pci_create_host_bridge(parent, domain, bus, resources);
+ host = pci_create_host_bridge(parent, domain, bus,
+ sysdata, resources);
if (!host)
return NULL;
- host->bus = __pci_scan_root_bus(host, ops, sysdata);
+ host->bus = __pci_scan_root_bus(host, ops);
if (!host->bus)
pci_free_host_bridge(host);
--
1.7.1
pcibios_root_bridge_prepare() in powerpc set
root bus speed, it's not the preparation for
pci host bridge. Rename it for better readability,
and we could move pcibios_root_bridge_prepare()
to pci_create_host_bridge(), in which root bus
is not created. We will clean up these weak functions,
and add pci_host_bridge_ops to do the same thing
in later patch.
Signed-off-by: Yijing Wang <[email protected]>
---
arch/powerpc/include/asm/machdep.h | 2 +-
arch/powerpc/kernel/pci-common.c | 8 +++-----
arch/powerpc/platforms/pseries/pci.c | 8 ++++----
arch/powerpc/platforms/pseries/pseries.h | 2 +-
arch/powerpc/platforms/pseries/setup.c | 2 +-
drivers/pci/probe.c | 5 +++++
6 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index c8175a3..b811d12 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -129,7 +129,7 @@ struct machdep_calls {
void (*pcibios_fixup)(void);
int (*pci_probe_mode)(struct pci_bus *);
void (*pci_irq_fixup)(struct pci_dev *dev);
- int (*pcibios_root_bridge_prepare)(struct pci_host_bridge
+ void (*pcibios_set_root_bus_speed)(struct pci_host_bridge
*bridge);
/* To setup PHBs when using automatic OF platform driver for PCI */
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 9913f6c..2c58200 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -767,12 +767,10 @@ int pci_proc_domain(struct pci_bus *bus)
return 1;
}
-int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+void pcibios_set_root_bus_speed(struct pci_host_bridge *bridge)
{
- if (ppc_md.pcibios_root_bridge_prepare)
- return ppc_md.pcibios_root_bridge_prepare(bridge);
-
- return 0;
+ if (ppc_md.pcibios_set_root_bus_speed)
+ return ppc_md.pcibios_set_root_bus_speed(bridge);
}
/* This header fixup will do the resource fixup for all devices as they are
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index fe16a50..89ff79c 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -110,7 +110,7 @@ static void fixup_winbond_82c105(struct pci_dev* dev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105,
fixup_winbond_82c105);
-int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
+void pseries_set_root_bus_speed(struct pci_host_bridge *bridge)
{
struct device_node *dn, *pdn;
struct pci_bus *bus;
@@ -121,7 +121,7 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
dn = pcibios_get_phb_of_node(bus);
if (!dn)
- return 0;
+ return;
for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
rc = of_property_read_u32_array(pdn,
@@ -135,7 +135,7 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
if (rc) {
pr_debug("no ibm,pcie-link-speed-stats property\n");
- return 0;
+ return;
}
switch (pcie_link_speed_stats[0]) {
@@ -168,5 +168,5 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
break;
}
- return 0;
+ return;
}
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 1796c54..9aa9c13 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -63,7 +63,7 @@ extern int dlpar_detach_node(struct device_node *);
/* PCI root bridge prepare function override for pseries */
struct pci_host_bridge;
-int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);
+void pseries_set_root_bus_speed(struct pci_host_bridge *bridge);
unsigned long pseries_memory_block_size(void);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index e445b67..b196c0d 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -496,7 +496,7 @@ static void __init pSeries_setup_arch(void)
ppc_md.enable_pmcs = power4_enable_pmcs;
}
- ppc_md.pcibios_root_bridge_prepare = pseries_root_bridge_prepare;
+ ppc_md.pcibios_set_root_bus_speed = pseries_set_root_bus_speed;
if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
long rc;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0ac2bf6..418a426 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1856,6 +1856,10 @@ int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
return 0;
}
+void __weak pcibios_set_root_bus_speed(struct pci_host_bridge *bridge)
+{
+}
+
void __weak pcibios_add_bus(struct pci_bus *bus)
{
}
@@ -1893,6 +1897,7 @@ static struct pci_bus *__pci_create_root_bus(
if (error)
goto put_dev;
+ pcibios_set_root_bus_speed(bridge);
device_enable_async_suspend(b->bridge);
pci_set_bus_of_node(b);
--
1.7.1
Move pcibios_root_bridge_prepare() to pci_create_host_bridge().
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 16 +++++++++++++---
drivers/pci/probe.c | 3 ---
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 98047c6..8733b19 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -92,9 +92,7 @@ struct pci_host_bridge *pci_create_host_bridge(
pr_warn("pci host bridge pci%04x:%02x exist\n",
host->domain, bus);
mutex_unlock(&pci_host_mutex);
- pci_free_resource_list(&host->windows);
- kfree(host);
- return NULL;
+ goto free_res;
}
}
list_add_tail(&host->list, &pci_host_bridge_list);
@@ -105,6 +103,10 @@ struct pci_host_bridge *pci_create_host_bridge(
dev_set_name(&host->dev, "pci%04x:%02x",
host->domain, bus);
+ error = pcibios_root_bridge_prepare(host);
+ if (error)
+ goto list_del;
+
error = device_register(&host->dev);
if (error) {
put_device(&host->dev);
@@ -112,6 +114,14 @@ struct pci_host_bridge *pci_create_host_bridge(
}
return host;
+list_del:
+ mutex_lock(&pci_host_mutex);
+ list_del(&host->list);
+ mutex_unlock(&pci_host_mutex);
+free_res:
+ pci_free_resource_list(&host->windows);
+ kfree(host);
+ return NULL;
}
void pci_free_host_bridge(struct pci_host_bridge *host)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 418a426..ee17d9a 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1893,9 +1893,6 @@ static struct pci_bus *__pci_create_root_bus(
bridge->bus = b;
b->bridge = get_device(&bridge->dev);
- error = pcibios_root_bridge_prepare(bridge);
- if (error)
- goto put_dev;
pcibios_set_root_bus_speed(bridge);
device_enable_async_suspend(b->bridge);
--
1.7.1
Now we have weak functions like pcibios_root_bridge_prepare()
to setup pci host bridge, We could introduce pci_host_bridge_ops
which contain host bridge specific ops to setup pci_host_bridge.
Then host bridge driver could add pci_host_bridge_ops hooks
intead of weak function to setup pci_host_bridge.
This patch add following pci_host_bridge_ops hooks:
pci_host_bridge_ops {
struct pci_ops *ops;
/* set root bus speed, some platform need this like powerpc */
void (*set_root_bus_speed)(struct pci_host_bridge *host);
/* setup pci_host_bridge before pci_host_bridge be added to driver core */
int (*prepare)(struct pci_host_bridge *host);
/* platform specific of scan hook to scan pci device */
int (*scan_bus)(struct pci_host_bridge *);
}
We could easily extend it to support different host bridge
specific operations.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 9 ++++++++-
drivers/pci/pci.h | 5 +++--
drivers/pci/probe.c | 11 ++++++++---
include/linux/pci.h | 9 +++++++++
4 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 8733b19..f2639f7 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -63,7 +63,8 @@ static bool pci_host_busn_res_overlap(
struct pci_host_bridge *pci_create_host_bridge(
struct device *parent, int domain, int bus,
- void *sysdata, struct list_head *resources)
+ void *sysdata, struct list_head *resources,
+ struct pci_host_bridge_ops *ops)
{
int error;
struct pci_host_bridge *host, *tmp;
@@ -98,10 +99,16 @@ struct pci_host_bridge *pci_create_host_bridge(
list_add_tail(&host->list, &pci_host_bridge_list);
mutex_unlock(&pci_host_mutex);
+ host->ops = ops;
host->dev.release = pci_release_host_bridge_dev;
dev_set_drvdata(&host->dev, sysdata);
dev_set_name(&host->dev, "pci%04x:%02x",
host->domain, bus);
+ if (host->ops && host->ops->prepare) {
+ error = host->ops->prepare(host);
+ if (error)
+ goto list_del;
+ }
error = pcibios_root_bridge_prepare(host);
if (error)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 027fba0..ef10cc1 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -334,8 +334,9 @@ static inline void pci_host_assign_domain_nr(struct pci_host_bridge *host)
}
#endif
-struct pci_host_bridge *pci_create_host_bridge(struct device *parent,
- int domain, int bus, void *sysdata, struct list_head *resources);
+struct pci_host_bridge *pci_create_host_bridge(
+ struct device *parent, int domain, int bus, void *sysdata,
+ struct list_head *resources, struct pci_host_bridge_ops *ops);
void pci_free_host_bridge(struct pci_host_bridge *host);
static inline int pci_host_first_busnr(struct pci_host_bridge *host)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ee17d9a..36dfee0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1894,6 +1894,8 @@ static struct pci_bus *__pci_create_root_bus(
bridge->bus = b;
b->bridge = get_device(&bridge->dev);
+ if (bridge->ops && bridge->ops->set_root_bus_speed)
+ bridge->ops->set_root_bus_speed(bridge);
pcibios_set_root_bus_speed(bridge);
device_enable_async_suspend(b->bridge);
pci_set_bus_of_node(b);
@@ -1958,7 +1960,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent,
struct pci_host_bridge *host;
host = pci_create_host_bridge(parent, domain, bus,
- sysdata, resources);
+ sysdata, resources, NULL);
if (!host)
return NULL;
@@ -2048,7 +2050,10 @@ static struct pci_bus *__pci_scan_root_bus(
if (!b)
return NULL;
- max = pci_scan_child_bus(b);
+ if (host->ops && host->ops->scan_bus)
+ max = host->ops->scan_bus(host);
+ else
+ max = pci_scan_child_bus(b);
/* If default busn resource used, update the max bus number */
if (host->busn_res.flags & IORESOURCE_BUS) {
@@ -2066,7 +2071,7 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
struct pci_host_bridge *host;
host = pci_create_host_bridge(parent, domain, bus,
- sysdata, resources);
+ sysdata, resources, NULL);
if (!host)
return NULL;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 91cba01..2702a51 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -400,6 +400,14 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
return (pdev->error_state != pci_channel_io_normal);
}
+struct pci_host_bridge;
+struct pci_host_bridge_ops {
+ struct pci_ops *pci_ops;
+ int (*prepare)(struct pci_host_bridge *host);
+ void (*set_root_bus_speed)(struct pci_host_bridge *host);
+ int (*scan_bus)(struct pci_host_bridge *host);
+};
+
struct pci_host_bridge {
int domain;
struct device dev;
@@ -408,6 +416,7 @@ struct pci_host_bridge {
struct resource busn_res;
struct list_head windows; /* resource_entry */
struct list_head list;
+ struct pci_host_bridge_ops *ops;
void (*release_fn)(struct pci_host_bridge *);
void *release_data;
};
--
1.7.1
Introduce new scan function pci_scan_host_bridge() to
support host bridge drivers that need to provide platform
own pci_host_bridge_ops.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/probe.c | 22 ++++++++++++++++++++++
include/linux/pci.h | 3 +++
2 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 36dfee0..b3d9b1b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2064,6 +2064,28 @@ static struct pci_bus *__pci_scan_root_bus(
return b;
}
+struct pci_host_bridge *pci_scan_host_bridge(
+ struct device *parent, int domain, int bus,
+ void *sysdata, struct list_head *resources,
+ struct pci_host_bridge_ops *ops)
+{
+ struct pci_host_bridge *host;
+
+ host = pci_create_host_bridge(parent, domain, bus, sysdata,
+ resources, ops);
+ if (!host)
+ return NULL;
+
+ host->bus = __pci_scan_root_bus(host, ops->pci_ops);
+ if (!host->bus) {
+ pci_free_host_bridge(host);
+ return NULL;
+ }
+
+ return host;
+}
+EXPORT_SYMBOL(pci_scan_host_bridge);
+
struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
int bus, struct pci_ops *ops, void *sysdata,
struct list_head *resources)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2702a51..7f4f182 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -793,6 +793,9 @@ void pci_bus_release_busn_res(struct pci_bus *b);
struct pci_bus *pci_scan_root_bus(struct device *parent, int domain, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources);
+struct pci_host_bridge *pci_scan_host_bridge(struct device *parent, int domain,
+ int bus, void *sysdata, struct list_head *resources,
+ struct pci_host_bridge_ops *ops);
struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
int busnr);
void pcie_update_link_speed(struct pci_bus *bus, u16 link_status);
--
1.7.1
Sometimes, we want to know the highest reserved
busnr for children bus. Because parent's bus->busn_res
may have padding in it. For example, some host drivers
don't know the bus end, so they supply the bus
resource (root_bus, 255), they want to update the
max bus number after pci scan complete. But pci scan
functions won't return the actual max bus number.
So we could use pci_bus_child_max_busnr() to find
that.
Signed-off-by: Fengguang Wu <[email protected]>
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/hotplug/acpiphp_glue.c | 29 +----------------------------
drivers/pci/pci.c | 27 +++++++++++++++++++++++++--
include/linux/pci.h | 2 +-
3 files changed, 27 insertions(+), 31 deletions(-)
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index bcb90e4..84f2584 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -397,33 +397,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
acpi_unlock_hp_context();
}
-/**
- * acpiphp_max_busnr - return the highest reserved bus number under the given bus.
- * @bus: bus to start search with
- */
-static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
-{
- struct pci_bus *tmp;
- unsigned char max, n;
-
- /*
- * pci_bus_max_busnr will return the highest
- * reserved busnr for all these children.
- * that is equivalent to the bus->subordinate
- * value. We don't want to use the parent's
- * bus->subordinate value because it could have
- * padding in it.
- */
- max = bus->busn_res.start;
-
- list_for_each_entry(tmp, &bus->children, node) {
- n = pci_bus_max_busnr(tmp);
- if (n > max)
- max = n;
- }
- return max;
-}
-
static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
@@ -489,7 +462,7 @@ static void enable_slot(struct acpiphp_slot *slot)
LIST_HEAD(add_list);
acpiphp_rescan_slot(slot);
- max = acpiphp_max_busnr(bus);
+ max = pci_bus_child_max_busnr(bus);
for (pass = 0; pass < 2; pass++) {
list_for_each_entry(dev, &bus->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != slot->device)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 6677fac..8a2f12c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -108,7 +108,7 @@ static bool pcie_ari_disabled;
* Given a PCI bus, returns the highest PCI bus number present in the set
* including the given PCI bus and its list of child PCI buses.
*/
-unsigned char pci_bus_max_busnr(struct pci_bus *bus)
+static unsigned char pci_bus_max_busnr(struct pci_bus *bus)
{
struct pci_bus *tmp;
unsigned char max, n;
@@ -121,7 +121,30 @@ unsigned char pci_bus_max_busnr(struct pci_bus *bus)
}
return max;
}
-EXPORT_SYMBOL_GPL(pci_bus_max_busnr);
+
+unsigned char pci_bus_child_max_busnr(struct pci_bus *bus)
+{
+ struct pci_bus *tmp;
+ unsigned char max, n;
+
+ /*
+ * pci_bus_max_busnr will return the highest
+ * reserved busnr for all these children.
+ * that is equivalent to the bus->subordinate
+ * value. We don't want to use the parent's
+ * bus->subordinate value because it could have
+ * padding in it.
+ */
+ max = bus->busn_res.start;
+
+ list_for_each_entry(tmp, &bus->children, node) {
+ n = pci_bus_max_busnr(tmp);
+ if (n > max)
+ max = n;
+ }
+ return max;
+}
+EXPORT_SYMBOL_GPL(pci_bus_child_max_busnr);
#ifdef CONFIG_HAS_IOMEM
void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7f4f182..0b921d6 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1185,7 +1185,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
void *userdata);
int pci_cfg_space_size(struct pci_dev *dev);
-unsigned char pci_bus_max_busnr(struct pci_bus *bus);
+unsigned char pci_bus_child_max_busnr(struct pci_bus *bus);
void pci_setup_bridge(struct pci_bus *bus);
resource_size_t pcibios_window_alignment(struct pci_bus *bus,
unsigned long type);
--
1.7.1
Signed-off-by: Yijing Wang <[email protected]>
CC: Thomas Gleixner <[email protected]>
CC: [email protected]
---
arch/x86/pci/acpi.c | 37 +++++++++++++++++++++----------------
1 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index d2655d5..877acaf 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -349,6 +349,19 @@ static void probe_pci_root_info(struct pci_root_info *info,
entry->res->name = info->name;
}
+static int pci_host_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ struct pci_sysdata *sd = dev_get_drvdata(&bridge->dev);
+
+ ACPI_COMPANION_SET(&bridge->dev, sd->companion);
+ return 0;
+}
+
+static struct pci_host_bridge_ops pci_host_ops = {
+ .pci_ops = &pci_root_ops,
+ .prepare = pci_host_bridge_prepare,
+};
+
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
struct acpi_device *device = root->device;
@@ -359,6 +372,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
LIST_HEAD(crs_res);
LIST_HEAD(resources);
struct pci_bus *bus;
+ struct pci_host_bridge *host = NULL;
struct pci_sysdata *sd;
int node;
@@ -425,14 +439,13 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
(u8)root->secondary.end, root->mcfg_addr))
- bus = pci_create_root_bus(NULL, domain, busnum,
- &pci_root_ops, sd, &resources);
-
- if (bus) {
- pci_scan_child_bus(bus);
- pci_set_host_bridge_release(
- to_pci_host_bridge(bus->bridge),
- release_pci_root_info, info);
+ host = pci_scan_host_bridge(NULL, domain, busnum, sd,
+ &resources, &pci_host_ops);
+
+ if (host) {
+ bus = host->bus;
+ pci_set_host_bridge_release(host,
+ release_pci_root_info, info);
} else {
resource_list_free(&resources);
teardown_mcfg_map(info);
@@ -455,14 +468,6 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
return bus;
}
-int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
-{
- struct pci_sysdata *sd = bridge->bus->sysdata;
-
- ACPI_COMPANION_SET(&bridge->dev, sd->companion);
- return 0;
-}
-
int __init pci_acpi_init(void)
{
struct pci_dev *dev = NULL;
--
1.7.1
From: Yijing Wang <[email protected]>
Signed-off-by: Yijing Wang <[email protected]>
CC: Tony Luck <[email protected]>
CC: Fenghua Yu <[email protected]>
CC: [email protected]
---
arch/ia64/pci/pci.c | 34 +++++++++++++++++++---------------
1 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index c642bc8..95dc43b 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -420,6 +420,19 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
return 0;
}
+static int pci_host_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ struct pci_controller *controller = bridge->bus->sysdata;
+
+ ACPI_COMPANION_SET(&bridge->dev, controller->companion);
+ return 0;
+}
+
+static struct pci_host_bridge_ops pci_host_ops = {
+ .pci_ops = &pci_root_ops,
+ .prepare = pci_host_bridge_prepare,
+};
+
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
struct acpi_device *device = root->device;
@@ -428,7 +441,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
struct pci_controller *controller;
struct pci_root_info *info = NULL;
int busnum = root->secondary.start;
- struct pci_bus *pbus;
+ struct pci_host_bridge *host;
int ret;
controller = alloc_pci_controller(domain);
@@ -465,26 +478,17 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
* should handle the case here, but it appears that IA64 hasn't
* such quirk. So we just ignore the case now.
*/
- pbus = pci_create_root_bus(NULL, domain, bus, &pci_root_ops,
- controller, &info->resources);
- if (!pbus) {
+ host = pci_scan_host_bridge(NULL, domain, bus, controller,
+ &info->resources, &pci_host_ops);
+ if (!host) {
pci_free_resource_list(&info->resources);
__release_pci_root_info(info);
return NULL;
}
- pci_set_host_bridge_release(to_pci_host_bridge(pbus->bridge),
+ pci_set_host_bridge_release(host,
release_pci_root_info, info);
- pci_scan_child_bus(pbus);
- return pbus;
-}
-
-int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
-{
- struct pci_controller *controller = bridge->bus->sysdata;
-
- ACPI_COMPANION_SET(&bridge->dev, controller->companion);
- return 0;
+ return host->bus;
}
void pcibios_fixup_device_resources(struct pci_dev *dev)
--
1.7.1
Now we could use pci_scan_host_bridge() to scan
pci buses, provide powerpc specific pci_host_bridge_ops.
Signed-off-by: Yijing Wang <[email protected]>
CC: Benjamin Herrenschmidt <[email protected]>
CC: [email protected]
---
arch/powerpc/kernel/pci-common.c | 62 +++++++++++++++++++++++--------------
1 files changed, 38 insertions(+), 24 deletions(-)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 2c58200..50b32f6 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -773,6 +773,29 @@ void pcibios_set_root_bus_speed(struct pci_host_bridge *bridge)
return ppc_md.pcibios_set_root_bus_speed(bridge);
}
+static int pci_host_scan_bus(struct pci_host_bridge *host)
+{
+ int mode = PCI_PROBE_NORMAL;
+ struct pci_bus *bus = host->bus;
+ struct pci_controller *hose = dev_get_drvdata(&host->dev);
+
+ /* Get probe mode and perform scan */
+ if (hose->dn && ppc_md.pci_probe_mode)
+ mode = ppc_md.pci_probe_mode(bus);
+
+ pr_debug(" probe mode: %d\n", mode);
+ if (mode == PCI_PROBE_DEVTREE)
+ of_scan_bus(hose->dn, bus);
+
+ if (mode == PCI_PROBE_NORMAL) {
+ pci_bus_update_busn_res_end(bus, 255);
+ hose->last_busno = pci_scan_child_bus(bus);
+ pci_bus_update_busn_res_end(bus, hose->last_busno);
+ }
+
+ return pci_bus_child_max_busnr(bus);
+}
+
/* This header fixup will do the resource fixup for all devices as they are
* probed, but not for bridge ranges
*/
@@ -1585,6 +1608,11 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
return of_node_get(hose->dn);
}
+static struct pci_host_bridge_ops pci_host_ops = {
+ .set_root_bus_speed = pcibios_set_root_bus_speed,
+ .scan_bus = pci_host_scan_bus,
+};
+
/**
* pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
* @hose: Pointer to the PCI host controller instance structure
@@ -1592,9 +1620,8 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
void pcibios_scan_phb(struct pci_controller *hose)
{
LIST_HEAD(resources);
- struct pci_bus *bus;
+ struct pci_host_bridge *host;
struct device_node *node = hose->dn;
- int mode;
pr_debug("PCI: Scanning PHB %s\n", of_node_full_name(node));
@@ -1609,30 +1636,17 @@ void pcibios_scan_phb(struct pci_controller *hose)
hose->busn.flags = IORESOURCE_BUS;
pci_add_resource(&resources, &hose->busn);
+ pci_host_ops.pci_ops = hose->ops;
/* Create an empty bus for the toplevel */
- bus = pci_create_root_bus(hose->parent, hose->global_number,
- hose->first_busno, hose->ops, hose, &resources);
- if (bus == NULL) {
- pr_err("Failed to create bus for PCI domain %04x\n",
- hose->global_number);
+ host = pci_scan_host_bridge(hose->parent, hose->global_number,
+ hose->first_busno, hose, &resources, &pci_host_ops);
+ if (host == NULL) {
+ pr_err("Failed to create host bridge for pci%04x:%02x\n",
+ hose->global_number, hose->first_busno);
pci_free_resource_list(&resources);
return;
}
- hose->bus = bus;
-
- /* Get probe mode and perform scan */
- mode = PCI_PROBE_NORMAL;
- if (node && ppc_md.pci_probe_mode)
- mode = ppc_md.pci_probe_mode(bus);
- pr_debug(" probe mode: %d\n", mode);
- if (mode == PCI_PROBE_DEVTREE)
- of_scan_bus(node, bus);
-
- if (mode == PCI_PROBE_NORMAL) {
- pci_bus_update_busn_res_end(bus, 255);
- hose->last_busno = pci_scan_child_bus(bus);
- pci_bus_update_busn_res_end(bus, hose->last_busno);
- }
+ hose->bus = host->bus;
/* Platform gets a chance to do some global fixups before
* we proceed to resource allocation
@@ -1641,9 +1655,9 @@ void pcibios_scan_phb(struct pci_controller *hose)
ppc_md.pcibios_fixup_phb(hose);
/* Configure PCI Express settings */
- if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
+ if (host->bus && !pci_has_flag(PCI_PROBE_ONLY)) {
struct pci_bus *child;
- list_for_each_entry(child, &bus->children, node)
+ list_for_each_entry(child, &host->bus->children, node)
pcie_bus_configure_settings(child);
}
}
--
1.7.1
Now no one use weak pcibios_root_bridge_prepare() and
pcibios_set_root_bus_speed, we could clean up them.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 4 ----
drivers/pci/probe.c | 18 +-----------------
include/linux/pci.h | 2 --
3 files changed, 1 insertions(+), 23 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index f2639f7..832e1c3 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -110,10 +110,6 @@ struct pci_host_bridge *pci_create_host_bridge(
goto list_del;
}
- error = pcibios_root_bridge_prepare(host);
- if (error)
- goto list_del;
-
error = device_register(&host->dev);
if (error) {
put_device(&host->dev);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b3d9b1b..7796bf8 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1844,22 +1844,6 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
-/**
- * pcibios_root_bridge_prepare - Platform-specific host bridge setup.
- * @bridge: Host bridge to set up.
- *
- * Default empty implementation. Replace with an architecture-specific setup
- * routine, if necessary.
- */
-int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
-{
- return 0;
-}
-
-void __weak pcibios_set_root_bus_speed(struct pci_host_bridge *bridge)
-{
-}
-
void __weak pcibios_add_bus(struct pci_bus *bus)
{
}
@@ -1896,7 +1880,7 @@ static struct pci_bus *__pci_create_root_bus(
if (bridge->ops && bridge->ops->set_root_bus_speed)
bridge->ops->set_root_bus_speed(bridge);
- pcibios_set_root_bus_speed(bridge);
+
device_enable_async_suspend(b->bridge);
pci_set_bus_of_node(b);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 0b921d6..61e0853 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -426,8 +426,6 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
void (*release_fn)(struct pci_host_bridge *),
void *release_data);
-int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge);
-
/*
* The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond
* to P2P or CardBus bridge windows) go in a table. Additional ones (for
--
1.7.1
Now we could use pci_scan_host_bridge() to scan
pci buses, provide sparc specific pci_host_bridge_ops.
Signed-off-by: Yijing Wang <[email protected]>
CC: "David S. Miller" <[email protected]>
CC: [email protected]
---
arch/sparc/kernel/pci.c | 28 ++++++++++++++++++++++------
1 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index e40e456..fa95a1d 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -650,12 +650,27 @@ static void pci_claim_bus_resources(struct pci_bus *bus)
pci_claim_bus_resources(child_bus);
}
+static int pci_host_of_scan_bus(
+ struct pci_host_bridge *host)
+{
+ struct pci_pbm_info *pbm = dev_get_drvdata(&host->dev);
+ struct device_node *node = pbm->op->dev.of_node;
+
+ pci_of_scan_bus(pbm, node, host->bus);
+ return pci_bus_child_max_busnr(host->bus);
+}
+
+static struct pci_host_bridge_ops pci_host_ops = {
+ .scan_bus = pci_host_of_scan_bus,
+};
+
struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
struct device *parent)
{
LIST_HEAD(resources);
struct device_node *node = pbm->op->dev.of_node;
struct pci_bus *bus;
+ struct pci_host_bridge *host;
printk("PCI: Scanning PBM %s\n", node->full_name);
@@ -667,16 +682,17 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
pbm->busn.end = pbm->pci_last_busno;
pbm->busn.flags = IORESOURCE_BUS;
pci_add_resource(&resources, &pbm->busn);
- bus = pci_create_root_bus(parent, pbm->index, pbm->pci_first_busno,
- pbm->pci_ops, pbm, &resources);
- if (!bus) {
- printk(KERN_ERR "Failed to create bus for %s\n",
- node->full_name);
+ pci_host_ops.pci_ops = pbm->pci_ops;
+ host = pci_scan_host_bridge(parent, pbm->index, pbm->pci_first_busno,
+ pbm, &resources, &pci_host_ops);
+ if (!host) {
+ pr_err("Failed to create host bridge pci%04x:%02x for %s\n",
+ pbm->index, pbm->pci_first_busno, node->full_name);
pci_free_resource_list(&resources);
return NULL;
}
- pci_of_scan_bus(pbm, node, bus);
+ bus = host->bus;
pci_bus_register_of_sysfs(bus);
pci_claim_bus_resources(bus);
--
1.7.1
From: Yijing Wang <[email protected]>
Now pci_bus_add_devices() has been ripped out
from pci_scan_root_bus(), we could use pci_scan_root_bus()
instead of pci_create_root_bus() + pci_scan_child_bus()
for simplicity.
Signed-off-by: Yijing Wang <[email protected]>
CC: "James E.J. Bottomley" <[email protected]>
CC: [email protected]
---
drivers/parisc/dino.c | 4 ++--
drivers/parisc/lba_pci.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index f375252..146c3ff 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -985,7 +985,7 @@ static int __init dino_probe(struct parisc_device *dev)
** It's not used to avoid chicken/egg problems
** with configuration accessor functions.
*/
- dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev,
+ dino_dev->hba.hba_bus = bus = pci_scan_root_bus(&dev->dev,
0, dino_current_bus, &dino_cfg_ops, NULL, &resources);
if (!bus) {
printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
@@ -996,7 +996,7 @@ static int __init dino_probe(struct parisc_device *dev)
return 0;
}
- max = pci_scan_child_bus(bus);
+ max = pci_bus_child_max_busnr(bus);
pci_bus_update_busn_res_end(bus, max);
/* This code *depends* on scanning being single threaded
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 2949030..b630364 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1563,14 +1563,14 @@ lba_driver_probe(struct parisc_device *dev)
dev->dev.platform_data = lba_dev;
lba_bus = lba_dev->hba.hba_bus =
- pci_create_root_bus(&dev->dev, 0, lba_dev->hba.bus_num.start,
+ pci_scan_root_bus(&dev->dev, 0, lba_dev->hba.bus_num.start,
cfg_ops, NULL, &resources);
if (!lba_bus) {
pci_free_resource_list(&resources);
return 0;
}
- max = pci_scan_child_bus(lba_bus);
+ max = pci_bus_child_max_busnr(lba_bus);
/* This is in lieu of calling pci_assign_unassigned_resources() */
if (is_pdc_pat()) {
--
1.7.1
Mvebu_pcie_scan_bus() is not necessary, we could use
pci_common_init_dev() instead of pci_common_init(),
and pass the device pointer as the parent. Then
pci_scan_root_bus() will be called to scan the pci busses.
Signed-off-by: Yijing Wang <[email protected]>
CC: Thomas Petazzoni <[email protected]>
CC: Jason Cooper <[email protected]>
---
drivers/pci/host/pci-mvebu.c | 18 +-----------------
1 files changed, 1 insertions(+), 17 deletions(-)
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index 0cfc494..d5a2b70 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -750,21 +750,6 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
return 1;
}
-static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
-{
- struct mvebu_pcie *pcie = sys_to_pcie(sys);
- struct pci_bus *bus;
-
- bus = pci_create_root_bus(&pcie->pdev->dev, -1, sys->busnr,
- &mvebu_pcie_ops, sys, &sys->resources);
- if (!bus)
- return NULL;
-
- pci_scan_child_bus(bus);
-
- return bus;
-}
-
static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
const struct resource *res,
resource_size_t start,
@@ -808,12 +793,11 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
hw.nr_controllers = 1;
hw.private_data = (void **)&pcie;
hw.setup = mvebu_pcie_setup;
- hw.scan = mvebu_pcie_scan_bus;
hw.map_irq = of_irq_parse_and_map_pci;
hw.ops = &mvebu_pcie_ops;
hw.align_resource = mvebu_pcie_align_resource;
- pci_common_init(&hw);
+ pci_common_init_dev(&pcie->pdev->dev, &hw);
}
/*
--
1.7.1
Now pci_scan_root_bus() is almost similar to
pci_create_root_bus() + pci_scan_child_bus().
So we could use common pci_scan_root_bus() in
pci_common_init_dev() to scan pci busses.
tegra_pcie_scan_bus() is redundant, remove it.
Tested-by: Thierry Reding <[email protected]>
Signed-off-by: Yijing Wang <[email protected]>
Acked-by: Thierry Reding <[email protected]>
CC: Thierry Reding <[email protected]>
CC: [email protected]
---
drivers/pci/host/pci-tegra.c | 16 ----------------
1 files changed, 0 insertions(+), 16 deletions(-)
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 94e9362..10c0571 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -630,21 +630,6 @@ static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
return irq;
}
-static struct pci_bus *tegra_pcie_scan_bus(int nr, struct pci_sys_data *sys)
-{
- struct tegra_pcie *pcie = sys_to_pcie(sys);
- struct pci_bus *bus;
-
- bus = pci_create_root_bus(pcie->dev, -1, sys->busnr, &tegra_pcie_ops,
- sys, &sys->resources);
- if (!bus)
- return NULL;
-
- pci_scan_child_bus(bus);
-
- return bus;
-}
-
static irqreturn_t tegra_pcie_isr(int irq, void *arg)
{
const char *err_msg[] = {
@@ -1831,7 +1816,6 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie)
hw.private_data = (void **)&pcie;
hw.setup = tegra_pcie_setup;
hw.map_irq = tegra_pcie_map_irq;
- hw.scan = tegra_pcie_scan_bus;
hw.ops = &tegra_pcie_ops;
pci_common_init_dev(pcie->dev, &hw);
--
1.7.1
Use pci_scan_root_bus() instead of pci_create_root_bus() +
pci_scan_child_bus() for simplicity.
Signed-off-by: Yijing Wang <[email protected]>
CC: Mohit Kumar <[email protected]>
CC: Jingoo Han <[email protected]>
---
drivers/pci/host/pcie-designware.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 93778b9..3d7d6fb 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -728,13 +728,11 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
struct pcie_port *pp = sys_to_pcie(sys);
pp->root_bus_nr = sys->busnr;
- bus = pci_create_root_bus(pp->dev, -1, sys->busnr,
+ bus = pci_scan_root_bus(pp->dev, -1, sys->busnr,
&dw_pcie_ops, sys, &sys->resources);
if (!bus)
return NULL;
- pci_scan_child_bus(bus);
-
if (bus && pp->ops->scan_bus)
pp->ops->scan_bus(pp);
--
1.7.1
Use pci_scan_root_bus() instead of pci_create_root_bus() +
pci_scan_child_bus() for simplicity.
Signed-off-by: Yijing Wang <[email protected]>
CC: Tanmay Inamdar <[email protected]>
---
drivers/pci/host/pci-xgene.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
index 078e853..380c259 100644
--- a/drivers/pci/host/pci-xgene.c
+++ b/drivers/pci/host/pci-xgene.c
@@ -499,12 +499,11 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
if (ret)
return ret;
- bus = pci_create_root_bus(&pdev->dev, -1, 0,
+ bus = pci_scan_root_bus(&pdev->dev, -1, 0,
&xgene_pcie_ops, port, &res);
if (!bus)
return -ENOMEM;
- pci_scan_child_bus(bus);
pci_assign_unassigned_bus_resources(bus);
pci_bus_add_devices(bus);
--
1.7.1
Now no one use pci_create_root_bus(), we could remove it
and rename __pci_create_root_bus() to pci_create_root_bus().
Signed-off-by: [email protected]
---
drivers/pci/probe.c | 35 +++++++++--------------------------
include/linux/pci.h | 3 ---
2 files changed, 9 insertions(+), 29 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 7796bf8..cb0237f 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1852,7 +1852,7 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
{
}
-static struct pci_bus *__pci_create_root_bus(
+static struct pci_bus *pci_create_root_bus(
struct pci_host_bridge *bridge, struct pci_ops *ops)
{
int error;
@@ -1937,24 +1937,6 @@ put_dev:
return NULL;
}
-struct pci_bus *pci_create_root_bus(struct device *parent,
- int domain, int bus, struct pci_ops *ops, void *sysdata,
- struct list_head *resources)
-{
- struct pci_host_bridge *host;
-
- host = pci_create_host_bridge(parent, domain, bus,
- sysdata, resources, NULL);
- if (!host)
- return NULL;
-
- host->bus = __pci_create_root_bus(host, ops);
- if (!host->bus)
- pci_free_host_bridge(host);
-
- return host->bus;
-}
-
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
{
struct resource *res = &b->busn_res;
@@ -2030,7 +2012,7 @@ static struct pci_bus *__pci_scan_root_bus(
struct pci_bus *b;
int max;
- b = __pci_create_root_bus(host, ops);
+ b = pci_create_root_bus(host, ops);
if (!b)
return NULL;
@@ -2093,19 +2075,20 @@ struct pci_bus *pci_scan_bus(int domain, int bus,
struct pci_ops *ops, void *sysdata)
{
LIST_HEAD(resources);
- struct pci_bus *b;
+ struct pci_host_bridge *host;
pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
pci_add_resource(&resources, &busn_resource);
- b = pci_create_root_bus(NULL, domain, bus, ops, sysdata,
- &resources);
- if (b) {
- pci_scan_child_bus(b);
+ host = pci_create_host_bridge(NULL, domain, bus, sysdata,
+ &resources, NULL);
+ if (host) {
+ __pci_scan_root_bus(host, ops);
+ return host->bus;
} else {
pci_free_resource_list(&resources);
}
- return b;
+ return NULL;
}
EXPORT_SYMBOL(pci_scan_bus);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 61e0853..62333ff 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -782,9 +782,6 @@ struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
struct pci_bus *pci_scan_bus(int domain, int bus, struct pci_ops *ops,
void *sysdata);
-struct pci_bus *pci_create_root_bus(struct device *parent, int domain, int bus,
- struct pci_ops *ops, void *sysdata,
- struct list_head *resources);
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
void pci_bus_release_busn_res(struct pci_bus *b);
--
1.7.1
Now pci_host_bridge holds the domain number,
so we could eliminate all platform specific
pci_domain_nr().
Signed-off-by: Yijing Wang <[email protected]>
---
arch/alpha/include/asm/pci.h | 2 --
arch/ia64/include/asm/pci.h | 1 -
arch/microblaze/pci/pci-common.c | 11 -----------
arch/mips/include/asm/pci.h | 2 --
arch/powerpc/kernel/pci-common.c | 11 -----------
arch/s390/pci/pci.c | 6 ------
arch/sh/include/asm/pci.h | 2 --
arch/sparc/kernel/pci.c | 17 -----------------
arch/tile/include/asm/pci.h | 2 --
arch/x86/include/asm/pci.h | 6 ------
drivers/pci/host-bridge.c | 10 ++++++++++
include/linux/pci.h | 7 +------
12 files changed, 11 insertions(+), 66 deletions(-)
diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
index f7f680f..63a9a1e 100644
--- a/arch/alpha/include/asm/pci.h
+++ b/arch/alpha/include/asm/pci.h
@@ -95,8 +95,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
return channel ? 15 : 14;
}
-#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
-
static inline int pci_proc_domain(struct pci_bus *bus)
{
struct pci_controller *hose = bus->sysdata;
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 52af5ed..1dcea49 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -99,7 +99,6 @@ struct pci_controller {
#define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata)
-#define pci_domain_nr(busdev) (PCI_CONTROLLER(busdev)->segment)
extern struct pci_ops pci_root_ops;
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index d232c8a..6f64908 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -123,17 +123,6 @@ unsigned long pci_address_to_pio(phys_addr_t address)
}
EXPORT_SYMBOL_GPL(pci_address_to_pio);
-/*
- * Return the domain number for this bus.
- */
-int pci_domain_nr(struct pci_bus *bus)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
-
- return hose->global_number;
-}
-EXPORT_SYMBOL(pci_domain_nr);
-
/* This routine is meant to be used early during boot, when the
* PCI bus numbers have not yet been assigned, and you need to
* issue PCI config cycles to an OF device.
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 193b4c6..2e4d808 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -122,8 +122,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
#endif
#ifdef CONFIG_PCI_DOMAINS
-#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
-
static inline int pci_proc_domain(struct pci_bus *bus)
{
struct pci_controller *hose = bus->sysdata;
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 50b32f6..362f82e 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -181,17 +181,6 @@ unsigned long pci_address_to_pio(phys_addr_t address)
}
EXPORT_SYMBOL_GPL(pci_address_to_pio);
-/*
- * Return the domain number for this bus.
- */
-int pci_domain_nr(struct pci_bus *bus)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
-
- return hose->global_number;
-}
-EXPORT_SYMBOL(pci_domain_nr);
-
/* This routine is meant to be used early during boot, when the
* PCI bus numbers have not yet been assigned, and you need to
* issue PCI config cycles to an OF device.
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 7c5199b..d2c108e 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -101,12 +101,6 @@ static struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus)
return (bus && bus->sysdata) ? (struct zpci_dev *) bus->sysdata : NULL;
}
-int pci_domain_nr(struct pci_bus *bus)
-{
- return ((struct zpci_dev *) bus->sysdata)->domain;
-}
-EXPORT_SYMBOL_GPL(pci_domain_nr);
-
int pci_proc_domain(struct pci_bus *bus)
{
return pci_domain_nr(bus);
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 5b45115..4dc3ad6 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -109,8 +109,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
/* Board-specific fixup routines. */
int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin);
-#define pci_domain_nr(bus) ((struct pci_channel *)(bus)->sysdata)->index
-
static inline int pci_proc_domain(struct pci_bus *bus)
{
struct pci_channel *hose = bus->sysdata;
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index fa95a1d..57857c7 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -905,23 +905,6 @@ int pcibus_to_node(struct pci_bus *pbus)
EXPORT_SYMBOL(pcibus_to_node);
#endif
-/* Return the domain number for this pci bus */
-
-int pci_domain_nr(struct pci_bus *pbus)
-{
- struct pci_pbm_info *pbm = pbus->sysdata;
- int ret;
-
- if (!pbm) {
- ret = -ENXIO;
- } else {
- ret = pbm->index;
- }
-
- return ret;
-}
-EXPORT_SYMBOL(pci_domain_nr);
-
#ifdef CONFIG_PCI_MSI
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
diff --git a/arch/tile/include/asm/pci.h b/arch/tile/include/asm/pci.h
index dfedd7a..23a726e 100644
--- a/arch/tile/include/asm/pci.h
+++ b/arch/tile/include/asm/pci.h
@@ -199,8 +199,6 @@ int __init pcibios_init(void);
void pcibios_fixup_bus(struct pci_bus *bus);
-#define pci_domain_nr(bus) (((struct pci_controller *)(bus)->sysdata)->index)
-
/*
* This decides whether to display the domain number in /proc.
*/
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 4e370a5..4fe0458 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -29,12 +29,6 @@ extern int noioapicreroute;
#ifdef CONFIG_PCI
#ifdef CONFIG_PCI_DOMAINS
-static inline int pci_domain_nr(struct pci_bus *bus)
-{
- struct pci_sysdata *sd = bus->sysdata;
- return sd->domain;
-}
-
static inline int pci_proc_domain(struct pci_bus *bus)
{
return pci_domain_nr(bus);
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 832e1c3..04c69c5 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -151,6 +151,16 @@ static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
return to_pci_host_bridge(root_bus->bridge);
}
+#ifdef CONFIG_PCI_DOMAINS
+int pci_domain_nr(struct pci_bus *bus)
+{
+ struct pci_host_bridge *host = find_pci_host_bridge(bus);
+
+ return host->domain;
+}
+EXPORT_SYMBOL(pci_domain_nr);
+#endif
+
void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
void (*release_fn)(struct pci_host_bridge *),
void *release_data)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 62333ff..c2c6675 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1320,6 +1320,7 @@ void pci_cfg_access_unlock(struct pci_dev *dev);
#ifdef CONFIG_PCI_DOMAINS
extern int pci_domains_supported;
int pci_get_new_domain_nr(void);
+int pci_domain_nr(struct pci_bus *bus);
#else
enum { pci_domains_supported = 0 };
static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
@@ -1332,12 +1333,6 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
* architecture does not need custom management of PCI
* domains then this implementation will be used
*/
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-static inline int pci_domain_nr(struct pci_bus *bus)
-{
- return bus->domain_nr;
-}
-#endif
/* some architectures require additional setup to direct VGA traffic */
typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
--
1.7.1
Now we save the domain number in pci_host_bridge,
we could remove pci_bus_assign_domain_nr() and
clean the domain member in pci_bus. Also move
pci_host_assign_domain_nr() to drivers/pci/host-bridge.c
for simplicity.
Signed-off-by: Yijing Wang <[email protected]>
---
drivers/pci/host-bridge.c | 63 ++++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.c | 67 ---------------------------------------------
drivers/pci/pci.h | 13 ---------
drivers/pci/probe.c | 11 ++-----
include/linux/pci.h | 3 --
5 files changed, 66 insertions(+), 91 deletions(-)
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 04c69c5..f193136 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -11,6 +11,8 @@
static LIST_HEAD(pci_host_bridge_list);
static DEFINE_MUTEX(pci_host_mutex);
+static void pci_host_assign_domain_nr(struct pci_host_bridge *host);
+
static void pci_release_host_bridge_dev(struct device *dev)
{
struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
@@ -159,8 +161,69 @@ int pci_domain_nr(struct pci_bus *bus)
return host->domain;
}
EXPORT_SYMBOL(pci_domain_nr);
+
+static atomic_t __domain_nr = ATOMIC_INIT(-1);
+
+int pci_get_new_domain_nr(void)
+{
+ return atomic_inc_return(&__domain_nr);
+}
+
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+static int pci_assign_domain_nr(struct device *dev)
+{
+ static int use_dt_domains = -1;
+ int domain = of_get_pci_domain_nr(dev->of_node);
+
+ /*
+ * Check DT domain and use_dt_domains values.
+ *
+ * If DT domain property is valid (domain >= 0) and
+ * use_dt_domains != 0, the DT assignment is valid since this means
+ * we have not previously allocated a domain number by using
+ * pci_get_new_domain_nr(); we should also update use_dt_domains to
+ * 1, to indicate that we have just assigned a domain number from
+ * DT.
+ *
+ * If DT domain property value is not valid (ie domain < 0), and we
+ * have not previously assigned a domain number from DT
+ * (use_dt_domains != 1) we should assign a domain number by
+ * using the:
+ *
+ * pci_get_new_domain_nr()
+ *
+ * API and update the use_dt_domains value to keep track of method we
+ * are using to assign domain numbers (use_dt_domains = 0).
+ *
+ * All other combinations imply we have a platform that is trying
+ * to mix domain numbers obtained from DT and pci_get_new_domain_nr(),
+ * which is a recipe for domain mishandling and it is prevented by
+ * invalidating the domain value (domain = -1) and printing a
+ * corresponding error.
+ */
+ if (domain >= 0 && use_dt_domains) {
+ use_dt_domains = 1;
+ } else if (domain < 0 && use_dt_domains != 1) {
+ use_dt_domains = 0;
+ domain = pci_get_new_domain_nr();
+ } else {
+ dev_err(dev, "Node %s has inconsistent \"linux,pci-domain\" property in DT\n",
+ dev->of_node->full_name);
+ domain = -1;
+ }
+
+ return domain;
+}
+#endif
#endif
+static void pci_host_assign_domain_nr(struct pci_host_bridge *host)
+{
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+ host->domain = pci_assign_domain_nr(host->dev.parent);
+#endif
+}
+
void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
void (*release_fn)(struct pci_host_bridge *),
void *release_data)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8a2f12c..044801c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4515,73 +4515,6 @@ static void pci_no_domains(void)
#endif
}
-#ifdef CONFIG_PCI_DOMAINS
-static atomic_t __domain_nr = ATOMIC_INIT(-1);
-
-int pci_get_new_domain_nr(void)
-{
- return atomic_inc_return(&__domain_nr);
-}
-
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-static int pci_assign_domain_nr(struct device *dev)
-{
- static int use_dt_domains = -1;
- int domain = of_get_pci_domain_nr(dev->of_node);
-
- /*
- * Check DT domain and use_dt_domains values.
- *
- * If DT domain property is valid (domain >= 0) and
- * use_dt_domains != 0, the DT assignment is valid since this means
- * we have not previously allocated a domain number by using
- * pci_get_new_domain_nr(); we should also update use_dt_domains to
- * 1, to indicate that we have just assigned a domain number from
- * DT.
- *
- * If DT domain property value is not valid (ie domain < 0), and we
- * have not previously assigned a domain number from DT
- * (use_dt_domains != 1) we should assign a domain number by
- * using the:
- *
- * pci_get_new_domain_nr()
- *
- * API and update the use_dt_domains value to keep track of method we
- * are using to assign domain numbers (use_dt_domains = 0).
- *
- * All other combinations imply we have a platform that is trying
- * to mix domain numbers obtained from DT and pci_get_new_domain_nr(),
- * which is a recipe for domain mishandling and it is prevented by
- * invalidating the domain value (domain = -1) and printing a
- * corresponding error.
- */
- if (domain >= 0 && use_dt_domains) {
- use_dt_domains = 1;
- } else if (domain < 0 && use_dt_domains != 1) {
- use_dt_domains = 0;
- domain = pci_get_new_domain_nr();
- } else {
- dev_err(dev, "Node %s has inconsistent \"linux,pci-domain\" property in DT\n",
- dev->of_node->full_name);
- domain = -1;
- }
-
- return domain;
-}
-
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
-{
- bus->domain_nr = pci_assign_domain_nr(parent);
-}
-
-void pci_host_assign_domain_nr(struct pci_host_bridge *host)
-{
- host->domain = pci_assign_domain_nr(host->dev.parent);
-}
-
-#endif
-#endif
-
/**
* pci_ext_cfg_avail - can we access extended PCI config space?
*
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index ef10cc1..a6e4d8f 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -321,19 +321,6 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
}
#endif
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
-void pci_host_assign_domain_nr(struct pci_host_bridge *host);
-#else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
- struct device *parent)
-{
-}
-static inline void pci_host_assign_domain_nr(struct pci_host_bridge *host)
-{
-}
-#endif
-
struct pci_host_bridge *pci_create_host_bridge(
struct device *parent, int domain, int bus, void *sysdata,
struct list_head *resources, struct pci_host_bridge_ops *ops);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cb0237f..53e4887 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -480,7 +480,7 @@ void pci_read_bridge_bases(struct pci_bus *child)
}
}
-static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)
+static struct pci_bus *pci_alloc_bus(void)
{
struct pci_bus *b;
@@ -495,10 +495,6 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)
INIT_LIST_HEAD(&b->resources);
b->max_bus_speed = PCI_SPEED_UNKNOWN;
b->cur_bus_speed = PCI_SPEED_UNKNOWN;
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
- if (parent)
- b->domain_nr = parent->domain_nr;
-#endif
return b;
}
@@ -645,7 +641,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
/*
* Allocate a new bus, and inherit stuff from the parent..
*/
- child = pci_alloc_bus(parent);
+ child = pci_alloc_bus();
if (!child)
return NULL;
@@ -1865,7 +1861,7 @@ static struct pci_bus *pci_create_root_bus(
char *fmt;
parent = bridge->dev.parent;
- b = pci_alloc_bus(NULL);
+ b = pci_alloc_bus();
if (!b)
return NULL;
@@ -1873,7 +1869,6 @@ static struct pci_bus *pci_create_root_bus(
b->ops = ops;
b->number = b->busn_res.start =
pci_host_first_busnr(bridge);
- pci_bus_assign_domain_nr(b, parent);
bridge->bus = b;
b->bridge = get_device(&bridge->dev);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index c2c6675..7ef205c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -469,9 +469,6 @@ struct pci_bus {
unsigned char primary; /* number of primary bridge */
unsigned char max_bus_speed; /* enum pci_bus_speed */
unsigned char cur_bus_speed; /* enum pci_bus_speed */
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
- int domain_nr;
-#endif
char name[48];
--
1.7.1
Now we could clean up CONFIG_PCI_DOMAINS_GENERIC.
Signed-off-by: Yijing Wang <[email protected]>
---
arch/arm/Kconfig | 3 ---
arch/arm64/Kconfig | 3 ---
drivers/pci/host-bridge.c | 11 ++++++-----
drivers/pci/pci.c | 2 --
4 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9f1f09a..b5dab6c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1283,9 +1283,6 @@ config PCI_DOMAINS
bool
depends on PCI
-config PCI_DOMAINS_GENERIC
- def_bool PCI_DOMAINS
-
config PCI_NANOENGINE
bool "BSE nanoEngine PCI support"
depends on SA1100_NANOENGINE
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 1b8e973..4b1cc27 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -242,9 +242,6 @@ config PCI
config PCI_DOMAINS
def_bool PCI
-config PCI_DOMAINS_GENERIC
- def_bool PCI
-
config PCI_SYSCALL
def_bool PCI
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index f193136..eb901b2 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -4,6 +4,8 @@
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/of_pci.h>
+#include <linux/of.h>
#include <linux/module.h>
#include "pci.h"
@@ -82,12 +84,13 @@ struct pci_host_bridge *pci_create_host_bridge(
resource_list_for_each_entry_safe(window, n, resources)
list_move_tail(&window->node, &host->windows);
/*
- * If support CONFIG_PCI_DOMAINS_GENERIC, use
+ * If domain == -1, we need to use
* pci_host_assign_domain_nr() to update domain
* number.
*/
host->domain = domain;
- pci_host_assign_domain_nr(host);
+ if (host->domain == -1)
+ pci_host_assign_domain_nr(host);
mutex_lock(&pci_host_mutex);
list_for_each_entry(tmp, &pci_host_bridge_list, list) {
if (tmp->domain == host->domain
@@ -169,7 +172,6 @@ int pci_get_new_domain_nr(void)
return atomic_inc_return(&__domain_nr);
}
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
static int pci_assign_domain_nr(struct device *dev)
{
static int use_dt_domains = -1;
@@ -215,11 +217,10 @@ static int pci_assign_domain_nr(struct device *dev)
return domain;
}
#endif
-#endif
static void pci_host_assign_domain_nr(struct pci_host_bridge *host)
{
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
+#ifdef CONFIG_PCI_DOMAINS
host->domain = pci_assign_domain_nr(host->dev.parent);
#endif
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 044801c..5b18429 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -10,8 +10,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/of.h>
-#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/slab.h>
--
1.7.1
Please ignore this one, it is the same as [PATCH v9 11/30] PCI: Save sysdata in pci_host_bridge drvdata.
Thanks!
Yijing.
On 2015/4/3 17:25, Yijing Wang wrote:
> Save platform specific sysdata in pci_host_bridge
> drvdata, host bridge specific operation need to
> access it before the pci bus creation.
>
> Signed-off-by: Yijing Wang <[email protected]>
> ---
> drivers/pci/host-bridge.c | 3 ++-
> drivers/pci/pci.h | 2 +-
> drivers/pci/probe.c | 20 ++++++++++----------
> 3 files changed, 13 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
> index dffb345..98047c6 100644
> --- a/drivers/pci/host-bridge.c
> +++ b/drivers/pci/host-bridge.c
> @@ -63,7 +63,7 @@ static bool pci_host_busn_res_overlap(
>
> struct pci_host_bridge *pci_create_host_bridge(
> struct device *parent, int domain, int bus,
> - struct list_head *resources)
> + void *sysdata, struct list_head *resources)
> {
> int error;
> struct pci_host_bridge *host, *tmp;
> @@ -101,6 +101,7 @@ struct pci_host_bridge *pci_create_host_bridge(
> mutex_unlock(&pci_host_mutex);
>
> host->dev.release = pci_release_host_bridge_dev;
> + dev_set_drvdata(&host->dev, sysdata);
> dev_set_name(&host->dev, "pci%04x:%02x",
> host->domain, bus);
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 886d72f..aa8dff6 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -335,7 +335,7 @@ static inline void pci_host_assign_domain_nr(struct pci_host_bridge *host)
> #endif
>
> struct pci_host_bridge *pci_create_host_bridge(struct device *parent,
> - int domain, int bus, struct list_head *resources);
> + int domain, int bus, void *sysdata, struct list_head *resources);
> void pci_free_host_bridge(struct pci_host_bridge *host);
>
> static inline int pci_host_first_busnr(struct pci_host_bridge *host)
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 8517d1b..0ac2bf6 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1865,8 +1865,7 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
> }
>
> static struct pci_bus *__pci_create_root_bus(
> - struct pci_host_bridge *bridge, struct pci_ops *ops,
> - void *sysdata)
> + struct pci_host_bridge *bridge, struct pci_ops *ops)
> {
> int error;
> struct pci_bus *b;
> @@ -1882,7 +1881,7 @@ static struct pci_bus *__pci_create_root_bus(
> if (!b)
> return NULL;
>
> - b->sysdata = sysdata;
> + b->sysdata = dev_get_drvdata(&bridge->dev);
> b->ops = ops;
> b->number = b->busn_res.start =
> pci_host_first_busnr(bridge);
> @@ -1956,11 +1955,12 @@ struct pci_bus *pci_create_root_bus(struct device *parent,
> {
> struct pci_host_bridge *host;
>
> - host = pci_create_host_bridge(parent, domain, bus, resources);
> + host = pci_create_host_bridge(parent, domain, bus,
> + sysdata, resources);
> if (!host)
> return NULL;
>
> - host->bus = __pci_create_root_bus(host, ops, sysdata);
> + host->bus = __pci_create_root_bus(host, ops);
> if (!host->bus)
> pci_free_host_bridge(host);
>
> @@ -2037,13 +2037,12 @@ void pci_bus_release_busn_res(struct pci_bus *b)
> }
>
> static struct pci_bus *__pci_scan_root_bus(
> - struct pci_host_bridge *host, struct pci_ops *ops,
> - void *sysdata)
> + struct pci_host_bridge *host, struct pci_ops *ops)
> {
> struct pci_bus *b;
> int max;
>
> - b = __pci_create_root_bus(host, ops, sysdata);
> + b = __pci_create_root_bus(host, ops);
> if (!b)
> return NULL;
>
> @@ -2064,11 +2063,12 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
> {
> struct pci_host_bridge *host;
>
> - host = pci_create_host_bridge(parent, domain, bus, resources);
> + host = pci_create_host_bridge(parent, domain, bus,
> + sysdata, resources);
> if (!host)
> return NULL;
>
> - host->bus = __pci_scan_root_bus(host, ops, sysdata);
> + host->bus = __pci_scan_root_bus(host, ops);
> if (!host->bus)
> pci_free_host_bridge(host);
>
>
--
Thanks!
Yijing
I've been looking at this patch series for a while now, and I now
believe it's ready on the PowerPC side.
I was originally concerned that it would break odd corner cases,
particularly where similar code appears (namely kernel/pci_hotplug.c and
kernel/pci_of_scan.c). However, upon further examination, talking with
Yijing, and some testing, I'm now convinced that it is indeed restricted
to the generic code, and doesn't change behaviour.
This is both a plus and a minus: because it's currently restricted to
generic code, I'm confident it works, but the down side is that it
doesn't yet simplify our arch-specific complexity. We'll need to do some
more work on our side to reap the full benefits.
I tested this entire series on a PowerNV machine, including doing EEH
injection to trigger PCI hotplug:
Tested-by: Daniel Axtens <[email protected]>
For completeness, it would be good to test it on Cell, as they are the
only remaining user of pci_of_scan.c
In conclusion, this patch is
Reviewed-by: Daniel Axtens <[email protected]>
Regards,
Daniel Axtens
On Fri, 2015-04-03 at 17:25 +0800, Yijing Wang wrote:
> Now we could use pci_scan_host_bridge() to scan
> pci buses, provide powerpc specific pci_host_bridge_ops.
>
> Signed-off-by: Yijing Wang <[email protected]>
> CC: Benjamin Herrenschmidt <[email protected]>
> CC: [email protected]
> ---
> arch/powerpc/kernel/pci-common.c | 62 +++++++++++++++++++++++--------------
> 1 files changed, 38 insertions(+), 24 deletions(-)
>
> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> index 2c58200..50b32f6 100644
> --- a/arch/powerpc/kernel/pci-common.c
> +++ b/arch/powerpc/kernel/pci-common.c
> @@ -773,6 +773,29 @@ void pcibios_set_root_bus_speed(struct pci_host_bridge *bridge)
> return ppc_md.pcibios_set_root_bus_speed(bridge);
> }
>
> +static int pci_host_scan_bus(struct pci_host_bridge *host)
> +{
> + int mode = PCI_PROBE_NORMAL;
> + struct pci_bus *bus = host->bus;
> + struct pci_controller *hose = dev_get_drvdata(&host->dev);
> +
> + /* Get probe mode and perform scan */
> + if (hose->dn && ppc_md.pci_probe_mode)
> + mode = ppc_md.pci_probe_mode(bus);
> +
> + pr_debug(" probe mode: %d\n", mode);
> + if (mode == PCI_PROBE_DEVTREE)
> + of_scan_bus(hose->dn, bus);
> +
> + if (mode == PCI_PROBE_NORMAL) {
> + pci_bus_update_busn_res_end(bus, 255);
> + hose->last_busno = pci_scan_child_bus(bus);
> + pci_bus_update_busn_res_end(bus, hose->last_busno);
> + }
> +
> + return pci_bus_child_max_busnr(bus);
> +}
> +
> /* This header fixup will do the resource fixup for all devices as they are
> * probed, but not for bridge ranges
> */
> @@ -1585,6 +1608,11 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
> return of_node_get(hose->dn);
> }
>
> +static struct pci_host_bridge_ops pci_host_ops = {
> + .set_root_bus_speed = pcibios_set_root_bus_speed,
> + .scan_bus = pci_host_scan_bus,
> +};
> +
> /**
> * pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
> * @hose: Pointer to the PCI host controller instance structure
> @@ -1592,9 +1620,8 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
> void pcibios_scan_phb(struct pci_controller *hose)
> {
> LIST_HEAD(resources);
> - struct pci_bus *bus;
> + struct pci_host_bridge *host;
> struct device_node *node = hose->dn;
> - int mode;
>
> pr_debug("PCI: Scanning PHB %s\n", of_node_full_name(node));
>
> @@ -1609,30 +1636,17 @@ void pcibios_scan_phb(struct pci_controller *hose)
> hose->busn.flags = IORESOURCE_BUS;
> pci_add_resource(&resources, &hose->busn);
>
> + pci_host_ops.pci_ops = hose->ops;
> /* Create an empty bus for the toplevel */
> - bus = pci_create_root_bus(hose->parent, hose->global_number,
> - hose->first_busno, hose->ops, hose, &resources);
> - if (bus == NULL) {
> - pr_err("Failed to create bus for PCI domain %04x\n",
> - hose->global_number);
> + host = pci_scan_host_bridge(hose->parent, hose->global_number,
> + hose->first_busno, hose, &resources, &pci_host_ops);
> + if (host == NULL) {
> + pr_err("Failed to create host bridge for pci%04x:%02x\n",
> + hose->global_number, hose->first_busno);
> pci_free_resource_list(&resources);
> return;
> }
> - hose->bus = bus;
> -
> - /* Get probe mode and perform scan */
> - mode = PCI_PROBE_NORMAL;
> - if (node && ppc_md.pci_probe_mode)
> - mode = ppc_md.pci_probe_mode(bus);
> - pr_debug(" probe mode: %d\n", mode);
> - if (mode == PCI_PROBE_DEVTREE)
> - of_scan_bus(node, bus);
> -
> - if (mode == PCI_PROBE_NORMAL) {
> - pci_bus_update_busn_res_end(bus, 255);
> - hose->last_busno = pci_scan_child_bus(bus);
> - pci_bus_update_busn_res_end(bus, hose->last_busno);
> - }
> + hose->bus = host->bus;
>
> /* Platform gets a chance to do some global fixups before
> * we proceed to resource allocation
> @@ -1641,9 +1655,9 @@ void pcibios_scan_phb(struct pci_controller *hose)
> ppc_md.pcibios_fixup_phb(hose);
>
> /* Configure PCI Express settings */
> - if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
> + if (host->bus && !pci_has_flag(PCI_PROBE_ONLY)) {
> struct pci_bus *child;
> - list_for_each_entry(child, &bus->children, node)
> + list_for_each_entry(child, &host->bus->children, node)
> pcie_bus_configure_settings(child);
> }
> }
On 2015/4/7 7:35, Daniel Axtens wrote:
> I've been looking at this patch series for a while now, and I now
> believe it's ready on the PowerPC side.
>
> I was originally concerned that it would break odd corner cases,
> particularly where similar code appears (namely kernel/pci_hotplug.c and
> kernel/pci_of_scan.c). However, upon further examination, talking with
> Yijing, and some testing, I'm now convinced that it is indeed restricted
> to the generic code, and doesn't change behaviour.
>
> This is both a plus and a minus: because it's currently restricted to
> generic code, I'm confident it works, but the down side is that it
> doesn't yet simplify our arch-specific complexity. We'll need to do some
> more work on our side to reap the full benefits.
>
> I tested this entire series on a PowerNV machine, including doing EEH
> injection to trigger PCI hotplug:
> Tested-by: Daniel Axtens <[email protected]>
> For completeness, it would be good to test it on Cell, as they are the
> only remaining user of pci_of_scan.c
>
> In conclusion, this patch is
> Reviewed-by: Daniel Axtens <[email protected]>
>
Thanks very much for your test and review.
Thanks!
Yijing.
>
>
> On Fri, 2015-04-03 at 17:25 +0800, Yijing Wang wrote:
>> Now we could use pci_scan_host_bridge() to scan
>> pci buses, provide powerpc specific pci_host_bridge_ops.
>>
>> Signed-off-by: Yijing Wang <[email protected]>
>> CC: Benjamin Herrenschmidt <[email protected]>
>> CC: [email protected]
>> ---
>> arch/powerpc/kernel/pci-common.c | 62 +++++++++++++++++++++++--------------
>> 1 files changed, 38 insertions(+), 24 deletions(-)
>>
>> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
>> index 2c58200..50b32f6 100644
>> --- a/arch/powerpc/kernel/pci-common.c
>> +++ b/arch/powerpc/kernel/pci-common.c
>> @@ -773,6 +773,29 @@ void pcibios_set_root_bus_speed(struct pci_host_bridge *bridge)
>> return ppc_md.pcibios_set_root_bus_speed(bridge);
>> }
>>
>> +static int pci_host_scan_bus(struct pci_host_bridge *host)
>> +{
>> + int mode = PCI_PROBE_NORMAL;
>> + struct pci_bus *bus = host->bus;
>> + struct pci_controller *hose = dev_get_drvdata(&host->dev);
>> +
>> + /* Get probe mode and perform scan */
>> + if (hose->dn && ppc_md.pci_probe_mode)
>> + mode = ppc_md.pci_probe_mode(bus);
>> +
>> + pr_debug(" probe mode: %d\n", mode);
>> + if (mode == PCI_PROBE_DEVTREE)
>> + of_scan_bus(hose->dn, bus);
>> +
>> + if (mode == PCI_PROBE_NORMAL) {
>> + pci_bus_update_busn_res_end(bus, 255);
>> + hose->last_busno = pci_scan_child_bus(bus);
>> + pci_bus_update_busn_res_end(bus, hose->last_busno);
>> + }
>> +
>> + return pci_bus_child_max_busnr(bus);
>> +}
>> +
>> /* This header fixup will do the resource fixup for all devices as they are
>> * probed, but not for bridge ranges
>> */
>> @@ -1585,6 +1608,11 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
>> return of_node_get(hose->dn);
>> }
>>
>> +static struct pci_host_bridge_ops pci_host_ops = {
>> + .set_root_bus_speed = pcibios_set_root_bus_speed,
>> + .scan_bus = pci_host_scan_bus,
>> +};
>> +
>> /**
>> * pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
>> * @hose: Pointer to the PCI host controller instance structure
>> @@ -1592,9 +1620,8 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
>> void pcibios_scan_phb(struct pci_controller *hose)
>> {
>> LIST_HEAD(resources);
>> - struct pci_bus *bus;
>> + struct pci_host_bridge *host;
>> struct device_node *node = hose->dn;
>> - int mode;
>>
>> pr_debug("PCI: Scanning PHB %s\n", of_node_full_name(node));
>>
>> @@ -1609,30 +1636,17 @@ void pcibios_scan_phb(struct pci_controller *hose)
>> hose->busn.flags = IORESOURCE_BUS;
>> pci_add_resource(&resources, &hose->busn);
>>
>> + pci_host_ops.pci_ops = hose->ops;
>> /* Create an empty bus for the toplevel */
>> - bus = pci_create_root_bus(hose->parent, hose->global_number,
>> - hose->first_busno, hose->ops, hose, &resources);
>> - if (bus == NULL) {
>> - pr_err("Failed to create bus for PCI domain %04x\n",
>> - hose->global_number);
>> + host = pci_scan_host_bridge(hose->parent, hose->global_number,
>> + hose->first_busno, hose, &resources, &pci_host_ops);
>> + if (host == NULL) {
>> + pr_err("Failed to create host bridge for pci%04x:%02x\n",
>> + hose->global_number, hose->first_busno);
>> pci_free_resource_list(&resources);
>> return;
>> }
>> - hose->bus = bus;
>> -
>> - /* Get probe mode and perform scan */
>> - mode = PCI_PROBE_NORMAL;
>> - if (node && ppc_md.pci_probe_mode)
>> - mode = ppc_md.pci_probe_mode(bus);
>> - pr_debug(" probe mode: %d\n", mode);
>> - if (mode == PCI_PROBE_DEVTREE)
>> - of_scan_bus(node, bus);
>> -
>> - if (mode == PCI_PROBE_NORMAL) {
>> - pci_bus_update_busn_res_end(bus, 255);
>> - hose->last_busno = pci_scan_child_bus(bus);
>> - pci_bus_update_busn_res_end(bus, hose->last_busno);
>> - }
>> + hose->bus = host->bus;
>>
>> /* Platform gets a chance to do some global fixups before
>> * we proceed to resource allocation
>> @@ -1641,9 +1655,9 @@ void pcibios_scan_phb(struct pci_controller *hose)
>> ppc_md.pcibios_fixup_phb(hose);
>>
>> /* Configure PCI Express settings */
>> - if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
>> + if (host->bus && !pci_has_flag(PCI_PROBE_ONLY)) {
>> struct pci_bus *child;
>> - list_for_each_entry(child, &bus->children, node)
>> + list_for_each_entry(child, &host->bus->children, node)
>> pcie_bus_configure_settings(child);
>> }
>> }
>
--
Thanks!
Yijing
On Fri, 2015-04-03 at 17:25 +0800, Yijing Wang wrote:
> Now we have weak functions like pcibios_root_bridge_prepare()
> to setup pci host bridge, We could introduce pci_host_bridge_ops
> which contain host bridge specific ops to setup pci_host_bridge.
> Then host bridge driver could add pci_host_bridge_ops hooks
> intead of weak function to setup pci_host_bridge.
> This patch add following pci_host_bridge_ops hooks:
>
> pci_host_bridge_ops {
> struct pci_ops *ops;
Trivial nit, but this is 'struct pci_ops *pci_ops' in the code below.
> +struct pci_host_bridge;
> +struct pci_host_bridge_ops {
> + struct pci_ops *pci_ops;
> + int (*prepare)(struct pci_host_bridge *host);
> + void (*set_root_bus_speed)(struct pci_host_bridge *host);
> + int (*scan_bus)(struct pci_host_bridge *host);
> +};
> +
Regards,
Daniel
On Fri, Apr 03, 2015 at 05:25:40PM +0800, Yijing Wang wrote:
> This patch separate pci_host_bridge creation out
> of pci_create_root_bus(), and try to make a generic
> pci_host_bridge, then we could make it hold host
> bridge specific operations like
> pcibios_root_bridge_prepare(). The changes are
> transparent to platform host bridge drivers.
>
> Signed-off-by: Yijing Wang <[email protected]>
> ---
> drivers/pci/host-bridge.c | 52 +++++++++++++++++++++
> drivers/pci/pci.h | 3 +
> drivers/pci/probe.c | 113 +++++++++++++++++++++------------------------
> 3 files changed, 108 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
> index 39b2dbe..7d52a0a 100644
> --- a/drivers/pci/host-bridge.c
> +++ b/drivers/pci/host-bridge.c
> @@ -8,6 +8,58 @@
>
> #include "pci.h"
>
> +static void pci_release_host_bridge_dev(struct device *dev)
> +{
> + struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
> +
> + if (bridge->release_fn)
> + bridge->release_fn(bridge);
> +
> + pci_free_resource_list(&bridge->windows);
> + kfree(bridge);
> +}
> +
> +struct pci_host_bridge *pci_create_host_bridge(
> + struct device *parent, int domain, int bus,
> + struct list_head *resources)
> +{
> + int error;
> + struct pci_host_bridge *host;
> + struct resource_entry *window, *n;
> +
> + host = kzalloc(sizeof(*host), GFP_KERNEL);
> + if (!host)
> + return NULL;
> +
> + host->dev.parent = parent;
> + INIT_LIST_HEAD(&host->windows);
> + resource_list_for_each_entry_safe(window, n, resources)
> + list_move_tail(&window->node, &host->windows);
> + /*
> + * If support CONFIG_PCI_DOMAINS_GENERIC, use
> + * pci_host_assign_domain_nr() to update domain
> + * number.
> + */
> + host->domain = domain;
> + pci_host_assign_domain_nr(host);
I think it's a bit confusing that there's another "host->domain ="
assignment buried inside pci_host_assign_domain_nr(), so the first
assignment is overwritten when CONFIG_PCI_DOMAINS_GENERIC is set.
Can you do something like this instead:
int pci_host_assign_domain_nr(struct pci_host_bridge *host, int domain)
{
#ifdef CONFIG_PCI_DOMAINS_GENERIC
host->domain = pci_assign_domain_nr(host->dev.parent);
#else
host->domain = domain;
#endif
}
Then the alternatives (CONFIG_PCI_DOMAINS_GENERIC=y and
CONFIG_PCI_DOMAINS_GENERIC being unset) are close together and right at the
#ifdef CONFIG_PCI_DOMAINS_GENERIC, so no extra comments are needed.
Bjorn
On Fri, Apr 03, 2015 at 05:25:41PM +0800, Yijing Wang wrote:
> If there is no busn resource provided for pci_scan_root_bus(),
> we would insert a default bus resource (root_bus_number, 255)
> in root bus, and update the max bus number we found after
> pci_scan_child_bus(). We also need to hold the default bus
> resource in pci_host_bridge, then we could identify whether
> the new pci host bridge conflict with existing one.
>
> Signed-off-by: Yijing Wang <[email protected]>
> ---
> drivers/pci/host-bridge.c | 20 ++++++++++++++++++++
> drivers/pci/probe.c | 26 ++++++++++----------------
> include/linux/pci.h | 2 ++
> 3 files changed, 32 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
> index 7d52a0a..ecc1a7c 100644
> --- a/drivers/pci/host-bridge.c
> +++ b/drivers/pci/host-bridge.c
> @@ -19,6 +19,25 @@ static void pci_release_host_bridge_dev(struct device *dev)
> kfree(bridge);
> }
>
> +static void pci_host_update_busn_res(
> + struct pci_host_bridge *host, int bus,
> + struct list_head *resources)
> +{
> + struct resource_entry *window;
> +
> + resource_list_for_each_entry(window, resources)
> + if (window->res->flags & IORESOURCE_BUS)
> + return;
> +
> + pr_info(
> + "No busn resource found for pci%04x:%02x, will use [bus %02x-ff]\n",
> + host->domain, bus, bus);
> + host->busn_res.flags = IORESOURCE_BUS;
> + host->busn_res.start = bus;
> + host->busn_res.end = 255;
> + pci_add_resource(resources, &host->busn_res);
> +}
> +
> struct pci_host_bridge *pci_create_host_bridge(
> struct device *parent, int domain, int bus,
> struct list_head *resources)
> @@ -33,6 +52,7 @@ struct pci_host_bridge *pci_create_host_bridge(
>
> host->dev.parent = parent;
> INIT_LIST_HEAD(&host->windows);
> + pci_host_update_busn_res(host, bus, resources);
> resource_list_for_each_entry_safe(window, n, resources)
> list_move_tail(&window->node, &host->windows);
> /*
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 9bc4784..d5a12d9 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -2022,6 +2022,12 @@ int pci_bus_update_busn_res_end(struct pci_bus *b, int bus_max)
> return ret;
> }
>
> +static void pci_host_update_busn_res_end(
> + struct pci_host_bridge *host, int max)
> +{
> + host->busn_res.end = max;
> +}
> +
> void pci_bus_release_busn_res(struct pci_bus *b)
> {
> struct resource *res = &b->busn_res;
> @@ -2040,32 +2046,20 @@ static struct pci_bus *__pci_scan_root_bus(int bus,
> struct pci_host_bridge *host, struct pci_ops *ops,
> void *sysdata)
> {
> - struct resource_entry *window;
> - bool found = false;
> struct pci_bus *b;
> int max;
>
> - resource_list_for_each_entry(window, &host->windows)
> - if (window->res->flags & IORESOURCE_BUS) {
> - found = true;
> - break;
> - }
> -
> b = __pci_create_root_bus(bus, host, ops, sysdata);
> if (!b)
> return NULL;
>
> - if (!found) {
> - dev_info(&b->dev,
> - "No busn resource found for root bus, will use [bus %02x-ff]\n",
> - bus);
> - pci_bus_insert_busn_res(b, bus, 255);
> - }
> -
> max = pci_scan_child_bus(b);
>
> - if (!found)
> + /* If default busn resource used, update the max bus number */
> + if (host->busn_res.flags & IORESOURCE_BUS) {
> + pci_host_update_busn_res_end(host, max);
> pci_bus_update_busn_res_end(b, max);
> + }
>
> return b;
> }
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 1542df8..f189dfb 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -404,6 +404,8 @@ struct pci_host_bridge {
> int domain;
> struct device dev;
> struct pci_bus *bus; /* root bus */
> + /* we use default bus resource if no bus resource provided */
> + struct resource busn_res;
I don't understand the need for another busn_res here. The host bridge bus
range should be identical to the root bus range. Having two copies will
confuse things.
And apparently this host->busn_res is only filled in if the arch doesn't
provide a busn resource?
To check for conflicts between host bridges, can you iterate through the
existing ones and check the range of their root buses?
> struct list_head windows; /* resource_entry */
> void (*release_fn)(struct pci_host_bridge *);
> void *release_data;
> --
> 1.7.1
>
On Fri, Apr 03, 2015 at 05:25:42PM +0800, Yijing Wang wrote:
> From: Yijing Wang <[email protected]>
>
> Sometimes, the bus resource start number is not equal to
> root bus number. For example, in pci_scan_bus(), we always
> add the default bus resource which start bus number is 0,
> but the root bus number callers given may != 0, so
> we need to update pci_host_bridge bus resource, because we
> would check whether host bridge bus resoruce is confict
> in later patch.
It's true that pci_scan_bus() always inserts [bus 00-ff]. But I think
that's completely bogus. The caller of pci_scan_bus() supplies a root bus
number X. Any bus numbers below X are useless as far as this host bridge
is concerned, and it's pointless to include them in the range inserted by
pci_scan_bus().
I think we'd be better off if we forced every pci_scan_bus() caller to
supply a real non-overlapping bus number range. We probably can't do that
easily because the arch knows the beginning bus number, but some don't know
how to figure out the ending bus number.
Do we have a per-domain structure that tracks the bus numbers in use in the
domain? It seems like if we had one, we could use that to approximate the
end. For example, if the arch scans three root buses, at bus 00, bus 40,
and bus 80, we could start with the first one at [bus 00-ff], and when we
scan the one at bus 40, we could either report a conflict (if the bus 00
tree included a bus 40) or reduce the first range to [bus 00-3f].
> Signed-off-by: Yijing Wang <[email protected]>
> ---
> drivers/pci/host-bridge.c | 5 ++++-
> 1 files changed, 4 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
> index ecc1a7c..1a9834b 100644
> --- a/drivers/pci/host-bridge.c
> +++ b/drivers/pci/host-bridge.c
> @@ -26,8 +26,11 @@ static void pci_host_update_busn_res(
> struct resource_entry *window;
>
> resource_list_for_each_entry(window, resources)
> - if (window->res->flags & IORESOURCE_BUS)
> + if (window->res->flags & IORESOURCE_BUS) {
> + if (bus > window->res->start)
> + window->res->start = bus;
I see what you're trying to do here, but I think this is the wrong place to
do it. I'd rather figure out a way to insert something other than
busn_resource in pci_scan_bus(). That probably means we need to
dynamically allocate a new busn_res struct.
> return;
> + }
>
> pr_info(
> "No busn resource found for pci%04x:%02x, will use [bus %02x-ff]\n",
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> + /*
>> + * If support CONFIG_PCI_DOMAINS_GENERIC, use
>> + * pci_host_assign_domain_nr() to update domain
>> + * number.
>> + */
>> + host->domain = domain;
>> + pci_host_assign_domain_nr(host);
>
> I think it's a bit confusing that there's another "host->domain ="
> assignment buried inside pci_host_assign_domain_nr(), so the first
> assignment is overwritten when CONFIG_PCI_DOMAINS_GENERIC is set.
>
> Can you do something like this instead:
>
> int pci_host_assign_domain_nr(struct pci_host_bridge *host, int domain)
> {
> #ifdef CONFIG_PCI_DOMAINS_GENERIC
> host->domain = pci_assign_domain_nr(host->dev.parent);
> #else
> host->domain = domain;
> #endif
> }
>
> Then the alternatives (CONFIG_PCI_DOMAINS_GENERIC=y and
> CONFIG_PCI_DOMAINS_GENERIC being unset) are close together and right at the
> #ifdef CONFIG_PCI_DOMAINS_GENERIC, so no extra comments are needed.
OK, I would use #ifdef to update pci_host_assign_domain_nr(), and I would drop the
last patch [PATCH v9 30/30] PCI: Clean up CONFIG_PCI_DOMAINS_GENERIC.
Thanks!
Yijing.
>
> Bjorn
>
> .
>
--
Thanks!
Yijing
Hi Yijing,
On 03/04/2015 11:25, Yijing Wang wrote:
> Mvebu_pcie_scan_bus() is not necessary, we could use
> pci_common_init_dev() instead of pci_common_init(),
> and pass the device pointer as the parent. Then
> pci_scan_root_bus() will be called to scan the pci busses.
>
2 months ago, Thomas Petazzoni was concerned about the removal of
mvebu_pcie_scan_bus(). So I dig the archives of the discussion
surrounding the pcie-mvebu drive. I found that the main purpose
of using this function was to allow to pass "struct device *" pointer.
Thanks to the introduction of pci_common_init_dev it was not needed
anymore. Actually we should have done this change when this function
had been introduced. So for the point of view of the code it's fine.
Then I tested your full series on Armada XP, Armada 375 and Armada 38x
SoCs, and I didn't saw any regression. So you can add my:
Reviewed-by: Gregory CLEMENT <[email protected]>
Tested-by: Gregory CLEMENT <[email protected]>
Thanks,
Gregory
> Signed-off-by: Yijing Wang <[email protected]>
> CC: Thomas Petazzoni <[email protected]>
> CC: Jason Cooper <[email protected]>
> ---
> drivers/pci/host/pci-mvebu.c | 18 +-----------------
> 1 files changed, 1 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
> index 0cfc494..d5a2b70 100644
> --- a/drivers/pci/host/pci-mvebu.c
> +++ b/drivers/pci/host/pci-mvebu.c
> @@ -750,21 +750,6 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
> return 1;
> }
>
> -static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> -{
> - struct mvebu_pcie *pcie = sys_to_pcie(sys);
> - struct pci_bus *bus;
> -
> - bus = pci_create_root_bus(&pcie->pdev->dev, -1, sys->busnr,
> - &mvebu_pcie_ops, sys, &sys->resources);
> - if (!bus)
> - return NULL;
> -
> - pci_scan_child_bus(bus);
> -
> - return bus;
> -}
> -
> static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
> const struct resource *res,
> resource_size_t start,
> @@ -808,12 +793,11 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
> hw.nr_controllers = 1;
> hw.private_data = (void **)&pcie;
> hw.setup = mvebu_pcie_setup;
> - hw.scan = mvebu_pcie_scan_bus;
> hw.map_irq = of_irq_parse_and_map_pci;
> hw.ops = &mvebu_pcie_ops;
> hw.align_resource = mvebu_pcie_align_resource;
>
> - pci_common_init(&hw);
> + pci_common_init_dev(&pcie->pdev->dev, &hw);
> }
>
> /*
>
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
Hi Yijing,
On 03/04/2015 11:25, Yijing Wang wrote:
> Save domain in pci_host_bridge, so we could get domain
> from pci_host_bridge, and at the end of series, we could
> clean up the arch specific pci_domain_nr(). For arm,
> we pass -1 as the domain number, we would update the
> domain number in core by pci_bus_assign_domain_nr().
>
For the mvebu part I tested on Armada XP, Armada 375 and Armada 38x
SoCs, and I didn't saw any regression. So you can add my:
Tested-by: Gregory CLEMENT <[email protected]>
Thanks,
Gregory
> Signed-off-by: Yijing Wang <[email protected]>
> ---
> arch/alpha/kernel/pci.c | 4 ++--
> arch/alpha/kernel/sys_nautilus.c | 2 +-
> arch/arm/kernel/bios32.c | 2 +-
> arch/arm/mach-dove/pcie.c | 2 +-
> arch/arm/mach-iop13xx/pci.c | 4 ++--
> arch/arm/mach-mv78xx0/pcie.c | 2 +-
> arch/arm/mach-orion5x/pci.c | 4 ++--
> arch/frv/mb93090-mb00/pci-vdk.c | 3 ++-
> arch/ia64/pci/pci.c | 4 ++--
> arch/ia64/sn/kernel/io_init.c | 4 ++--
> arch/m68k/coldfire/pci.c | 2 +-
> arch/microblaze/pci/pci-common.c | 4 ++--
> arch/mips/pci/pci.c | 4 ++--
> arch/mn10300/unit-asb2305/pci.c | 3 ++-
> arch/powerpc/kernel/pci-common.c | 4 ++--
> arch/s390/pci/pci.c | 4 ++--
> arch/sh/drivers/pci/pci.c | 4 ++--
> arch/sparc/kernel/leon_pci.c | 2 +-
> arch/sparc/kernel/pci.c | 4 ++--
> arch/sparc/kernel/pcic.c | 2 +-
> arch/tile/kernel/pci.c | 4 ++--
> arch/tile/kernel/pci_gx.c | 4 ++--
> arch/unicore32/kernel/pci.c | 2 +-
> arch/x86/pci/acpi.c | 4 ++--
> arch/x86/pci/common.c | 2 +-
> arch/xtensa/kernel/pci.c | 2 +-
> drivers/parisc/dino.c | 2 +-
> drivers/parisc/lba_pci.c | 2 +-
> drivers/pci/host/pci-mvebu.c | 2 +-
> drivers/pci/host/pci-tegra.c | 4 ++--
> drivers/pci/host/pci-versatile.c | 3 ++-
> drivers/pci/host/pci-xgene.c | 2 +-
> drivers/pci/host/pcie-designware.c | 2 +-
> drivers/pci/host/pcie-xilinx.c | 2 +-
> drivers/pci/hotplug/ibmphp_core.c | 2 +-
> drivers/pci/probe.c | 21 +++++++++++++--------
> drivers/pci/xen-pcifront.c | 2 +-
> include/linux/pci.h | 8 +++++---
> 38 files changed, 72 insertions(+), 62 deletions(-)
>
> diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
> index 82f738e..2b0bce9 100644
> --- a/arch/alpha/kernel/pci.c
> +++ b/arch/alpha/kernel/pci.c
> @@ -336,8 +336,8 @@ common_init_pci(void)
> pci_add_resource_offset(&resources, hose->mem_space,
> hose->mem_space->start);
>
> - bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
> - hose, &resources);
> + bus = pci_scan_root_bus(NULL, hose->index, next_busno,
> + alpha_mv.pci_ops, hose, &resources);
> if (!bus)
> continue;
> hose->bus = bus;
> diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
> index 700686d..9614e4e 100644
> --- a/arch/alpha/kernel/sys_nautilus.c
> +++ b/arch/alpha/kernel/sys_nautilus.c
> @@ -206,7 +206,7 @@ nautilus_init_pci(void)
> unsigned long memtop = max_low_pfn << PAGE_SHIFT;
>
> /* Scan our single hose. */
> - bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
> + bus = pci_scan_bus(hose->index, 0, alpha_mv.pci_ops, hose);
> if (!bus)
> return;
>
> diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
> index ab19b7c..fec2c90 100644
> --- a/arch/arm/kernel/bios32.c
> +++ b/arch/arm/kernel/bios32.c
> @@ -486,7 +486,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
> if (hw->scan)
> sys->bus = hw->scan(nr, sys);
> else
> - sys->bus = pci_scan_root_bus(parent, sys->busnr,
> + sys->bus = pci_scan_root_bus(parent, -1, sys->busnr,
> hw->ops, sys, &sys->resources);
>
> if (!sys->bus)
> diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
> index 91fe971..a379287 100644
> --- a/arch/arm/mach-dove/pcie.c
> +++ b/arch/arm/mach-dove/pcie.c
> @@ -160,7 +160,7 @@ dove_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> return NULL;
> }
>
> - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
> + return pci_scan_root_bus(NULL, -1, sys->busnr, &pcie_ops, sys,
> &sys->resources);
> }
>
> diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
> index 9082b84..bc4ba7e 100644
> --- a/arch/arm/mach-iop13xx/pci.c
> +++ b/arch/arm/mach-iop13xx/pci.c
> @@ -535,12 +535,12 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys)
> while(time_before(jiffies, atux_trhfa_timeout))
> udelay(100);
>
> - bus = pci_bus_atux = pci_scan_root_bus(NULL, sys->busnr,
> + bus = pci_bus_atux = pci_scan_root_bus(NULL, -1, sys->busnr,
> &iop13xx_atux_ops,
> sys, &sys->resources);
> break;
> case IOP13XX_INIT_ATU_ATUE:
> - bus = pci_bus_atue = pci_scan_root_bus(NULL, sys->busnr,
> + bus = pci_bus_atue = pci_scan_root_bus(NULL, -1, sys->busnr,
> &iop13xx_atue_ops,
> sys, &sys->resources);
> break;
> diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c
> index 097ea4c..4010a95 100644
> --- a/arch/arm/mach-mv78xx0/pcie.c
> +++ b/arch/arm/mach-mv78xx0/pcie.c
> @@ -202,7 +202,7 @@ mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> return NULL;
> }
>
> - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
> + return pci_scan_root_bus(NULL, -1, sys->busnr, &pcie_ops, sys,
> &sys->resources);
> }
>
> diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
> index b02f394..83898cc 100644
> --- a/arch/arm/mach-orion5x/pci.c
> +++ b/arch/arm/mach-orion5x/pci.c
> @@ -558,11 +558,11 @@ int __init orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys)
> struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys)
> {
> if (nr == 0)
> - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
> + return pci_scan_root_bus(NULL, -1, sys->busnr, &pcie_ops, sys,
> &sys->resources);
>
> if (nr == 1 && !orion5x_pci_disabled)
> - return pci_scan_root_bus(NULL, sys->busnr, &pci_ops, sys,
> + return pci_scan_root_bus(NULL, -1, sys->busnr, &pci_ops, sys,
> &sys->resources);
>
> BUG();
> diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
> index f211839..719fb75 100644
> --- a/arch/frv/mb93090-mb00/pci-vdk.c
> +++ b/arch/frv/mb93090-mb00/pci-vdk.c
> @@ -384,7 +384,8 @@ int __init pcibios_init(void)
> printk("PCI: Probing PCI hardware\n");
> pci_add_resource(&resources, &pci_ioport_resource);
> pci_add_resource(&resources, &pci_iomem_resource);
> - bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources);
> + bus = pci_scan_root_bus(NULL, 0, 0, pci_root_ops, NULL,
> + &resources);
>
> pcibios_irq_init();
> pcibios_fixup_irqs();
> diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
> index 48cc657..c642bc8 100644
> --- a/arch/ia64/pci/pci.c
> +++ b/arch/ia64/pci/pci.c
> @@ -465,8 +465,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> * should handle the case here, but it appears that IA64 hasn't
> * such quirk. So we just ignore the case now.
> */
> - pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
> - &info->resources);
> + pbus = pci_create_root_bus(NULL, domain, bus, &pci_root_ops,
> + controller, &info->resources);
> if (!pbus) {
> pci_free_resource_list(&info->resources);
> __release_pci_root_info(info);
> diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
> index 1be65eb..d528814 100644
> --- a/arch/ia64/sn/kernel/io_init.c
> +++ b/arch/ia64/sn/kernel/io_init.c
> @@ -266,8 +266,8 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
> pci_add_resource_offset(&resources, &res[1],
> prom_bussoft_ptr->bs_legacy_mem);
>
> - bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller,
> - &resources);
> + bus = pci_scan_root_bus(NULL, controller->segment, busnum,
> + &pci_root_ops, controller, &resources);
> if (bus == NULL) {
> kfree(res);
> kfree(controller);
> diff --git a/arch/m68k/coldfire/pci.c b/arch/m68k/coldfire/pci.c
> index 821de92..63c0c2f 100644
> --- a/arch/m68k/coldfire/pci.c
> +++ b/arch/m68k/coldfire/pci.c
> @@ -312,7 +312,7 @@ static int __init mcf_pci_init(void)
> set_current_state(TASK_UNINTERRUPTIBLE);
> schedule_timeout(msecs_to_jiffies(200));
>
> - rootbus = pci_scan_bus(0, &mcf_pci_ops, NULL);
> + rootbus = pci_scan_bus(0, 0, &mcf_pci_ops, NULL);
> if (!rootbus)
> return -ENODEV;
>
> diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
> index ae838ed..d232c8a 100644
> --- a/arch/microblaze/pci/pci-common.c
> +++ b/arch/microblaze/pci/pci-common.c
> @@ -1350,8 +1350,8 @@ static void pcibios_scan_phb(struct pci_controller *hose)
>
> pcibios_setup_phb_resources(hose, &resources);
>
> - bus = pci_scan_root_bus(hose->parent, hose->first_busno,
> - hose->ops, hose, &resources);
> + bus = pci_scan_root_bus(hose->parent, hose->global_number,
> + hose->first_busno, hose->ops, hose, &resources);
> if (bus == NULL) {
> pr_err("Failed to create bus for PCI domain %04x\n",
> hose->global_number);
> diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
> index 8bb13a4..d6361d5 100644
> --- a/arch/mips/pci/pci.c
> +++ b/arch/mips/pci/pci.c
> @@ -92,8 +92,8 @@ static void pcibios_scanbus(struct pci_controller *hose)
> pci_add_resource_offset(&resources,
> hose->mem_resource, hose->mem_offset);
> pci_add_resource_offset(&resources, hose->io_resource, hose->io_offset);
> - bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
> - &resources);
> + bus = pci_scan_root_bus(NULL, hose->index, next_busno,
> + hose->pci_ops, hose, &resources);
> hose->bus = bus;
>
> need_domain_info = need_domain_info || hose->index;
> diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
> index 3dfe2d3..a298172 100644
> --- a/arch/mn10300/unit-asb2305/pci.c
> +++ b/arch/mn10300/unit-asb2305/pci.c
> @@ -372,7 +372,8 @@ static int __init pcibios_init(void)
>
> pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
> pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
> - bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, &resources);
> + bus = pci_scan_root_bus(NULL, 0, 0, &pci_direct_ampci,
> + NULL, &resources);
> if (!bus)
> return 0;
>
> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> index 2a525c9..9913f6c 100644
> --- a/arch/powerpc/kernel/pci-common.c
> +++ b/arch/powerpc/kernel/pci-common.c
> @@ -1612,8 +1612,8 @@ void pcibios_scan_phb(struct pci_controller *hose)
> pci_add_resource(&resources, &hose->busn);
>
> /* Create an empty bus for the toplevel */
> - bus = pci_create_root_bus(hose->parent, hose->first_busno,
> - hose->ops, hose, &resources);
> + bus = pci_create_root_bus(hose->parent, hose->global_number,
> + hose->first_busno, hose->ops, hose, &resources);
> if (bus == NULL) {
> pr_err("Failed to create bus for PCI domain %04x\n",
> hose->global_number);
> diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
> index a2a7391..7c5199b 100644
> --- a/arch/s390/pci/pci.c
> +++ b/arch/s390/pci/pci.c
> @@ -770,8 +770,8 @@ static int zpci_scan_bus(struct zpci_dev *zdev)
> if (ret)
> return ret;
>
> - zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
> - zdev, &resources);
> + zdev->bus = pci_scan_root_bus(NULL, zdev->domain, ZPCI_BUS_NR,
> + &pci_root_ops, zdev, &resources);
> if (!zdev->bus) {
> zpci_cleanup_bus_resources(zdev);
> return -EIO;
> diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
> index d5462b7..293249a 100644
> --- a/arch/sh/drivers/pci/pci.c
> +++ b/arch/sh/drivers/pci/pci.c
> @@ -52,8 +52,8 @@ static void pcibios_scanbus(struct pci_channel *hose)
> pci_add_resource_offset(&resources, res, offset);
> }
>
> - bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
> - &resources);
> + bus = pci_scan_root_bus(NULL, hose->index, next_busno,
> + hose->pci_ops, hose, &resources);
> hose->bus = bus;
>
> need_domain_info = need_domain_info || hose->index;
> diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
> index 4371f72..36d702d 100644
> --- a/arch/sparc/kernel/leon_pci.c
> +++ b/arch/sparc/kernel/leon_pci.c
> @@ -32,7 +32,7 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
> info->busn.flags = IORESOURCE_BUS;
> pci_add_resource(&resources, &info->busn);
>
> - root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
> + root_bus = pci_scan_root_bus(&ofdev->dev, 0, 0, info->ops, info,
> &resources);
> if (!root_bus) {
> pci_free_resource_list(&resources);
> diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
> index 9e267ca..e40e456 100644
> --- a/arch/sparc/kernel/pci.c
> +++ b/arch/sparc/kernel/pci.c
> @@ -667,8 +667,8 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
> pbm->busn.end = pbm->pci_last_busno;
> pbm->busn.flags = IORESOURCE_BUS;
> pci_add_resource(&resources, &pbm->busn);
> - bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
> - pbm, &resources);
> + bus = pci_create_root_bus(parent, pbm->index, pbm->pci_first_busno,
> + pbm->pci_ops, pbm, &resources);
> if (!bus) {
> printk(KERN_ERR "Failed to create bus for %s\n",
> node->full_name);
> diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
> index 24384e1..7e86410 100644
> --- a/arch/sparc/kernel/pcic.c
> +++ b/arch/sparc/kernel/pcic.c
> @@ -390,7 +390,7 @@ static void __init pcic_pbm_scan_bus(struct linux_pcic *pcic)
> {
> struct linux_pbm_info *pbm = &pcic->pbm;
>
> - pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, &pcic_ops, pbm);
> + pbm->pci_bus = pci_scan_bus(0, pbm->pci_first_busno, &pcic_ops, pbm);
> if (!pbm->pci_bus)
> return;
>
> diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
> index 9475a74..6ae0871 100644
> --- a/arch/tile/kernel/pci.c
> +++ b/arch/tile/kernel/pci.c
> @@ -306,8 +306,8 @@ int __init pcibios_init(void)
>
> pci_add_resource(&resources, &ioport_resource);
> pci_add_resource(&resources, &iomem_resource);
> - bus = pci_scan_root_bus(NULL, 0, controller->ops,
> - controller, &resources);
> + bus = pci_scan_root_bus(NULL, controller->index, 0,
> + controller->ops, controller, &resources);
> controller->root_bus = bus;
> controller->last_busno = bus->busn_res.end;
> }
> diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
> index b1df847..d47a698 100644
> --- a/arch/tile/kernel/pci_gx.c
> +++ b/arch/tile/kernel/pci_gx.c
> @@ -881,8 +881,8 @@ int __init pcibios_init(void)
> controller->mem_offset);
> pci_add_resource(&resources, &controller->io_space);
> controller->first_busno = next_busno;
> - bus = pci_scan_root_bus(NULL, next_busno, controller->ops,
> - controller, &resources);
> + bus = pci_scan_root_bus(NULL, controller->index, next_busno,
> + controller->ops, controller, &resources);
> controller->root_bus = bus;
> next_busno = bus->busn_res.end + 1;
> }
> diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
> index d45fa5f..ef9be16 100644
> --- a/arch/unicore32/kernel/pci.c
> +++ b/arch/unicore32/kernel/pci.c
> @@ -258,7 +258,7 @@ static int __init pci_common_init(void)
>
> pci_puv3_preinit();
>
> - puv3_bus = pci_scan_bus(0, &pci_puv3_ops, NULL);
> + puv3_bus = pci_scan_bus(0, 0, &pci_puv3_ops, NULL);
>
> if (!puv3_bus)
> panic("PCI: unable to scan bus!");
> diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
> index 6ac2738..d2655d5 100644
> --- a/arch/x86/pci/acpi.c
> +++ b/arch/x86/pci/acpi.c
> @@ -425,8 +425,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
>
> if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
> (u8)root->secondary.end, root->mcfg_addr))
> - bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
> - sd, &resources);
> + bus = pci_create_root_bus(NULL, domain, busnum,
> + &pci_root_ops, sd, &resources);
>
> if (bus) {
> pci_scan_child_bus(bus);
> diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
> index 95a0ba7..9813266 100644
> --- a/arch/x86/pci/common.c
> +++ b/arch/x86/pci/common.c
> @@ -486,7 +486,7 @@ void pcibios_scan_root(int busnum)
> sd->node = x86_pci_root_bus_node(busnum);
> x86_pci_root_bus_resources(busnum, &resources);
> printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
> - bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
> + bus = pci_scan_root_bus(NULL, 0, busnum, &pci_root_ops, sd, &resources);
> if (!bus) {
> pci_free_resource_list(&resources);
> kfree(sd);
> diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
> index b848cc3..66da4c3 100644
> --- a/arch/xtensa/kernel/pci.c
> +++ b/arch/xtensa/kernel/pci.c
> @@ -183,7 +183,7 @@ static int __init pcibios_init(void)
> pci_ctrl->last_busno = 0xff;
> INIT_LIST_HEAD(&resources);
> pci_controller_apertures(pci_ctrl, &resources);
> - bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno,
> + bus = pci_scan_root_bus(NULL, 0, pci_ctrl->first_busno,
> pci_ctrl->ops, pci_ctrl, &resources);
> if (!bus)
> continue;
> diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
> index a0580af..f375252 100644
> --- a/drivers/parisc/dino.c
> +++ b/drivers/parisc/dino.c
> @@ -986,7 +986,7 @@ static int __init dino_probe(struct parisc_device *dev)
> ** with configuration accessor functions.
> */
> dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev,
> - dino_current_bus, &dino_cfg_ops, NULL, &resources);
> + 0, dino_current_bus, &dino_cfg_ops, NULL, &resources);
> if (!bus) {
> printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
> dev_name(&dev->dev), dino_current_bus);
> diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
> index dceb9dd..2949030 100644
> --- a/drivers/parisc/lba_pci.c
> +++ b/drivers/parisc/lba_pci.c
> @@ -1563,7 +1563,7 @@ lba_driver_probe(struct parisc_device *dev)
>
> dev->dev.platform_data = lba_dev;
> lba_bus = lba_dev->hba.hba_bus =
> - pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start,
> + pci_create_root_bus(&dev->dev, 0, lba_dev->hba.bus_num.start,
> cfg_ops, NULL, &resources);
> if (!lba_bus) {
> pci_free_resource_list(&resources);
> diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
> index 1309cfb..0cfc494 100644
> --- a/drivers/pci/host/pci-mvebu.c
> +++ b/drivers/pci/host/pci-mvebu.c
> @@ -755,7 +755,7 @@ static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> struct mvebu_pcie *pcie = sys_to_pcie(sys);
> struct pci_bus *bus;
>
> - bus = pci_create_root_bus(&pcie->pdev->dev, sys->busnr,
> + bus = pci_create_root_bus(&pcie->pdev->dev, -1, sys->busnr,
> &mvebu_pcie_ops, sys, &sys->resources);
> if (!bus)
> return NULL;
> diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
> index 00e9272..94e9362 100644
> --- a/drivers/pci/host/pci-tegra.c
> +++ b/drivers/pci/host/pci-tegra.c
> @@ -635,8 +635,8 @@ static struct pci_bus *tegra_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> struct tegra_pcie *pcie = sys_to_pcie(sys);
> struct pci_bus *bus;
>
> - bus = pci_create_root_bus(pcie->dev, sys->busnr, &tegra_pcie_ops, sys,
> - &sys->resources);
> + bus = pci_create_root_bus(pcie->dev, -1, sys->busnr, &tegra_pcie_ops,
> + sys, &sys->resources);
> if (!bus)
> return NULL;
>
> diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c
> index e3a2450..58a22a9 100644
> --- a/drivers/pci/host/pci-versatile.c
> +++ b/drivers/pci/host/pci-versatile.c
> @@ -208,7 +208,8 @@ static int versatile_pci_probe(struct platform_device *pdev)
> pci_add_flags(PCI_ENABLE_PROC_DOMAINS);
> pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC);
>
> - bus = pci_scan_root_bus(&pdev->dev, 0, &pci_versatile_ops, &sys, &pci_res);
> + bus = pci_scan_root_bus(&pdev->dev, -1, 0, &pci_versatile_ops,
> + &sys, &pci_res);
> if (!bus)
> return -ENOMEM;
>
> diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
> index aab5547..078e853 100644
> --- a/drivers/pci/host/pci-xgene.c
> +++ b/drivers/pci/host/pci-xgene.c
> @@ -499,7 +499,7 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
> if (ret)
> return ret;
>
> - bus = pci_create_root_bus(&pdev->dev, 0,
> + bus = pci_create_root_bus(&pdev->dev, -1, 0,
> &xgene_pcie_ops, port, &res);
> if (!bus)
> return -ENOMEM;
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index 1f4ea6f..93778b9 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -728,7 +728,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> struct pcie_port *pp = sys_to_pcie(sys);
>
> pp->root_bus_nr = sys->busnr;
> - bus = pci_create_root_bus(pp->dev, sys->busnr,
> + bus = pci_create_root_bus(pp->dev, -1, sys->busnr,
> &dw_pcie_ops, sys, &sys->resources);
> if (!bus)
> return NULL;
> diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c
> index f1a06a0..b5a72a5 100644
> --- a/drivers/pci/host/pcie-xilinx.c
> +++ b/drivers/pci/host/pcie-xilinx.c
> @@ -647,7 +647,7 @@ static struct pci_bus *xilinx_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> struct pci_bus *bus;
>
> port->root_busno = sys->busnr;
> - bus = pci_scan_root_bus(port->dev, sys->busnr, &xilinx_pcie_ops,
> + bus = pci_scan_root_bus(port->dev, -1, sys->busnr, &xilinx_pcie_ops,
> sys, &sys->resources);
>
> return bus;
> diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
> index 1530247..db6240e 100644
> --- a/drivers/pci/hotplug/ibmphp_core.c
> +++ b/drivers/pci/hotplug/ibmphp_core.c
> @@ -765,7 +765,7 @@ static u8 bus_structure_fixup(u8 busno)
> (l != 0x0000) && (l != 0xffff)) {
> debug("%s - Inside bus_structure_fixup()\n",
> __func__);
> - b = pci_scan_bus(busno, ibmphp_pci_bus->ops, NULL);
> + b = pci_scan_bus(0, busno, ibmphp_pci_bus->ops, NULL);
> if (!b)
> continue;
>
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 699a238..767f009 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1889,8 +1889,9 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
> {
> }
>
> -struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> - struct pci_ops *ops, void *sysdata, struct list_head *resources)
> +struct pci_bus *pci_create_root_bus(struct device *parent, int domain,
> + int bus, struct pci_ops *ops, void *sysdata,
> + struct list_head *resources)
> {
> int error;
> struct pci_host_bridge *bridge;
> @@ -1920,6 +1921,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> if (!bridge)
> goto err_out;
>
> + bridge->domain = domain;
> bridge->dev.parent = parent;
> bridge->dev.release = pci_release_host_bridge_dev;
> dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
> @@ -2057,8 +2059,9 @@ void pci_bus_release_busn_res(struct pci_bus *b)
> res, ret ? "can not be" : "is");
> }
>
> -struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
> - struct pci_ops *ops, void *sysdata, struct list_head *resources)
> +struct pci_bus *pci_scan_root_bus(struct device *parent, int domain,
> + int bus, struct pci_ops *ops, void *sysdata,
> + struct list_head *resources)
> {
> struct resource_entry *window;
> bool found = false;
> @@ -2071,7 +2074,8 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
> break;
> }
>
> - b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
> + b = pci_create_root_bus(parent, domain, bus, ops,
> + sysdata, resources);
> if (!b)
> return NULL;
>
> @@ -2091,8 +2095,8 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
> }
> EXPORT_SYMBOL(pci_scan_root_bus);
>
> -struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
> - void *sysdata)
> +struct pci_bus *pci_scan_bus(int domain, int bus,
> + struct pci_ops *ops, void *sysdata)
> {
> LIST_HEAD(resources);
> struct pci_bus *b;
> @@ -2100,7 +2104,8 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
> pci_add_resource(&resources, &ioport_resource);
> pci_add_resource(&resources, &iomem_resource);
> pci_add_resource(&resources, &busn_resource);
> - b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
> + b = pci_create_root_bus(NULL, domain, bus, ops, sysdata,
> + &resources);
> if (b) {
> pci_scan_child_bus(b);
> } else {
> diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
> index a69e529..830a31e 100644
> --- a/drivers/pci/xen-pcifront.c
> +++ b/drivers/pci/xen-pcifront.c
> @@ -483,7 +483,7 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
>
> pci_lock_rescan_remove();
>
> - b = pci_scan_root_bus(&pdev->xdev->dev, bus,
> + b = pci_scan_root_bus(&pdev->xdev->dev, sd->domain, bus,
> &pcifront_bus_ops, sd, &resources);
> if (!b) {
> dev_err(&pdev->xdev->dev,
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 36effb8..2b575bc 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -401,6 +401,7 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
> }
>
> struct pci_host_bridge {
> + int domain;
> struct device dev;
> struct pci_bus *bus; /* root bus */
> struct list_head windows; /* resource_entry */
> @@ -769,14 +770,15 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
> void pcibios_scan_specific_bus(int busn);
> struct pci_bus *pci_find_bus(int domain, int busnr);
> void pci_bus_add_devices(const struct pci_bus *bus);
> -struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
> -struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> +struct pci_bus *pci_scan_bus(int domain, int bus, struct pci_ops *ops,
> + void *sysdata);
> +struct pci_bus *pci_create_root_bus(struct device *parent, int domain, int bus,
> struct pci_ops *ops, void *sysdata,
> struct list_head *resources);
> int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
> int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
> void pci_bus_release_busn_res(struct pci_bus *b);
> -struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
> +struct pci_bus *pci_scan_root_bus(struct device *parent, int domain, int bus,
> struct pci_ops *ops, void *sysdata,
> struct list_head *resources);
> struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
>
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index 1542df8..f189dfb 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -404,6 +404,8 @@ struct pci_host_bridge {
>> int domain;
>> struct device dev;
>> struct pci_bus *bus; /* root bus */
>> + /* we use default bus resource if no bus resource provided */
>> + struct resource busn_res;
>
> I don't understand the need for another busn_res here. The host bridge bus
> range should be identical to the root bus range. Having two copies will
> confuse things.
>
> And apparently this host->busn_res is only filled in if the arch doesn't
> provide a busn resource?
>
> To check for conflicts between host bridges, can you iterate through the
> existing ones and check the range of their root buses?
Checking root buses is not enough, there is time gap between pci_host_bridge creation and
pci root bus creation.
E.g. A and B do pci scan sync in two cpus, A first check the buses resource, and find free
bus resource, then it go to create pci_host_bridge and scan root bus, at the same time, B
also check the buses resource, because A has not created root bus, B also think there are
free buses, this is a problem.
I agree you that having two copies is not a good idea.
For pci bus resource, we have the following request path:
1. arch supplies the busn_res or PCI core add the default bus resource(in pci_scan_bus);
2. Call pci_bus_insert_busn_res() to insert the bus resource for root bus.
3. Call get_pci_domain_busn_res() to return the per-domain bus resource.
4. Request root bus resource under per-domain bus resource.
We have the per-domain structure pci_domain_busn_res to manage the bus resources in one domain,
so what about add a bitmap to manage the free bus resource ?
In pci_create_host_bridge(), first check whether the new pci_host_bridge bus resources required
is free, if yes, we set the bitmap to occupy the bus resource at once, then create the host bridge
and add it to the global list.
struct pci_domain_busn_res {
struct list_head list;
struct resource res;
int domain_nr;
bitmap used;
};
Another problem, I found it's unnecessary to add bus resource to pci_host_bridge->windows.
Unlike the IO and MEM resource, we never use the pci_host_bridge bus resource again after
pci enumeration. I think we could clean it up, or in some cases, when arch supplies the
bus resource, we still have the two copies.
Thanks!
Yijing.
>
>> struct list_head windows; /* resource_entry */
>> void (*release_fn)(struct pci_host_bridge *);
>> void *release_data;
>> --
>> 1.7.1
>>
>
> .
>
--
Thanks!
Yijing
> 2 months ago, Thomas Petazzoni was concerned about the removal of
> mvebu_pcie_scan_bus(). So I dig the archives of the discussion
> surrounding the pcie-mvebu drive. I found that the main purpose
> of using this function was to allow to pass "struct device *" pointer.
>
> Thanks to the introduction of pci_common_init_dev it was not needed
> anymore. Actually we should have done this change when this function
> had been introduced. So for the point of view of the code it's fine.
> Then I tested your full series on Armada XP, Armada 375 and Armada 38x
> SoCs, and I didn't saw any regression. So you can add my:
>
> Reviewed-by: Gregory CLEMENT <[email protected]>
> Tested-by: Gregory CLEMENT <[email protected]>
Great, thanks very much!
Thanks!
Yijing.
>
>
>
>> Signed-off-by: Yijing Wang <[email protected]>
>> CC: Thomas Petazzoni <[email protected]>
>> CC: Jason Cooper <[email protected]>
>> ---
>> drivers/pci/host/pci-mvebu.c | 18 +-----------------
>> 1 files changed, 1 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
>> index 0cfc494..d5a2b70 100644
>> --- a/drivers/pci/host/pci-mvebu.c
>> +++ b/drivers/pci/host/pci-mvebu.c
>> @@ -750,21 +750,6 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
>> return 1;
>> }
>>
>> -static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>> -{
>> - struct mvebu_pcie *pcie = sys_to_pcie(sys);
>> - struct pci_bus *bus;
>> -
>> - bus = pci_create_root_bus(&pcie->pdev->dev, -1, sys->busnr,
>> - &mvebu_pcie_ops, sys, &sys->resources);
>> - if (!bus)
>> - return NULL;
>> -
>> - pci_scan_child_bus(bus);
>> -
>> - return bus;
>> -}
>> -
>> static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
>> const struct resource *res,
>> resource_size_t start,
>> @@ -808,12 +793,11 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
>> hw.nr_controllers = 1;
>> hw.private_data = (void **)&pcie;
>> hw.setup = mvebu_pcie_setup;
>> - hw.scan = mvebu_pcie_scan_bus;
>> hw.map_irq = of_irq_parse_and_map_pci;
>> hw.ops = &mvebu_pcie_ops;
>> hw.align_resource = mvebu_pcie_align_resource;
>>
>> - pci_common_init(&hw);
>> + pci_common_init_dev(&pcie->pdev->dev, &hw);
>> }
>>
>> /*
>>
>
>
--
Thanks!
Yijing
On 2015/4/8 16:09, Gregory CLEMENT wrote:
> Hi Yijing,
>
> On 03/04/2015 11:25, Yijing Wang wrote:
>> Save domain in pci_host_bridge, so we could get domain
>> from pci_host_bridge, and at the end of series, we could
>> clean up the arch specific pci_domain_nr(). For arm,
>> we pass -1 as the domain number, we would update the
>> domain number in core by pci_bus_assign_domain_nr().
>>
> For the mvebu part I tested on Armada XP, Armada 375 and Armada 38x
> SoCs, and I didn't saw any regression. So you can add my:
>
> Tested-by: Gregory CLEMENT <[email protected]>
Thanks a lot for your test!
Thanks!
Yijing.
>>
>
>
--
Thanks!
Yijing
On 2015/4/8 6:42, Bjorn Helgaas wrote:
> On Fri, Apr 03, 2015 at 05:25:42PM +0800, Yijing Wang wrote:
>> From: Yijing Wang <[email protected]>
>>
>> Sometimes, the bus resource start number is not equal to
>> root bus number. For example, in pci_scan_bus(), we always
>> add the default bus resource which start bus number is 0,
>> but the root bus number callers given may != 0, so
>> we need to update pci_host_bridge bus resource, because we
>> would check whether host bridge bus resoruce is confict
>> in later patch.
>
> It's true that pci_scan_bus() always inserts [bus 00-ff]. But I think
> that's completely bogus. The caller of pci_scan_bus() supplies a root bus
> number X. Any bus numbers below X are useless as far as this host bridge
> is concerned, and it's pointless to include them in the range inserted by
> pci_scan_bus().
Agree, I think it's better to use the [bus start - FF] instead of [00-FF].
>
> I think we'd be better off if we forced every pci_scan_bus() caller to
> supply a real non-overlapping bus number range. We probably can't do that
> easily because the arch knows the beginning bus number, but some don't know
> how to figure out the ending bus number.
It seems to have some problems in pci_scan_bus() if we have more than one pci host bridge
in a domain. Because we add the default busn_res[00-FF] to resource list in pci_scan_bus(),
and pass the resource list to pci_create_root_bus(). The pci root bus would
consume the bus range from the start to the 0xFF, and request it from the per-domain resource[00-FF].
So if we have another pci host bridge in this domain, and pass another start bus number, it would
fail when the root bus try to request bus resource from per-domain resource. Now only several archs
call pci_scan_bus(), I guess they didn't run the code in above case, so we didn't find
the bus report.
>
> Do we have a per-domain structure that tracks the bus numbers in use in the
> domain? It seems like if we had one, we could use that to approximate the
> end. For example, if the arch scans three root buses, at bus 00, bus 40,
> and bus 80, we could start with the first one at [bus 00-ff], and when we
> scan the one at bus 40, we could either report a conflict (if the bus 00
> tree included a bus 40) or reduce the first range to [bus 00-3f].
Per-domain resource pci_domain_busn_res is what we are looking for.
For simplicity, we could report a conflict and fail when we find a conflict bus
resource in system.
>> resource_list_for_each_entry(window, resources)
>> - if (window->res->flags & IORESOURCE_BUS)
>> + if (window->res->flags & IORESOURCE_BUS) {
>> + if (bus > window->res->start)
>> + window->res->start = bus;
>
> I see what you're trying to do here, but I think this is the wrong place to
> do it. I'd rather figure out a way to insert something other than
> busn_resource in pci_scan_bus(). That probably means we need to
> dynamically allocate a new busn_res struct.
Allocate a new busn_res maybe unnecessary, the bus resource we added to resource list
and passed to pci_create_root_bus() will never be used again after we call
pci_bus_insert_busn_res(), we may could consider to use local busn_res in pci_scan_bus().
Thanks!
Yijing.
>
>> return;
>> + }
>>
>> pr_info(
>> "No busn resource found for pci%04x:%02x, will use [bus %02x-ff]\n",
>> --
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> .
>
--
Thanks!
Yijing