summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt14
-rw-r--r--MAINTAINERS4
-rw-r--r--arch/alpha/include/asm/pci.h7
-rw-r--r--arch/alpha/kernel/pci.c86
-rw-r--r--arch/alpha/kernel/pci_impl.h3
-rw-r--r--arch/alpha/kernel/sys_marvel.c3
-rw-r--r--arch/alpha/kernel/sys_titan.c3
-rw-r--r--arch/arm/common/it8152.c4
-rw-r--r--arch/arm/include/asm/pci.h8
-rw-r--r--arch/arm/kernel/bios32.c75
-rw-r--r--arch/arm/mach-cns3xxx/pcie.c4
-rw-r--r--arch/arm/mach-dove/pcie.c4
-rw-r--r--arch/arm/mach-footbridge/dc21285.c8
-rw-r--r--arch/arm/mach-integrator/pci_v3.c7
-rw-r--r--arch/arm/mach-iop13xx/pci.c4
-rw-r--r--arch/arm/mach-ixp2000/ixdp2400.c4
-rw-r--r--arch/arm/mach-ixp2000/ixdp2800.c4
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x00.c4
-rw-r--r--arch/arm/mach-ixp2000/pci.c6
-rw-r--r--arch/arm/mach-ixp23xx/pci.c6
-rw-r--r--arch/arm/mach-ixp4xx/common-pci.c4
-rw-r--r--arch/arm/mach-kirkwood/pcie.c4
-rw-r--r--arch/arm/mach-ks8695/pci.c4
-rw-r--r--arch/arm/mach-mv78xx0/pcie.c4
-rw-r--r--arch/arm/mach-orion5x/pci.c14
-rw-r--r--arch/arm/mach-sa1100/pci-nanoengine.c8
-rw-r--r--arch/arm/mach-tegra/pcie.c6
-rw-r--r--arch/arm/mach-versatile/pci.c6
-rw-r--r--arch/arm/mm/iomap.c3
-rw-r--r--arch/arm/plat-iop/pci.c4
-rw-r--r--arch/ia64/include/asm/pci.h6
-rw-r--r--arch/ia64/pci/pci.c55
-rw-r--r--arch/ia64/sn/kernel/io_init.c16
-rw-r--r--arch/microblaze/include/asm/pci-bridge.h1
-rw-r--r--arch/microblaze/include/asm/pci.h8
-rw-r--r--arch/microblaze/pci/pci-common.c117
-rw-r--r--arch/mips/include/asm/pci.h9
-rw-r--r--arch/mips/pci/fixup-cobalt.c61
-rw-r--r--arch/mips/pci/pci-bcm1480.c2
-rw-r--r--arch/mips/pci/pci-ip27.c2
-rw-r--r--arch/mips/pci/pci-lantiq.c3
-rw-r--r--arch/mips/pci/pci-sb1250.c2
-rw-r--r--arch/mips/pci/pci-xlr.c2
-rw-r--r--arch/mips/pci/pci.c86
-rw-r--r--arch/mn10300/include/asm/pci.h16
-rw-r--r--arch/mn10300/unit-asb2305/pci.c62
-rw-r--r--arch/parisc/include/asm/pci.h38
-rw-r--r--arch/parisc/kernel/pci.c52
-rw-r--r--arch/powerpc/include/asm/pci.h9
-rw-r--r--arch/powerpc/include/asm/ppc-pci.h2
-rw-r--r--arch/powerpc/kernel/pci-common.c86
-rw-r--r--arch/powerpc/kernel/pci_32.c6
-rw-r--r--arch/powerpc/kernel/pci_64.c7
-rw-r--r--arch/powerpc/kernel/pci_of_scan.c12
-rw-r--r--arch/powerpc/kernel/rtas_pci.c10
-rw-r--r--arch/powerpc/platforms/maple/pci.c2
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c3
-rw-r--r--arch/powerpc/platforms/powermac/pci.c3
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c5
-rw-r--r--arch/powerpc/platforms/powernv/pci.c5
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c3
-rw-r--r--arch/powerpc/platforms/wsp/wsp_pci.c1
-rw-r--r--arch/sh/drivers/pci/pci.c75
-rw-r--r--arch/sh/include/asm/pci.h6
-rw-r--r--arch/sparc/include/asm/pci_32.h8
-rw-r--r--arch/sparc/include/asm/pci_64.h8
-rw-r--r--arch/sparc/kernel/leon_pci.c47
-rw-r--r--arch/sparc/kernel/pci.c106
-rw-r--r--arch/unicore32/include/asm/pci.h1
-rw-r--r--arch/unicore32/kernel/pci.c5
-rw-r--r--arch/x86/kernel/pci-dma.c5
-rw-r--r--arch/x86/pci/acpi.c7
-rw-r--r--arch/x86/pci/fixup.c12
-rw-r--r--arch/x86/pci/i386.c85
-rw-r--r--arch/x86/pci/mrst.c40
-rw-r--r--arch/xtensa/kernel/pci.c17
-rw-r--r--drivers/message/fusion/mptbase.c2
-rw-r--r--drivers/parisc/dino.c27
-rw-r--r--drivers/parisc/lba_pci.c31
-rw-r--r--drivers/pci/Kconfig13
-rw-r--r--drivers/pci/bus.c30
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c33
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c2
-rw-r--r--drivers/pci/hotplug/cpcihp_generic.c2
-rw-r--r--drivers/pci/hotplug/cpqphp_pci.c2
-rw-r--r--drivers/pci/hotplug/fakephp.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_core.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_ebda.c6
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c133
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c2
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c2
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c2
-rw-r--r--drivers/pci/hotplug/shpchp_pci.c2
-rw-r--r--drivers/pci/iov.c12
-rw-r--r--drivers/pci/pci-driver.c10
-rw-r--r--drivers/pci/pci-sysfs.c7
-rw-r--r--drivers/pci/pci.c108
-rw-r--r--drivers/pci/pci.h10
-rw-r--r--drivers/pci/pcie/Kconfig25
-rw-r--r--drivers/pci/pcie/aspm.c8
-rw-r--r--drivers/pci/pcie/portdrv.h12
-rw-r--r--drivers/pci/pcie/portdrv_core.c16
-rw-r--r--drivers/pci/probe.c298
-rw-r--r--drivers/pci/quirks.c182
-rw-r--r--drivers/pci/remove.c27
-rw-r--r--drivers/pci/setup-bus.c660
-rw-r--r--drivers/pci/setup-res.c94
-rw-r--r--drivers/pci/xen-pcifront.c4
-rw-r--r--drivers/pcmcia/cardbus.c2
-rw-r--r--drivers/platform/x86/asus-wmi.c2
-rw-r--r--drivers/platform/x86/eeepc-laptop.c2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c2
-rw-r--r--drivers/usb/host/pci-quirks.c3
-rw-r--r--include/asm-generic/pci-bridge.h6
-rw-r--r--include/asm-generic/pci.h24
-rw-r--r--include/linux/ioport.h6
-rw-r--r--include/linux/pci.h105
-rw-r--r--include/linux/pci_regs.h1
119 files changed, 1649 insertions, 1701 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 7c33ef8a1ba..1c9a348548d 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2147,8 +2147,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
the default.
off: Turn ECRC off
on: Turn ECRC on.
- realloc reallocate PCI resources if allocations done by BIOS
- are erroneous.
+ realloc= Enable/disable reallocating PCI bridge resources
+ if allocations done by BIOS are too small to
+ accommodate resources required by all child
+ devices.
+ off: Turn realloc off
+ on: Turn realloc on
+ realloc same as realloc=on
+ noari do not use PCIe ARI.
pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
Management.
@@ -2156,6 +2162,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
force Enable ASPM even on devices that claim not to support it.
WARNING: Forcing ASPM on may cause system lockups.
+ pcie_hp= [PCIE] PCI Express Hotplug driver options:
+ nomsi Do not use MSI for PCI Express Native Hotplug (this
+ makes all PCIe ports use INTx for hotplug services).
+
pcie_ports= [PCIE] PCIe ports handling:
auto Ask the BIOS whether or not to use native PCIe services
associated with PCIe ports (PME, hot-plug, AER). Use
diff --git a/MAINTAINERS b/MAINTAINERS
index 95eba313501..3b733fafb05 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5120,7 +5120,7 @@ F: Documentation/PCI/pci-error-recovery.txt
F: Documentation/powerpc/eeh-pci-error-recovery.txt
PCI SUBSYSTEM
-M: Jesse Barnes <jbarnes@virtuousgeek.org>
+M: Bjorn Helgaas <bhelgaas@google.com>
L: linux-pci@vger.kernel.org
Q: http://patchwork.kernel.org/project/linux-pci/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6.git
@@ -5130,7 +5130,7 @@ F: drivers/pci/
F: include/linux/pci*
PCI HOTPLUG
-M: Jesse Barnes <jbarnes@virtuousgeek.org>
+M: Bjorn Helgaas <bhelgaas@google.com>
L: linux-pci@vger.kernel.org
S: Supported
F: drivers/pci/hotplug
diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
index 28d0497fd3c..d01afb78919 100644
--- a/arch/alpha/include/asm/pci.h
+++ b/arch/alpha/include/asm/pci.h
@@ -7,6 +7,7 @@
#include <linux/dma-mapping.h>
#include <asm/scatterlist.h>
#include <asm/machvec.h>
+#include <asm-generic/pci-bridge.h>
/*
* The following structure is used to manage multiple PCI busses.
@@ -99,12 +100,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
return channel ? 15 : 14;
}
-extern void pcibios_resource_to_bus(struct pci_dev *, struct pci_bus_region *,
- struct resource *);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region);
-
#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
static inline int pci_proc_domain(struct pci_bus *bus)
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 8c723c1b086..1a629636cc1 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -43,12 +43,10 @@ const char *const pci_mem_names[] = {
const char pci_hae0_name[] = "HAE0";
-/* Indicate whether we respect the PCI setup left by console. */
/*
- * Make this long-lived so that we know when shutting down
- * whether we probed only or not.
+ * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource
+ * assignments.
*/
-int pci_probe_only;
/*
* The PCI controller list.
@@ -215,7 +213,7 @@ pdev_save_srm_config(struct pci_dev *dev)
struct pdev_srm_saved_conf *tmp;
static int printed = 0;
- if (!alpha_using_srm || pci_probe_only)
+ if (!alpha_using_srm || pci_has_flag(PCI_PROBE_ONLY))
return;
if (!printed) {
@@ -242,7 +240,7 @@ pci_restore_srm_config(void)
struct pdev_srm_saved_conf *tmp;
/* No need to restore if probed only. */
- if (pci_probe_only)
+ if (pci_has_flag(PCI_PROBE_ONLY))
return;
/* Restore SRM config. */
@@ -253,46 +251,17 @@ pci_restore_srm_config(void)
#endif
void __devinit
-pcibios_fixup_resource(struct resource *res, struct resource *root)
-{
- res->start += root->start;
- res->end += root->start;
-}
-
-void __devinit
-pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
-{
- /* Update device resources. */
- struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
- int i;
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- if (!dev->resource[i].start)
- continue;
- if (dev->resource[i].flags & IORESOURCE_IO)
- pcibios_fixup_resource(&dev->resource[i],
- hose->io_space);
- else if (dev->resource[i].flags & IORESOURCE_MEM)
- pcibios_fixup_resource(&dev->resource[i],
- hose->mem_space);
- }
-}
-
-void __devinit
pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_dev *dev = bus->self;
- if (pci_probe_only && dev &&
+ if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_read_bridge_bases(bus);
- pcibios_fixup_device_resources(dev, bus);
}
list_for_each_entry(dev, &bus->devices, bus_list) {
pdev_save_srm_config(dev);
- if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
- pcibios_fixup_device_resources(dev, bus);
}
}
@@ -302,42 +271,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
-void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
- unsigned long offset = 0;
-
- if (res->flags & IORESOURCE_IO)
- offset = hose->io_space->start;
- else if (res->flags & IORESOURCE_MEM)
- offset = hose->mem_space->start;
-
- region->start = res->start - offset;
- region->end = res->end - offset;
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
- unsigned long offset = 0;
-
- if (res->flags & IORESOURCE_IO)
- offset = hose->io_space->start;
- else if (res->flags & IORESOURCE_MEM)
- offset = hose->mem_space->start;
-
- res->start = region->start + offset;
- res->end = region->end + offset;
-}
-
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-#endif
-
int
pcibios_enable_device(struct pci_dev *dev, int mask)
{
@@ -374,7 +307,8 @@ pcibios_claim_one_bus(struct pci_bus *b)
if (r->parent || !r->start || !r->flags)
continue;
- if (pci_probe_only || (r->flags & IORESOURCE_PCI_FIXED))
+ if (pci_has_flag(PCI_PROBE_ONLY) ||
+ (r->flags & IORESOURCE_PCI_FIXED))
pci_claim_resource(dev, i);
}
}
@@ -416,8 +350,10 @@ common_init_pci(void)
hose->mem_space->end = end;
INIT_LIST_HEAD(&resources);
- pci_add_resource(&resources, hose->io_space);
- pci_add_resource(&resources, hose->mem_space);
+ pci_add_resource_offset(&resources, hose->io_space,
+ hose->io_space->start);
+ 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);
diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h
index 85457b2d451..2b0ac429f5e 100644
--- a/arch/alpha/kernel/pci_impl.h
+++ b/arch/alpha/kernel/pci_impl.h
@@ -173,9 +173,6 @@ extern void pci_restore_srm_config(void);
extern struct pci_controller *hose_head, **hose_tail;
extern struct pci_controller *pci_isa_hose;
-/* Indicate that we trust the console to configure things properly. */
-extern int pci_probe_only;
-
extern unsigned long alpha_agpgart_size;
extern void common_init_pci(void);
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
index 95cfc83ece8..fc8b1250861 100644
--- a/arch/alpha/kernel/sys_marvel.c
+++ b/arch/alpha/kernel/sys_marvel.c
@@ -384,7 +384,8 @@ marvel_init_pci(void)
marvel_register_error_handlers();
- pci_probe_only = 1;
+ /* Indicate that we trust the console to configure things properly */
+ pci_set_flags(PCI_PROBE_ONLY);
common_init_pci();
locate_and_init_vga(NULL);
diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
index f47b30a2a11..b8eafa05353 100644
--- a/arch/alpha/kernel/sys_titan.c
+++ b/arch/alpha/kernel/sys_titan.c
@@ -331,7 +331,8 @@ titan_init_pci(void)
*/
titan_late_init();
- pci_probe_only = 1;
+ /* Indicate that we trust the console to configure things properly */
+ pci_set_flags(PCI_PROBE_ONLY);
common_init_pci();
SMC669_Init(0);
locate_and_init_vga(NULL);
diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c
index fb1f1cfce60..dcb13494ca0 100644
--- a/arch/arm/common/it8152.c
+++ b/arch/arm/common/it8152.c
@@ -299,8 +299,8 @@ int __init it8152_pci_setup(int nr, struct pci_sys_data *sys)
goto err1;
}
- pci_add_resource(&sys->resources, &it8152_io);
- pci_add_resource(&sys->resources, &it8152_mem);
+ pci_add_resource_offset(&sys->resources, &it8152_io, sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &it8152_mem, sys->mem_offset);
if (platform_notify || platform_notify_remove) {
printk(KERN_ERR "PCI: Can't use platform_notify\n");
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index da337ba57ff..a98a2e112fa 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -57,14 +57,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region);
-
/*
* Dummy implementation; always return 0.
*/
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index f58ba358990..632df9a66f8 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -16,7 +16,6 @@
#include <asm/mach/pci.h>
static int debug_pci;
-static int use_firmware;
/*
* We can't use pci_find_device() here since we are
@@ -295,28 +294,6 @@ static inline int pdev_bad_for_parity(struct pci_dev *dev)
}
/*
- * Adjust the device resources from bus-centric to Linux-centric.
- */
-static void __devinit
-pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev)
-{
- resource_size_t offset;
- int i;
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- if (dev->resource[i].start == 0)
- continue;
- if (dev->resource[i].flags & IORESOURCE_MEM)
- offset = root->mem_offset;
- else
- offset = root->io_offset;
-
- dev->resource[i].start += offset;
- dev->resource[i].end += offset;
- }
-}
-
-/*
* pcibios_fixup_bus - Called after each bus is probed,
* but before its children are examined.
*/
@@ -333,8 +310,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 status;
- pdev_fixup_device_resources(root, dev);
-
pci_read_config_word(dev, PCI_STATUS, &status);
/*
@@ -400,43 +375,6 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
#endif
/*
- * Convert from Linux-centric to bus-centric addresses for bridge devices.
- */
-void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- struct pci_sys_data *root = dev->sysdata;
- unsigned long offset = 0;
-
- if (res->flags & IORESOURCE_IO)
- offset = root->io_offset;
- if (res->flags & IORESOURCE_MEM)
- offset = root->mem_offset;
-
- region->start = res->start - offset;
- region->end = res->end - offset;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void __devinit
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- struct pci_sys_data *root = dev->sysdata;
- unsigned long offset = 0;
-
- if (res->flags & IORESOURCE_IO)
- offset = root->io_offset;
- if (res->flags & IORESOURCE_MEM)
- offset = root->mem_offset;
-
- res->start = region->start + offset;
- res->end = region->end + offset;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/*
* Swizzle the device pin each time we cross a bridge.
* This might update pin and returns the slot number.
*/
@@ -497,10 +435,10 @@ static void __init pcibios_init_hw(struct hw_pci *hw)
if (ret > 0) {
if (list_empty(&sys->resources)) {
- pci_add_resource(&sys->resources,
- &ioport_resource);
- pci_add_resource(&sys->resources,
- &iomem_resource);
+ pci_add_resource_offset(&sys->resources,
+ &ioport_resource, sys->io_offset);
+ pci_add_resource_offset(&sys->resources,
+ &iomem_resource, sys->mem_offset);
}
sys->bus = hw->scan(nr, sys);
@@ -525,6 +463,7 @@ void __init pci_common_init(struct hw_pci *hw)
INIT_LIST_HEAD(&hw->buses);
+ pci_add_flags(PCI_REASSIGN_ALL_RSRC);
if (hw->preinit)
hw->preinit();
pcibios_init_hw(hw);
@@ -536,7 +475,7 @@ void __init pci_common_init(struct hw_pci *hw)
list_for_each_entry(sys, &hw->buses, node) {
struct pci_bus *bus = sys->bus;
- if (!use_firmware) {
+ if (!pci_has_flag(PCI_PROBE_ONLY)) {
/*
* Size the bridge windows.
*/
@@ -573,7 +512,7 @@ char * __init pcibios_setup(char *str)
debug_pci = 1;
return NULL;
} else if (!strcmp(str, "firmware")) {
- use_firmware = 1;
+ pci_add_flags(PCI_PROBE_ONLY);
return NULL;
}
return str;
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
index e159d69967c..79d001f831e 100644
--- a/arch/arm/mach-cns3xxx/pcie.c
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -155,8 +155,8 @@ static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys)
BUG_ON(request_resource(&iomem_resource, res_io) ||
request_resource(&iomem_resource, res_mem));
- pci_add_resource(&sys->resources, res_io);
- pci_add_resource(&sys->resources, res_mem);
+ pci_add_resource_offset(&sys->resources, res_io, sys->io_offset);
+ pci_add_resource_offset(&sys->resources, res_mem, sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
index 52e96d397ba..48a032005ea 100644
--- a/arch/arm/mach-dove/pcie.c
+++ b/arch/arm/mach-dove/pcie.c
@@ -69,7 +69,7 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
pp->res[0].flags = IORESOURCE_IO;
if (request_resource(&ioport_resource, &pp->res[0]))
panic("Request PCIe IO resource failed\n");
- pci_add_resource(&sys->resources, &pp->res[0]);
+ pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
/*
* IORESOURCE_MEM
@@ -88,7 +88,7 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
pp->res[1].flags = IORESOURCE_MEM;
if (request_resource(&iomem_resource, &pp->res[1]))
panic("Request PCIe Memory resource failed\n");
- pci_add_resource(&sys->resources, &pp->res[1]);
+ pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index f685650c25d..3194d3f7350 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -275,11 +275,13 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys)
allocate_resource(&iomem_resource, &res[0], 0x40000000,
0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
- pci_add_resource(&sys->resources, &ioport_resource);
- pci_add_resource(&sys->resources, &res[0]);
- pci_add_resource(&sys->resources, &res[1]);
sys->mem_offset = DC21285_PCI_MEM;
+ pci_add_resource_offset(&sys->resources,
+ &ioport_resource, sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
+ pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+
return 1;
}
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index 3c82566acec..015be770c1d 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -378,9 +378,10 @@ static int __init pci_v3_setup_resources(struct pci_sys_data *sys)
* the mem resource for this bus
* the prefetch mem resource for this bus
*/
- pci_add_resource(&sys->resources, &ioport_resource);
- pci_add_resource(&sys->resources, &non_mem);
- pci_add_resource(&sys->resources, &pre_mem);
+ pci_add_resource_offset(&sys->resources,
+ &ioport_resource, sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
+ pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index b8f5a873651..861cb12ef43 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -1084,8 +1084,8 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
request_resource(&ioport_resource, &res[0]);
request_resource(&iomem_resource, &res[1]);
- pci_add_resource(&sys->resources, &res[0]);
- pci_add_resource(&sys->resources, &res[1]);
+ pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
index f53e911ec94..d519944653a 100644
--- a/arch/arm/mach-ixp2000/ixdp2400.c
+++ b/arch/arm/mach-ixp2000/ixdp2400.c
@@ -134,11 +134,11 @@ static void ixdp2400_pci_postinit(void)
if (ixdp2x00_master_npu()) {
dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
} else {
dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN);
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
ixdp2x00_slave_pci_postinit();
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
index a2e7c393e74..b415febd202 100644
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -262,14 +262,14 @@ int __init ixdp2800_pci_init(void)
pci_common_init(&ixdp2800_pci);
if (ixdp2x00_master_npu()) {
dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
ixdp2800_master_enable_slave();
ixdp2800_master_wait_for_slave_bus_scan();
} else {
dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
}
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 634b6c852f6..dd983829906 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -239,12 +239,12 @@ void ixdp2x00_slave_pci_postinit(void)
* Remove PMC device is there is one
*/
if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) {
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN);
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
index 626fda435aa..49c36f3cd60 100644
--- a/arch/arm/mach-ixp2000/pci.c
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -243,8 +243,10 @@ int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
if (nr >= 1)
return 0;
- pci_add_resource(&sys->resources, &ixp2000_pci_io_space);
- pci_add_resource(&sys->resources, &ixp2000_pci_mem_space);
+ pci_add_resource_offset(&sys->resources,
+ &ixp2000_pci_io_space, sys->io_offset);
+ pci_add_resource_offset(&sys->resources,
+ &ixp2000_pci_mem_space, sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c
index 25b5c462cea..3cbbd3208fa 100644
--- a/arch/arm/mach-ixp23xx/pci.c
+++ b/arch/arm/mach-ixp23xx/pci.c
@@ -281,8 +281,10 @@ int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys)
if (nr >= 1)
return 0;
- pci_add_resource(&sys->resources, &ixp23xx_pci_io_space);
- pci_add_resource(&sys->resources, &ixp23xx_pci_mem_space);
+ pci_add_resource_offset(&sys->resources,
+ &ixp23xx_pci_io_space, sys->io_offset);
+ pci_add_resource_offset(&sys->resources,
+ &ixp23xx_pci_mem_space, sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index 5eff15f24bc..8508882b13f 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -472,8 +472,8 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys)
request_resource(&ioport_resource, &res[0]);
request_resource(&iomem_resource, &res[1]);
- pci_add_resource(&sys->resources, &res[0]);
- pci_add_resource(&sys->resources, &res[1]);
+ pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
platform_notify = ixp4xx_pci_platform_notify;
platform_notify_remove = ixp4xx_pci_platform_notify_remove;
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index a066a6d8d9d..f56a0118c1b 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -198,9 +198,9 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
if (request_resource(&iomem_resource, &pp->res[1]))
panic("Request PCIe%d Memory resource failed\n", index);
- pci_add_resource(&sys->resources, &pp->res[0]);
- pci_add_resource(&sys->resources, &pp->res[1]);
sys->io_offset = 0;
+ pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
/*
* Generic PCIe unit setup.
diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c
index b26f992071d..acc70143581 100644
--- a/arch/arm/mach-ks8695/pci.c
+++ b/arch/arm/mach-ks8695/pci.c
@@ -169,8 +169,8 @@ static int __init ks8695_pci_setup(int nr, struct pci_sys_data *sys)
request_resource(&iomem_resource, &pci_mem);
request_resource(&ioport_resource, &pci_io);
- pci_add_resource(&sys->resources, &pci_io);
- pci_add_resource(&sys->resources, &pci_mem);
+ pci_add_resource_offset(&sys->resources, &pci_io, sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &pci_mem, sys->mem_offset);
/* Assign and enable processor bridge */
ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA);
diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c
index 8459f6d7d8c..df3e38055a2 100644
--- a/arch/arm/mach-mv78xx0/pcie.c
+++ b/arch/arm/mach-mv78xx0/pcie.c
@@ -155,8 +155,8 @@ static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys)
orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
orion_pcie_setup(pp->base);
- pci_add_resource(&sys->resources, &pp->res[0]);
- pci_add_resource(&sys->resources, &pp->res[1]);
+ pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index 09a045f0c40..d6a91948e4d 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -171,13 +171,14 @@ static int __init pcie_setup(struct pci_sys_data *sys)
/*
* IORESOURCE_IO
*/
+ sys->io_offset = 0;
res[0].name = "PCIe I/O Space";
res[0].flags = IORESOURCE_IO;
res[0].start = ORION5X_PCIE_IO_BUS_BASE;
res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
if (request_resource(&ioport_resource, &res[0]))
panic("Request PCIe IO resource failed\n");
- pci_add_resource(&sys->resources, &res[0]);
+ pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
/*
* IORESOURCE_MEM
@@ -188,9 +189,7 @@ static int __init pcie_setup(struct pci_sys_data *sys)
res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
if (request_resource(&iomem_resource, &res[1]))
panic("Request PCIe Memory resource failed\n");
- pci_add_resource(&sys->resources, &res[1]);
-
- sys->io_offset = 0;
+ pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
return 1;
}
@@ -499,13 +498,14 @@ static int __init pci_setup(struct pci_sys_data *sys)
/*
* IORESOURCE_IO
*/
+ sys->io_offset = 0;
res[0].name = "PCI I/O Space";
res[0].flags = IORESOURCE_IO;
res[0].start = ORION5X_PCI_IO_BUS_BASE;
res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
if (request_resource(&ioport_resource, &res[0]))
panic("Request PCI IO resource failed\n");
- pci_add_resource(&sys->resources, &res[0]);
+ pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
/*
* IORESOURCE_MEM
@@ -516,9 +516,7 @@ static int __init pci_setup(struct pci_sys_data *sys)
res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
if (request_resource(&iomem_resource, &res[1]))
panic("Request PCI Memory resource failed\n");
- pci_add_resource(&sys->resources, &res[1]);
-
- sys->io_offset = 0;
+ pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-sa1100/pci-nanoengine.c b/arch/arm/mach-sa1100/pci-nanoengine.c
index 0d01ca78892..b466bca9c65 100644
--- a/arch/arm/mach-sa1100/pci-nanoengine.c
+++ b/arch/arm/mach-sa1100/pci-nanoengine.c
@@ -244,9 +244,11 @@ static int __init pci_nanoengine_setup_resources(struct pci_sys_data *sys)
printk(KERN_ERR "PCI: unable to allocate prefetchable\n");
return -EBUSY;
}
- pci_add_resource(&sys->resources, &pci_io_ports);
- pci_add_resource(&sys->resources, &pci_non_prefetchable_memory);
- pci_add_resource(&sys->resources, &pci_prefetchable_memory);
+ pci_add_resource_offset(&sys->resources, &pci_io_ports, sys->io_offset);
+ pci_add_resource_offset(&sys->resources,
+ &pci_non_prefetchable_memory, sys->mem_offset);
+ pci_add_resource_offset(&sys->resources,
+ &pci_prefetchable_memory, sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index af8b6343572..14b29ab5d8f 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -408,7 +408,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
pp->res[0].flags = IORESOURCE_IO;
if (request_resource(&ioport_resource, &pp->res[0]))
panic("Request PCIe IO resource failed\n");
- pci_add_resource(&sys->resources, &pp->res[0]);
+ pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
/*
* IORESOURCE_MEM
@@ -427,7 +427,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
pp->res[1].flags = IORESOURCE_MEM;
if (request_resource(&iomem_resource, &pp->res[1]))
panic("Request PCIe Memory resource failed\n");
- pci_add_resource(&sys->resources, &pp->res[1]);
+ pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
/*
* IORESOURCE_MEM | IORESOURCE_PREFETCH
@@ -446,7 +446,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (request_resource(&iomem_resource, &pp->res[2]))
panic("Request PCIe Prefetch Memory resource failed\n");
- pci_add_resource(&sys->resources, &pp->res[2]);
+ pci_add_resource_offset(&sys->resources, &pp->res[2], sys->mem_offset);
return 1;
}
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index 90069bce23b..51733b022d0 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -219,9 +219,9 @@ static int __init pci_versatile_setup_resources(struct list_head *resources)
* the mem resource for this bus
* the prefetch mem resource for this bus
*/
- pci_add_resource(resources, &io_mem);
- pci_add_resource(resources, &non_mem);
- pci_add_resource(resources, &pre_mem);
+ pci_add_resource_offset(resources, &io_mem, sys->io_offset);
+ pci_add_resource_offset(resources, &non_mem, sys->mem_offset);
+ pci_add_resource_offset(resources, &pre_mem, sys->mem_offset);
goto out;
diff --git a/arch/arm/mm/iomap.c b/arch/arm/mm/iomap.c
index e62956e1203..4614208369f 100644
--- a/arch/arm/mm/iomap.c
+++ b/arch/arm/mm/iomap.c
@@ -32,9 +32,6 @@ EXPORT_SYMBOL(pcibios_min_io);
unsigned long pcibios_min_mem = 0x01000000;
EXPORT_SYMBOL(pcibios_min_mem);
-unsigned int pci_flags = PCI_REASSIGN_ALL_RSRC;
-EXPORT_SYMBOL(pci_flags);
-
void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
{
if ((unsigned long)addr >= VMALLOC_START &&
diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
index f4d40a27111..72768356447 100644
--- a/arch/arm/plat-iop/pci.c
+++ b/arch/arm/plat-iop/pci.c
@@ -215,8 +215,8 @@ int iop3xx_pci_setup(int nr, struct pci_sys_data *sys)
sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
sys->io_offset = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
- pci_add_resource(&sys->resources, &res[0]);
- pci_add_resource(&sys->resources, &res[1]);
+ pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
return 1;
}
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 279b38ae74a..b22e5f5fa59 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -108,12 +108,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
return (pci_domain_nr(bus) != 0);
}
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
- struct resource *res, struct pci_bus_region *region);
-
static inline struct resource *
pcibios_select_root(struct pci_dev *pdev, struct resource *res)
{
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index f82f5d4b65f..d1ce3200147 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -320,7 +320,8 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
* Ignore these tiny memory ranges */
if (!((window->resource.flags & IORESOURCE_MEM) &&
(window->resource.end - window->resource.start < 16)))
- pci_add_resource(&info->resources, &window->resource);
+ pci_add_resource_offset(&info->resources, &window->resource,
+ window->offset);
return AE_OK;
}
@@ -395,54 +396,6 @@ out1:
return NULL;
}
-void pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region, struct resource *res)
-{
- struct pci_controller *controller = PCI_CONTROLLER(dev);
- unsigned long offset = 0;
- int i;
-
- for (i = 0; i < controller->windows; i++) {
- struct pci_window *window = &controller->window[i];
- if (!(window->resource.flags & res->flags))
- continue;
- if (window->resource.start > res->start)
- continue;
- if (window->resource.end < res->end)
- continue;
- offset = window->offset;
- break;
- }
-
- region->start = res->start - offset;
- region->end = res->end - offset;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev,
- struct resource *res, struct pci_bus_region *region)
-{
- struct pci_controller *controller = PCI_CONTROLLER(dev);
- unsigned long offset = 0;
- int i;
-
- for (i = 0; i < controller->windows; i++) {
- struct pci_window *window = &controller->window[i];
- if (!(window->resource.flags & res->flags))
- continue;
- if (window->resource.start - window->offset > region->start)
- continue;
- if (window->resource.end - window->offset < region->end)
- continue;
- offset = window->offset;
- break;
- }
-
- res->start = region->start + offset;
- res->end = region->end + offset;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
{
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
@@ -464,15 +417,11 @@ static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
static void __devinit
pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
{
- struct pci_bus_region region;
int i;
for (i = start; i < limit; i++) {
if (!dev->resource[i].flags)
continue;
- region.start = dev->resource[i].start;
- region.end = dev->resource[i].end;
- pcibios_bus_to_resource(dev, &dev->resource[i], &region);
if ((is_valid_resource(dev, i)))
pci_claim_resource(dev, i);
}
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 0a36f082eaf..238e2c511d9 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -297,7 +297,8 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
s64 status = 0;
struct pci_controller *controller;
struct pcibus_bussoft *prom_bussoft_ptr;
-
+ LIST_HEAD(resources);
+ int i;
status = sal_get_pcibus_info((u64) segment, (u64) busnum,
(u64) ia64_tpa(&prom_bussoft_ptr));
@@ -315,7 +316,15 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
*/
controller->platform_data = prom_bussoft_ptr;
- bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+ sn_legacy_pci_window_fixup(controller,
+ prom_bussoft_ptr->bs_legacy_io,
+ prom_bussoft_ptr->bs_legacy_mem);
+ for (i = 0; i < controller->windows; i++)
+ pci_add_resource_offset(&resources,
+ &controller->window[i].resource,
+ controller->window[i].offset);
+ bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller,
+ &resources);
if (bus == NULL)
goto error_return; /* error, or bus already scanned */
@@ -348,9 +357,6 @@ sn_bus_fixup(struct pci_bus *bus)
return;
}
sn_common_bus_fixup(bus, prom_bussoft_ptr);
- sn_legacy_pci_window_fixup(PCI_CONTROLLER(bus),
- prom_bussoft_ptr->bs_legacy_io,
- prom_bussoft_ptr->bs_legacy_mem);
}
list_for_each_entry(pci_dev, &bus->devices, bus_list) {
sn_io_slot_fixup(pci_dev);
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index e9834b2991d..cb5d3979480 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -10,7 +10,6 @@
#include <linux/pci.h>
#include <linux/list.h>
#include <linux/ioport.h>
-#include <asm-generic/pci-bridge.h>
struct device_node;
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index 033137628e8..a0da88bf70c 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -94,14 +94,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
*/
#define PCI_DMA_BUS_IS_PHYS (1)
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region,
- struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
- struct resource *res,
- struct pci_bus_region *region);
-
static inline struct resource *pcibios_select_root(struct pci_dev *pdev,
struct resource *res)
{
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 85f2ac1230a..d10403dadd2 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -46,9 +46,6 @@ static int global_phb_number; /* Global phb counter */
/* ISA Memory physical address */
resource_size_t isa_mem_base;
-/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
-unsigned int pci_flags;
-
static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
unsigned long isa_io_base;
@@ -833,64 +830,7 @@ int pci_proc_domain(struct pci_bus *bus)
{
struct pci_controller *hose = pci_bus_to_host(bus);
- if (!(pci_flags & PCI_ENABLE_PROC_DOMAINS))
- return 0;
- if (pci_flags & PCI_COMPAT_DOMAIN_0)
- return hose->global_number != 0;
- return 1;
-}
-
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- resource_size_t offset = 0, mask = (resource_size_t)-1;
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
- if (!hose)
- return;
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
-
- region->start = (res->start - offset) & mask;
- region->end = (res->end - offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- resource_size_t offset = 0, mask = (resource_size_t)-1;
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
- if (!hose)
- return;
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
- res->start = (region->start + offset) & mask;
- res->end = (region->end + offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/* Fixup a bus resource into a linux resource */
-static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
-{
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
- resource_size_t offset = 0, mask = (resource_size_t)-1;
-
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
-
- res->start = (res->start + offset) & mask;
- res->end = (res->end + offset) & mask;
+ return 0;
}
/* This header fixup will do the resource fixup for all devices as they are
@@ -910,13 +850,7 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
struct resource *res = dev->resource + i;
if (!res->flags)
continue;
- /* On platforms that have PCI_PROBE_ONLY set, we don't
- * consider 0 as an unassigned BAR value. It's technically
- * a valid value, but linux doesn't like it... so when we can
- * re-assign things, we do so, but if we can't, we keep it
- * around and hope for the best...
- */
- if (res->start == 0 && !(pci_flags & PCI_PROBE_ONLY)) {
+ if (res->start == 0) {
pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]" \
"is unassigned\n",
pci_name(dev), i,
@@ -929,18 +863,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
continue;
}
- pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
+ pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n",
pci_name(dev), i,
(unsigned long long)res->start,\
(unsigned long long)res->end,
(unsigned int)res->flags);
-
- fixup_resource(res, dev);
-
- pr_debug("PCI:%s %016llx-%016llx\n",
- pci_name(dev),
- (unsigned long long)res->start,
- (unsigned long long)res->end);
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
@@ -959,10 +886,6 @@ static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
u16 command;
int i;
- /* We don't do anything if PCI_PROBE_ONLY is set */
- if (pci_flags & PCI_PROBE_ONLY)
- return 0;
-
/* Job is a bit different between memory and IO */
if (res->flags & IORESOURCE_MEM) {
/* If the BAR is non-0 (res != pci_mem_offset) then it's
@@ -1037,9 +960,6 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
(unsigned long long)res->end,
(unsigned int)res->flags);
- /* Perform fixup */
- fixup_resource(res, dev);
-
/* Try to detect uninitialized P2P bridge resources,
* and clear them out so they get re-assigned later
*/
@@ -1107,9 +1027,6 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
static int skip_isa_ioresource_align(struct pci_dev *dev)
{
- if ((pci_flags & PCI_CAN_SKIP_ISA_ALIGN) &&
- !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
- return 1;
return 0;
}
@@ -1236,8 +1153,6 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus)
* and as such ensure proper re-allocation
* later.
*/
- if (pci_flags & PCI_REASSIGN_ALL_RSRC)
- goto clear_resource;
pr = pci_find_parent_resource(bus->self, res);
if (pr == res) {
/* this happens when the generic PCI
@@ -1422,27 +1337,19 @@ void __init pcibios_resource_survey(void)
list_for_each_entry(b, &pci_root_buses, node)
pcibios_allocate_bus_resources(b);
- if (!(pci_flags & PCI_REASSIGN_ALL_RSRC)) {
- pcibios_allocate_resources(0);
- pcibios_allocate_resources(1);
- }
+ pcibios_allocate_resources(0);
+ pcibios_allocate_resources(1);
/* Before we start assigning unassigned resource, we try to reserve
* the low IO area and the VGA memory area if they intersect the
* bus available resources to avoid allocating things on top of them
*/
- if (!(pci_flags & PCI_PROBE_ONLY)) {
- list_for_each_entry(b, &pci_root_buses, node)
- pcibios_reserve_legacy_regions(b);
- }
+ list_for_each_entry(b, &pci_root_buses, node)
+ pcibios_reserve_legacy_regions(b);
- /* Now, if the platform didn't decide to blindly trust the firmware,
- * we proceed to assigning things that were left unassigned
- */
- if (!(pci_flags & PCI_PROBE_ONLY)) {
- pr_debug("PCI: Assigning unassigned resources...\n");
- pci_assign_unassigned_resources();
- }
+ /* Now proceed to assigning things that were left unassigned */
+ pr_debug("PCI: Assigning unassigned resources...\n");
+ pci_assign_unassigned_resources();
}
#ifdef CONFIG_HOTPLUG
@@ -1535,7 +1442,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
res->end = res->start + IO_SPACE_LIMIT;
res->flags = IORESOURCE_IO;
}
- pci_add_resource(resources, res);
+ pci_add_resource_offset(resources, res, hose->io_base_virt - _IO_BASE);
pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n",
(unsigned long long)res->start,
@@ -1558,7 +1465,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
res->flags = IORESOURCE_MEM;
}
- pci_add_resource(resources, res);
+ pci_add_resource_offset(resources, res, hose->pci_mem_offset);
pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
i, (unsigned long long)res->start,
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 576397c6992..fcd4060f642 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -92,6 +92,7 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
#include <asm/scatterlist.h>
#include <linux/string.h>
#include <asm/io.h>
+#include <asm-generic/pci-bridge.h>
struct pci_dev;
@@ -112,12 +113,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
}
#endif
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region);
-
#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
static inline int pci_proc_domain(struct pci_bus *bus)
@@ -145,8 +140,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
#define arch_setup_msi_irqs arch_setup_msi_irqs
#endif
-extern int pci_probe_only;
-
extern char * (*pcibios_plat_setup)(char *str);
#endif /* _ASM_PCI_H */
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c
index acacd1407c6..9553b14002d 100644
--- a/arch/mips/pci/fixup-cobalt.c
+++ b/arch/mips/pci/fixup-cobalt.c
@@ -51,67 +51,6 @@ static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
qube_raq_galileo_early_fixup);
-static void __devinit cobalt_legacy_ide_resource_fixup(struct pci_dev *dev,
- struct resource *res)
-{
- struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
- unsigned long offset = hose->io_offset;
- struct resource orig = *res;
-
- if (!(res->flags & IORESOURCE_IO) ||
- !(res->flags & IORESOURCE_PCI_FIXED))
- return;
-
- res->start -= offset;
- res->end -= offset;
- dev_printk(KERN_DEBUG, &dev->dev, "converted legacy %pR to bus %pR\n",
- &orig, res);
-}
-
-static void __devinit cobalt_legacy_ide_fixup(struct pci_dev *dev)
-{
- u32 class;
- u8 progif;
-
- /*
- * If the IDE controller is in legacy mode, pci_setup_device() fills in
- * the resources with the legacy addresses that normally appear on the
- * PCI bus, just as if we had read them from a BAR.
- *
- * However, with the GT-64111, those legacy addresses, e.g., 0x1f0,
- * will never appear on the PCI bus because it converts memory accesses
- * in the PCI I/O region (which is never at address zero) into I/O port
- * accesses with no address translation.
- *
- * For example, if GT_DEF_PCI0_IO_BASE is 0x10000000, a load or store
- * to physical address 0x100001f0 will become a PCI access to I/O port
- * 0x100001f0. There's no way to generate an access to I/O port 0x1f0,
- * but the VT82C586 IDE controller does respond at 0x100001f0 because
- * it only decodes the low 24 bits of the address.
- *
- * When this quirk runs, the pci_dev resources should contain bus
- * addresses, not Linux I/O port numbers, so convert legacy addresses
- * like 0x1f0 to bus addresses like 0x100001f0. Later, we'll convert
- * them back with pcibios_fixup_bus() or pcibios_bus_to_resource().
- */
- class = dev->class >> 8;
- if (class != PCI_CLASS_STORAGE_IDE)
- return;
-
- pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
- if ((progif & 1) == 0) {
- cobalt_legacy_ide_resource_fixup(dev, &dev->resource[0]);
- cobalt_legacy_ide_resource_fixup(dev, &dev->resource[1]);
- }
- if ((progif & 4) == 0) {
- cobalt_legacy_ide_resource_fixup(dev, &dev->resource[2]);
- cobalt_legacy_ide_resource_fixup(dev, &dev->resource[3]);
- }
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
- cobalt_legacy_ide_fixup);
-
static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
{
unsigned short cfgword;
diff --git a/arch/mips/pci/pci-bcm1480.c b/arch/mips/pci/pci-bcm1480.c
index af8c3199696..37b52dc3d27 100644
--- a/arch/mips/pci/pci-bcm1480.c
+++ b/arch/mips/pci/pci-bcm1480.c
@@ -204,7 +204,7 @@ static int __init bcm1480_pcibios_init(void)
uint64_t reg;
/* CFE will assign PCI resources */
- pci_probe_only = 1;
+ pci_set_flags(PCI_PROBE_ONLY);
/* Avoid ISA compat ranges. */
PCIBIOS_MIN_IO = 0x00008000UL;
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index 193e9494f98..0fbe4c0c170 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -50,7 +50,7 @@ int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid)
bridge_t *bridge;
int slot;
- pci_probe_only = 1;
+ pci_set_flags(PCI_PROBE_ONLY);
printk("a bridge\n");
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index be1e1afe12c..030c77e7926 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -270,7 +270,8 @@ static int __devinit ltq_pci_probe(struct platform_device *pdev)
{
struct ltq_pci_data *ltq_pci_data =
(struct ltq_pci_data *) pdev->dev.platform_data;
- pci_probe_only = 0;
+
+ pci_clear_flags(PCI_PROBE_ONLY);
ltq_pci_irq_map = ltq_pci_data->irq;
ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
ltq_pci_mapped_cfg =
diff --git a/arch/mips/pci/pci-sb1250.c b/arch/mips/pci/pci-sb1250.c
index 1711e8e101b..dd97f3a83ba 100644
--- a/arch/mips/pci/pci-sb1250.c
+++ b/arch/mips/pci/pci-sb1250.c
@@ -213,7 +213,7 @@ static int __init sb1250_pcibios_init(void)
uint64_t reg;
/* CFE will assign PCI resources */
- pci_probe_only = 1;
+ pci_set_flags(PCI_PROBE_ONLY);
/* Avoid ISA compat ranges. */
PCIBIOS_MIN_IO = 0x00008000UL;
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c
index 3d701a962ef..1644805a673 100644
--- a/arch/mips/pci/pci-xlr.c
+++ b/arch/mips/pci/pci-xlr.c
@@ -292,7 +292,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
static int __init pcibios_init(void)
{
/* PSB assigns PCI resources */
- pci_probe_only = 1;
+ pci_set_flags(PCI_PROBE_ONLY);
pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20);
/* Extend IO port for memory mapped io */
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 15521505ebe..0514866fa92 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -20,16 +20,9 @@
#include <asm/cpu-info.h>
/*
- * Indicate whether we respect the PCI setup left by the firmware.
- *
- * Make this long-lived so that we know when shutting down
- * whether we probed only or not.
+ * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource
+ * assignments.
*/
-int pci_probe_only;
-
-#define PCI_ASSIGN_ALL_BUSSES 1
-
-unsigned int pci_probe = PCI_ASSIGN_ALL_BUSSES;
/*
* The PCI controller list.
@@ -92,11 +85,12 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
if (!hose->iommu)
PCI_DMA_BUS_IS_PHYS = 1;
- if (hose->get_busno && pci_probe_only)
+ if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY))
next_busno = (*hose->get_busno)();
- pci_add_resource(&resources, hose->mem_resource);
- pci_add_resource(&resources, hose->io_resource);
+ 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);
if (!bus)
@@ -115,7 +109,7 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
need_domain_info = 1;
}
- if (!pci_probe_only) {
+ if (!pci_has_flag(PCI_PROBE_ONLY)) {
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
pci_enable_bridges(bus);
@@ -241,7 +235,7 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask)
unsigned int pcibios_assign_all_busses(void)
{
- return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
+ return 1;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
@@ -254,42 +248,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return pcibios_plat_dev_init(dev);
}
-static void pcibios_fixup_device_resources(struct pci_dev *dev,
- struct pci_bus *bus)
-{
- /* Update device resources. */
- struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
- unsigned long offset = 0;
- int i;
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- if (!dev->resource[i].start)
- continue;
- if (dev->resource[i].flags & IORESOURCE_IO)
- offset = hose->io_offset;
- else if (dev->resource[i].flags & IORESOURCE_MEM)
- offset = hose->mem_offset;
-
- dev->resource[i].start += offset;
- dev->resource[i].end += offset;
- }
-}
-
void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
- /* Propagate hose info into the subordinate devices. */
-
struct pci_dev *dev = bus->self;
- if (pci_probe_only && dev &&
+ if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_read_bridge_bases(bus);
- pcibios_fixup_device_resources(dev, bus);
- }
-
- list_for_each_entry(dev, &bus->devices, bus_list) {
- if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
- pcibios_fixup_device_resources(dev, bus);
}
}
@@ -299,40 +264,7 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
- unsigned long offset = 0;
-
- if (res->flags & IORESOURCE_IO)
- offset = hose->io_offset;
- else if (res->flags & IORESOURCE_MEM)
- offset = hose->mem_offset;
-
- region->start = res->start - offset;
- region->end = res->end - offset;
-}
-
-void __devinit
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
- unsigned long offset = 0;
-
- if (res->flags & IORESOURCE_IO)
- offset = hose->io_offset;
- else if (res->flags & IORESOURCE_MEM)
- offset = hose->mem_offset;
-
- res->start = region->start + offset;
- res->end = region->end + offset;
-}
-
#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
EXPORT_SYMBOL(PCIBIOS_MIN_IO);
EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
#endif
diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h
index 6095a28561d..8137c25c4e1 100644
--- a/arch/mn10300/include/asm/pci.h
+++ b/arch/mn10300/include/asm/pci.h
@@ -85,22 +85,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
/* implement the pci_ DMA API in terms of the generic device dma_ one */
#include <asm-generic/pci-dma-compat.h>
-/**
- * pcibios_resource_to_bus - convert resource to PCI bus address
- * @dev: device which owns this resource
- * @region: converted bus-centric region (start,end)
- * @res: resource to convert
- *
- * Convert a resource to a PCI device bus address or bus window.
- */
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region,
- struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
- struct resource *res,
- struct pci_bus_region *region);
-
static inline struct resource *
pcibios_select_root(struct pci_dev *pdev, struct resource *res)
{
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index a7c5f08ca9f..6dce9fc2cf3 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -32,8 +32,7 @@ struct pci_ops *pci_root_ops;
* insert specific PCI bus resources instead of using the platform-level bus
* resources directly for the PCI root bus.
*
- * These are configured and inserted by pcibios_init() and are attached to the
- * root bus by pcibios_fixup_bus().
+ * These are configured and inserted by pcibios_init().
*/
static struct resource pci_ioport_resource = {
.name = "PCI IO",
@@ -78,52 +77,6 @@ static inline int __query(const struct pci_bus *bus, unsigned int devfn)
}
/*
- * translate Linuxcentric addresses to PCI bus addresses
- */
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- if (res->flags & IORESOURCE_IO) {
- region->start = (res->start & 0x00ffffff);
- region->end = (res->end & 0x00ffffff);
- }
-
- if (res->flags & IORESOURCE_MEM) {
- region->start = (res->start & 0x03ffffff) | MEM_PAGING_REG;
- region->end = (res->end & 0x03ffffff) | MEM_PAGING_REG;
- }
-
-#if 0
- printk(KERN_DEBUG "RES->BUS: %lx-%lx => %lx-%lx\n",
- res->start, res->end, region->start, region->end);
-#endif
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-/*
- * translate PCI bus addresses to Linuxcentric addresses
- */
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- if (res->flags & IORESOURCE_IO) {
- res->start = (region->start & 0x00ffffff) | 0xbe000000;
- res->end = (region->end & 0x00ffffff) | 0xbe000000;
- }
-
- if (res->flags & IORESOURCE_MEM) {
- res->start = (region->start & 0x03ffffff) | 0xb8000000;
- res->end = (region->end & 0x03ffffff) | 0xb8000000;
- }
-
-#if 0
- printk(KERN_INFO "BUS->RES: %lx-%lx => %lx-%lx\n",
- region->start, region->end, res->start, res->end);
-#endif
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/*
*
*/
static int pci_ampci_read_config_byte(struct pci_bus *bus, unsigned int devfn,
@@ -364,9 +317,6 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
if (!dev->resource[i].flags)
continue;
- region.start = dev->resource[i].start;
- region.end = dev->resource[i].end;
- pcibios_bus_to_resource(dev, &dev->resource[i], &region);
if (is_valid_resource(dev, i))
pci_claim_resource(dev, i);
}
@@ -397,6 +347,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
*/
static int __init pcibios_init(void)
{
+ resource_size_t io_offset, mem_offset;
LIST_HEAD(resources);
ioport_resource.start = 0xA0000000;
@@ -420,8 +371,13 @@ static int __init pcibios_init(void)
printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n",
MEM_PAGING_REG);
- pci_add_resource(&resources, &pci_ioport_resource);
- pci_add_resource(&resources, &pci_iomem_resource);
+ io_offset = pci_ioport_resource.start -
+ (pci_ioport_resource.start & 0x00ffffff);
+ mem_offset = pci_iomem_resource.start -
+ ((pci_iomem_resource.start & 0x03ffffff) | MEM_PAGING_REG);
+
+ pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
+ pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL,
&resources);
diff --git a/arch/parisc/include/asm/pci.h b/arch/parisc/include/asm/pci.h
index 2242a5c636c..3234f492d57 100644
--- a/arch/parisc/include/asm/pci.h
+++ b/arch/parisc/include/asm/pci.h
@@ -82,38 +82,8 @@ struct pci_hba_data {
#ifdef CONFIG_64BIT
#define PCI_F_EXTEND 0xffffffff00000000UL
-#define PCI_IS_LMMIO(hba,a) pci_is_lmmio(hba,a)
-
-/* We need to know if an address is LMMMIO or GMMIO.
- * LMMIO requires mangling and GMMIO we must use as-is.
- */
-static __inline__ int pci_is_lmmio(struct pci_hba_data *hba, unsigned long a)
-{
- return(((a) & PCI_F_EXTEND) == PCI_F_EXTEND);
-}
-
-/*
-** Convert between PCI (IO_VIEW) addresses and processor (PA_VIEW) addresses.
-** See pci.c for more conversions used by Generic PCI code.
-**
-** Platform characteristics/firmware guarantee that
-** (1) PA_VIEW - IO_VIEW = lmmio_offset for both LMMIO and ELMMIO
-** (2) PA_VIEW == IO_VIEW for GMMIO
-*/
-#define PCI_BUS_ADDR(hba,a) (PCI_IS_LMMIO(hba,a) \
- ? ((a) - hba->lmmio_space_offset) /* mangle LMMIO */ \
- : (a)) /* GMMIO */
-#define PCI_HOST_ADDR(hba,a) (((a) & PCI_F_EXTEND) == 0 \
- ? (a) + hba->lmmio_space_offset \
- : (a))
-
#else /* !CONFIG_64BIT */
-
-#define PCI_BUS_ADDR(hba,a) (a)
-#define PCI_HOST_ADDR(hba,a) (a)
#define PCI_F_EXTEND 0UL
-#define PCI_IS_LMMIO(hba,a) (1) /* 32-bit doesn't support GMMIO */
-
#endif /* !CONFIG_64BIT */
/*
@@ -245,14 +215,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
}
#endif
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region);
-
static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't need to penalize isa irq's */
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index 9efd9740531..74d544b1cd2 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -195,58 +195,6 @@ void __init pcibios_init_bus(struct pci_bus *bus)
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl);
}
-/* called by drivers/pci/setup-bus.c:pci_setup_bridge(). */
-void __devinit pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region, struct resource *res)
-{
-#ifdef CONFIG_64BIT
- struct pci_hba_data *hba = HBA_DATA(dev->bus->bridge->platform_data);
-#endif
-
- if (res->flags & IORESOURCE_IO) {
- /*
- ** I/O space may see busnumbers here. Something
- ** in the form of 0xbbxxxx where bb is the bus num
- ** and xxxx is the I/O port space address.
- ** Remaining address translation are done in the
- ** PCI Host adapter specific code - ie dino_out8.
- */
- region->start = PCI_PORT_ADDR(res->start);
- region->end = PCI_PORT_ADDR(res->end);
- } else if (res->flags & IORESOURCE_MEM) {
- /* Convert MMIO addr to PCI addr (undo global virtualization) */
- region->start = PCI_BUS_ADDR(hba, res->start);
- region->end = PCI_BUS_ADDR(hba, res->end);
- }
-
- DBG_RES("pcibios_resource_to_bus(%02x %s [%lx,%lx])\n",
- dev->bus->number, res->flags & IORESOURCE_IO ? "IO" : "MEM",
- region->start, region->end);
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
-#ifdef CONFIG_64BIT
- struct pci_hba_data *hba = HBA_DATA(dev->bus->bridge->platform_data);
-#endif
-
- if (res->flags & IORESOURCE_MEM) {
- res->start = PCI_HOST_ADDR(hba, region->start);
- res->end = PCI_HOST_ADDR(hba, region->end);
- }
-
- if (res->flags & IORESOURCE_IO) {
- res->start = region->start;
- res->end = region->end;
- }
-}
-
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-#endif
-
/*
* pcibios align resources() is called every time generic PCI code
* wants to generate a new address. The process of looking for
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index f54b3d26ce9..6653f2743c4 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -154,14 +154,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
#endif /* CONFIG_PPC64 */
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region,
- struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
- struct resource *res,
- struct pci_bus_region *region);
-
extern void pcibios_claim_one_bus(struct pci_bus *b);
extern void pcibios_finish_adding_to_bus(struct pci_bus *bus);
@@ -190,6 +182,7 @@ extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
const struct resource *rsrc,
resource_size_t *start, resource_size_t *end);
+extern resource_size_t pcibios_io_space_offset(struct pci_controller *hose);
extern void pcibios_setup_bus_devices(struct pci_bus *bus);
extern void pcibios_setup_bus_self(struct pci_bus *bus);
extern void pcibios_setup_phb_io_space(struct pci_controller *hose);
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
index e660b37aa7d..80fa704d410 100644
--- a/arch/powerpc/include/asm/ppc-pci.h
+++ b/arch/powerpc/include/asm/ppc-pci.h
@@ -45,8 +45,6 @@ extern void init_pci_config_tokens (void);
extern unsigned long get_phb_buid (struct device_node *);
extern int rtas_setup_phb(struct pci_controller *phb);
-extern unsigned long pci_probe_only;
-
#ifdef CONFIG_EEH
void pci_addr_cache_build(void);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index d0373bcb7c9..8e78e93c818 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -49,9 +49,6 @@ static int global_phb_number; /* Global phb counter */
/* ISA Memory physical address */
resource_size_t isa_mem_base;
-/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
-unsigned int pci_flags = 0;
-
static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
@@ -834,60 +831,6 @@ int pci_proc_domain(struct pci_bus *bus)
return 1;
}
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- resource_size_t offset = 0, mask = (resource_size_t)-1;
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
- if (!hose)
- return;
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
-
- region->start = (res->start - offset) & mask;
- region->end = (res->end - offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- resource_size_t offset = 0, mask = (resource_size_t)-1;
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
- if (!hose)
- return;
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
- res->start = (region->start + offset) & mask;
- res->end = (region->end + offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/* Fixup a bus resource into a linux resource */
-static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
-{
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
- resource_size_t offset = 0, mask = (resource_size_t)-1;
-
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
-
- res->start = (res->start + offset) & mask;
- res->end = (res->end + offset) & mask;
-}
-
-
/* This header fixup will do the resource fixup for all devices as they are
* probed, but not for bridge ranges
*/
@@ -927,18 +870,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
continue;
}
- pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
+ pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n",
pci_name(dev), i,
(unsigned long long)res->start,\
(unsigned long long)res->end,
(unsigned int)res->flags);
-
- fixup_resource(res, dev);
-
- pr_debug("PCI:%s %016llx-%016llx\n",
- pci_name(dev),
- (unsigned long long)res->start,
- (unsigned long long)res->end);
}
/* Call machine specific resource fixup */
@@ -1040,27 +976,18 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
continue;
}
- pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
+ pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x]\n",
pci_name(dev), i,
(unsigned long long)res->start,\
(unsigned long long)res->end,
(unsigned int)res->flags);
- /* Perform fixup */
- fixup_resource(res, dev);
-
/* Try to detect uninitialized P2P bridge resources,
* and clear them out so they get re-assigned later
*/
if (pcibios_uninitialized_bridge_resource(bus, res)) {
res->flags = 0;
pr_debug("PCI:%s (unassigned)\n", pci_name(dev));
- } else {
-
- pr_debug("PCI:%s %016llx-%016llx\n",
- pci_name(dev),
- (unsigned long long)res->start,
- (unsigned long long)res->end);
}
}
}
@@ -1550,6 +1477,11 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return pci_enable_resources(dev, mask);
}
+resource_size_t pcibios_io_space_offset(struct pci_controller *hose)
+{
+ return (unsigned long) hose->io_base_virt - _IO_BASE;
+}
+
static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
{
struct resource *res;
@@ -1574,7 +1506,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
(unsigned long long)res->start,
(unsigned long long)res->end,
(unsigned long)res->flags);
- pci_add_resource(resources, res);
+ pci_add_resource_offset(resources, res, pcibios_io_space_offset(hose));
/* Hookup PHB Memory resources */
for (i = 0; i < 3; ++i) {
@@ -1597,7 +1529,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
(unsigned long long)res->start,
(unsigned long long)res->end,
(unsigned long)res->flags);
- pci_add_resource(resources, res);
+ pci_add_resource_offset(resources, res, hose->pci_mem_offset);
}
pr_debug("PCI: PHB MEM offset = %016llx\n",
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index fdd1a3d951d..4b06ec5a502 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -219,9 +219,9 @@ void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
struct resource *res = &hose->io_resource;
/* Fixup IO space offset */
- io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
- res->start = (res->start + io_offset) & 0xffffffffu;
- res->end = (res->end + io_offset) & 0xffffffffu;
+ io_offset = pcibios_io_space_offset(hose);
+ res->start += io_offset;
+ res->end += io_offset;
}
static int __init pcibios_init(void)
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 3318d39b7d4..94a54f61d34 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -33,8 +33,6 @@
#include <asm/machdep.h>
#include <asm/ppc-pci.h>
-unsigned long pci_probe_only = 1;
-
/* pci_io_base -- the base address from which io bars are offsets.
* This is the lowest I/O base address (so bar values are always positive),
* and it *must* be the start of ISA space if an ISA bus exists because
@@ -55,9 +53,6 @@ static int __init pcibios_init(void)
*/
ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
- if (pci_probe_only)
- pci_add_flags(PCI_PROBE_ONLY);
-
/* On ppc64, we always enable PCI domains and we keep domain 0
* backward compatible in /proc for video cards
*/
@@ -173,7 +168,7 @@ static int __devinit pcibios_map_phb_io_space(struct pci_controller *hose)
return -ENOMEM;
/* Fixup hose IO resource */
- io_virt_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+ io_virt_offset = pcibios_io_space_offset(hose);
hose->io_resource.start += io_virt_offset;
hose->io_resource.end += io_virt_offset;
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index b37d0b5a796..89dde171a6f 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -75,6 +75,7 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
{
u64 base, size;
unsigned int flags;
+ struct pci_bus_region region;
struct resource *res;
const u32 *addrs;
u32 i;
@@ -106,10 +107,11 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
continue;
}
- res->start = base;
- res->end = base + size - 1;
res->flags = flags;
res->name = pci_name(dev);
+ region.start = base;
+ region.end = base + size - 1;
+ pcibios_bus_to_resource(dev, res, &region);
}
}
@@ -209,6 +211,7 @@ void __devinit of_scan_pci_bridge(struct pci_dev *dev)
struct pci_bus *bus;
const u32 *busrange, *ranges;
int len, i, mode;
+ struct pci_bus_region region;
struct resource *res;
unsigned int flags;
u64 size;
@@ -270,9 +273,10 @@ void __devinit of_scan_pci_bridge(struct pci_dev *dev)
res = bus->resource[i];
++i;
}
- res->start = of_read_number(&ranges[1], 2);
- res->end = res->start + size - 1;
res->flags = flags;
+ region.start = of_read_number(&ranges[1], 2);
+ region.end = region.start + size - 1;
+ pcibios_bus_to_resource(dev, res, &region);
}
sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
bus->number);
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 517bd86bc3f..179af906dcd 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -279,7 +279,7 @@ void __init find_and_init_phbs(void)
eeh_dev_phb_init();
/*
- * pci_probe_only and pci_assign_all_buses can be set via properties
+ * PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties
* in chosen.
*/
if (of_chosen) {
@@ -287,8 +287,12 @@ void __init find_and_init_phbs(void)
prop = of_get_property(of_chosen,
"linux,pci-probe-only", NULL);
- if (prop)
- pci_probe_only = *prop;
+ if (prop) {
+ if (*prop)
+ pci_add_flags(PCI_PROBE_ONLY);
+ else
+ pci_clear_flags(PCI_PROBE_ONLY);
+ }
#ifdef CONFIG_PPC32 /* Will be made generic soon */
prop = of_get_property(of_chosen,
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 401e3f3f74c..465ee8f5c08 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -620,7 +620,7 @@ void __init maple_pci_init(void)
}
/* Tell pci.c to not change any resource allocations. */
- pci_probe_only = 1;
+ pci_add_flags(PCI_PROBE_ONLY);
}
int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index b6a0ec45c69..aa862713258 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -229,9 +229,6 @@ void __init pas_pci_init(void)
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
-
- /* Use the common resource allocation mechanism */
- pci_probe_only = 1;
}
void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset)
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 31a7d3a7ce2..43bbe1bda93 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1059,9 +1059,6 @@ void __init pmac_pci_init(void)
}
/* pmac_check_ht_link(); */
- /* We can allocate missing resources if any */
- pci_probe_only = 0;
-
#else /* CONFIG_PPC64 */
init_p2pbridge();
init_second_ohare();
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 5e155dfc432..fbdd74dac3a 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1299,15 +1299,14 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np)
/* Setup MSI support */
pnv_pci_init_ioda_msis(phb);
- /* We set both probe_only and PCI_REASSIGN_ALL_RSRC. This is an
+ /* We set both PCI_PROBE_ONLY and PCI_REASSIGN_ALL_RSRC. This is an
* odd combination which essentially means that we skip all resource
* fixups and assignments in the generic code, and do it all
* ourselves here
*/
- pci_probe_only = 1;
ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb;
ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
- pci_add_flags(PCI_REASSIGN_ALL_RSRC);
+ pci_add_flags(PCI_PROBE_ONLY | PCI_REASSIGN_ALL_RSRC);
/* Reset IODA tables to a clean state */
rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET);
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 214478d781a..be3cfc5ceab 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -562,10 +562,7 @@ void __init pnv_pci_init(void)
{
struct device_node *np;
- pci_set_flags(PCI_CAN_SKIP_ISA_ALIGN);
-
- /* We do not want to just probe */
- pci_probe_only = 0;
+ pci_add_flags(PCI_CAN_SKIP_ISA_ALIGN);
/* OPAL absent, try POPAL first then RTAS detection of PHBs */
if (!firmware_has_feature(FW_FEATURE_OPAL)) {
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index fbb21fc3080..8b7bafa489c 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -84,7 +84,7 @@ void pcibios_remove_pci_devices(struct pci_bus *bus)
list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
pr_debug(" * Removing %s...\n", pci_name(dev));
eeh_remove_bus_device(dev);
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
}
}
EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 8f137af616a..51ecac920dd 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -383,6 +383,9 @@ static void __init pSeries_setup_arch(void)
fwnmi_init();
+ /* By default, only probe PCI (can be overriden by rtas_pci) */
+ pci_add_flags(PCI_PROBE_ONLY);
+
/* Find and initialize PCI host bridges */
init_pci_config_tokens();
eeh_pseries_init();
diff --git a/arch/powerpc/platforms/wsp/wsp_pci.c b/arch/powerpc/platforms/wsp/wsp_pci.c
index d24b3acf858..763014cd1e6 100644
--- a/arch/powerpc/platforms/wsp/wsp_pci.c
+++ b/arch/powerpc/platforms/wsp/wsp_pci.c
@@ -682,7 +682,6 @@ static int __init wsp_setup_one_phb(struct device_node *np)
/* XXX Force re-assigning of everything for now */
pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC |
PCI_ENABLE_PROC_DOMAINS);
- pci_probe_only = 0;
/* Calculate how the TCE space is divided */
phb->dma32_base = 0;
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 1e7b0e2e764..9d10a3cb879 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -37,11 +37,20 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
static int next_busno;
static int need_domain_info;
LIST_HEAD(resources);
+ struct resource *res;
+ resource_size_t offset;
int i;
struct pci_bus *bus;
- for (i = 0; i < hose->nr_resources; i++)
- pci_add_resource(&resources, hose->resources + i);
+ for (i = 0; i < hose->nr_resources; i++) {
+ res = hose->resources + i;
+ offset = 0;
+ if (res->flags & IORESOURCE_IO)
+ offset = hose->io_offset;
+ else if (res->flags & IORESOURCE_MEM)
+ offset = hose->mem_offset;
+ pci_add_resource_offset(&resources, res, offset);
+ }
bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
&resources);
@@ -143,42 +152,12 @@ static int __init pcibios_init(void)
}
subsys_initcall(pcibios_init);
-static void pcibios_fixup_device_resources(struct pci_dev *dev,
- struct pci_bus *bus)
-{
- /* Update device resources. */
- struct pci_channel *hose = bus->sysdata;
- unsigned long offset = 0;
- int i;
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- if (!dev->resource[i].start)
- continue;
- if (dev->resource[i].flags & IORESOURCE_IO)
- offset = hose->io_offset;
- else if (dev->resource[i].flags & IORESOURCE_MEM)
- offset = hose->mem_offset;
-
- dev->resource[i].start += offset;
- dev->resource[i].end += offset;
- }
-}
-
/*
* Called after each bus is probed, but before its children
* are examined.
*/
void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
- struct pci_dev *dev;
- struct list_head *ln;
-
- for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
- dev = pci_dev_b(ln);
-
- if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
- pcibios_fixup_device_resources(dev, bus);
- }
}
/*
@@ -208,36 +187,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
return start;
}
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- struct pci_channel *hose = dev->sysdata;
- unsigned long offset = 0;
-
- if (res->flags & IORESOURCE_IO)
- offset = hose->io_offset;
- else if (res->flags & IORESOURCE_MEM)
- offset = hose->mem_offset;
-
- region->start = res->start - offset;
- region->end = res->end - offset;
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- struct pci_channel *hose = dev->sysdata;
- unsigned long offset = 0;
-
- if (res->flags & IORESOURCE_IO)
- offset = hose->io_offset;
- else if (res->flags & IORESOURCE_MEM)
- offset = hose->mem_offset;
-
- res->start = region->start + offset;
- res->end = region->end + offset;
-}
-
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
return pci_enable_resources(dev, mask);
@@ -381,8 +330,6 @@ EXPORT_SYMBOL(pci_iounmap);
#endif /* CONFIG_GENERIC_IOMAP */
#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
EXPORT_SYMBOL(PCIBIOS_MIN_IO);
EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
#endif
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index cb21e2399dc..bff96c2e7d2 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -114,12 +114,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);
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region);
-
#define pci_domain_nr(bus) ((struct pci_channel *)(bus)->sysdata)->index
static inline int pci_proc_domain(struct pci_bus *bus)
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index 6de7f7bf956..dc503297481 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -52,14 +52,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
* 64Kbytes by the Host controller.
*/
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region);
-
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
return PCI_IRQ_NONE;
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index 755a4bb6bcd..1633b718d3b 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -73,14 +73,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine);
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region);
-
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
return PCI_IRQ_NONE;
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index c7bec25fdb1..aba6b958b2a 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -15,14 +15,19 @@
/* The LEON architecture does not rely on a BIOS or bootloader to setup
* PCI for us. The Linux generic routines are used to setup resources,
- * reset values of confuration-space registers settings ae preseved.
+ * reset values of configuration-space register settings are preserved.
+ *
+ * PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is
+ * accessed through a Window which is translated to low 64KB in PCI space, the
+ * first 4KB is not used so 60KB is available.
*/
void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
{
LIST_HEAD(resources);
struct pci_bus *root_bus;
- pci_add_resource(&resources, &info->io_space);
+ pci_add_resource_offset(&resources, &info->io_space,
+ info->io_space.start - 0x1000);
pci_add_resource(&resources, &info->mem_space);
root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
@@ -38,44 +43,6 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
}
}
-/* PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is
- * accessed through a Window which is translated to low 64KB in PCI space, the
- * first 4KB is not used so 60KB is available.
- *
- * This function is used by generic code to translate resource addresses into
- * PCI addresses.
- */
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- struct leon_pci_info *info = dev->bus->sysdata;
-
- region->start = res->start;
- region->end = res->end;
-
- if (res->flags & IORESOURCE_IO) {
- region->start -= (info->io_space.start - 0x1000);
- region->end -= (info->io_space.start - 0x1000);
- }
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-/* see pcibios_resource_to_bus() comment */
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- struct leon_pci_info *info = dev->bus->sysdata;
-
- res->start = region->start;
- res->end = region->end;
-
- if (res->flags & IORESOURCE_IO) {
- res->start += (info->io_space.start - 0x1000);
- res->end += (info->io_space.start - 0x1000);
- }
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
{
struct leon_pci_info *info = pbus->sysdata;
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index bb8bc2e519a..fdaf2181167 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -375,13 +375,6 @@ static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
*last_p = last;
}
-static void pci_resource_adjust(struct resource *res,
- struct resource *root)
-{
- res->start += root->start;
- res->end += root->start;
-}
-
/* For PCI bus devices which lack a 'ranges' property we interrogate
* the config space values to set the resources, just like the generic
* Linux PCI probing code does.
@@ -390,7 +383,8 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
struct pci_bus *bus,
struct pci_pbm_info *pbm)
{
- struct resource *res;
+ struct pci_bus_region region;
+ struct resource *res, res2;
u8 io_base_lo, io_limit_lo;
u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
@@ -412,11 +406,14 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
res = bus->resource[0];
if (base <= limit) {
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+ res2.flags = res->flags;
+ region.start = base;
+ region.end = limit + 0xfff;
+ pcibios_bus_to_resource(dev, &res2, &region);
if (!res->start)
- res->start = base;
+ res->start = res2.start;
if (!res->end)
- res->end = limit + 0xfff;
- pci_resource_adjust(res, &pbm->io_space);
+ res->end = res2.end;
}
pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
@@ -428,9 +425,9 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
if (base <= limit) {
res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
IORESOURCE_MEM);
- res->start = base;
- res->end = limit + 0xfffff;
- pci_resource_adjust(res, &pbm->mem_space);
+ region.start = base;
+ region.end = limit + 0xfffff;
+ pcibios_bus_to_resource(dev, res, &region);
}
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
@@ -459,9 +456,9 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
if (base <= limit) {
res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
IORESOURCE_MEM | IORESOURCE_PREFETCH);
- res->start = base;
- res->end = limit + 0xfffff;
- pci_resource_adjust(res, &pbm->mem_space);
+ region.start = base;
+ region.end = limit + 0xfffff;
+ pcibios_bus_to_resource(dev, res, &region);
}
}
@@ -472,6 +469,7 @@ static void __devinit apb_fake_ranges(struct pci_dev *dev,
struct pci_bus *bus,
struct pci_pbm_info *pbm)
{
+ struct pci_bus_region region;
struct resource *res;
u32 first, last;
u8 map;
@@ -479,18 +477,18 @@ static void __devinit apb_fake_ranges(struct pci_dev *dev,
pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map);
apb_calc_first_last(map, &first, &last);
res = bus->resource[0];
- res->start = (first << 21);
- res->end = (last << 21) + ((1 << 21) - 1);
res->flags = IORESOURCE_IO;
- pci_resource_adjust(res, &pbm->io_space);
+ region.start = (first << 21);
+ region.end = (last << 21) + ((1 << 21) - 1);
+ pcibios_bus_to_resource(dev, res, &region);
pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map);
apb_calc_first_last(map, &first, &last);
res = bus->resource[1];
- res->start = (first << 21);
- res->end = (last << 21) + ((1 << 21) - 1);
res->flags = IORESOURCE_MEM;
- pci_resource_adjust(res, &pbm->mem_space);
+ region.start = (first << 21);
+ region.end = (last << 21) + ((1 << 21) - 1);
+ pcibios_bus_to_resource(dev, res, &region);
}
static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
@@ -506,6 +504,7 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
struct pci_bus *bus;
const u32 *busrange, *ranges;
int len, i, simba;
+ struct pci_bus_region region;
struct resource *res;
unsigned int flags;
u64 size;
@@ -556,8 +555,6 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
}
i = 1;
for (; len >= 32; len -= 32, ranges += 8) {
- struct resource *root;
-
flags = pci_parse_of_flags(ranges[0]);
size = GET_64BIT(ranges, 6);
if (flags == 0 || size == 0)
@@ -569,7 +566,6 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
" for bridge %s\n", node->full_name);
continue;
}
- root = &pbm->io_space;
} else {
if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
printk(KERN_ERR "PCI: too many memory ranges"
@@ -578,18 +574,12 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
}
res = bus->resource[i];
++i;
- root = &pbm->mem_space;
}
- res->start = GET_64BIT(ranges, 1);
- res->end = res->start + size - 1;
res->flags = flags;
-
- /* Another way to implement this would be to add an of_device
- * layer routine that can calculate a resource for a given
- * range property value in a PCI device.
- */
- pci_resource_adjust(res, root);
+ region.start = GET_64BIT(ranges, 1);
+ region.end = region.start + size - 1;
+ pcibios_bus_to_resource(dev, res, &region);
}
after_ranges:
sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
@@ -691,8 +681,10 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
printk("PCI: Scanning PBM %s\n", node->full_name);
- pci_add_resource(&resources, &pbm->io_space);
- pci_add_resource(&resources, &pbm->mem_space);
+ pci_add_resource_offset(&resources, &pbm->io_space,
+ pbm->io_space.start);
+ pci_add_resource_offset(&resources, &pbm->mem_space,
+ pbm->mem_space.start);
bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
pbm, &resources);
if (!bus) {
@@ -755,46 +747,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return 0;
}
-void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region,
- struct resource *res)
-{
- struct pci_pbm_info *pbm = pdev->bus->sysdata;
- struct resource zero_res, *root;
-
- zero_res.start = 0;
- zero_res.end = 0;
- zero_res.flags = res->flags;
-
- if (res->flags & IORESOURCE_IO)
- root = &pbm->io_space;
- else
- root = &pbm->mem_space;
-
- pci_resource_adjust(&zero_res, root);
-
- region->start = res->start - zero_res.start;
- region->end = res->end - zero_res.start;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res,
- struct pci_bus_region *region)
-{
- struct pci_pbm_info *pbm = pdev->bus->sysdata;
- struct resource *root;
-
- res->start = region->start;
- res->end = region->end;
-
- if (res->flags & IORESOURCE_IO)
- root = &pbm->io_space;
- else
- root = &pbm->mem_space;
-
- pci_resource_adjust(res, root);
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
char * __devinit pcibios_setup(char *str)
{
return str;
diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h
index dd3867727c3..f5e108f4a15 100644
--- a/arch/unicore32/include/asm/pci.h
+++ b/arch/unicore32/include/asm/pci.h
@@ -14,6 +14,7 @@
#ifdef __KERNEL__
#include <asm-generic/pci-dma-compat.h>
+#include <asm-generic/pci-bridge.h>
#include <asm-generic/pci.h>
#include <mach/hardware.h> /* for PCIBIOS_MIN_* */
diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index a8f07fe10ca..2fc2b1ba825 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -21,7 +21,6 @@
#include <linux/io.h>
static int debug_pci;
-static int use_firmware;
#define CONFIG_CMD(bus, devfn, where) \
(0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
@@ -276,7 +275,7 @@ static int __init pci_common_init(void)
pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
- if (!use_firmware) {
+ if (!pci_has_flag(PCI_PROBE_ONLY)) {
/*
* Size the bridge windows.
*/
@@ -303,7 +302,7 @@ char * __devinit pcibios_setup(char *str)
debug_pci = 1;
return NULL;
} else if (!strcmp(str, "firmware")) {
- use_firmware = 1;
+ pci_add_flags(PCI_PROBE_ONLY);
return NULL;
}
return str;
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 1c4d769e21e..28e5e06fcba 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -262,10 +262,11 @@ rootfs_initcall(pci_iommu_init);
static __devinit void via_no_dac(struct pci_dev *dev)
{
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
+ if (forbid_dac == 0) {
dev_info(&dev->dev, "disabling DAC on VIA PCI bridge\n");
forbid_dac = 1;
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID,
+ PCI_CLASS_BRIDGE_PCI, 8, via_no_dac);
#endif
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 49a5cb55429..ed2835e148b 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -416,7 +416,12 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
kfree(sd);
} else {
get_current_resources(device, busnum, domain, &resources);
- if (list_empty(&resources))
+
+ /*
+ * _CRS with no apertures is normal, so only fall back to
+ * defaults or native bridge info if we're ignoring _CRS.
+ */
+ if (!pci_use_crs)
x86_pci_root_bus_resources(busnum, &resources);
bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
&resources);
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index 6dd89555fbf..d0e6e403b4f 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -164,11 +164,11 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_
*/
static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev)
{
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
- (dev->device & 0xff00) == 0x2400)
+ if ((dev->device & 0xff00) == 0x2400)
dev->transparent = 1;
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+ PCI_CLASS_BRIDGE_PCI, 8, pci_fixup_transparent_bridge);
/*
* Fixup for C1 Halt Disconnect problem on nForce2 systems.
@@ -322,9 +322,6 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
struct pci_bus *bus;
u16 config;
- if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
- return;
-
/* Is VGA routed to us? */
bus = pdev->bus;
while (bus) {
@@ -353,7 +350,8 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
static const struct dmi_system_id __devinitconst msi_k8t_dmi_table[] = {
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 91821a1a0c3..831971e731f 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -39,6 +39,87 @@
#include <asm/io_apic.h>
+/*
+ * This list of dynamic mappings is for temporarily maintaining
+ * original BIOS BAR addresses for possible reinstatement.
+ */
+struct pcibios_fwaddrmap {
+ struct list_head list;
+ struct pci_dev *dev;
+ resource_size_t fw_addr[DEVICE_COUNT_RESOURCE];
+};
+
+static LIST_HEAD(pcibios_fwaddrmappings);
+static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock);
+
+/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */
+static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev)
+{
+ struct pcibios_fwaddrmap *map;
+
+ WARN_ON(!spin_is_locked(&pcibios_fwaddrmap_lock));
+
+ list_for_each_entry(map, &pcibios_fwaddrmappings, list)
+ if (map->dev == dev)
+ return map;
+
+ return NULL;
+}
+
+static void
+pcibios_save_fw_addr(struct pci_dev *dev, int idx, resource_size_t fw_addr)
+{
+ unsigned long flags;
+ struct pcibios_fwaddrmap *map;
+
+ spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+ map = pcibios_fwaddrmap_lookup(dev);
+ if (!map) {
+ spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return;
+
+ map->dev = pci_dev_get(dev);
+ map->fw_addr[idx] = fw_addr;
+ INIT_LIST_HEAD(&map->list);
+
+ spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+ list_add_tail(&map->list, &pcibios_fwaddrmappings);
+ } else
+ map->fw_addr[idx] = fw_addr;
+ spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+}
+
+resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
+{
+ unsigned long flags;
+ struct pcibios_fwaddrmap *map;
+ resource_size_t fw_addr = 0;
+
+ spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+ map = pcibios_fwaddrmap_lookup(dev);
+ if (map)
+ fw_addr = map->fw_addr[idx];
+ spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+
+ return fw_addr;
+}
+
+static void pcibios_fw_addr_list_del(void)
+{
+ unsigned long flags;
+ struct pcibios_fwaddrmap *entry, *next;
+
+ spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+ list_for_each_entry_safe(entry, next, &pcibios_fwaddrmappings, list) {
+ list_del(&entry->list);
+ pci_dev_put(entry->dev);
+ kfree(entry);
+ }
+ spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+}
+
static int
skip_isa_ioresource_align(struct pci_dev *dev) {
@@ -182,7 +263,8 @@ static void __init pcibios_allocate_resources(int pass)
idx, r, disabled, pass);
if (pci_claim_resource(dev, idx) < 0) {
/* We'll assign a new address later */
- dev->fw_addr[idx] = r->start;
+ pcibios_save_fw_addr(dev,
+ idx, r->start);
r->end -= r->start;
r->start = 0;
}
@@ -228,6 +310,7 @@ static int __init pcibios_assign_resources(void)
}
pci_assign_unassigned_resources();
+ pcibios_fw_addr_list_del();
return 0;
}
diff --git a/arch/x86/pci/mrst.c b/arch/x86/pci/mrst.c
index cb29191cee5..140942f66b3 100644
--- a/arch/x86/pci/mrst.c
+++ b/arch/x86/pci/mrst.c
@@ -43,6 +43,8 @@
#define PCI_FIXED_BAR_4_SIZE 0x14
#define PCI_FIXED_BAR_5_SIZE 0x1c
+static int pci_soc_mode = 0;
+
/**
* fixed_bar_cap - return the offset of the fixed BAR cap if found
* @bus: PCI bus
@@ -148,7 +150,9 @@ static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg)
*/
if (reg >= 0x100 || reg == PCI_STATUS || reg == PCI_HEADER_TYPE)
return 0;
- if (bus == 0 && (devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(0, 0)))
+ if (bus == 0 && (devfn == PCI_DEVFN(2, 0)
+ || devfn == PCI_DEVFN(0, 0)
+ || devfn == PCI_DEVFN(3, 0)))
return 1;
return 0; /* langwell on others */
}
@@ -231,14 +235,43 @@ struct pci_ops pci_mrst_ops = {
*/
int __init pci_mrst_init(void)
{
- printk(KERN_INFO "Moorestown platform detected, using MRST PCI ops\n");
+ printk(KERN_INFO "Intel MID platform detected, using MID PCI ops\n");
pci_mmcfg_late_init();
pcibios_enable_irq = mrst_pci_irq_enable;
pci_root_ops = pci_mrst_ops;
+ pci_soc_mode = 1;
/* Continue with standard init */
return 1;
}
+/* Langwell devices are not true pci devices, they are not subject to 10 ms
+ * d3 to d0 delay required by pci spec.
+ */
+static void __devinit pci_d3delay_fixup(struct pci_dev *dev)
+{
+ /* PCI fixups are effectively decided compile time. If we have a dual
+ SoC/non-SoC kernel we don't want to mangle d3 on non SoC devices */
+ if (!pci_soc_mode)
+ return;
+ /* true pci devices in lincroft should allow type 1 access, the rest
+ * are langwell fake pci devices.
+ */
+ if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
+ return;
+ dev->d3_delay = 0;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
+
+static void __devinit mrst_power_off_unused_dev(struct pci_dev *dev)
+{
+ pci_set_power_state(dev, PCI_D3cold);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0812, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev);
+
/*
* Langwell devices reside at fixed offsets, don't try to move them.
*/
@@ -248,6 +281,9 @@ static void __devinit pci_fixed_bar_fixup(struct pci_dev *dev)
u32 size;
int i;
+ if (!pci_soc_mode)
+ return;
+
/* Must have extended configuration space */
if (dev->cfg_size < PCIE_CAP_OFFSET + 4)
return;
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 61045c192e8..eb30e356f5b 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -153,7 +153,7 @@ static void __init pci_controller_apertures(struct pci_controller *pci_ctrl,
}
res->start += io_offset;
res->end += io_offset;
- pci_add_resource(resources, res);
+ pci_add_resource_offset(resources, res, io_offset);
for (i = 0; i < 3; i++) {
res = &pci_ctrl->mem_resources[i];
@@ -200,24 +200,9 @@ subsys_initcall(pcibios_init);
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
- struct pci_controller *pci_ctrl = bus->sysdata;
- struct resource *res;
- unsigned long io_offset;
- int i;
-
- io_offset = (unsigned long)pci_ctrl->io_space.base;
if (bus->parent) {
/* This is a subordinate bridge */
pci_read_bridge_bases(bus);
-
- for (i = 0; i < 4; i++) {
- if ((res = bus->resource[i]) == NULL || !res->flags)
- continue;
- if (io_offset && (res->flags & IORESOURCE_IO)) {
- res->start += io_offset;
- res->end += io_offset;
- }
- }
}
}
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index a7dc4672d99..a5c591ffe39 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -346,7 +346,7 @@ static int mpt_remove_dead_ioc_func(void *arg)
if ((pdev == NULL))
return -1;
- pci_remove_bus_device(pdev);
+ pci_stop_and_remove_bus_device(pdev);
return 0;
}
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 7ff10c1e866..0610e91bceb 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -553,7 +553,6 @@ dino_fixup_bus(struct pci_bus *bus)
struct list_head *ln;
struct pci_dev *dev;
struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
- int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num);
DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n",
__func__, bus, bus->secondary,
@@ -599,8 +598,6 @@ dino_fixup_bus(struct pci_bus *bus)
list_for_each(ln, &bus->devices) {
- int i;
-
dev = pci_dev_b(ln);
if (is_card_dino(&dino_dev->hba.dev->id))
dino_card_fixup(dev);
@@ -612,21 +609,6 @@ dino_fixup_bus(struct pci_bus *bus)
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
continue;
- /* Adjust the I/O Port space addresses */
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *res = &dev->resource[i];
- if (res->flags & IORESOURCE_IO) {
- res->start |= port_base;
- res->end |= port_base;
- }
-#ifdef __LP64__
- /* Sign Extend MMIO addresses */
- else if (res->flags & IORESOURCE_MEM) {
- res->start |= F_EXTEND(0UL);
- res->end |= F_EXTEND(0UL);
- }
-#endif
- }
/* null out the ROM resource if there is one (we don't
* care about an expansion rom on parisc, since it
* usually contains (x86) bios code) */
@@ -991,11 +973,14 @@ static int __init dino_probe(struct parisc_device *dev)
dev->dev.platform_data = dino_dev;
- pci_add_resource(&resources, &dino_dev->hba.io_space);
+ pci_add_resource_offset(&resources, &dino_dev->hba.io_space,
+ HBA_PORT_BASE(dino_dev->hba.hba_num));
if (dino_dev->hba.lmmio_space.flags)
- pci_add_resource(&resources, &dino_dev->hba.lmmio_space);
+ pci_add_resource_offset(&resources, &dino_dev->hba.lmmio_space,
+ dino_dev->hba.lmmio_space_offset);
if (dino_dev->hba.elmmio_space.flags)
- pci_add_resource(&resources, &dino_dev->hba.elmmio_space);
+ pci_add_resource_offset(&resources, &dino_dev->hba.elmmio_space,
+ dino_dev->hba.lmmio_space_offset);
if (dino_dev->hba.gmmio_space.flags)
pci_add_resource(&resources, &dino_dev->hba.gmmio_space);
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index d5f3d753a10..e8857647e21 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -635,7 +635,6 @@ lba_fixup_bus(struct pci_bus *bus)
u16 status;
#endif
struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->bridge));
- int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
DBG("lba_fixup_bus(0x%p) bus %d platform_data 0x%p\n",
bus, bus->secondary, bus->bridge->platform_data);
@@ -726,27 +725,6 @@ lba_fixup_bus(struct pci_bus *bus)
if (!res->start)
continue;
- if (res->flags & IORESOURCE_IO) {
- DBG("lba_fixup_bus() I/O Ports [%lx/%lx] -> ",
- res->start, res->end);
- res->start |= lba_portbase;
- res->end |= lba_portbase;
- DBG("[%lx/%lx]\n", res->start, res->end);
- } else if (res->flags & IORESOURCE_MEM) {
- /*
- ** Convert PCI (IO_VIEW) addresses to
- ** processor (PA_VIEW) addresses
- */
- DBG("lba_fixup_bus() MMIO [%lx/%lx] -> ",
- res->start, res->end);
- res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start);
- res->end = PCI_HOST_ADDR(HBA_DATA(ldev), res->end);
- DBG("[%lx/%lx]\n", res->start, res->end);
- } else {
- DBG("lba_fixup_bus() WTF? 0x%lx [%lx/%lx] XXX",
- res->flags, res->start, res->end);
- }
-
/*
** FIXME: this will result in whinging for devices
** that share expansion ROMs (think quad tulip), but
@@ -1514,11 +1492,14 @@ lba_driver_probe(struct parisc_device *dev)
lba_dev->hba.lmmio_space.flags = 0;
}
- pci_add_resource(&resources, &lba_dev->hba.io_space);
+ pci_add_resource_offset(&resources, &lba_dev->hba.io_space,
+ HBA_PORT_BASE(lba_dev->hba.hba_num));
if (lba_dev->hba.elmmio_space.start)
- pci_add_resource(&resources, &lba_dev->hba.elmmio_space);
+ pci_add_resource_offset(&resources, &lba_dev->hba.elmmio_space,
+ lba_dev->hba.lmmio_space_offset);
if (lba_dev->hba.lmmio_space.flags)
- pci_add_resource(&resources, &lba_dev->hba.lmmio_space);
+ pci_add_resource_offset(&resources, &lba_dev->hba.lmmio_space,
+ lba_dev->hba.lmmio_space_offset);
if (lba_dev->hba.gmmio_space.flags)
pci_add_resource(&resources, &lba_dev->hba.gmmio_space);
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 37856f7c778..848bfb84c04 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -31,6 +31,19 @@ config PCI_DEBUG
When in doubt, say N.
+config PCI_REALLOC_ENABLE_AUTO
+ bool "Enable PCI resource re-allocation detection"
+ depends on PCI
+ help
+ Say Y here if you want the PCI core to detect if PCI resource
+ re-allocation needs to be enabled. You can always use pci=realloc=on
+ or pci=realloc=off to override it. Note this feature is a no-op
+ unless PCI_IOV support is also enabled; in that case it will
+ automatically re-allocate PCI resources if SR-IOV BARs have not
+ been allocated by the BIOS.
+
+ When in doubt, say N.
+
config PCI_STUB
tristate "PCI Stub driver"
depends on PCI
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 398f5d85979..4ce5ef2f282 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -18,28 +18,36 @@
#include "pci.h"
-void pci_add_resource(struct list_head *resources, struct resource *res)
+void pci_add_resource_offset(struct list_head *resources, struct resource *res,
+ resource_size_t offset)
{
- struct pci_bus_resource *bus_res;
+ struct pci_host_bridge_window *window;
- bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
- if (!bus_res) {
- printk(KERN_ERR "PCI: can't add bus resource %pR\n", res);
+ window = kzalloc(sizeof(struct pci_host_bridge_window), GFP_KERNEL);
+ if (!window) {
+ printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res);
return;
}
- bus_res->res = res;
- list_add_tail(&bus_res->list, resources);
+ window->res = res;
+ window->offset = offset;
+ list_add_tail(&window->list, resources);
+}
+EXPORT_SYMBOL(pci_add_resource_offset);
+
+void pci_add_resource(struct list_head *resources, struct resource *res)
+{
+ pci_add_resource_offset(resources, res, 0);
}
EXPORT_SYMBOL(pci_add_resource);
void pci_free_resource_list(struct list_head *resources)
{
- struct pci_bus_resource *bus_res, *tmp;
+ struct pci_host_bridge_window *window, *tmp;
- list_for_each_entry_safe(bus_res, tmp, resources, list) {
- list_del(&bus_res->list);
- kfree(bus_res);
+ list_for_each_entry_safe(window, tmp, resources, list) {
+ list_del(&window->list);
+ kfree(window);
}
}
EXPORT_SYMBOL(pci_free_resource_list);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 9ddf69e3bbe..806c44fa645 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -800,20 +800,10 @@ static int __ref enable_device(struct acpiphp_slot *slot)
if (slot->flags & SLOT_ENABLED)
goto err_exit;
- /* sanity check: dev should be NULL when hot-plugged in */
- dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
- if (dev) {
- /* This case shouldn't happen */
- err("pci_dev structure already exists.\n");
- pci_dev_put(dev);
- retval = -1;
- goto err_exit;
- }
-
num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
if (num == 0) {
- err("No new device found\n");
- retval = -1;
+ /* Maybe only part of funcs are added. */
+ dbg("No new device found\n");
goto err_exit;
}
@@ -848,11 +838,16 @@ static int __ref enable_device(struct acpiphp_slot *slot)
pci_bus_add_devices(bus);
+ slot->flags |= SLOT_ENABLED;
list_for_each_entry(func, &slot->funcs, sibling) {
dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
func->function));
- if (!dev)
+ if (!dev) {
+ /* Do not set SLOT_ENABLED flag if some funcs
+ are not added. */
+ slot->flags &= (~SLOT_ENABLED);
continue;
+ }
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
@@ -867,7 +862,6 @@ static int __ref enable_device(struct acpiphp_slot *slot)
pci_dev_put(dev);
}
- slot->flags |= SLOT_ENABLED;
err_exit:
return retval;
@@ -892,9 +886,12 @@ static int disable_device(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
struct pci_dev *pdev;
+ struct pci_bus *bus = slot->bridge->pci_bus;
- /* is this slot already disabled? */
- if (!(slot->flags & SLOT_ENABLED))
+ /* The slot will be enabled when func 0 is added, so check
+ func 0 before disable the slot. */
+ pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
+ if (!pdev)
goto err_exit;
list_for_each_entry(func, &slot->funcs, sibling) {
@@ -913,7 +910,7 @@ static int disable_device(struct acpiphp_slot *slot)
disable_bridges(pdev->subordinate);
pci_disable_device(pdev);
}
- pci_remove_bus_device(pdev);
+ __pci_remove_bus_device(pdev);
pci_dev_put(pdev);
}
}
@@ -1070,7 +1067,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
res->end) {
/* Could not assign a required resources
* for this device, remove it */
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
break;
}
}
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 829c327cfb5..ae853ccd0cd 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -341,7 +341,7 @@ int cpci_unconfigure_slot(struct slot* slot)
dev = pci_get_slot(slot->bus,
PCI_DEVFN(PCI_SLOT(slot->devfn), i));
if (dev) {
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
}
diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c
index fb3f84661bd..81af764c629 100644
--- a/drivers/pci/hotplug/cpcihp_generic.c
+++ b/drivers/pci/hotplug/cpcihp_generic.c
@@ -62,7 +62,7 @@
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
/* local variables */
-static int debug;
+static bool debug;
static char *bridge;
static u8 bridge_busnr;
static u8 bridge_slot;
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index 6173b9a4544..1c8494021a4 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -127,7 +127,7 @@ int cpqhp_unconfigure_device(struct pci_func* func)
struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j));
if (temp) {
pci_dev_put(temp);
- pci_remove_bus_device(temp);
+ pci_stop_and_remove_bus_device(temp);
}
}
return 0;
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index 17d10e2e8fb..a019c9a712b 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -40,7 +40,7 @@ static ssize_t legacy_show(struct kobject *kobj, struct attribute *attr,
static void remove_callback(void *data)
{
- pci_remove_bus_device((struct pci_dev *)data);
+ pci_stop_and_remove_bus_device((struct pci_dev *)data);
}
static ssize_t legacy_store(struct kobject *kobj, struct attribute *attr,
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 5506e0e8fbc..4fda7e6a86a 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -721,7 +721,7 @@ static void ibm_unconfigure_device(struct pci_func *func)
for (j = 0; j < 0x08; j++) {
temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
if (temp) {
- pci_remove_bus_device(temp);
+ pci_stop_and_remove_bus_device(temp);
pci_dev_put(temp);
}
}
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
index 2850e64deda..714ca5c4ed5 100644
--- a/drivers/pci/hotplug/ibmphp_ebda.c
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -368,8 +368,10 @@ int __init ibmphp_access_ebda (void)
debug ("rio blk id: %x\n", blk_id);
rio_table_ptr = kzalloc(sizeof(struct rio_table_hdr), GFP_KERNEL);
- if (!rio_table_ptr)
- return -ENOMEM;
+ if (!rio_table_ptr) {
+ rc = -ENOMEM;
+ goto out;
+ }
rio_table_ptr->ver_num = readb (io_mem + offset);
rio_table_ptr->scal_count = readb (io_mem + offset + 1);
rio_table_ptr->riodev_count = readb (io_mem + offset + 2);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index bcdbb164362..a960faec102 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -241,34 +241,79 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
return retval;
}
-static inline int check_link_active(struct controller *ctrl)
+static bool check_link_active(struct controller *ctrl)
{
- u16 link_status;
+ bool ret = false;
+ u16 lnk_status;
- if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &link_status))
- return 0;
- return !!(link_status & PCI_EXP_LNKSTA_DLLLA);
+ if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status))
+ return ret;
+
+ ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
+
+ if (ret)
+ ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
+
+ return ret;
}
-static void pcie_wait_link_active(struct controller *ctrl)
+static void __pcie_wait_link_active(struct controller *ctrl, bool active)
{
int timeout = 1000;
- if (check_link_active(ctrl))
+ if (check_link_active(ctrl) == active)
return;
while (timeout > 0) {
msleep(10);
timeout -= 10;
- if (check_link_active(ctrl))
+ if (check_link_active(ctrl) == active)
return;
}
- ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n");
+ ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
+ active ? "set" : "cleared");
+}
+
+static void pcie_wait_link_active(struct controller *ctrl)
+{
+ __pcie_wait_link_active(ctrl, true);
+}
+
+static void pcie_wait_link_not_active(struct controller *ctrl)
+{
+ __pcie_wait_link_active(ctrl, false);
+}
+
+static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
+{
+ u32 l;
+ int count = 0;
+ int delay = 1000, step = 20;
+ bool found = false;
+
+ do {
+ found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0);
+ count++;
+
+ if (found)
+ break;
+
+ msleep(step);
+ delay -= step;
+ } while (delay > 0);
+
+ if (count > 1 && pciehp_debug)
+ printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n",
+ pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), count, step, l);
+
+ return found;
}
int pciehp_check_link_status(struct controller *ctrl)
{
u16 lnk_status;
int retval = 0;
+ bool found = false;
/*
* Data Link Layer Link Active Reporting must be capable for
@@ -280,13 +325,10 @@ int pciehp_check_link_status(struct controller *ctrl)
else
msleep(1000);
- /*
- * Need to wait for 1000 ms after Data Link Layer Link Active
- * (DLLLA) bit reads 1b before sending configuration request.
- * We need it before checking Link Training (LT) bit becuase
- * LT is still set even after DLLLA bit is set on some platform.
- */
- msleep(1000);
+ /* wait 100ms before read pci conf, and try in 1s */
+ msleep(100);
+ found = pci_bus_check_dev(ctrl->pcie->port->subordinate,
+ PCI_DEVFN(0, 0));
retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
if (retval) {
@@ -302,19 +344,50 @@ int pciehp_check_link_status(struct controller *ctrl)
return retval;
}
- /*
- * If the port supports Link speeds greater than 5.0 GT/s, we
- * must wait for 100 ms after Link training completes before
- * sending configuration request.
- */
- if (ctrl->pcie->port->subordinate->max_bus_speed > PCIE_SPEED_5_0GT)
- msleep(100);
-
pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
+ if (!found && !retval)
+ retval = -1;
+
return retval;
}
+static int __pciehp_link_set(struct controller *ctrl, bool enable)
+{
+ u16 lnk_ctrl;
+ int retval = 0;
+
+ retval = pciehp_readw(ctrl, PCI_EXP_LNKCTL, &lnk_ctrl);
+ if (retval) {
+ ctrl_err(ctrl, "Cannot read LNKCTRL register\n");
+ return retval;
+ }
+
+ if (enable)
+ lnk_ctrl &= ~PCI_EXP_LNKCTL_LD;
+ else
+ lnk_ctrl |= PCI_EXP_LNKCTL_LD;
+
+ retval = pciehp_writew(ctrl, PCI_EXP_LNKCTL, lnk_ctrl);
+ if (retval) {
+ ctrl_err(ctrl, "Cannot write LNKCTRL register\n");
+ return retval;
+ }
+ ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl);
+
+ return retval;
+}
+
+static int pciehp_link_enable(struct controller *ctrl)
+{
+ return __pciehp_link_set(ctrl, true);
+}
+
+static int pciehp_link_disable(struct controller *ctrl)
+{
+ return __pciehp_link_set(ctrl, false);
+}
+
int pciehp_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
@@ -533,6 +606,10 @@ int pciehp_power_on_slot(struct slot * slot)
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
+ retval = pciehp_link_enable(ctrl);
+ if (retval)
+ ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__);
+
return retval;
}
@@ -543,6 +620,14 @@ int pciehp_power_off_slot(struct slot * slot)
u16 cmd_mask;
int retval;
+ /* Disable the link at first */
+ pciehp_link_disable(ctrl);
+ /* wait the link is down */
+ if (ctrl->link_active_reporting)
+ pcie_wait_link_not_active(ctrl);
+ else
+ msleep(1000);
+
slot_cmd = POWER_OFF;
cmd_mask = PCI_EXP_SLTCTL_PCC;
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index a4031dfe938..47d9dc06b10 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -141,7 +141,7 @@ int pciehp_unconfigure_device(struct slot *p_slot)
break;
}
}
- pci_remove_bus_device(temp);
+ pci_stop_and_remove_bus_device(temp);
/*
* Ensure that no new Requests will be generated from
* the device.
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index c56a9413e1a..1e117c2a3ca 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -389,7 +389,7 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
BUG_ON(!bus->self);
pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
eeh_remove_bus_device(bus->self);
- pci_remove_bus_device(bus->self);
+ pci_stop_and_remove_bus_device(bus->self);
return 0;
}
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 72d507b6a2a..de573113c10 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -554,7 +554,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
PCI_FUNC(func)));
if (dev) {
sn_bus_free_data(dev);
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
}
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
index a2ccfcd3c29..df7e4bfadae 100644
--- a/drivers/pci/hotplug/shpchp_pci.c
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -124,7 +124,7 @@ int shpchp_unconfigure_device(struct slot *p_slot)
break;
}
}
- pci_remove_bus_device(temp);
+ pci_stop_and_remove_bus_device(temp);
pci_dev_put(temp);
}
return rc;
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 0dab5ecf61b..6554e1a0f63 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -142,7 +142,7 @@ failed2:
failed1:
pci_dev_put(dev);
mutex_lock(&iov->dev->sriov->lock);
- pci_remove_bus_device(virtfn);
+ pci_stop_and_remove_bus_device(virtfn);
virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
mutex_unlock(&iov->dev->sriov->lock);
@@ -173,10 +173,16 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
sprintf(buf, "virtfn%u", id);
sysfs_remove_link(&dev->dev.kobj, buf);
- sysfs_remove_link(&virtfn->dev.kobj, "physfn");
+ /*
+ * pci_stop_dev() could have been called for this virtfn already,
+ * so the directory for the virtfn may have been removed before.
+ * Double check to avoid spurious sysfs warnings.
+ */
+ if (virtfn->dev.kobj.sd)
+ sysfs_remove_link(&virtfn->dev.kobj, "physfn");
mutex_lock(&iov->dev->sriov->lock);
- pci_remove_bus_device(virtfn);
+ pci_stop_and_remove_bus_device(virtfn);
virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
mutex_unlock(&iov->dev->sriov->lock);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 8d9616b821c..6b54b23b990 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -419,6 +419,16 @@ static void pci_device_shutdown(struct device *dev)
drv->shutdown(pci_dev);
pci_msi_shutdown(pci_dev);
pci_msix_shutdown(pci_dev);
+
+ /*
+ * Devices may be enabled to wake up by runtime PM, but they need not
+ * be supposed to wake up the system from its "power off" state (e.g.
+ * ACPI S5). Therefore disable wakeup for all devices that aren't
+ * supposed to wake up the system at this point. The state argument
+ * will be ignored by pci_enable_wake().
+ */
+ if (!device_may_wakeup(dev))
+ pci_enable_wake(pci_dev, PCI_UNKNOWN, false);
}
#ifdef CONFIG_PM
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index a3cd8cad532..a55e248618c 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -330,7 +330,7 @@ static void remove_callback(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
mutex_lock(&pci_remove_rescan_mutex);
- pci_remove_bus_device(pdev);
+ pci_stop_and_remove_bus_device(pdev);
mutex_unlock(&pci_remove_rescan_mutex);
}
@@ -366,7 +366,10 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
if (val) {
mutex_lock(&pci_remove_rescan_mutex);
- pci_rescan_bus(bus);
+ if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
+ pci_rescan_bus_bridge_resize(bus->self);
+ else
+ pci_rescan_bus(bus);
mutex_unlock(&pci_remove_rescan_mutex);
}
return count;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 053670e09e2..81567441526 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -94,6 +94,9 @@ u8 pci_cache_line_size;
*/
unsigned int pcibios_max_latency = 255;
+/* If set, the PCIe ARI capability will not be used. */
+static bool pcie_ari_disabled;
+
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
* @bus: pointer to PCI bus structure to search
@@ -825,6 +828,19 @@ EXPORT_SYMBOL(pci_choose_state);
#define pcie_cap_has_sltctl2(type, flags) \
((flags & PCI_EXP_FLAGS_VERS) > 1)
+static struct pci_cap_saved_state *pci_find_saved_cap(
+ struct pci_dev *pci_dev, char cap)
+{
+ struct pci_cap_saved_state *tmp;
+ struct hlist_node *pos;
+
+ hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) {
+ if (tmp->cap.cap_nr == cap)
+ return tmp;
+ }
+ return NULL;
+}
+
static int pci_save_pcie_state(struct pci_dev *dev)
{
int pos, i = 0;
@@ -959,6 +975,7 @@ void pci_restore_state(struct pci_dev *dev)
{
int i;
u32 val;
+ int tries;
if (!dev->state_saved)
return;
@@ -973,12 +990,16 @@ void pci_restore_state(struct pci_dev *dev)
*/
for (i = 15; i >= 0; i--) {
pci_read_config_dword(dev, i * 4, &val);
- if (val != dev->saved_config_space[i]) {
+ tries = 10;
+ while (tries && val != dev->saved_config_space[i]) {
dev_dbg(&dev->dev, "restoring config "
"space at offset %#x (was %#x, writing %#x)\n",
i, val, (int)dev->saved_config_space[i]);
pci_write_config_dword(dev,i * 4,
dev->saved_config_space[i]);
+ pci_read_config_dword(dev, i * 4, &val);
+ mdelay(10);
+ tries--;
}
}
pci_restore_pcix_state(dev);
@@ -1864,6 +1885,12 @@ void platform_pci_wakeup_init(struct pci_dev *dev)
platform_pci_sleep_wake(dev, false);
}
+static void pci_add_saved_cap(struct pci_dev *pci_dev,
+ struct pci_cap_saved_state *new_cap)
+{
+ hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
+}
+
/**
* pci_add_save_buffer - allocate buffer for saving given capability registers
* @dev: the PCI device
@@ -1911,6 +1938,15 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
"unable to preallocate PCI-X save buffer\n");
}
+void pci_free_cap_save_buffers(struct pci_dev *dev)
+{
+ struct pci_cap_saved_state *tmp;
+ struct hlist_node *pos, *n;
+
+ hlist_for_each_entry_safe(tmp, pos, n, &dev->saved_cap_space, next)
+ kfree(tmp);
+}
+
/**
* pci_enable_ari - enable ARI forwarding if hardware support it
* @dev: the PCI device
@@ -1922,7 +1958,7 @@ void pci_enable_ari(struct pci_dev *dev)
u16 flags, ctrl;
struct pci_dev *bridge;
- if (!pci_is_pcie(dev) || dev->devfn)
+ if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
return;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
@@ -3661,6 +3697,68 @@ int pci_is_reassigndev(struct pci_dev *dev)
return (pci_specified_resource_alignment(dev) != 0);
}
+/*
+ * This function disables memory decoding and releases memory resources
+ * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
+ * It also rounds up size to specified alignment.
+ * Later on, the kernel will assign page-aligned memory resource back
+ * to the device.
+ */
+void pci_reassigndev_resource_alignment(struct pci_dev *dev)
+{
+ int i;
+ struct resource *r;
+ resource_size_t align, size;
+ u16 command;
+
+ if (!pci_is_reassigndev(dev))
+ return;
+
+ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
+ (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
+ dev_warn(&dev->dev,
+ "Can't reassign resources to host bridge.\n");
+ return;
+ }
+
+ dev_info(&dev->dev,
+ "Disabling memory decoding and releasing memory resources.\n");
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ command &= ~PCI_COMMAND_MEMORY;
+ pci_write_config_word(dev, PCI_COMMAND, command);
+
+ align = pci_specified_resource_alignment(dev);
+ for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
+ r = &dev->resource[i];
+ if (!(r->flags & IORESOURCE_MEM))
+ continue;
+ size = resource_size(r);
+ if (size < align) {
+ size = align;
+ dev_info(&dev->dev,
+ "Rounding up size of resource #%d to %#llx.\n",
+ i, (unsigned long long)size);
+ }
+ r->end = size - 1;
+ r->start = 0;
+ }
+ /* Need to disable bridge's resource window,
+ * to enable the kernel to reassign new resource
+ * window later on.
+ */
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+ (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+ r = &dev->resource[i];
+ if (!(r->flags & IORESOURCE_MEM))
+ continue;
+ r->end = resource_size(r) - 1;
+ r->start = 0;
+ }
+ pci_disable_bridge_window(dev);
+ }
+}
+
ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
{
if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
@@ -3739,10 +3837,14 @@ static int __init pci_setup(char *str)
pci_no_msi();
} else if (!strcmp(str, "noaer")) {
pci_no_aer();
+ } else if (!strncmp(str, "realloc=", 8)) {
+ pci_realloc_get_opt(str + 8);
} else if (!strncmp(str, "realloc", 7)) {
- pci_realloc();
+ pci_realloc_get_opt("on");
} else if (!strcmp(str, "nodomains")) {
pci_no_domains();
+ } else if (!strncmp(str, "noari", 5)) {
+ pcie_ari_disabled = true;
} else if (!strncmp(str, "cbiosize=", 9)) {
pci_cardbus_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "cbmemsize=", 10)) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 1009a5e88e5..e4943479b23 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -73,6 +73,7 @@ extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
extern void pci_pm_init(struct pci_dev *dev);
extern void platform_pci_wakeup_init(struct pci_dev *dev);
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
+void pci_free_cap_save_buffers(struct pci_dev *dev);
static inline void pci_wakeup_event(struct pci_dev *dev)
{
@@ -148,7 +149,7 @@ static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif
-extern void pci_realloc(void);
+void pci_realloc_get_opt(char *);
static inline int pci_no_d1d2(struct pci_dev *dev)
{
@@ -207,6 +208,8 @@ enum pci_bar_type {
pci_bar_mem64, /* A 64-bit memory BAR */
};
+bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
+ int crs_timeout);
extern int pci_setup_device(struct pci_dev *dev);
extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int reg);
@@ -225,11 +228,8 @@ static inline int pci_ari_enabled(struct pci_bus *bus)
return bus->self && bus->self->ari_enabled;
}
-#ifdef CONFIG_PCI_QUIRKS
-extern int pci_is_reassigndev(struct pci_dev *dev);
-resource_size_t pci_specified_resource_alignment(struct pci_dev *dev);
+void pci_reassigndev_resource_alignment(struct pci_dev *dev);
extern void pci_disable_bridge_window(struct pci_dev *dev);
-#endif
/* Single Root I/O Virtualization */
struct pci_sriov {
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 72962cc92e0..6c8bc580978 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -55,6 +55,31 @@ config PCIEASPM_DEBUG
This enables PCI Express ASPM debug support. It will add per-device
interface to control ASPM.
+choice
+ prompt "Default ASPM policy"
+ default PCIEASPM_DEFAULT
+ depends on PCIEASPM
+
+config PCIEASPM_DEFAULT
+ bool "BIOS default"
+ depends on PCIEASPM
+ help
+ Use the BIOS defaults for PCI Express ASPM.
+
+config PCIEASPM_POWERSAVE
+ bool "Powersave"
+ depends on PCIEASPM
+ help
+ Enable PCI Express ASPM L0s and L1 where possible, even if the
+ BIOS did not.
+
+config PCIEASPM_PERFORMANCE
+ bool "Performance"
+ depends on PCIEASPM
+ help
+ Disable PCI Express ASPM L0s and L1, even if the BIOS enabled them.
+endchoice
+
config PCIE_PME
def_bool y
depends on PCIEPORTBUS && PM_RUNTIME && EXPERIMENTAL && ACPI
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 24f049e7395..4bdef24cd41 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -76,7 +76,15 @@ static LIST_HEAD(link_list);
#define POLICY_DEFAULT 0 /* BIOS default setting */
#define POLICY_PERFORMANCE 1 /* high performance */
#define POLICY_POWERSAVE 2 /* high power saving */
+
+#ifdef CONFIG_PCIEASPM_PERFORMANCE
+static int aspm_policy = POLICY_PERFORMANCE;
+#elif defined CONFIG_PCIEASPM_POWERSAVE
+static int aspm_policy = POLICY_POWERSAVE;
+#else
static int aspm_policy;
+#endif
+
static const char *policy_str[] = {
[POLICY_DEFAULT] = "default",
[POLICY_PERFORMANCE] = "performance",
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index bd00a01aef1..eea2ca2375e 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -34,6 +34,18 @@ struct pci_dev;
extern void pcie_clear_root_pme_status(struct pci_dev *dev);
+#ifdef CONFIG_HOTPLUG_PCI_PCIE
+extern bool pciehp_msi_disabled;
+
+static inline bool pciehp_no_msi(void)
+{
+ return pciehp_msi_disabled;
+}
+
+#else /* !CONFIG_HOTPLUG_PCI_PCIE */
+static inline bool pciehp_no_msi(void) { return false; }
+#endif /* !CONFIG_HOTPLUG_PCI_PCIE */
+
#ifdef CONFIG_PCIE_PME
extern bool pcie_pme_msi_disabled;
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 595654a1a6a..2f589a54f9b 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -19,6 +19,17 @@
#include "../pci.h"
#include "portdrv.h"
+bool pciehp_msi_disabled;
+
+static int __init pciehp_setup(char *str)
+{
+ if (!strncmp(str, "nomsi", 5))
+ pciehp_msi_disabled = true;
+
+ return 1;
+}
+__setup("pcie_hp=", pciehp_setup);
+
/**
* release_pcie_device - free PCI Express port service device structure
* @dev: Port service device to release
@@ -189,8 +200,9 @@ static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
{
int i, irq = -1;
- /* We have to use INTx if MSI cannot be used for PCIe PME. */
- if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) {
+ /* We have to use INTx if MSI cannot be used for PCIe PME or pciehp. */
+ if (((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) ||
+ ((mask & PCIE_PORT_SERVICE_HP) && pciehp_no_msi())) {
if (dev->pin)
irq = dev->irq;
goto no_msi;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 71eac9cd724..5e1ca3c58a7 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -15,6 +15,8 @@
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3
+static LIST_HEAD(pci_host_bridges);
+
/* Ugh. Need to stop exporting this to modules. */
LIST_HEAD(pci_root_buses);
EXPORT_SYMBOL(pci_root_buses);
@@ -42,6 +44,82 @@ int no_pci_devices(void)
}
EXPORT_SYMBOL(no_pci_devices);
+static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev)
+{
+ struct pci_bus *bus;
+ struct pci_host_bridge *bridge;
+
+ bus = dev->bus;
+ while (bus->parent)
+ bus = bus->parent;
+
+ list_for_each_entry(bridge, &pci_host_bridges, list) {
+ if (bridge->bus == bus)
+ return bridge;
+ }
+
+ return NULL;
+}
+
+static bool resource_contains(struct resource *res1, struct resource *res2)
+{
+ return res1->start <= res2->start && res1->end >= res2->end;
+}
+
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+ struct resource *res)
+{
+ struct pci_host_bridge *bridge = pci_host_bridge(dev);
+ struct pci_host_bridge_window *window;
+ resource_size_t offset = 0;
+
+ list_for_each_entry(window, &bridge->windows, list) {
+ if (resource_type(res) != resource_type(window->res))
+ continue;
+
+ if (resource_contains(window->res, res)) {
+ offset = window->offset;
+ break;
+ }
+ }
+
+ region->start = res->start - offset;
+ region->end = res->end - offset;
+}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+
+static bool region_contains(struct pci_bus_region *region1,
+ struct pci_bus_region *region2)
+{
+ return region1->start <= region2->start && region1->end >= region2->end;
+}
+
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+ struct pci_bus_region *region)
+{
+ struct pci_host_bridge *bridge = pci_host_bridge(dev);
+ struct pci_host_bridge_window *window;
+ struct pci_bus_region bus_region;
+ resource_size_t offset = 0;
+
+ list_for_each_entry(window, &bridge->windows, list) {
+ if (resource_type(res) != resource_type(window->res))
+ continue;
+
+ bus_region.start = window->res->start - window->offset;
+ bus_region.end = window->res->end - window->offset;
+
+ if (region_contains(&bus_region, region)) {
+ offset = window->offset;
+ break;
+ }
+ }
+
+ res->start = region->start + offset;
+ res->end = region->end + offset;
+}
+EXPORT_SYMBOL(pcibios_bus_to_resource);
+
/*
* PCI Bus Class
*/
@@ -135,6 +213,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
{
u32 l, sz, mask;
u16 orig_cmd;
+ struct pci_bus_region region;
mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
@@ -214,11 +293,13 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
/* Address above 32-bit boundary; disable the BAR */
pci_write_config_dword(dev, pos, 0);
pci_write_config_dword(dev, pos + 4, 0);
- res->start = 0;
- res->end = sz64;
+ region.start = 0;
+ region.end = sz64;
+ pcibios_bus_to_resource(dev, res, &region);
} else {
- res->start = l64;
- res->end = l64 + sz64;
+ region.start = l64;
+ region.end = l64 + sz64;
+ pcibios_bus_to_resource(dev, res, &region);
dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n",
pos, res);
}
@@ -228,8 +309,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
if (!sz)
goto fail;
- res->start = l;
- res->end = l + sz;
+ region.start = l;
+ region.end = l + sz;
+ pcibios_bus_to_resource(dev, res, &region);
dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res);
}
@@ -266,7 +348,8 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
unsigned long base, limit;
- struct resource *res;
+ struct pci_bus_region region;
+ struct resource *res, res2;
res = child->resource[0];
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
@@ -284,10 +367,14 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
if (base && base <= limit) {
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+ res2.flags = res->flags;
+ region.start = base;
+ region.end = limit + 0xfff;
+ pcibios_bus_to_resource(dev, &res2, &region);
if (!res->start)
- res->start = base;
+ res->start = res2.start;
if (!res->end)
- res->end = limit + 0xfff;
+ res->end = res2.end;
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
}
}
@@ -297,6 +384,7 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
struct pci_dev *dev = child->self;
u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
+ struct pci_bus_region region;
struct resource *res;
res = child->resource[1];
@@ -306,8 +394,9 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
- res->start = base;
- res->end = limit + 0xfffff;
+ region.start = base;
+ region.end = limit + 0xfffff;
+ pcibios_bus_to_resource(dev, res, &region);
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
}
}
@@ -317,6 +406,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
struct pci_dev *dev = child->self;
u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
+ struct pci_bus_region region;
struct resource *res;
res = child->resource[2];
@@ -353,8 +443,9 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (res->flags & PCI_PREF_RANGE_TYPE_64)
res->flags |= IORESOURCE_MEM_64;
- res->start = base;
- res->end = limit + 0xfffff;
+ region.start = base;
+ region.end = limit + 0xfffff;
+ pcibios_bus_to_resource(dev, res, &region);
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
}
}
@@ -900,6 +991,8 @@ int pci_setup_device(struct pci_dev *dev)
u8 hdr_type;
struct pci_slot *slot;
int pos = 0;
+ struct pci_bus_region region;
+ struct resource *res;
if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
return -EIO;
@@ -926,12 +1019,10 @@ int pci_setup_device(struct pci_dev *dev)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
dev->revision = class & 0xff;
- class >>= 8; /* upper 3 bytes */
- dev->class = class;
- class >>= 8;
+ dev->class = class >> 8; /* upper 3 bytes */
- dev_printk(KERN_DEBUG, &dev->dev, "[%04x:%04x] type %d class %#08x\n",
- dev->vendor, dev->device, dev->hdr_type, class);
+ dev_printk(KERN_DEBUG, &dev->dev, "[%04x:%04x] type %02x class %#08x\n",
+ dev->vendor, dev->device, dev->hdr_type, dev->class);
/* need to have dev->class ready */
dev->cfg_size = pci_cfg_space_size(dev);
@@ -963,20 +1054,28 @@ int pci_setup_device(struct pci_dev *dev)
u8 progif;
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
if ((progif & 1) == 0) {
- dev->resource[0].start = 0x1F0;
- dev->resource[0].end = 0x1F7;
- dev->resource[0].flags = LEGACY_IO_RESOURCE;
- dev->resource[1].start = 0x3F6;
- dev->resource[1].end = 0x3F6;
- dev->resource[1].flags = LEGACY_IO_RESOURCE;
+ region.start = 0x1F0;
+ region.end = 0x1F7;
+ res = &dev->resource[0];
+ res->flags = LEGACY_IO_RESOURCE;
+ pcibios_bus_to_resource(dev, res, &region);
+ region.start = 0x3F6;
+ region.end = 0x3F6;
+ res = &dev->resource[1];
+ res->flags = LEGACY_IO_RESOURCE;
+ pcibios_bus_to_resource(dev, res, &region);
}
if ((progif & 4) == 0) {
- dev->resource[2].start = 0x170;
- dev->resource[2].end = 0x177;
- dev->resource[2].flags = LEGACY_IO_RESOURCE;
- dev->resource[3].start = 0x376;
- dev->resource[3].end = 0x376;
- dev->resource[3].flags = LEGACY_IO_RESOURCE;
+ region.start = 0x170;
+ region.end = 0x177;
+ res = &dev->resource[2];
+ res->flags = LEGACY_IO_RESOURCE;
+ pcibios_bus_to_resource(dev, res, &region);
+ region.start = 0x376;
+ region.end = 0x376;
+ res = &dev->resource[3];
+ res->flags = LEGACY_IO_RESOURCE;
+ pcibios_bus_to_resource(dev, res, &region);
}
}
break;
@@ -1013,8 +1112,8 @@ int pci_setup_device(struct pci_dev *dev)
return -EIO;
bad:
- dev_err(&dev->dev, "ignoring class %02x (doesn't match header "
- "type %02x)\n", class, dev->hdr_type);
+ dev_err(&dev->dev, "ignoring class %#08x (doesn't match header "
+ "type %02x)\n", dev->class, dev->hdr_type);
dev->class = PCI_CLASS_NOT_DEFINED;
}
@@ -1026,6 +1125,7 @@ static void pci_release_capabilities(struct pci_dev *dev)
{
pci_vpd_release(dev);
pci_iov_release(dev);
+ pci_free_cap_save_buffers(dev);
}
/**
@@ -1118,40 +1218,54 @@ struct pci_dev *alloc_pci_dev(void)
}
EXPORT_SYMBOL(alloc_pci_dev);
-/*
- * Read the config data for a PCI device, sanity-check it
- * and fill in the dev structure...
- */
-static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
+bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
+ int crs_timeout)
{
- struct pci_dev *dev;
- u32 l;
int delay = 1;
- if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
- return NULL;
+ if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+ return false;
/* some broken boards return 0 or ~0 if a slot is empty: */
- if (l == 0xffffffff || l == 0x00000000 ||
- l == 0x0000ffff || l == 0xffff0000)
- return NULL;
+ if (*l == 0xffffffff || *l == 0x00000000 ||
+ *l == 0x0000ffff || *l == 0xffff0000)
+ return false;
/* Configuration request Retry Status */
- while (l == 0xffff0001) {
+ while (*l == 0xffff0001) {
+ if (!crs_timeout)
+ return false;
+
msleep(delay);
delay *= 2;
- if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
- return NULL;
+ if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+ return false;
/* Card hasn't responded in 60 seconds? Must be stuck. */
- if (delay > 60 * 1000) {
+ if (delay > crs_timeout) {
printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not "
"responding\n", pci_domain_nr(bus),
bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn));
- return NULL;
+ return false;
}
}
+ return true;
+}
+EXPORT_SYMBOL(pci_bus_read_dev_vendor_id);
+
+/*
+ * Read the config data for a PCI device, sanity-check it
+ * and fill in the dev structure...
+ */
+static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
+{
+ struct pci_dev *dev;
+ u32 l;
+
+ if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
+ return NULL;
+
dev = alloc_pci_dev();
if (!dev)
return NULL;
@@ -1212,6 +1326,9 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
/* Fix up broken headers */
pci_fixup_device(pci_fixup_header, dev);
+ /* moved out from quirk header fixup code */
+ pci_reassigndev_resource_alignment(dev);
+
/* Clear the state_saved flag. */
dev->state_saved = false;
@@ -1530,21 +1647,27 @@ unsigned int __devinit pci_scan_child_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)
{
- int error, i;
+ int error;
+ struct pci_host_bridge *bridge;
struct pci_bus *b, *b2;
struct device *dev;
- struct pci_bus_resource *bus_res, *n;
+ struct pci_host_bridge_window *window, *n;
struct resource *res;
+ resource_size_t offset;
+ char bus_addr[64];
+ char *fmt;
+
+ bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+ if (!bridge)
+ return NULL;
b = pci_alloc_bus();
if (!b)
- return NULL;
+ goto err_bus;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- kfree(b);
- return NULL;
- }
+ if (!dev)
+ goto err_dev;
b->sysdata = sysdata;
b->ops = ops;
@@ -1556,10 +1679,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
goto err_out;
}
- down_write(&pci_bus_sem);
- list_add_tail(&b->node, &pci_root_buses);
- up_write(&pci_bus_sem);
-
dev->parent = parent;
dev->release = pci_release_bus_bridge_dev;
dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus);
@@ -1585,31 +1704,53 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
b->number = b->secondary = bus;
- /* Add initial resources to the bus */
- list_for_each_entry_safe(bus_res, n, resources, list)
- list_move_tail(&bus_res->list, &b->resources);
+ bridge->bus = b;
+ INIT_LIST_HEAD(&bridge->windows);
if (parent)
dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
else
printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
- pci_bus_for_each_resource(b, res, i) {
- if (res)
- dev_info(&b->dev, "root bus resource %pR\n", res);
+ /* Add initial resources to the bus */
+ list_for_each_entry_safe(window, n, resources, list) {
+ list_move_tail(&window->list, &bridge->windows);
+ res = window->res;
+ offset = window->offset;
+ pci_bus_add_resource(b, res, 0);
+ if (offset) {
+ if (resource_type(res) == IORESOURCE_IO)
+ fmt = " (bus address [%#06llx-%#06llx])";
+ else
+ fmt = " (bus address [%#010llx-%#010llx])";
+ snprintf(bus_addr, sizeof(bus_addr), fmt,
+ (unsigned long long) (res->start - offset),
+ (unsigned long long) (res->end - offset));
+ } else
+ bus_addr[0] = '\0';
+ dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr);
}
+ down_write(&pci_bus_sem);
+ list_add_tail(&bridge->list, &pci_host_bridges);
+ list_add_tail(&b->node, &pci_root_buses);
+ up_write(&pci_bus_sem);
+
return b;
class_dev_reg_err:
device_unregister(dev);
dev_reg_err:
down_write(&pci_bus_sem);
+ list_del(&bridge->list);
list_del(&b->node);
up_write(&pci_bus_sem);
err_out:
kfree(dev);
+err_dev:
kfree(b);
+err_bus:
+ kfree(bridge);
return NULL;
}
@@ -1667,36 +1808,29 @@ EXPORT_SYMBOL(pci_scan_bus);
#ifdef CONFIG_HOTPLUG
/**
- * pci_rescan_bus - scan a PCI bus for devices.
- * @bus: PCI bus to scan
+ * pci_rescan_bus_bridge_resize - scan a PCI bus for devices.
+ * @bridge: PCI bridge for the bus to scan
*
- * Scan a PCI bus and child buses for new devices, adds them,
- * and enables them.
+ * Scan a PCI bus and child buses for new devices, add them,
+ * and enable them, resizing bridge mmio/io resource if necessary
+ * and possible. The caller must ensure the child devices are already
+ * removed for resizing to occur.
*
* Returns the max number of subordinate bus discovered.
*/
-unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
{
unsigned int max;
- struct pci_dev *dev;
+ struct pci_bus *bus = bridge->subordinate;
max = pci_scan_child_bus(bus);
- down_read(&pci_bus_sem);
- list_for_each_entry(dev, &bus->devices, bus_list)
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
- dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
- if (dev->subordinate)
- pci_bus_size_bridges(dev->subordinate);
- up_read(&pci_bus_sem);
+ pci_assign_unassigned_bridge_resources(bridge);
- pci_bus_assign_resources(bus);
- pci_enable_bridges(bus);
pci_bus_add_devices(bus);
return max;
}
-EXPORT_SYMBOL_GPL(pci_rescan_bus);
EXPORT_SYMBOL(pci_add_new_bus);
EXPORT_SYMBOL(pci_scan_slot);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index f722c5f6951..4bf71028556 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -26,73 +26,12 @@
#include <linux/dmi.h>
#include <linux/pci-aspm.h>
#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/ktime.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
/*
- * This quirk function disables memory decoding and releases memory resources
- * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
- * It also rounds up size to specified alignment.
- * Later on, the kernel will assign page-aligned memory resource back
- * to the device.
- */
-static void __devinit quirk_resource_alignment(struct pci_dev *dev)
-{
- int i;
- struct resource *r;
- resource_size_t align, size;
- u16 command;
-
- if (!pci_is_reassigndev(dev))
- return;
-
- if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
- (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
- dev_warn(&dev->dev,
- "Can't reassign resources to host bridge.\n");
- return;
- }
-
- dev_info(&dev->dev,
- "Disabling memory decoding and releasing memory resources.\n");
- pci_read_config_word(dev, PCI_COMMAND, &command);
- command &= ~PCI_COMMAND_MEMORY;
- pci_write_config_word(dev, PCI_COMMAND, command);
-
- align = pci_specified_resource_alignment(dev);
- for (i=0; i < PCI_BRIDGE_RESOURCES; i++) {
- r = &dev->resource[i];
- if (!(r->flags & IORESOURCE_MEM))
- continue;
- size = resource_size(r);
- if (size < align) {
- size = align;
- dev_info(&dev->dev,
- "Rounding up size of resource #%d to %#llx.\n",
- i, (unsigned long long)size);
- }
- r->end = size - 1;
- r->start = 0;
- }
- /* Need to disable bridge's resource window,
- * to enable the kernel to reassign new resource
- * window later on.
- */
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
- (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
- for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
- r = &dev->resource[i];
- if (!(r->flags & IORESOURCE_MEM))
- continue;
- r->end = resource_size(r) - 1;
- r->start = 0;
- }
- pci_disable_bridge_window(dev);
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
-
-/*
* Decoding should be disabled for a PCI device during BAR sizing to avoid
* conflict. But doing so may cause problems on host bridge and perhaps other
* key system devices. For devices that need to have mmio decoding always-on,
@@ -100,10 +39,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
*/
static void __devinit quirk_mmio_always_on(struct pci_dev *dev)
{
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
- dev->mmio_always_on = 1;
+ dev->mmio_always_on = 1;
}
-DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_mmio_always_on);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
/* The Mellanox Tavor device gives false positive parity errors
* Mark this device with a broken_parity_status, to allow
@@ -1002,12 +941,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt
*/
static void quirk_cardbus_legacy(struct pci_dev *dev)
{
- if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
- return;
pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_BRIDGE_CARDBUS, 8, quirk_cardbus_legacy);
+DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_BRIDGE_CARDBUS, 8, quirk_cardbus_legacy);
/*
* Following the PCI ordering rules is optional on the AMD762. I'm not
@@ -1164,17 +1103,20 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, qui
static void __devinit quirk_no_ata_d3(struct pci_dev *pdev)
{
- /* Quirk the legacy ATA devices only. The AHCI ones are ok */
- if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
- pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
+ pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
}
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID, quirk_no_ata_d3);
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID, quirk_no_ata_d3);
+/* Quirk the legacy ATA devices only. The AHCI ones are ok */
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
/* ALi loses some register settings that we cannot then restore */
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
/* VIA comes back fine but we need to keep it alive or ACPI GTM failures
occur when mode detecting */
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
/* This was originally an Alpha specific thing, but it really fits here.
* The i82375 PCI/EISA bridge appears as non-classified. Fix that.
@@ -1873,8 +1815,7 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
case PCI_DEVICE_ID_NETMOS_9745:
case PCI_DEVICE_ID_NETMOS_9845:
case PCI_DEVICE_ID_NETMOS_9855:
- if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
- num_parallel) {
+ if (num_parallel) {
dev_info(&dev->dev, "Netmos %04x (%u parallel, "
"%u serial); changing class SERIAL to OTHER "
"(use parport_serial)\n",
@@ -1884,7 +1825,8 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
}
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos);
static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
{
@@ -1952,7 +1894,8 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
iounmap(csr);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+ PCI_CLASS_NETWORK_ETHERNET, 8, quirk_e100_interrupt);
/*
* The 82575 and 82598 may experience data corruption issues when transitioning
@@ -2834,12 +2777,11 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors);
static void __devinit fixup_ti816x_class(struct pci_dev* dev)
{
/* TI 816x devices do not have class code set when in PCIe boot mode */
- if (dev->class == PCI_CLASS_NOT_DEFINED) {
- dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n");
- dev->class = PCI_CLASS_MULTIMEDIA_VIDEO;
- }
+ dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n");
+ dev->class = PCI_CLASS_MULTIMEDIA_VIDEO;
}
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_TI, 0xb800, fixup_ti816x_class);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_TI, 0xb800,
+ PCI_CLASS_NOT_DEFINED, 0, fixup_ti816x_class);
/* Some PCIe devices do not work reliably with the claimed maximum
* payload size supported.
@@ -2924,17 +2866,73 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f8, quirk_intel_mc_errata);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
+
+static void do_one_fixup_debug(void (*fn)(struct pci_dev *dev), struct pci_dev *dev)
+{
+ ktime_t calltime, delta, rettime;
+ unsigned long long duration;
+
+ printk(KERN_DEBUG "calling %pF @ %i for %s\n",
+ fn, task_pid_nr(current), dev_name(&dev->dev));
+ calltime = ktime_get();
+ fn(dev);
+ rettime = ktime_get();
+ delta = ktime_sub(rettime, calltime);
+ duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+ printk(KERN_DEBUG "pci fixup %pF returned after %lld usecs for %s\n",
+ fn, duration, dev_name(&dev->dev));
+}
+
+/*
+ * Some BIOS implementations leave the Intel GPU interrupts enabled,
+ * even though no one is handling them (f.e. i915 driver is never loaded).
+ * Additionally the interrupt destination is not set up properly
+ * and the interrupt ends up -somewhere-.
+ *
+ * These spurious interrupts are "sticky" and the kernel disables
+ * the (shared) interrupt line after 100.000+ generated interrupts.
+ *
+ * Fix it by disabling the still enabled interrupts.
+ * This resolves crashes often seen on monitor unplug.
+ */
+#define I915_DEIER_REG 0x4400c
+static void __devinit disable_igfx_irq(struct pci_dev *dev)
+{
+ void __iomem *regs = pci_iomap(dev, 0, 0);
+ if (regs == NULL) {
+ dev_warn(&dev->dev, "igfx quirk: Can't iomap PCI device\n");
+ return;
+ }
+
+ /* Check if any interrupt line is still enabled */
+ if (readl(regs + I915_DEIER_REG) != 0) {
+ dev_warn(&dev->dev, "BIOS left Intel GPU interrupts enabled; "
+ "disabling\n");
+
+ writel(0, regs + I915_DEIER_REG);
+ }
+
+ pci_iounmap(dev, regs);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
+
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end)
{
- while (f < end) {
- if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
- (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
+ for (; f < end; f++)
+ if ((f->class == (u32) (dev->class >> f->class_shift) ||
+ f->class == (u32) PCI_ANY_ID) &&
+ (f->vendor == dev->vendor ||
+ f->vendor == (u16) PCI_ANY_ID) &&
+ (f->device == dev->device ||
+ f->device == (u16) PCI_ANY_ID)) {
dev_dbg(&dev->dev, "calling %pF\n", f->hook);
- f->hook(dev);
+ if (initcall_debug)
+ do_one_fixup_debug(f->hook, dev);
+ else
+ f->hook(dev);
}
- f++;
- }
}
extern struct pci_fixup __start_pci_fixups_early[];
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index ef8b18c48f2..fd77e2bde2e 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -79,7 +79,7 @@ EXPORT_SYMBOL(pci_remove_bus);
static void __pci_remove_behind_bridge(struct pci_dev *dev);
/**
- * pci_remove_bus_device - remove a PCI device and any children
+ * pci_stop_and_remove_bus_device - remove a PCI device and any children
* @dev: the device to remove
*
* Remove a PCI device from the device lists, informing the drivers
@@ -90,7 +90,7 @@ static void __pci_remove_behind_bridge(struct pci_dev *dev);
* device lists, remove the /proc entry, and notify userspace
* (/sbin/hotplug).
*/
-static void __pci_remove_bus_device(struct pci_dev *dev)
+void __pci_remove_bus_device(struct pci_dev *dev)
{
if (dev->subordinate) {
struct pci_bus *b = dev->subordinate;
@@ -102,7 +102,9 @@ static void __pci_remove_bus_device(struct pci_dev *dev)
pci_destroy_dev(dev);
}
-void pci_remove_bus_device(struct pci_dev *dev)
+EXPORT_SYMBOL(__pci_remove_bus_device);
+
+void pci_stop_and_remove_bus_device(struct pci_dev *dev)
{
pci_stop_bus_device(dev);
__pci_remove_bus_device(dev);
@@ -127,14 +129,15 @@ static void pci_stop_behind_bridge(struct pci_dev *dev)
}
/**
- * pci_remove_behind_bridge - remove all devices behind a PCI bridge
+ * pci_stop_and_remove_behind_bridge - stop and remove all devices behind
+ * a PCI bridge
* @dev: PCI bridge device
*
* Remove all devices on the bus, except for the parent bridge.
* This also removes any child buses, and any devices they may
* contain in a depth-first manner.
*/
-void pci_remove_behind_bridge(struct pci_dev *dev)
+void pci_stop_and_remove_behind_bridge(struct pci_dev *dev)
{
pci_stop_behind_bridge(dev);
__pci_remove_behind_bridge(dev);
@@ -144,7 +147,15 @@ static void pci_stop_bus_devices(struct pci_bus *bus)
{
struct list_head *l, *n;
- list_for_each_safe(l, n, &bus->devices) {
+ /*
+ * VFs could be removed by pci_stop_and_remove_bus_device() in the
+ * pci_stop_bus_devices() code path for PF.
+ * aka, bus->devices get updated in the process.
+ * but VFs are inserted after PFs when SRIOV is enabled for PF,
+ * We can iterate the list backwards to get prev valid PF instead
+ * of removed VF.
+ */
+ list_for_each_prev_safe(l, n, &bus->devices) {
struct pci_dev *dev = pci_dev_b(l);
pci_stop_bus_device(dev);
}
@@ -166,6 +177,6 @@ void pci_stop_bus_device(struct pci_dev *dev)
pci_stop_dev(dev);
}
-EXPORT_SYMBOL(pci_remove_bus_device);
-EXPORT_SYMBOL(pci_remove_behind_bridge);
+EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
+EXPORT_SYMBOL(pci_stop_and_remove_behind_bridge);
EXPORT_SYMBOL_GPL(pci_stop_bus_device);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 86b69f85f90..8fa2d4be88d 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -25,10 +25,13 @@
#include <linux/ioport.h>
#include <linux/cache.h>
#include <linux/slab.h>
+#include <asm-generic/pci-bridge.h>
#include "pci.h"
-struct resource_list_x {
- struct resource_list_x *next;
+unsigned int pci_flags;
+
+struct pci_dev_resource {
+ struct list_head list;
struct resource *res;
struct pci_dev *dev;
resource_size_t start;
@@ -38,21 +41,14 @@ struct resource_list_x {
unsigned long flags;
};
-#define free_list(type, head) do { \
- struct type *list, *tmp; \
- for (list = (head)->next; list;) { \
- tmp = list; \
- list = list->next; \
- kfree(tmp); \
- } \
- (head)->next = NULL; \
-} while (0)
-
-int pci_realloc_enable = 0;
-#define pci_realloc_enabled() pci_realloc_enable
-void pci_realloc(void)
+static void free_list(struct list_head *head)
{
- pci_realloc_enable = 1;
+ struct pci_dev_resource *dev_res, *tmp;
+
+ list_for_each_entry_safe(dev_res, tmp, head, list) {
+ list_del(&dev_res->list);
+ kfree(dev_res);
+ }
}
/**
@@ -64,21 +60,18 @@ void pci_realloc(void)
* @add_size: additional size to be optionally added
* to the resource
*/
-static void add_to_list(struct resource_list_x *head,
+static int add_to_list(struct list_head *head,
struct pci_dev *dev, struct resource *res,
resource_size_t add_size, resource_size_t min_align)
{
- struct resource_list_x *list = head;
- struct resource_list_x *ln = list->next;
- struct resource_list_x *tmp;
+ struct pci_dev_resource *tmp;
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
pr_warning("add_to_list: kmalloc() failed!\n");
- return;
+ return -ENOMEM;
}
- tmp->next = ln;
tmp->res = res;
tmp->dev = dev;
tmp->start = res->start;
@@ -86,19 +79,100 @@ static void add_to_list(struct resource_list_x *head,
tmp->flags = res->flags;
tmp->add_size = add_size;
tmp->min_align = min_align;
- list->next = tmp;
+
+ list_add(&tmp->list, head);
+
+ return 0;
}
-static void add_to_failed_list(struct resource_list_x *head,
- struct pci_dev *dev, struct resource *res)
+static void remove_from_list(struct list_head *head,
+ struct resource *res)
{
- add_to_list(head, dev, res,
- 0 /* dont care */,
- 0 /* dont care */);
+ struct pci_dev_resource *dev_res, *tmp;
+
+ list_for_each_entry_safe(dev_res, tmp, head, list) {
+ if (dev_res->res == res) {
+ list_del(&dev_res->list);
+ kfree(dev_res);
+ break;
+ }
+ }
+}
+
+static resource_size_t get_res_add_size(struct list_head *head,
+ struct resource *res)
+{
+ struct pci_dev_resource *dev_res;
+
+ list_for_each_entry(dev_res, head, list) {
+ if (dev_res->res == res) {
+ int idx = res - &dev_res->dev->resource[0];
+
+ dev_printk(KERN_DEBUG, &dev_res->dev->dev,
+ "res[%d]=%pR get_res_add_size add_size %llx\n",
+ idx, dev_res->res,
+ (unsigned long long)dev_res->add_size);
+
+ return dev_res->add_size;
+ }
+ }
+
+ return 0;
+}
+
+/* Sort resources by alignment */
+static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *r;
+ struct pci_dev_resource *dev_res, *tmp;
+ resource_size_t r_align;
+ struct list_head *n;
+
+ r = &dev->resource[i];
+
+ if (r->flags & IORESOURCE_PCI_FIXED)
+ continue;
+
+ if (!(r->flags) || r->parent)
+ continue;
+
+ r_align = pci_resource_alignment(dev, r);
+ if (!r_align) {
+ dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n",
+ i, r);
+ continue;
+ }
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ panic("pdev_sort_resources(): "
+ "kmalloc() failed!\n");
+ tmp->res = r;
+ tmp->dev = dev;
+
+ /* fallback is smallest one or list is empty*/
+ n = head;
+ list_for_each_entry(dev_res, head, list) {
+ resource_size_t align;
+
+ align = pci_resource_alignment(dev_res->dev,
+ dev_res->res);
+
+ if (r_align > align) {
+ n = &dev_res->list;
+ break;
+ }
+ }
+ /* Insert it just before n*/
+ list_add_tail(&tmp->list, n);
+ }
}
static void __dev_sort_resources(struct pci_dev *dev,
- struct resource_list *head)
+ struct list_head *head)
{
u16 class = dev->class >> 8;
@@ -136,49 +210,54 @@ static inline void reset_resource(struct resource *res)
* additional resources for the element, provided the element
* is in the head list.
*/
-static void reassign_resources_sorted(struct resource_list_x *realloc_head,
- struct resource_list *head)
+static void reassign_resources_sorted(struct list_head *realloc_head,
+ struct list_head *head)
{
struct resource *res;
- struct resource_list_x *list, *tmp, *prev;
- struct resource_list *hlist;
+ struct pci_dev_resource *add_res, *tmp;
+ struct pci_dev_resource *dev_res;
resource_size_t add_size;
int idx;
- prev = realloc_head;
- for (list = realloc_head->next; list;) {
- res = list->res;
+ list_for_each_entry_safe(add_res, tmp, realloc_head, list) {
+ bool found_match = false;
+
+ res = add_res->res;
/* skip resource that has been reset */
if (!res->flags)
goto out;
/* skip this resource if not found in head list */
- for (hlist = head->next; hlist && hlist->res != res;
- hlist = hlist->next);
- if (!hlist) { /* just skip */
- prev = list;
- list = list->next;
- continue;
+ list_for_each_entry(dev_res, head, list) {
+ if (dev_res->res == res) {
+ found_match = true;
+ break;
+ }
}
+ if (!found_match)/* just skip */
+ continue;
- idx = res - &list->dev->resource[0];
- add_size=list->add_size;
+ idx = res - &add_res->dev->resource[0];
+ add_size = add_res->add_size;
if (!resource_size(res)) {
- res->start = list->start;
+ res->start = add_res->start;
res->end = res->start + add_size - 1;
- if(pci_assign_resource(list->dev, idx))
+ if (pci_assign_resource(add_res->dev, idx))
reset_resource(res);
} else {
- resource_size_t align = list->min_align;
- res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
- if (pci_reassign_resource(list->dev, idx, add_size, align))
- dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n",
- res);
+ resource_size_t align = add_res->min_align;
+ res->flags |= add_res->flags &
+ (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
+ if (pci_reassign_resource(add_res->dev, idx,
+ add_size, align))
+ dev_printk(KERN_DEBUG, &add_res->dev->dev,
+ "failed to add %llx res[%d]=%pR\n",
+ (unsigned long long)add_size,
+ idx, res);
}
out:
- tmp = list;
- prev->next = list = list->next;
- kfree(tmp);
+ list_del(&add_res->list);
+ kfree(add_res);
}
}
@@ -192,35 +271,99 @@ out:
* Satisfy resource requests of each element in the list. Add
* requests that could not satisfied to the failed_list.
*/
-static void assign_requested_resources_sorted(struct resource_list *head,
- struct resource_list_x *fail_head)
+static void assign_requested_resources_sorted(struct list_head *head,
+ struct list_head *fail_head)
{
struct resource *res;
- struct resource_list *list;
+ struct pci_dev_resource *dev_res;
int idx;
- for (list = head->next; list; list = list->next) {
- res = list->res;
- idx = res - &list->dev->resource[0];
- if (resource_size(res) && pci_assign_resource(list->dev, idx)) {
- if (fail_head && !pci_is_root_bus(list->dev->bus)) {
+ list_for_each_entry(dev_res, head, list) {
+ res = dev_res->res;
+ idx = res - &dev_res->dev->resource[0];
+ if (resource_size(res) &&
+ pci_assign_resource(dev_res->dev, idx)) {
+ if (fail_head && !pci_is_root_bus(dev_res->dev->bus)) {
/*
* if the failed res is for ROM BAR, and it will
* be enabled later, don't add it to the list
*/
if (!((idx == PCI_ROM_RESOURCE) &&
(!(res->flags & IORESOURCE_ROM_ENABLE))))
- add_to_failed_list(fail_head, list->dev, res);
+ add_to_list(fail_head,
+ dev_res->dev, res,
+ 0 /* dont care */,
+ 0 /* dont care */);
}
reset_resource(res);
}
}
}
-static void __assign_resources_sorted(struct resource_list *head,
- struct resource_list_x *realloc_head,
- struct resource_list_x *fail_head)
+static void __assign_resources_sorted(struct list_head *head,
+ struct list_head *realloc_head,
+ struct list_head *fail_head)
{
+ /*
+ * Should not assign requested resources at first.
+ * they could be adjacent, so later reassign can not reallocate
+ * them one by one in parent resource window.
+ * Try to assign requested + add_size at begining
+ * if could do that, could get out early.
+ * if could not do that, we still try to assign requested at first,
+ * then try to reassign add_size for some resources.
+ */
+ LIST_HEAD(save_head);
+ LIST_HEAD(local_fail_head);
+ struct pci_dev_resource *save_res;
+ struct pci_dev_resource *dev_res;
+
+ /* Check if optional add_size is there */
+ if (!realloc_head || list_empty(realloc_head))
+ goto requested_and_reassign;
+
+ /* Save original start, end, flags etc at first */
+ list_for_each_entry(dev_res, head, list) {
+ if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) {
+ free_list(&save_head);
+ goto requested_and_reassign;
+ }
+ }
+
+ /* Update res in head list with add_size in realloc_head list */
+ list_for_each_entry(dev_res, head, list)
+ dev_res->res->end += get_res_add_size(realloc_head,
+ dev_res->res);
+
+ /* Try updated head list with add_size added */
+ assign_requested_resources_sorted(head, &local_fail_head);
+
+ /* all assigned with add_size ? */
+ if (list_empty(&local_fail_head)) {
+ /* Remove head list from realloc_head list */
+ list_for_each_entry(dev_res, head, list)
+ remove_from_list(realloc_head, dev_res->res);
+ free_list(&save_head);
+ free_list(head);
+ return;
+ }
+
+ free_list(&local_fail_head);
+ /* Release assigned resource */
+ list_for_each_entry(dev_res, head, list)
+ if (dev_res->res->parent)
+ release_resource(dev_res->res);
+ /* Restore start/end/flags from saved list */
+ list_for_each_entry(save_res, &save_head, list) {
+ struct resource *res = save_res->res;
+
+ res->start = save_res->start;
+ res->end = save_res->end;
+ res->flags = save_res->flags;
+ }
+ free_list(&save_head);
+
+requested_and_reassign:
/* Satisfy the must-have resource requests */
assign_requested_resources_sorted(head, fail_head);
@@ -228,28 +371,27 @@ static void __assign_resources_sorted(struct resource_list *head,
requests */
if (realloc_head)
reassign_resources_sorted(realloc_head, head);
- free_list(resource_list, head);
+ free_list(head);
}
static void pdev_assign_resources_sorted(struct pci_dev *dev,
- struct resource_list_x *fail_head)
+ struct list_head *add_head,
+ struct list_head *fail_head)
{
- struct resource_list head;
+ LIST_HEAD(head);
- head.next = NULL;
__dev_sort_resources(dev, &head);
- __assign_resources_sorted(&head, NULL, fail_head);
+ __assign_resources_sorted(&head, add_head, fail_head);
}
static void pbus_assign_resources_sorted(const struct pci_bus *bus,
- struct resource_list_x *realloc_head,
- struct resource_list_x *fail_head)
+ struct list_head *realloc_head,
+ struct list_head *fail_head)
{
struct pci_dev *dev;
- struct resource_list head;
+ LIST_HEAD(head);
- head.next = NULL;
list_for_each_entry(dev, &bus->devices, bus_list)
__dev_sort_resources(dev, &head);
@@ -548,20 +690,6 @@ static resource_size_t calculate_memsize(resource_size_t size,
return size;
}
-static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
- struct resource *res)
-{
- struct resource_list_x *list;
-
- /* check if it is in realloc_head list */
- for (list = realloc_head->next; list && list->res != res;
- list = list->next);
- if (list)
- return list->add_size;
-
- return 0;
-}
-
/**
* pbus_size_io() - size the io window of a given bus
*
@@ -576,7 +704,7 @@ static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
* We must be careful with the ISA aliasing though.
*/
static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
- resource_size_t add_size, struct resource_list_x *realloc_head)
+ resource_size_t add_size, struct list_head *realloc_head)
{
struct pci_dev *dev;
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
@@ -612,7 +740,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
if (children_add_size > add_size)
add_size = children_add_size;
size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
- calculate_iosize(size, min_size+add_size, size1,
+ calculate_iosize(size, min_size, add_size + size1,
resource_size(b_res), 4096);
if (!size0 && !size1) {
if (b_res->start || b_res->end)
@@ -626,8 +754,12 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
b_res->start = 4096;
b_res->end = b_res->start + size0 - 1;
b_res->flags |= IORESOURCE_STARTALIGN;
- if (size1 > size0 && realloc_head)
+ if (size1 > size0 && realloc_head) {
add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
+ dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
+ "%pR to [bus %02x-%02x] add_size %lx\n", b_res,
+ bus->secondary, bus->subordinate, size1-size0);
+ }
}
/**
@@ -644,7 +776,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
unsigned long type, resource_size_t min_size,
resource_size_t add_size,
- struct resource_list_x *realloc_head)
+ struct list_head *realloc_head)
{
struct pci_dev *dev;
resource_size_t min_align, align, size, size0, size1;
@@ -726,7 +858,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
if (children_add_size > add_size)
add_size = children_add_size;
size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
- calculate_memsize(size, min_size+add_size, 0,
+ calculate_memsize(size, min_size, add_size,
resource_size(b_res), min_align);
if (!size0 && !size1) {
if (b_res->start || b_res->end)
@@ -739,8 +871,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
b_res->start = min_align;
b_res->end = size0 + min_align - 1;
b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
- if (size1 > size0 && realloc_head)
+ if (size1 > size0 && realloc_head) {
add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
+ dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
+ "%pR to [bus %02x-%02x] add_size %llx\n", b_res,
+ bus->secondary, bus->subordinate, (unsigned long long)size1-size0);
+ }
return 1;
}
@@ -754,25 +890,48 @@ unsigned long pci_cardbus_resource_alignment(struct resource *res)
}
static void pci_bus_size_cardbus(struct pci_bus *bus,
- struct resource_list_x *realloc_head)
+ struct list_head *realloc_head)
{
struct pci_dev *bridge = bus->self;
struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
+ resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
u16 ctrl;
+ if (b_res[0].parent)
+ goto handle_b_res_1;
/*
* Reserve some resources for CardBus. We reserve
* a fixed amount of bus space for CardBus bridges.
*/
- b_res[0].start = 0;
- b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
- if (realloc_head)
- add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, 0 /* dont care */);
+ b_res[0].start = pci_cardbus_io_size;
+ b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1;
+ b_res[0].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+ if (realloc_head) {
+ b_res[0].end -= pci_cardbus_io_size;
+ add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
+ pci_cardbus_io_size);
+ }
- b_res[1].start = 0;
- b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
- if (realloc_head)
- add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, 0 /* dont care */);
+handle_b_res_1:
+ if (b_res[1].parent)
+ goto handle_b_res_2;
+ b_res[1].start = pci_cardbus_io_size;
+ b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1;
+ b_res[1].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+ if (realloc_head) {
+ b_res[1].end -= pci_cardbus_io_size;
+ add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size,
+ pci_cardbus_io_size);
+ }
+
+handle_b_res_2:
+ /* MEM1 must not be pref mmio */
+ pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+ if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
+ ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
+ pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
+ pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+ }
/*
* Check whether prefetchable memory is supported
@@ -785,38 +944,46 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
}
+ if (b_res[2].parent)
+ goto handle_b_res_3;
/*
* If we have prefetchable memory support, allocate
* two regions. Otherwise, allocate one region of
* twice the size.
*/
if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
- b_res[2].start = 0;
- b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN;
- if (realloc_head)
- add_to_list(realloc_head, bridge, b_res+2, pci_cardbus_mem_size, 0 /* dont care */);
-
- b_res[3].start = 0;
- b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
- if (realloc_head)
- add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size, 0 /* dont care */);
- } else {
- b_res[3].start = 0;
- b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
- if (realloc_head)
- add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size * 2, 0 /* dont care */);
+ b_res[2].start = pci_cardbus_mem_size;
+ b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1;
+ b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
+ IORESOURCE_STARTALIGN;
+ if (realloc_head) {
+ b_res[2].end -= pci_cardbus_mem_size;
+ add_to_list(realloc_head, bridge, b_res+2,
+ pci_cardbus_mem_size, pci_cardbus_mem_size);
+ }
+
+ /* reduce that to half */
+ b_res_3_size = pci_cardbus_mem_size;
+ }
+
+handle_b_res_3:
+ if (b_res[3].parent)
+ goto handle_done;
+ b_res[3].start = pci_cardbus_mem_size;
+ b_res[3].end = b_res[3].start + b_res_3_size - 1;
+ b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
+ if (realloc_head) {
+ b_res[3].end -= b_res_3_size;
+ add_to_list(realloc_head, bridge, b_res+3, b_res_3_size,
+ pci_cardbus_mem_size);
}
- /* set the size of the resource to zero, so that the resource does not
- * get assigned during required-resource allocation cycle but gets assigned
- * during the optional-resource allocation cycle.
- */
- b_res[0].start = b_res[1].start = b_res[2].start = b_res[3].start = 1;
- b_res[0].end = b_res[1].end = b_res[2].end = b_res[3].end = 0;
+handle_done:
+ ;
}
void __ref __pci_bus_size_bridges(struct pci_bus *bus,
- struct resource_list_x *realloc_head)
+ struct list_head *realloc_head)
{
struct pci_dev *dev;
unsigned long mask, prefmask;
@@ -858,7 +1025,8 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
* Follow thru
*/
default:
- pbus_size_io(bus, 0, additional_io_size, realloc_head);
+ pbus_size_io(bus, realloc_head ? 0 : additional_io_size,
+ additional_io_size, realloc_head);
/* If the bridge supports prefetchable range, size it
separately. If it doesn't, or its prefetchable window
has already been allocated by arch code, try
@@ -866,11 +1034,15 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
resources. */
mask = IORESOURCE_MEM;
prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
- if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head))
+ if (pbus_size_mem(bus, prefmask, prefmask,
+ realloc_head ? 0 : additional_mem_size,
+ additional_mem_size, realloc_head))
mask = prefmask; /* Success, size non-prefetch only. */
else
additional_mem_size += additional_mem_size;
- pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head);
+ pbus_size_mem(bus, mask, IORESOURCE_MEM,
+ realloc_head ? 0 : additional_mem_size,
+ additional_mem_size, realloc_head);
break;
}
}
@@ -882,8 +1054,8 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
EXPORT_SYMBOL(pci_bus_size_bridges);
static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
- struct resource_list_x *realloc_head,
- struct resource_list_x *fail_head)
+ struct list_head *realloc_head,
+ struct list_head *fail_head)
{
struct pci_bus *b;
struct pci_dev *dev;
@@ -922,17 +1094,19 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
EXPORT_SYMBOL(pci_bus_assign_resources);
static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
- struct resource_list_x *fail_head)
+ struct list_head *add_head,
+ struct list_head *fail_head)
{
struct pci_bus *b;
- pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head);
+ pdev_assign_resources_sorted((struct pci_dev *)bridge,
+ add_head, fail_head);
b = bridge->subordinate;
if (!b)
return;
- __pci_bus_assign_resources(b, NULL, fail_head);
+ __pci_bus_assign_resources(b, add_head, fail_head);
switch (bridge->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
@@ -1095,6 +1269,58 @@ static int __init pci_get_max_depth(void)
return depth;
}
+/*
+ * -1: undefined, will auto detect later
+ * 0: disabled by user
+ * 1: disabled by auto detect
+ * 2: enabled by user
+ * 3: enabled by auto detect
+ */
+enum enable_type {
+ undefined = -1,
+ user_disabled,
+ auto_disabled,
+ user_enabled,
+ auto_enabled,
+};
+
+static enum enable_type pci_realloc_enable __initdata = undefined;
+void __init pci_realloc_get_opt(char *str)
+{
+ if (!strncmp(str, "off", 3))
+ pci_realloc_enable = user_disabled;
+ else if (!strncmp(str, "on", 2))
+ pci_realloc_enable = user_enabled;
+}
+static bool __init pci_realloc_enabled(void)
+{
+ return pci_realloc_enable >= user_enabled;
+}
+
+static void __init pci_realloc_detect(void)
+{
+#if defined(CONFIG_PCI_IOV) && defined(CONFIG_PCI_REALLOC_ENABLE_AUTO)
+ struct pci_dev *dev = NULL;
+
+ if (pci_realloc_enable != undefined)
+ return;
+
+ for_each_pci_dev(dev) {
+ int i;
+
+ for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
+ struct resource *r = &dev->resource[i];
+
+ /* Not assigned, or rejected by kernel ? */
+ if (r->flags && !r->start) {
+ pci_realloc_enable = auto_enabled;
+
+ return;
+ }
+ }
+ }
+#endif
+}
/*
* first try will not touch pci bridge res
@@ -1105,59 +1331,57 @@ void __init
pci_assign_unassigned_resources(void)
{
struct pci_bus *bus;
- struct resource_list_x realloc_list; /* list of resources that
+ LIST_HEAD(realloc_head); /* list of resources that
want additional resources */
+ struct list_head *add_list = NULL;
int tried_times = 0;
enum release_type rel_type = leaf_only;
- struct resource_list_x head, *list;
+ LIST_HEAD(fail_head);
+ struct pci_dev_resource *fail_res;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH;
- unsigned long failed_type;
- int max_depth = pci_get_max_depth();
- int pci_try_num;
-
+ int pci_try_num = 1;
- head.next = NULL;
- realloc_list.next = NULL;
+ /* don't realloc if asked to do so */
+ pci_realloc_detect();
+ if (pci_realloc_enabled()) {
+ int max_depth = pci_get_max_depth();
- pci_try_num = max_depth + 1;
- printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
- max_depth, pci_try_num);
+ pci_try_num = max_depth + 1;
+ printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
+ max_depth, pci_try_num);
+ }
again:
+ /*
+ * last try will use add_list, otherwise will try good to have as
+ * must have, so can realloc parent bridge resource
+ */
+ if (tried_times + 1 == pci_try_num)
+ add_list = &realloc_head;
/* Depth first, calculate sizes and alignments of all
subordinate buses. */
list_for_each_entry(bus, &pci_root_buses, node)
- __pci_bus_size_bridges(bus, &realloc_list);
+ __pci_bus_size_bridges(bus, add_list);
/* Depth last, allocate resources and update the hardware. */
list_for_each_entry(bus, &pci_root_buses, node)
- __pci_bus_assign_resources(bus, &realloc_list, &head);
- BUG_ON(realloc_list.next);
+ __pci_bus_assign_resources(bus, add_list, &fail_head);
+ if (add_list)
+ BUG_ON(!list_empty(add_list));
tried_times++;
/* any device complain? */
- if (!head.next)
+ if (list_empty(&fail_head))
goto enable_and_dump;
- /* don't realloc if asked to do so */
- if (!pci_realloc_enabled()) {
- free_list(resource_list_x, &head);
- goto enable_and_dump;
- }
+ if (tried_times >= pci_try_num) {
+ if (pci_realloc_enable == undefined)
+ printk(KERN_INFO "Some PCI device resources are unassigned, try booting with pci=realloc\n");
+ else if (pci_realloc_enable == auto_enabled)
+ printk(KERN_INFO "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
- failed_type = 0;
- for (list = head.next; list;) {
- failed_type |= list->flags;
- list = list->next;
- }
- /*
- * io port are tight, don't try extra
- * or if reach the limit, don't want to try more
- */
- failed_type &= type_mask;
- if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
- free_list(resource_list_x, &head);
+ free_list(&fail_head);
goto enable_and_dump;
}
@@ -1172,25 +1396,23 @@ again:
* Try to release leaf bridge's resources that doesn't fit resource of
* child device under that bridge
*/
- for (list = head.next; list;) {
- bus = list->dev->bus;
- pci_bus_release_bridge_resources(bus, list->flags & type_mask,
- rel_type);
- list = list->next;
+ list_for_each_entry(fail_res, &fail_head, list) {
+ bus = fail_res->dev->bus;
+ pci_bus_release_bridge_resources(bus,
+ fail_res->flags & type_mask,
+ rel_type);
}
/* restore size and flags */
- for (list = head.next; list;) {
- struct resource *res = list->res;
+ list_for_each_entry(fail_res, &fail_head, list) {
+ struct resource *res = fail_res->res;
- res->start = list->start;
- res->end = list->end;
- res->flags = list->flags;
- if (list->dev->subordinate)
+ res->start = fail_res->start;
+ res->end = fail_res->end;
+ res->flags = fail_res->flags;
+ if (fail_res->dev->subordinate)
res->flags = 0;
-
- list = list->next;
}
- free_list(resource_list_x, &head);
+ free_list(&fail_head);
goto again;
@@ -1207,26 +1429,27 @@ enable_and_dump:
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
{
struct pci_bus *parent = bridge->subordinate;
+ LIST_HEAD(add_list); /* list of resources that
+ want additional resources */
int tried_times = 0;
- struct resource_list_x head, *list;
+ LIST_HEAD(fail_head);
+ struct pci_dev_resource *fail_res;
int retval;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH;
- head.next = NULL;
-
again:
- pci_bus_size_bridges(parent);
- __pci_bridge_assign_resources(bridge, &head);
-
+ __pci_bus_size_bridges(parent, &add_list);
+ __pci_bridge_assign_resources(bridge, &add_list, &fail_head);
+ BUG_ON(!list_empty(&add_list));
tried_times++;
- if (!head.next)
+ if (list_empty(&fail_head))
goto enable_all;
if (tried_times >= 2) {
/* still fail, don't need to try more */
- free_list(resource_list_x, &head);
+ free_list(&fail_head);
goto enable_all;
}
@@ -1237,27 +1460,24 @@ again:
* Try to release leaf bridge's resources that doesn't fit resource of
* child device under that bridge
*/
- for (list = head.next; list;) {
- struct pci_bus *bus = list->dev->bus;
- unsigned long flags = list->flags;
+ list_for_each_entry(fail_res, &fail_head, list) {
+ struct pci_bus *bus = fail_res->dev->bus;
+ unsigned long flags = fail_res->flags;
pci_bus_release_bridge_resources(bus, flags & type_mask,
whole_subtree);
- list = list->next;
}
/* restore size and flags */
- for (list = head.next; list;) {
- struct resource *res = list->res;
+ list_for_each_entry(fail_res, &fail_head, list) {
+ struct resource *res = fail_res->res;
- res->start = list->start;
- res->end = list->end;
- res->flags = list->flags;
- if (list->dev->subordinate)
+ res->start = fail_res->start;
+ res->end = fail_res->end;
+ res->flags = fail_res->flags;
+ if (fail_res->dev->subordinate)
res->flags = 0;
-
- list = list->next;
}
- free_list(resource_list_x, &head);
+ free_list(&fail_head);
goto again;
@@ -1267,3 +1487,41 @@ enable_all:
pci_enable_bridges(parent);
}
EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
+
+#ifdef CONFIG_HOTPLUG
+/**
+ * pci_rescan_bus - scan a PCI bus for devices.
+ * @bus: PCI bus to scan
+ *
+ * Scan a PCI bus and child buses for new devices, adds them,
+ * and enables them.
+ *
+ * Returns the max number of subordinate bus discovered.
+ */
+unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+{
+ unsigned int max;
+ struct pci_dev *dev;
+ LIST_HEAD(add_list); /* list of resources that
+ want additional resources */
+
+ max = pci_scan_child_bus(bus);
+
+ down_read(&pci_bus_sem);
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+ if (dev->subordinate)
+ __pci_bus_size_bridges(dev->subordinate,
+ &add_list);
+ up_read(&pci_bus_sem);
+ __pci_bus_assign_resources(bus, &add_list, NULL);
+ BUG_ON(!list_empty(&add_list));
+
+ pci_enable_bridges(bus);
+ pci_bus_add_devices(bus);
+
+ return max;
+}
+EXPORT_SYMBOL_GPL(pci_rescan_bus);
+#endif
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index b66bfdbd21f..eea85dafc76 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -114,7 +114,6 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
}
EXPORT_SYMBOL(pci_claim_resource);
-#ifdef CONFIG_PCI_QUIRKS
void pci_disable_bridge_window(struct pci_dev *dev)
{
dev_info(&dev->dev, "disabling bridge mem windows\n");
@@ -127,9 +126,6 @@ void pci_disable_bridge_window(struct pci_dev *dev)
pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
}
-#endif /* CONFIG_PCI_QUIRKS */
-
-
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
int resno, resource_size_t size, resource_size_t align)
@@ -158,22 +154,44 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
return ret;
}
+/*
+ * Generic function that returns a value indicating that the device's
+ * original BIOS BAR address was not saved and so is not available for
+ * reinstatement.
+ *
+ * Can be over-ridden by architecture specific code that implements
+ * reinstatement functionality rather than leaving it disabled when
+ * normal allocation attempts fail.
+ */
+resource_size_t __weak pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
+{
+ return 0;
+}
+
static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
int resno, resource_size_t size)
{
struct resource *root, *conflict;
- resource_size_t start, end;
+ resource_size_t fw_addr, start, end;
int ret = 0;
- if (res->flags & IORESOURCE_IO)
- root = &ioport_resource;
- else
- root = &iomem_resource;
+ fw_addr = pcibios_retrieve_fw_addr(dev, resno);
+ if (!fw_addr)
+ return 1;
start = res->start;
end = res->end;
- res->start = dev->fw_addr[resno];
+ res->start = fw_addr;
res->end = res->start + size - 1;
+
+ root = pci_find_parent_resource(dev, res);
+ if (!root) {
+ if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+ else
+ root = &iomem_resource;
+ }
+
dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
resno, res);
conflict = request_resource_conflict(root, res);
@@ -228,16 +246,17 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
int ret;
if (!res->parent) {
- dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR "
+ dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR "
"\n", resno, res);
return -EINVAL;
}
- new_size = resource_size(res) + addsize + min_align;
+ /* already aligned with min_align */
+ new_size = resource_size(res) + addsize;
ret = _pci_assign_resource(dev, resno, new_size, min_align);
if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN;
- dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
+ dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, resno);
}
@@ -267,7 +286,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
* where firmware left it. That at least has a chance of
* working, which is better than just leaving it disabled.
*/
- if (ret < 0 && dev->fw_addr[resno])
+ if (ret < 0)
ret = pci_revert_fw_address(res, dev, resno, size);
if (!ret) {
@@ -279,53 +298,6 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
return ret;
}
-
-/* Sort resources by alignment */
-void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
-{
- int i;
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *r;
- struct resource_list *list, *tmp;
- resource_size_t r_align;
-
- r = &dev->resource[i];
-
- if (r->flags & IORESOURCE_PCI_FIXED)
- continue;
-
- if (!(r->flags) || r->parent)
- continue;
-
- r_align = pci_resource_alignment(dev, r);
- if (!r_align) {
- dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n",
- i, r);
- continue;
- }
- for (list = head; ; list = list->next) {
- resource_size_t align = 0;
- struct resource_list *ln = list->next;
-
- if (ln)
- align = pci_resource_alignment(ln->dev, ln->res);
-
- if (r_align > align) {
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
- if (!tmp)
- panic("pdev_sort_resources(): "
- "kmalloc() failed!\n");
- tmp->next = ln;
- tmp->res = r;
- tmp->dev = dev;
- list->next = tmp;
- break;
- }
- }
- }
-}
-
int pci_enable_resources(struct pci_dev *dev, int mask)
{
u16 cmd, old_cmd;
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 40109011092..fd00ff02ab4 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -544,7 +544,7 @@ static void free_root_bus_devs(struct pci_bus *bus)
dev = container_of(bus->devices.next, struct pci_dev,
bus_list);
dev_dbg(&dev->dev, "removing device\n");
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
}
}
@@ -1044,7 +1044,7 @@ static int pcifront_detach_devices(struct pcifront_device *pdev)
domain, bus, slot, func);
continue;
}
- pci_remove_bus_device(pci_dev);
+ pci_stop_and_remove_bus_device(pci_dev);
pci_dev_put(pci_dev);
dev_dbg(&pdev->xdev->dev,
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 9a58862f140..6e75153c5b4 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -108,5 +108,5 @@ void cb_free(struct pcmcia_socket *s)
struct pci_dev *bridge = s->cb_dev;
if (bridge)
- pci_remove_behind_bridge(bridge);
+ pci_stop_and_remove_behind_bridge(bridge);
}
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 72d731c21d4..9929246895d 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -571,7 +571,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
} else {
dev = pci_get_slot(bus, 0);
if (dev) {
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
}
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index ea44abd8df4..d9a9e2bedb3 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -646,7 +646,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
} else {
dev = pci_get_slot(bus, 0);
if (dev) {
- pci_remove_bus_device(dev);
+ pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 82fa6ce481f..5e69f468535 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -132,7 +132,7 @@ static int mpt2sas_remove_dead_ioc_func(void *arg)
pdev = ioc->pdev;
if ((pdev == NULL))
return -1;
- pci_remove_bus_device(pdev);
+ pci_stop_and_remove_bus_device(pdev);
return 0;
}
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 7732d69e49e..11de5f1be98 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -893,4 +893,5 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
quirk_usb_handoff_xhci(pdev);
pci_disable_device(pdev);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
diff --git a/include/asm-generic/pci-bridge.h b/include/asm-generic/pci-bridge.h
index 4a5aca2a2c9..a5b5d5a89a4 100644
--- a/include/asm-generic/pci-bridge.h
+++ b/include/asm-generic/pci-bridge.h
@@ -45,6 +45,11 @@ static inline void pci_add_flags(int flags)
pci_flags |= flags;
}
+static inline void pci_clear_flags(int flags)
+{
+ pci_flags &= ~flags;
+}
+
static inline int pci_has_flag(int flag)
{
return pci_flags & flag;
@@ -52,6 +57,7 @@ static inline int pci_has_flag(int flag)
#else
static inline void pci_set_flags(int flags) { }
static inline void pci_add_flags(int flags) { }
+static inline void pci_clear_flags(int flags) { }
static inline int pci_has_flag(int flag)
{
return 0;
diff --git a/include/asm-generic/pci.h b/include/asm-generic/pci.h
index 26373cff454..e80a0495e5b 100644
--- a/include/asm-generic/pci.h
+++ b/include/asm-generic/pci.h
@@ -6,30 +6,6 @@
#ifndef _ASM_GENERIC_PCI_H
#define _ASM_GENERIC_PCI_H
-/**
- * pcibios_resource_to_bus - convert resource to PCI bus address
- * @dev: device which owns this resource
- * @region: converted bus-centric region (start,end)
- * @res: resource to convert
- *
- * Convert a resource to a PCI device bus address or bus window.
- */
-static inline void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- region->start = res->start;
- region->end = res->end;
-}
-
-static inline void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- res->start = region->start;
- res->end = region->end;
-}
-
static inline struct resource *
pcibios_select_root(struct pci_dev *pdev, struct resource *res)
{
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 9d57a71775b..e885ba23de7 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -23,12 +23,6 @@ struct resource {
struct resource *parent, *sibling, *child;
};
-struct resource_list {
- struct resource_list *next;
- struct resource *res;
- struct pci_dev *dev;
-};
-
/*
* IO resources have these defined flags.
*/
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 900da5db60e..e444f5b4911 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -299,7 +299,6 @@ struct pci_dev {
*/
unsigned int irq;
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
- resource_size_t fw_addr[DEVICE_COUNT_RESOURCE]; /* FW-assigned addr */
/* These fields are used by common fixups */
unsigned int transparent:1; /* Transparent PCI bridge */
@@ -369,24 +368,17 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
return (pdev->error_state != pci_channel_io_normal);
}
-static inline struct pci_cap_saved_state *pci_find_saved_cap(
- struct pci_dev *pci_dev, char cap)
-{
- struct pci_cap_saved_state *tmp;
- struct hlist_node *pos;
-
- hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) {
- if (tmp->cap.cap_nr == cap)
- return tmp;
- }
- return NULL;
-}
+struct pci_host_bridge_window {
+ struct list_head list;
+ struct resource *res; /* host bridge aperture (CPU address) */
+ resource_size_t offset; /* bus address + offset = CPU address */
+};
-static inline void pci_add_saved_cap(struct pci_dev *pci_dev,
- struct pci_cap_saved_state *new_cap)
-{
- hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
-}
+struct pci_host_bridge {
+ struct list_head list;
+ struct pci_bus *bus; /* root bus */
+ struct list_head windows; /* pci_host_bridge_windows */
+};
/*
* The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond
@@ -656,6 +648,10 @@ void pci_fixup_cardbus(struct pci_bus *);
/* Generic PCI functions used internally */
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+ struct resource *res);
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+ struct pci_bus_region *region);
void pcibios_scan_specific_bus(int busn);
extern struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
@@ -690,7 +686,8 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp);
extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
extern void pci_dev_put(struct pci_dev *dev);
extern void pci_remove_bus(struct pci_bus *b);
-extern void pci_remove_bus_device(struct pci_dev *dev);
+extern void __pci_remove_bus_device(struct pci_dev *dev);
+extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
extern void pci_stop_bus_device(struct pci_dev *dev);
void pci_setup_cardbus(struct pci_bus *bus);
extern void pci_sort_breadthfirst(void);
@@ -883,6 +880,7 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev);
/* Functions for PCI Hotplug drivers to use */
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
#ifdef CONFIG_HOTPLUG
+unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge);
unsigned int pci_rescan_bus(struct pci_bus *bus);
#endif
@@ -892,13 +890,13 @@ ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void
int pci_vpd_truncate(struct pci_dev *dev, size_t size);
/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
+resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
void pci_bus_assign_resources(const struct pci_bus *bus);
void pci_bus_size_bridges(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
void pdev_enable_device(struct pci_dev *);
-void pdev_sort_resources(struct pci_dev *, struct resource_list *);
int pci_enable_resources(struct pci_dev *, int mask);
void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
int (*)(const struct pci_dev *, u8, u8));
@@ -915,6 +913,8 @@ void pci_release_selected_regions(struct pci_dev *, int);
/* drivers/pci/bus.c */
void pci_add_resource(struct list_head *resources, struct resource *res);
+void pci_add_resource_offset(struct list_head *resources, struct resource *res,
+ resource_size_t offset);
void pci_free_resource_list(struct list_head *resources);
void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
@@ -960,7 +960,7 @@ void pci_unregister_driver(struct pci_driver *dev);
module_driver(__pci_driver, pci_register_driver, \
pci_unregister_driver)
-void pci_remove_behind_bridge(struct pci_dev *dev);
+void pci_stop_and_remove_behind_bridge(struct pci_dev *dev);
struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
int pci_add_dynid(struct pci_driver *drv,
unsigned int vendor, unsigned int device,
@@ -1396,7 +1396,10 @@ static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
*/
struct pci_fixup {
- u16 vendor, device; /* You can use PCI_ANY_ID here of course */
+ u16 vendor; /* You can use PCI_ANY_ID here of course */
+ u16 device; /* You can use PCI_ANY_ID here of course */
+ u32 class; /* You can use PCI_ANY_ID here too */
+ unsigned int class_shift; /* should be 0, 8, 16 */
void (*hook)(struct pci_dev *dev);
};
@@ -1411,30 +1414,68 @@ enum pci_fixup_pass {
};
/* Anonymous variables would be nice... */
-#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, hook) \
- static const struct pci_fixup __pci_fixup_##name __used \
- __attribute__((__section__(#section))) = { vendor, device, hook };
+#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, class, \
+ class_shift, hook) \
+ static const struct pci_fixup const __pci_fixup_##name __used \
+ __attribute__((__section__(#section), aligned((sizeof(void *))))) \
+ = { vendor, device, class, class_shift, hook };
+
+#define DECLARE_PCI_FIXUP_CLASS_EARLY(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \
+ vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_HEADER(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header, \
+ vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_FINAL(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final, \
+ vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_ENABLE(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \
+ vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_RESUME(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume, \
+ resume##vendor##device##hook, vendor, device, class, \
+ class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume_early, \
+ resume_early##vendor##device##hook, vendor, device, \
+ class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_SUSPEND(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \
+ suspend##vendor##device##hook, vendor, device, class, \
+ class_shift, hook)
+
#define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \
- vendor##device##hook, vendor, device, hook)
+ vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
#define DECLARE_PCI_FIXUP_HEADER(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header, \
- vendor##device##hook, vendor, device, hook)
+ vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
#define DECLARE_PCI_FIXUP_FINAL(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final, \
- vendor##device##hook, vendor, device, hook)
+ vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
#define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \
- vendor##device##hook, vendor, device, hook)
+ vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
#define DECLARE_PCI_FIXUP_RESUME(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume, \
- resume##vendor##device##hook, vendor, device, hook)
+ resume##vendor##device##hook, vendor, device, \
+ PCI_ANY_ID, 0, hook)
#define DECLARE_PCI_FIXUP_RESUME_EARLY(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume_early, \
- resume_early##vendor##device##hook, vendor, device, hook)
+ resume_early##vendor##device##hook, vendor, device, \
+ PCI_ANY_ID, 0, hook)
#define DECLARE_PCI_FIXUP_SUSPEND(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \
- suspend##vendor##device##hook, vendor, device, hook)
+ suspend##vendor##device##hook, vendor, device, \
+ PCI_ANY_ID, 0, hook)
#ifdef CONFIG_PCI_QUIRKS
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index e41a10f5ae8..4b608f54341 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -391,6 +391,7 @@
#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */
+#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */
#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */
#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */
#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */