diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-11 18:50:26 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-11 18:50:26 -0800 |
commit | 7b67e751479d50b7f84d1a3cc5216eed5e534b66 (patch) | |
tree | a1a6746857cf65f04dde739fe271bf4143d55eaf | |
parent | 9f13a1fd452f11c18004ba2422a6384b424ec8a9 (diff) | |
parent | 76ccc297018d25d55b789bbd508861ef1e2cdb0c (diff) | |
download | linux-3.10-7b67e751479d50b7f84d1a3cc5216eed5e534b66.tar.gz linux-3.10-7b67e751479d50b7f84d1a3cc5216eed5e534b66.tar.bz2 linux-3.10-7b67e751479d50b7f84d1a3cc5216eed5e534b66.zip |
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci: (80 commits)
x86/PCI: Expand the x86_msi_ops to have a restore MSIs.
PCI: Increase resource array mask bit size in pcim_iomap_regions()
PCI: DEVICE_COUNT_RESOURCE should be equal to PCI_NUM_RESOURCES
PCI: pci_ids: add device ids for STA2X11 device (aka ConneXT)
PNP: work around Dell 1536/1546 BIOS MMCONFIG bug that breaks USB
x86/PCI: amd: factor out MMCONFIG discovery
PCI: Enable ATS at the device state restore
PCI: msi: fix imbalanced refcount of msi irq sysfs objects
PCI: kconfig: English typo in pci/pcie/Kconfig
PCI/PM/Runtime: make PCI traces quieter
PCI: remove pci_create_bus()
xtensa/PCI: convert to pci_scan_root_bus() for correct root bus resources
x86/PCI: convert to pci_create_root_bus() and pci_scan_root_bus()
x86/PCI: use pci_scan_bus() instead of pci_scan_bus_parented()
x86/PCI: read Broadcom CNB20LE host bridge info before PCI scan
sparc32, leon/PCI: convert to pci_scan_root_bus() for correct root bus resources
sparc/PCI: convert to pci_create_root_bus()
sh/PCI: convert to pci_scan_root_bus() for correct root bus resources
powerpc/PCI: convert to pci_create_root_bus()
powerpc/PCI: split PHB part out of pcibios_map_io_space()
...
Fix up conflicts in drivers/pci/msi.c and include/linux/pci_regs.h due
to the same patches being applied in other branches.
91 files changed, 1125 insertions, 806 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 5575759b84e..d49c2ec72d1 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -544,3 +544,15 @@ When: 3.5 Why: The iwlagn module has been renamed iwlwifi. The alias will be around for backward compatibility for several cycles and then dropped. Who: Don Fry <donald.h.fry@intel.com> + +---------------------------- + +What: pci_scan_bus_parented() +When: 3.5 +Why: The pci_scan_bus_parented() interface creates a new root bus. The + bus is created with default resources (ioport_resource and + iomem_resource) that are always wrong, so we rely on arch code to + correct them later. Callers of pci_scan_bus_parented() should + convert to using pci_scan_root_bus() so they can supply a list of + bus resources when the bus is created. +Who: Bjorn Helgaas <bhelgaas@google.com> diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index f3cae275d3f..8c723c1b086 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -281,27 +281,9 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus) void __devinit pcibios_fixup_bus(struct pci_bus *bus) { - /* Propagate hose info into the subordinate devices. */ - - struct pci_controller *hose = bus->sysdata; struct pci_dev *dev = bus->self; - if (!dev) { - /* Root bus. */ - u32 pci_mem_end; - u32 sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0; - unsigned long end; - - bus->resource[0] = hose->io_space; - bus->resource[1] = hose->mem_space; - - /* Adjust hose mem_space limit to prevent PCI allocations - in the iommu windows. */ - pci_mem_end = min((u32)__direct_map_base, sg_base) - 1; - end = hose->mem_space->start + pci_mem_end; - if (hose->mem_space->end > end) - hose->mem_space->end = end; - } else if (pci_probe_only && + if (pci_probe_only && dev && (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { pci_read_bridge_bases(bus); pcibios_fixup_device_resources(dev, bus); @@ -414,13 +396,31 @@ void __init common_init_pci(void) { struct pci_controller *hose; + struct list_head resources; struct pci_bus *bus; int next_busno; int need_domain_info = 0; + u32 pci_mem_end; + u32 sg_base; + unsigned long end; /* Scan all of the recorded PCI controllers. */ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { - bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose); + sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0; + + /* Adjust hose mem_space limit to prevent PCI allocations + in the iommu windows. */ + pci_mem_end = min((u32)__direct_map_base, sg_base) - 1; + end = hose->mem_space->start + pci_mem_end; + if (hose->mem_space->end > end) + hose->mem_space->end = end; + + INIT_LIST_HEAD(&resources); + pci_add_resource(&resources, hose->io_space); + pci_add_resource(&resources, hose->mem_space); + + bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops, + hose, &resources); hose->bus = bus; hose->need_domain_info = need_domain_info; next_busno = bus->subordinate + 1; diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c index b539ec855e1..d1bcd7b13eb 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; } - sys->resource[0] = &it8152_io; - sys->resource[1] = &it8152_mem; + pci_add_resource(&sys->resources, &it8152_io); + pci_add_resource(&sys->resources, &it8152_mem); if (platform_notify || platform_notify_remove) { printk(KERN_ERR "PCI: Can't use platform_notify\n"); @@ -327,6 +327,9 @@ err0: */ unsigned int pcibios_max_latency = 255; +/* ITE bridge requires setting latency timer to avoid early bus access + termination by PCI bus master devices +*/ void pcibios_set_master(struct pci_dev *dev) { u8 lat; @@ -352,7 +355,7 @@ void pcibios_set_master(struct pci_dev *dev) struct pci_bus * __init it8152_pci_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(nr, &it8152_ops, sys); + return pci_scan_root_bus(NULL, nr, &it8152_ops, sys, &sys->resources); } EXPORT_SYMBOL(dma_set_coherent_mask); diff --git a/arch/arm/common/via82c505.c b/arch/arm/common/via82c505.c index 8421d39109b..67dd2affc57 100644 --- a/arch/arm/common/via82c505.c +++ b/arch/arm/common/via82c505.c @@ -86,7 +86,8 @@ int __init via82c505_setup(int nr, struct pci_sys_data *sys) struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata) { if (nr == 0) - return pci_scan_bus(0, &via82c505_ops, sysdata); + return pci_scan_root_bus(NULL, 0, &via82c505_ops, sysdata, + &sysdata->resources); return NULL; } diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h index 186efd4e05c..d943b7d20f1 100644 --- a/arch/arm/include/asm/mach/pci.h +++ b/arch/arm/include/asm/mach/pci.h @@ -40,7 +40,7 @@ struct pci_sys_data { u64 mem_offset; /* bus->cpu memory mapping offset */ unsigned long io_offset; /* bus->cpu IO mapping offset */ struct pci_bus *bus; /* PCI bus */ - struct resource *resource[3]; /* Primary PCI bus resources */ + struct list_head resources; /* root bus resources (apertures) */ /* Bridge swizzling */ u8 (*swizzle)(struct pci_dev *, u8 *); /* IRQ mapping */ diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h index 2b1f245db0c..da337ba57ff 100644 --- a/arch/arm/include/asm/pci.h +++ b/arch/arm/include/asm/pci.h @@ -31,18 +31,6 @@ static inline int pci_proc_domain(struct pci_bus *bus) } #endif /* CONFIG_PCI_DOMAINS */ -#ifdef CONFIG_PCI_HOST_ITE8152 -/* ITE bridge requires setting latency timer to avoid early bus access - termination by PIC bus mater devices -*/ -extern void pcibios_set_master(struct pci_dev *dev); -#else -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} -#endif - static inline void pcibios_penalize_isa_irq(int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index b530e9116a0..f58ba358990 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -316,21 +316,6 @@ pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) } } -static void __devinit -pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root) -{ - struct pci_dev *dev = bus->self; - int i; - - if (!dev) { - /* - * Assign root bus resources. - */ - for (i = 0; i < 3; i++) - bus->resource[i] = root->resource[i]; - } -} - /* * pcibios_fixup_bus - Called after each bus is probed, * but before its children are examined. @@ -341,8 +326,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) struct pci_dev *dev; u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK; - pbus_assign_bus_resources(bus, root); - /* * Walk the devices on this bus, working out what we can * and can't support. @@ -508,12 +491,18 @@ static void __init pcibios_init_hw(struct hw_pci *hw) sys->busnr = busnr; sys->swizzle = hw->swizzle; sys->map_irq = hw->map_irq; - sys->resource[0] = &ioport_resource; - sys->resource[1] = &iomem_resource; + INIT_LIST_HEAD(&sys->resources); ret = hw->setup(nr, sys); if (ret > 0) { + if (list_empty(&sys->resources)) { + pci_add_resource(&sys->resources, + &ioport_resource); + pci_add_resource(&sys->resources, + &iomem_resource); + } + sys->bus = hw->scan(nr, sys); if (!sys->bus) @@ -571,6 +560,13 @@ void __init pci_common_init(struct hw_pci *hw) } } +#ifndef CONFIG_PCI_HOST_ITE8152 +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} +#endif + char * __init pcibios_setup(char *str) { if (!strcmp(str, "debug")) { diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index 0f8fca48a5e..e159d69967c 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -151,13 +151,12 @@ static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys) struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys); struct resource *res_io = &cnspci->res_io; struct resource *res_mem = &cnspci->res_mem; - struct resource **sysres = sys->resource; BUG_ON(request_resource(&iomem_resource, res_io) || request_resource(&iomem_resource, res_mem)); - sysres[0] = res_io; - sysres[1] = res_mem; + pci_add_resource(&sys->resources, res_io); + pci_add_resource(&sys->resources, res_mem); return 1; } @@ -169,7 +168,8 @@ static struct pci_ops cns3xxx_pcie_ops = { static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &cns3xxx_pcie_ops, sys, + &sys->resources); } static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c index 6c11a4df717..52e96d397ba 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"); - sys->resource[0] = &pp->res[0]; + pci_add_resource(&sys->resources, &pp->res[0]); /* * IORESOURCE_MEM @@ -88,9 +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"); - sys->resource[1] = &pp->res[1]; - - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &pp->res[1]); return 1; } @@ -184,7 +182,8 @@ dove_pcie_scan_bus(int nr, struct pci_sys_data *sys) struct pci_bus *bus; if (nr < num_pcie_ports) { - bus = pci_scan_bus(sys->busnr, &pcie_ops, sys); + bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, + &sys->resources); } else { bus = NULL; BUG(); diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c index 18c32a5541d..f685650c25d 100644 --- a/arch/arm/mach-footbridge/dc21285.c +++ b/arch/arm/mach-footbridge/dc21285.c @@ -275,9 +275,9 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys) allocate_resource(&iomem_resource, &res[0], 0x40000000, 0x80000000, 0xffffffff, 0x40000000, NULL, NULL); - sys->resource[0] = &ioport_resource; - sys->resource[1] = &res[0]; - sys->resource[2] = &res[1]; + 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; return 1; @@ -285,7 +285,7 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys) struct pci_bus * __init dc21285_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(0, &dc21285_ops, sys); + return pci_scan_root_bus(NULL, 0, &dc21285_ops, sys, &sys->resources); } #define dc21285_request_irq(_a, _b, _c, _d, _e) \ diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index b4d8f8b8a08..3c82566acec 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c @@ -359,7 +359,7 @@ static struct resource pre_mem = { .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH, }; -static int __init pci_v3_setup_resources(struct resource **resource) +static int __init pci_v3_setup_resources(struct pci_sys_data *sys) { if (request_resource(&iomem_resource, &non_mem)) { printk(KERN_ERR "PCI: unable to allocate non-prefetchable " @@ -374,13 +374,13 @@ static int __init pci_v3_setup_resources(struct resource **resource) } /* - * bus->resource[0] is the IO resource for this bus - * bus->resource[1] is the mem resource for this bus - * bus->resource[2] is the prefetch mem resource for this bus + * the IO resource for this bus + * the mem resource for this bus + * the prefetch mem resource for this bus */ - resource[0] = &ioport_resource; - resource[1] = &non_mem; - resource[2] = &pre_mem; + pci_add_resource(&sys->resources, &ioport_resource); + pci_add_resource(&sys->resources, &non_mem); + pci_add_resource(&sys->resources, &pre_mem); return 1; } @@ -481,7 +481,7 @@ int __init pci_v3_setup(int nr, struct pci_sys_data *sys) if (nr == 0) { sys->mem_offset = PHYS_PCI_MEM_BASE; - ret = pci_v3_setup_resources(sys->resource); + ret = pci_v3_setup_resources(sys); } return ret; @@ -489,7 +489,8 @@ int __init pci_v3_setup(int nr, struct pci_sys_data *sys) struct pci_bus * __init pci_v3_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &pci_v3_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &pci_v3_ops, sys, + &sys->resources); } /* diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c index db012fadf88..b8f5a873651 100644 --- a/arch/arm/mach-iop13xx/pci.c +++ b/arch/arm/mach-iop13xx/pci.c @@ -537,14 +537,14 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys) while(time_before(jiffies, atux_trhfa_timeout)) udelay(100); - bus = pci_bus_atux = pci_scan_bus(sys->busnr, - &iop13xx_atux_ops, - sys); + bus = pci_bus_atux = pci_scan_root_bus(NULL, sys->busnr, + &iop13xx_atux_ops, + sys, &sys->resources); break; case IOP13XX_INIT_ATU_ATUE: - bus = pci_bus_atue = pci_scan_bus(sys->busnr, - &iop13xx_atue_ops, - sys); + bus = pci_bus_atue = pci_scan_root_bus(NULL, sys->busnr, + &iop13xx_atue_ops, + sys, &sys->resources); break; } @@ -1084,9 +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]); - sys->resource[0] = &res[0]; - sys->resource[1] = &res[1]; - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &res[0]); + pci_add_resource(&sys->resources, &res[1]); return 1; } diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c index ee525416f0d..e872d238cd0 100644 --- a/arch/arm/mach-ixp2000/enp2611.c +++ b/arch/arm/mach-ixp2000/enp2611.c @@ -145,7 +145,8 @@ static struct pci_ops enp2611_pci_ops = { static struct pci_bus * __init enp2611_pci_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &enp2611_pci_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &enp2611_pci_ops, sys, + &sys->resources); } static int __init enp2611_pci_map_irq(const struct pci_dev *dev, u8 slot, diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c index f5098b306fd..626fda435aa 100644 --- a/arch/arm/mach-ixp2000/pci.c +++ b/arch/arm/mach-ixp2000/pci.c @@ -132,7 +132,8 @@ static struct pci_ops ixp2000_pci_ops = { struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata) { - return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata); + return pci_scan_root_bus(NULL, sysdata->busnr, &ixp2000_pci_ops, + sysdata, &sysdata->resources); } @@ -242,9 +243,8 @@ int ixp2000_pci_setup(int nr, struct pci_sys_data *sys) if (nr >= 1) return 0; - sys->resource[0] = &ixp2000_pci_io_space; - sys->resource[1] = &ixp2000_pci_mem_space; - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &ixp2000_pci_io_space); + pci_add_resource(&sys->resources, &ixp2000_pci_mem_space); return 1; } diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c index e6be5711c70..25b5c462cea 100644 --- a/arch/arm/mach-ixp23xx/pci.c +++ b/arch/arm/mach-ixp23xx/pci.c @@ -143,7 +143,8 @@ struct pci_ops ixp23xx_pci_ops = { struct pci_bus *ixp23xx_pci_scan_bus(int nr, struct pci_sys_data *sysdata) { - return pci_scan_bus(sysdata->busnr, &ixp23xx_pci_ops, sysdata); + return pci_scan_root_bus(NULL, sysdata->busnr, &ixp23xx_pci_ops, + sysdata, &sysdata->resources); } int ixp23xx_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) @@ -280,9 +281,8 @@ int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys) if (nr >= 1) return 0; - sys->resource[0] = &ixp23xx_pci_io_space; - sys->resource[1] = &ixp23xx_pci_mem_space; - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &ixp23xx_pci_io_space); + pci_add_resource(&sys->resources, &ixp23xx_pci_mem_space); return 1; } diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index 8325058ef87..5eff15f24bc 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -472,9 +472,8 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys) request_resource(&ioport_resource, &res[0]); request_resource(&iomem_resource, &res[1]); - sys->resource[0] = &res[0]; - sys->resource[1] = &res[1]; - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &res[0]); + pci_add_resource(&sys->resources, &res[1]); platform_notify = ixp4xx_pci_platform_notify; platform_notify_remove = ixp4xx_pci_platform_notify_remove; @@ -484,7 +483,8 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys) struct pci_bus * __devinit ixp4xx_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &ixp4xx_ops, sys, + &sys->resources); } int dma_set_coherent_mask(struct device *dev, u64 mask) diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index fb451bfe478..a066a6d8d9d 100644 --- a/arch/arm/mach-kirkwood/pcie.c +++ b/arch/arm/mach-kirkwood/pcie.c @@ -198,9 +198,8 @@ 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); - sys->resource[0] = &pp->res[0]; - sys->resource[1] = &pp->res[1]; - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &pp->res[0]); + pci_add_resource(&sys->resources, &pp->res[1]); sys->io_offset = 0; /* @@ -236,7 +235,8 @@ kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys) struct pci_bus *bus; if (nr < num_pcie_ports) { - bus = pci_scan_bus(sys->busnr, &pcie_ops, sys); + bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, + &sys->resources); } else { bus = NULL; BUG(); diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c index c7c9a188d10..b26f992071d 100644 --- a/arch/arm/mach-ks8695/pci.c +++ b/arch/arm/mach-ks8695/pci.c @@ -143,7 +143,8 @@ static struct pci_ops ks8695_pci_ops = { static struct pci_bus* __init ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &ks8695_pci_ops, sys, + &sys->resources); } static struct resource pci_mem = { @@ -168,9 +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); - sys->resource[0] = &pci_io; - sys->resource[1] = &pci_mem; - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &pci_io); + pci_add_resource(&sys->resources, &pci_mem); /* 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 12fcb108b0e..8459f6d7d8c 100644 --- a/arch/arm/mach-mv78xx0/pcie.c +++ b/arch/arm/mach-mv78xx0/pcie.c @@ -155,9 +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); - sys->resource[0] = &pp->res[0]; - sys->resource[1] = &pp->res[1]; - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &pp->res[0]); + pci_add_resource(&sys->resources, &pp->res[1]); return 1; } @@ -251,7 +250,8 @@ mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys) struct pci_bus *bus; if (nr < num_pcie_ports) { - bus = pci_scan_bus(sys->busnr, &pcie_ops, sys); + bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, + &sys->resources); } else { bus = NULL; BUG(); diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index a494c470e3e..09a045f0c40 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -177,7 +177,7 @@ static int __init pcie_setup(struct pci_sys_data *sys) 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"); - sys->resource[0] = &res[0]; + pci_add_resource(&sys->resources, &res[0]); /* * IORESOURCE_MEM @@ -188,9 +188,8 @@ 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"); - sys->resource[1] = &res[1]; + pci_add_resource(&sys->resources, &res[1]); - sys->resource[2] = NULL; sys->io_offset = 0; return 1; @@ -506,7 +505,7 @@ static int __init pci_setup(struct pci_sys_data *sys) 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"); - sys->resource[0] = &res[0]; + pci_add_resource(&sys->resources, &res[0]); /* * IORESOURCE_MEM @@ -517,9 +516,8 @@ 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"); - sys->resource[1] = &res[1]; + pci_add_resource(&sys->resources, &res[1]); - sys->resource[2] = NULL; sys->io_offset = 0; return 1; @@ -580,9 +578,11 @@ struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys struct pci_bus *bus; if (nr == 0) { - bus = pci_scan_bus(sys->busnr, &pcie_ops, sys); + bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, + &sys->resources); } else if (nr == 1 && !orion5x_pci_disabled) { - bus = pci_scan_bus(sys->busnr, &pci_ops, sys); + bus = pci_scan_root_bus(NULL, sys->busnr, &pci_ops, sys, + &sys->resources); } else { bus = NULL; BUG(); diff --git a/arch/arm/mach-sa1100/pci-nanoengine.c b/arch/arm/mach-sa1100/pci-nanoengine.c index dd39fee5954..0d01ca78892 100644 --- a/arch/arm/mach-sa1100/pci-nanoengine.c +++ b/arch/arm/mach-sa1100/pci-nanoengine.c @@ -131,7 +131,8 @@ static int __init pci_nanoengine_map_irq(const struct pci_dev *dev, u8 slot, struct pci_bus * __init pci_nanoengine_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &pci_nano_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &pci_nano_ops, sys, + &sys->resources); } static struct resource pci_io_ports = { @@ -226,7 +227,7 @@ static struct resource pci_prefetchable_memory = { .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH, }; -static int __init pci_nanoengine_setup_resources(struct resource **resource) +static int __init pci_nanoengine_setup_resources(struct pci_sys_data *sys) { if (request_resource(&ioport_resource, &pci_io_ports)) { printk(KERN_ERR "PCI: unable to allocate io port region\n"); @@ -243,9 +244,9 @@ static int __init pci_nanoengine_setup_resources(struct resource **resource) printk(KERN_ERR "PCI: unable to allocate prefetchable\n"); return -EBUSY; } - resource[0] = &pci_io_ports; - resource[1] = &pci_non_prefetchable_memory; - resource[2] = &pci_prefetchable_memory; + 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); return 1; } @@ -260,7 +261,7 @@ int __init pci_nanoengine_setup(int nr, struct pci_sys_data *sys) if (nr == 0) { sys->mem_offset = NANO_PCI_MEM_RW_PHYS; sys->io_offset = 0x400; - ret = pci_nanoengine_setup_resources(sys->resource); + ret = pci_nanoengine_setup_resources(sys); /* Enable alternate memory bus master mode, see * "Intel StrongARM SA1110 Developer's Manual", * section 10.8, "Alternate Memory Bus Master Mode". */ diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c index ec63c6b2b6b..af8b6343572 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"); - sys->resource[0] = &pp->res[0]; + pci_add_resource(&sys->resources, &pp->res[0]); /* * 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"); - sys->resource[1] = &pp->res[1]; + pci_add_resource(&sys->resources, &pp->res[1]); /* * 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"); - sys->resource[2] = &pp->res[2]; + pci_add_resource(&sys->resources, &pp->res[2]); return 1; } @@ -467,7 +467,8 @@ static struct pci_bus __init *tegra_pcie_scan_bus(int nr, pp = tegra_pcie.port + nr; pp->root_bus_nr = sys->busnr; - return pci_scan_bus(sys->busnr, &tegra_pcie_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &tegra_pcie_ops, sys, + &sys->resources); } static struct hw_pci tegra_pcie_hw __initdata = { diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c index c898deb3ada..90069bce23b 100644 --- a/arch/arm/mach-versatile/pci.c +++ b/arch/arm/mach-versatile/pci.c @@ -191,7 +191,7 @@ static struct resource pre_mem = { .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH, }; -static int __init pci_versatile_setup_resources(struct resource **resource) +static int __init pci_versatile_setup_resources(struct list_head *resources) { int ret = 0; @@ -215,13 +215,13 @@ static int __init pci_versatile_setup_resources(struct resource **resource) } /* - * bus->resource[0] is the IO resource for this bus - * bus->resource[1] is the mem resource for this bus - * bus->resource[2] is the prefetch mem resource for this bus + * the IO resource for this bus + * the mem resource for this bus + * the prefetch mem resource for this bus */ - resource[0] = &io_mem; - resource[1] = &non_mem; - resource[2] = &pre_mem; + pci_add_resource(resources, &io_mem); + pci_add_resource(resources, &non_mem); + pci_add_resource(resources, &pre_mem); goto out; @@ -250,7 +250,7 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys) if (nr == 0) { sys->mem_offset = 0; - ret = pci_versatile_setup_resources(sys->resource); + ret = pci_versatile_setup_resources(&sys->resources); if (ret < 0) { printk("pci_versatile_setup: resources... oops?\n"); goto out; @@ -306,7 +306,8 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys) struct pci_bus * __init pci_versatile_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &pci_versatile_ops, sys, + &sys->resources); } void __init pci_versatile_preinit(void) diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c index 845549cbbb2..f4d40a27111 100644 --- a/arch/arm/plat-iop/pci.c +++ b/arch/arm/plat-iop/pci.c @@ -215,16 +215,16 @@ 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; - sys->resource[0] = &res[0]; - sys->resource[1] = &res[1]; - sys->resource[2] = NULL; + pci_add_resource(&sys->resources, &res[0]); + pci_add_resource(&sys->resources, &res[1]); return 1; } struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &iop3xx_ops, sys); + return pci_scan_root_bus(NULL, sys->busnr, &iop3xx_ops, sys, + &sys->resources); } void __init iop3xx_atu_setup(void) diff --git a/arch/blackfin/include/asm/pci.h b/arch/blackfin/include/asm/pci.h index 99cae2e3bac..74352c4597d 100644 --- a/arch/blackfin/include/asm/pci.h +++ b/arch/blackfin/include/asm/pci.h @@ -10,10 +10,6 @@ #define PCIBIOS_MIN_IO 0x00001000 #define PCIBIOS_MIN_MEM 0x10000000 -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} static inline void pcibios_penalize_isa_irq(int irq) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c index 6b4fb28e9f9..c2812176544 100644 --- a/arch/frv/mb93090-mb00/pci-frv.c +++ b/arch/frv/mb93090-mb00/pci-frv.c @@ -194,23 +194,3 @@ void __init pcibios_resource_survey(void) pcibios_allocate_resources(1); pcibios_assign_resources(); } - -/* - * If we set up a device for bus mastering, we need to check the latency - * timer as certain crappy BIOSes forget to set it properly. - */ -unsigned int pcibios_max_latency = 255; - -void pcibios_set_master(struct pci_dev *dev) -{ - u8 lat; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - if (lat < 16) - lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; - else if (lat > pcibios_max_latency) - lat = pcibios_max_latency; - else - return; - printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} diff --git a/arch/frv/mb93090-mb00/pci-frv.h b/arch/frv/mb93090-mb00/pci-frv.h index f3fe5591479..089eeba4f3b 100644 --- a/arch/frv/mb93090-mb00/pci-frv.h +++ b/arch/frv/mb93090-mb00/pci-frv.h @@ -26,8 +26,6 @@ extern unsigned int __nongpreldata pci_probe; /* pci-frv.c */ -extern unsigned int pcibios_max_latency; - void pcibios_resource_survey(void); /* pci-vdk.c */ diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c index f8dd37e4953..6b0b82ff441 100644 --- a/arch/frv/mb93090-mb00/pci-vdk.c +++ b/arch/frv/mb93090-mb00/pci-vdk.c @@ -327,11 +327,6 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number); #endif - if (bus->number == 0) { - bus->resource[0] = &pci_ioport_resource; - bus->resource[1] = &pci_iomem_resource; - } - pci_read_bridge_bases(bus); if (bus->number == 0) { @@ -357,6 +352,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) int __init pcibios_init(void) { struct pci_ops *dir = NULL; + LIST_HEAD(resources); if (!mb93090_mb00_detected) return -ENXIO; @@ -420,7 +416,10 @@ int __init pcibios_init(void) } printk("PCI: Probing PCI hardware\n"); - pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL); + pci_add_resource(&resources, &pci_ioport_resource); + pci_add_resource(&resources, &pci_iomem_resource); + pci_root_bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, + &resources); pcibios_irq_init(); pcibios_fixup_peer_bridges(); diff --git a/arch/h8300/include/asm/pci.h b/arch/h8300/include/asm/pci.h index cc9762091c0..0b2acaa3dd8 100644 --- a/arch/h8300/include/asm/pci.h +++ b/arch/h8300/include/asm/pci.h @@ -9,11 +9,6 @@ #define pcibios_assign_all_busses() 0 -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - static inline void pcibios_penalize_isa_irq(int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h index 127dd7be346..279b38ae74a 100644 --- a/arch/ia64/include/asm/pci.h +++ b/arch/ia64/include/asm/pci.h @@ -43,12 +43,6 @@ extern unsigned long ia64_max_iommu_merge_mask; #define PCI_DMA_BUS_IS_PHYS (ia64_max_iommu_merge_mask == ~0UL) static inline void -pcibios_set_master (struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - -static inline void pcibios_penalize_isa_irq (int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 2c27714d7b7..f82f5d4b65f 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -134,6 +134,7 @@ alloc_pci_controller (int seg) struct pci_root_info { struct acpi_device *bridge; struct pci_controller *controller; + struct list_head resources; char *name; }; @@ -315,24 +316,13 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data) &window->resource); } - return AE_OK; -} - -static void __devinit -pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl) -{ - int i; + /* HP's firmware has a hack to work around a Windows bug. + * 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_bus_remove_resources(bus); - for (i = 0; i < ctrl->windows; i++) { - struct resource *res = &ctrl->window[i].resource; - /* HP's firmware has a hack to work around a Windows bug. - * Ignore these tiny memory ranges */ - if ((res->flags & IORESOURCE_MEM) && - (res->end - res->start < 16)) - continue; - pci_bus_add_resource(bus, res, 0); - } + return AE_OK; } struct pci_bus * __devinit @@ -343,6 +333,7 @@ pci_acpi_scan_root(struct acpi_pci_root *root) int bus = root->secondary.start; struct pci_controller *controller; unsigned int windows = 0; + struct pci_root_info info; struct pci_bus *pbus; char *name; int pxm; @@ -359,11 +350,10 @@ pci_acpi_scan_root(struct acpi_pci_root *root) controller->node = pxm_to_node(pxm); #endif + INIT_LIST_HEAD(&info.resources); acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, &windows); if (windows) { - struct pci_root_info info; - controller->window = kmalloc_node(sizeof(*controller->window) * windows, GFP_KERNEL, controller->node); @@ -387,8 +377,14 @@ pci_acpi_scan_root(struct acpi_pci_root *root) * should handle the case here, but it appears that IA64 hasn't * such quirk. So we just ignore the case now. */ - pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller); + pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller, + &info.resources); + if (!pbus) { + pci_free_resource_list(&info.resources); + return NULL; + } + pbus->subordinate = pci_scan_child_bus(pbus); return pbus; out3: @@ -504,14 +500,15 @@ pcibios_fixup_bus (struct pci_bus *b) if (b->self) { pci_read_bridge_bases(b); pcibios_fixup_bridge_resources(b->self); - } else { - pcibios_setup_root_windows(b, b->sysdata); } list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); platform_pci_fixup_bus(b); +} - return; +void pcibios_set_master (struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ } void __devinit diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h index 32764cd077c..e9834b2991d 100644 --- a/arch/microblaze/include/asm/pci-bridge.h +++ b/arch/microblaze/include/asm/pci-bridge.h @@ -140,7 +140,6 @@ extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, /* Allocate & free a PCI host bridge structure */ extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev); extern void pcibios_free_controller(struct pci_controller *phb); -extern void pcibios_setup_phb_resources(struct pci_controller *hose); #endif /* __KERNEL__ */ #endif /* _ASM_MICROBLAZE_PCI_BRIDGE_H */ diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h index 1dd9d6b1e27..033137628e8 100644 --- a/arch/microblaze/include/asm/pci.h +++ b/arch/microblaze/include/asm/pci.h @@ -42,11 +42,6 @@ struct pci_dev; */ #define pcibios_assign_all_busses() 0 -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - static inline void pcibios_penalize_isa_irq(int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index 0d71b2ed810..85f2ac1230a 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -190,6 +190,11 @@ int pcibios_add_platform_entries(struct pci_dev *pdev) return device_create_file(&pdev->dev, &dev_attr_devspec); } +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} + char __devinit *pcibios_setup(char *str) { return str; @@ -1019,7 +1024,6 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus) struct pci_dev *dev = bus->self; pci_bus_for_each_resource(bus, res, i) { - res = bus->resource[i]; if (!res) continue; if (!res->flags) @@ -1219,7 +1223,6 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus) pci_domain_nr(bus), bus->number); pci_bus_for_each_resource(bus, res, i) { - res = bus->resource[i]; if (!res || !res->flags || res->start > res->end || res->parent) continue; @@ -1510,14 +1513,18 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return pci_enable_resources(dev, mask); } -void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) +static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources) { - struct pci_bus *bus = hose->bus; struct resource *res; int i; /* Hookup PHB IO resource */ - bus->resource[0] = res = &hose->io_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; if (!res->flags) { printk(KERN_WARNING "PCI: I/O resource not set for host" @@ -1528,6 +1535,7 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) res->end = res->start + IO_SPACE_LIMIT; res->flags = IORESOURCE_IO; } + pci_add_resource(resources, res); pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n", (unsigned long long)res->start, @@ -1550,7 +1558,7 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) res->flags = IORESOURCE_MEM; } - bus->resource[i+1] = res; + pci_add_resource(resources, res); pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i, (unsigned long long)res->start, @@ -1573,34 +1581,27 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) static void __devinit pcibios_scan_phb(struct pci_controller *hose) { + LIST_HEAD(resources); struct pci_bus *bus; struct device_node *node = hose->dn; - unsigned long io_offset; - struct resource *res = &hose->io_resource; pr_debug("PCI: Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); - /* Create an empty bus for the toplevel */ - bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose); + pcibios_setup_phb_resources(hose, &resources); + + bus = pci_scan_root_bus(hose->parent, hose->first_busno, + hose->ops, hose, &resources); if (bus == NULL) { printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", hose->global_number); + pci_free_resource_list(&resources); return; } bus->secondary = hose->first_busno; hose->bus = bus; - /* 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; - - /* Wire up PHB bus resources */ - pcibios_setup_phb_resources(hose); - - /* Scan children */ - hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); + hose->last_busno = bus->subordinate; } static int __init pcibios_init(void) @@ -1614,8 +1615,6 @@ static int __init pcibios_init(void) list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { hose->last_busno = 0xff; pcibios_scan_phb(hose); - printk(KERN_INFO "calling pci_bus_add_devices()\n"); - pci_bus_add_devices(hose->bus); if (next_busno <= hose->last_busno) next_busno = hose->last_busno + 1; } diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 41af7fa2887..fa8e378413b 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -81,6 +81,7 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose) { static int next_busno; static int need_domain_info; + LIST_HEAD(resources); struct pci_bus *bus; if (!hose->iommu) @@ -89,7 +90,13 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose) if (hose->get_busno && pci_probe_only) next_busno = (*hose->get_busno)(); - bus = pci_scan_bus(next_busno, hose->pci_ops, hose); + pci_add_resource(&resources, hose->mem_resource); + pci_add_resource(&resources, hose->io_resource); + bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose, + &resources); + if (!bus) + pci_free_resource_list(&resources); + hose->bus = bus; need_domain_info = need_domain_info || hose->index; @@ -205,27 +212,6 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask) return 0; } -/* - * If we set up a device for bus mastering, we need to check the latency - * timer as certain crappy BIOSes forget to set it properly. - */ -static unsigned int pcibios_max_latency = 255; - -void pcibios_set_master(struct pci_dev *dev) -{ - u8 lat; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - if (lat < 16) - lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; - else if (lat > pcibios_max_latency) - lat = pcibios_max_latency; - else - return; - printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", - pci_name(dev), lat); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} - unsigned int pcibios_assign_all_busses(void) { return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; @@ -266,15 +252,11 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) { /* Propagate hose info into the subordinate devices. */ - struct pci_controller *hose = bus->sysdata; struct list_head *ln; struct pci_dev *dev = bus->self; - if (!dev) { - bus->resource[0] = hose->io_resource; - bus->resource[1] = hose->mem_resource; - } else if (pci_probe_only && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + if (pci_probe_only && dev && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { pci_read_bridge_bases(bus); pcibios_fixup_device_resources(dev, bus); } diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c index 8e6763e6f25..c4e2e79281e 100644 --- a/arch/mn10300/unit-asb2305/pci-asb2305.c +++ b/arch/mn10300/unit-asb2305/pci-asb2305.c @@ -213,28 +213,6 @@ void __init pcibios_resource_survey(void) pcibios_allocate_resources(1); } -/* - * If we set up a device for bus mastering, we need to check the latency - * timer as certain crappy BIOSes forget to set it properly. - */ -unsigned int pcibios_max_latency = 255; - -void pcibios_set_master(struct pci_dev *dev) -{ - u8 lat; - - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - - if (lat < 16) - lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; - else if (lat > pcibios_max_latency) - lat = pcibios_max_latency; - else - return; - - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} - int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine) { diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.h b/arch/mn10300/unit-asb2305/pci-asb2305.h index c3fa294b6e2..1194fe486b0 100644 --- a/arch/mn10300/unit-asb2305/pci-asb2305.h +++ b/arch/mn10300/unit-asb2305/pci-asb2305.h @@ -31,8 +31,6 @@ extern unsigned int pci_probe; /* pci-asb2305.c */ -extern unsigned int pcibios_max_latency; - extern void pcibios_resource_survey(void); /* pci.c */ diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c index a4954fe8209..a7c5f08ca9f 100644 --- a/arch/mn10300/unit-asb2305/pci.c +++ b/arch/mn10300/unit-asb2305/pci.c @@ -380,11 +380,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) { struct pci_dev *dev; - if (bus->number == 0) { - bus->resource[0] = &pci_ioport_resource; - bus->resource[1] = &pci_iomem_resource; - } - if (bus->self) { pci_read_bridge_bases(bus); pcibios_fixup_device_resources(bus->self); @@ -402,6 +397,8 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) */ static int __init pcibios_init(void) { + LIST_HEAD(resources); + ioport_resource.start = 0xA0000000; ioport_resource.end = 0xDFFFFFFF; iomem_resource.start = 0xA0000000; @@ -423,7 +420,10 @@ static int __init pcibios_init(void) printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n", MEM_PAGING_REG); - pci_root_bus = pci_scan_bus(0, &pci_direct_ampci, NULL); + pci_add_resource(&resources, &pci_ioport_resource); + pci_add_resource(&resources, &pci_iomem_resource); + pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, + &resources); pcibios_irq_init(); pcibios_fixup_irqs(); diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 882b6aa6c85..5d487657322 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -226,7 +226,6 @@ extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, /* Allocate & free a PCI host bridge structure */ extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev); extern void pcibios_free_controller(struct pci_controller *phb); -extern void pcibios_setup_phb_resources(struct pci_controller *hose); #ifdef CONFIG_PCI extern int pcibios_vaddr_is_ioport(void __iomem *address); diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index 1c92013466e..f54b3d26ce9 100644 --- a/arch/powerpc/include/asm/pci.h +++ b/arch/powerpc/include/asm/pci.h @@ -46,11 +46,6 @@ struct pci_dev; #define pcibios_assign_all_busses() \ (pci_has_flag(PCI_REASSIGN_ALL_BUS)) -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - static inline void pcibios_penalize_isa_irq(int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index fa4a573d671..cce98d76e90 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1131,6 +1131,11 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus) } } +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} + void __devinit pcibios_fixup_bus(struct pci_bus *bus) { /* When called from the generic PCI probe, read PCI<->PCI bridge @@ -1560,14 +1565,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return pci_enable_resources(dev, mask); } -void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) +static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources) { - struct pci_bus *bus = hose->bus; struct resource *res; int i; /* Hookup PHB IO resource */ - bus->resource[0] = res = &hose->io_resource; + res = &hose->io_resource; if (!res->flags) { printk(KERN_WARNING "PCI: I/O resource not set for host" @@ -1585,6 +1589,7 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) (unsigned long long)res->start, (unsigned long long)res->end, (unsigned long)res->flags); + pci_add_resource(resources, res); /* Hookup PHB Memory resources */ for (i = 0; i < 3; ++i) { @@ -1602,12 +1607,12 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) res->flags = IORESOURCE_MEM; #endif /* CONFIG_PPC32 */ } - bus->resource[i+1] = res; pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i, (unsigned long long)res->start, (unsigned long long)res->end, (unsigned long)res->flags); + pci_add_resource(resources, res); } pr_debug("PCI: PHB MEM offset = %016llx\n", @@ -1701,6 +1706,7 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) */ void __devinit pcibios_scan_phb(struct pci_controller *hose) { + LIST_HEAD(resources); struct pci_bus *bus; struct device_node *node = hose->dn; int mode; @@ -1708,22 +1714,24 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose) pr_debug("PCI: Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); + /* Get some IO space for the new PHB */ + pcibios_setup_phb_io_space(hose); + + /* Wire up PHB bus resources */ + pcibios_setup_phb_resources(hose, &resources); + /* Create an empty bus for the toplevel */ - bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose); + bus = pci_create_root_bus(hose->parent, hose->first_busno, + hose->ops, hose, &resources); if (bus == NULL) { pr_err("Failed to create bus for PCI domain %04x\n", hose->global_number); + pci_free_resource_list(&resources); return; } bus->secondary = hose->first_busno; hose->bus = bus; - /* Get some IO space for the new PHB */ - pcibios_setup_phb_io_space(hose); - - /* Wire up PHB bus resources */ - pcibios_setup_phb_resources(hose); - /* Get probe mode and perform scan */ mode = PCI_PROBE_NORMAL; if (node && ppc_md.pci_probe_mode) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index bcf4bf9e72d..3318d39b7d4 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -131,30 +131,13 @@ EXPORT_SYMBOL_GPL(pcibios_unmap_io_space); #endif /* CONFIG_HOTPLUG */ -int __devinit pcibios_map_io_space(struct pci_bus *bus) +static int __devinit pcibios_map_phb_io_space(struct pci_controller *hose) { struct vm_struct *area; unsigned long phys_page; unsigned long size_page; unsigned long io_virt_offset; - struct pci_controller *hose; - - WARN_ON(bus == NULL); - - /* If this not a PHB, nothing to do, page tables still exist and - * thus HPTEs will be faulted in when needed - */ - if (bus->self) { - pr_debug("IO mapping for PCI-PCI bridge %s\n", - pci_name(bus->self)); - pr_debug(" virt=0x%016llx...0x%016llx\n", - bus->resource[0]->start + _IO_BASE, - bus->resource[0]->end + _IO_BASE); - return 0; - } - /* Get the host bridge */ - hose = pci_bus_to_host(bus); phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE); size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE); @@ -198,11 +181,30 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus) return 0; } + +int __devinit pcibios_map_io_space(struct pci_bus *bus) +{ + WARN_ON(bus == NULL); + + /* If this not a PHB, nothing to do, page tables still exist and + * thus HPTEs will be faulted in when needed + */ + if (bus->self) { + pr_debug("IO mapping for PCI-PCI bridge %s\n", + pci_name(bus->self)); + pr_debug(" virt=0x%016llx...0x%016llx\n", + bus->resource[0]->start + _IO_BASE, + bus->resource[0]->end + _IO_BASE); + return 0; + } + + return pcibios_map_phb_io_space(pci_bus_to_host(bus)); +} EXPORT_SYMBOL_GPL(pcibios_map_io_space); void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose) { - pcibios_map_io_space(hose->bus); + pcibios_map_phb_io_space(hose); } #define IOBASE_BRIDGE_NUMBER 0 diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 11aaf2fdec8..8f18dd090a6 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -36,9 +36,15 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose) { static int next_busno; static int need_domain_info; + LIST_HEAD(resources); + int i; struct pci_bus *bus; - bus = pci_scan_bus(next_busno, hose->pci_ops, hose); + for (i = 0; i < hose->nr_resources; i++) + pci_add_resource(&resources, hose->resources + i); + + bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose, + &resources); hose->bus = bus; need_domain_info = need_domain_info || hose->index; @@ -55,6 +61,8 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose) pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); pci_enable_bridges(bus); + } else { + pci_free_resource_list(&resources); } } @@ -162,16 +170,8 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev, */ void __devinit pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_dev *dev = bus->self; + struct pci_dev *dev; struct list_head *ln; - struct pci_channel *hose = bus->sysdata; - - if (!dev) { - int i; - - for (i = 0; i < hose->nr_resources; i++) - bus->resource[i] = hose->resources + i; - } for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { dev = pci_dev_b(ln); @@ -243,27 +243,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return pci_enable_resources(dev, mask); } -/* - * If we set up a device for bus mastering, we need to check and set - * the latency timer as it may not be properly set. - */ -static unsigned int pcibios_max_latency = 255; - -void pcibios_set_master(struct pci_dev *dev) -{ - u8 lat; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - if (lat < 16) - lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; - else if (lat > pcibios_max_latency) - lat = pcibios_max_latency; - else - return; - printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", - pci_name(dev), lat); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} - void __init pcibios_update_irq(struct pci_dev *dev, int irq) { pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h index 02939abd356..6de7f7bf956 100644 --- a/arch/sparc/include/asm/pci_32.h +++ b/arch/sparc/include/asm/pci_32.h @@ -16,11 +16,6 @@ #define PCI_IRQ_NONE 0xffffffff -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - static inline void pcibios_penalize_isa_irq(int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h index 2614d96141c..755a4bb6bcd 100644 --- a/arch/sparc/include/asm/pci_64.h +++ b/arch/sparc/include/asm/pci_64.h @@ -16,11 +16,6 @@ #define PCI_IRQ_NONE 0xffffffff -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - static inline void pcibios_penalize_isa_irq(int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index f1cf6ef011a..c7bec25fdb1 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c @@ -19,22 +19,22 @@ */ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info) { + LIST_HEAD(resources); struct pci_bus *root_bus; - root_bus = pci_scan_bus_parented(&ofdev->dev, 0, info->ops, info); - if (root_bus) { - root_bus->resource[0] = &info->io_space; - root_bus->resource[1] = &info->mem_space; - root_bus->resource[2] = NULL; - - /* Init all PCI devices into PCI tree */ - pci_bus_add_devices(root_bus); + pci_add_resource(&resources, &info->io_space); + pci_add_resource(&resources, &info->mem_space); + root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info, + &resources); + if (root_bus) { /* Setup IRQs of all devices using custom routines */ pci_fixup_irqs(pci_common_swizzle, info->map_irq); /* Assign devices with resources */ pci_assign_unassigned_resources(); + } else { + pci_free_resource_list(&resources); } } @@ -83,15 +83,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *pbus) int i, has_io, has_mem; u16 cmd; - /* Generic PCI bus probing sets these to point at - * &io{port,mem}_resouce which is wrong for us. - */ - if (pbus->self == NULL) { - pbus->resource[0] = &info->io_space; - pbus->resource[1] = &info->mem_space; - pbus->resource[2] = NULL; - } - list_for_each_entry(dev, &pbus->devices, bus_list) { /* * We can not rely on that the bootloader has enabled I/O diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 31111e35281..bb8bc2e519a 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -685,23 +685,25 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm, struct device *parent) { + LIST_HEAD(resources); struct device_node *node = pbm->op->dev.of_node; struct pci_bus *bus; printk("PCI: Scanning PBM %s\n", node->full_name); - bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm); + pci_add_resource(&resources, &pbm->io_space); + pci_add_resource(&resources, &pbm->mem_space); + bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops, + pbm, &resources); if (!bus) { printk(KERN_ERR "Failed to create bus for %s\n", node->full_name); + pci_free_resource_list(&resources); return NULL; } bus->secondary = pbm->pci_first_busno; bus->subordinate = pbm->pci_last_busno; - bus->resource[0] = &pbm->io_space; - bus->resource[1] = &pbm->mem_space; - pci_of_scan_bus(pbm, node, bus); pci_bus_add_devices(bus); pci_bus_register_of_sysfs(bus); @@ -711,13 +713,6 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm, void __devinit pcibios_fixup_bus(struct pci_bus *pbus) { - struct pci_pbm_info *pbm = pbus->sysdata; - - /* Generic PCI bus probing sets these to point at - * &io{port,mem}_resouce which is wrong for us. - */ - pbus->resource[0] = &pbm->io_space; - pbus->resource[1] = &pbm->mem_space; } void pcibios_update_irq(struct pci_dev *pdev, int irq) @@ -1083,6 +1078,11 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar, *end = rp->end - offset; } +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} + static int __init pcibios_init(void) { pci_dfl_cache_line_size = 64 >> 2; diff --git a/arch/tile/include/asm/pci.h b/arch/tile/include/asm/pci.h index 1d25fea42e5..5d5a635530b 100644 --- a/arch/tile/include/asm/pci.h +++ b/arch/tile/include/asm/pci.h @@ -76,13 +76,6 @@ static inline int pcibios_assign_all_busses(void) return 1; } -/* - * No special bus mastering setup handling. - */ -static inline void pcibios_set_master(struct pci_dev *dev) -{ -} - #define PCIBIOS_MIN_MEM 0 #define PCIBIOS_MIN_IO 0 diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c index 25567934a21..a1bb59eecc1 100644 --- a/arch/tile/kernel/pci.c +++ b/arch/tile/kernel/pci.c @@ -395,6 +395,11 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) /* Nothing needs to be done. */ } +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling. */ +} + /* * This can be called from the generic PCI layer, but doesn't need to * do anything. diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h index c5b28b45953..dd3867727c3 100644 --- a/arch/unicore32/include/asm/pci.h +++ b/arch/unicore32/include/asm/pci.h @@ -17,11 +17,6 @@ #include <asm-generic/pci.h> #include <mach/hardware.h> /* for PCIBIOS_MIN_* */ -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - static inline void pcibios_penalize_isa_irq(int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c index 4892fbb54eb..a8f07fe10ca 100644 --- a/arch/unicore32/kernel/pci.c +++ b/arch/unicore32/kernel/pci.c @@ -309,6 +309,11 @@ char * __devinit pcibios_setup(char *str) return str; } +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} + /* * From arch/i386/kernel/pci-i386.c: * diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index 8e41071704a..49ad773f4b9 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -1,6 +1,7 @@ #ifndef _ASM_X86_AMD_NB_H #define _ASM_X86_AMD_NB_H +#include <linux/ioport.h> #include <linux/pci.h> struct amd_nb_bus_dev_range { @@ -13,6 +14,7 @@ extern const struct pci_device_id amd_nb_misc_ids[]; extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[]; extern bool early_is_amd_nb(u32 value); +extern struct resource *amd_get_mmconfig_range(struct resource *res); extern int amd_cache_northbridges(void); extern void amd_flush_garts(void); extern int amd_numa_init(void); diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index d498943b906..df75d07571c 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -112,19 +112,28 @@ static inline void x86_teardown_msi_irq(unsigned int irq) { x86_msi.teardown_msi_irq(irq); } +static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq) +{ + x86_msi.restore_msi_irqs(dev, irq); +} #define arch_setup_msi_irqs x86_setup_msi_irqs #define arch_teardown_msi_irqs x86_teardown_msi_irqs #define arch_teardown_msi_irq x86_teardown_msi_irq +#define arch_restore_msi_irqs x86_restore_msi_irqs /* implemented in arch/x86/kernel/apic/io_apic. */ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); void native_teardown_msi_irq(unsigned int irq); +void native_restore_msi_irqs(struct pci_dev *dev, int irq); /* default to the implementation in drivers/lib/msi.c */ #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS +#define HAVE_DEFAULT_MSI_RESTORE_IRQS void default_teardown_msi_irqs(struct pci_dev *dev); +void default_restore_msi_irqs(struct pci_dev *dev, int irq); #else #define native_setup_msi_irqs NULL #define native_teardown_msi_irq NULL #define default_teardown_msi_irqs NULL +#define default_restore_msi_irqs NULL #endif #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys) diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index e3819780685..b3a53174602 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h @@ -44,8 +44,6 @@ enum pci_bf_sort_state { /* pci-i386.c */ -extern unsigned int pcibios_max_latency; - void pcibios_resource_survey(void); void pcibios_set_cache_line_size(void); diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 800f77c6005..b9676ae37ad 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -172,7 +172,7 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) } struct pci_bus; -void x86_pci_root_bus_res_quirks(struct pci_bus *b); +void x86_pci_root_bus_resources(int bus, struct list_head *resources); #ifdef CONFIG_SMP #define mc_capable() ((boot_cpu_data.x86_max_cores > 1) && \ diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 1ac860a0984..517d4767ffd 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -179,6 +179,7 @@ struct x86_msi_ops { int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type); void (*teardown_msi_irq)(unsigned int irq); void (*teardown_msi_irqs)(struct pci_dev *dev); + void (*restore_msi_irqs)(struct pci_dev *dev, int irq); }; extern struct x86_init_ops x86_init; diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 013c1810ce7..be16854591c 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -119,6 +119,37 @@ bool __init early_is_amd_nb(u32 device) return false; } +struct resource *amd_get_mmconfig_range(struct resource *res) +{ + u32 address; + u64 base, msr; + unsigned segn_busn_bits; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return NULL; + + /* assume all cpus from fam10h have mmconfig */ + if (boot_cpu_data.x86 < 0x10) + return NULL; + + address = MSR_FAM10H_MMIO_CONF_BASE; + rdmsrl(address, msr); + + /* mmconfig is not enabled */ + if (!(msr & FAM10H_MMIO_CONF_ENABLE)) + return NULL; + + base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); + + segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & + FAM10H_MMIO_CONF_BUSRANGE_MASK; + + res->flags = IORESOURCE_MEM; + res->start = base; + res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1; + return res; +} + int amd_get_subcaches(int cpu) { struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link; diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 91f83e21b98..947a06ccc67 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -115,4 +115,5 @@ struct x86_msi_ops x86_msi = { .setup_msi_irqs = native_setup_msi_irqs, .teardown_msi_irq = native_teardown_msi_irq, .teardown_msi_irqs = default_teardown_msi_irqs, + .restore_msi_irqs = default_restore_msi_irqs, }; diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 404f21a3ff9..a312e76063a 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -12,7 +12,7 @@ struct pci_root_info { char *name; unsigned int res_num; struct resource *res; - struct pci_bus *bus; + struct list_head *resources; int busnum; }; @@ -24,6 +24,12 @@ static int __init set_use_crs(const struct dmi_system_id *id) return 0; } +static int __init set_nouse_crs(const struct dmi_system_id *id) +{ + pci_use_crs = false; + return 0; +} + static const struct dmi_system_id pci_use_crs_table[] __initconst = { /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */ { @@ -54,6 +60,29 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = { DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), }, }, + + /* Now for the blacklist.. */ + + /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */ + { + .callback = set_nouse_crs, + .ident = "Dell Studio 1557", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"), + DMI_MATCH(DMI_BIOS_VERSION, "A09"), + }, + }, + /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */ + { + .callback = set_nouse_crs, + .ident = "Thinkpad SL510", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "2847DFG"), + DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"), + }, + }, {} }; @@ -149,7 +178,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data) struct acpi_resource_address64 addr; acpi_status status; unsigned long flags; - u64 start, end; + u64 start, orig_end, end; status = resource_to_addr(acpi_res, &addr); if (!ACPI_SUCCESS(status)) @@ -165,7 +194,21 @@ setup_resource(struct acpi_resource *acpi_res, void *data) return AE_OK; start = addr.minimum + addr.translation_offset; - end = addr.maximum + addr.translation_offset; + orig_end = end = addr.maximum + addr.translation_offset; + + /* Exclude non-addressable range or non-addressable portion of range */ + end = min(end, (u64)iomem_resource.end); + if (end <= start) { + dev_info(&info->bridge->dev, + "host bridge window [%#llx-%#llx] " + "(ignored, not CPU addressable)\n", start, orig_end); + return AE_OK; + } else if (orig_end != end) { + dev_info(&info->bridge->dev, + "host bridge window [%#llx-%#llx] " + "([%#llx-%#llx] ignored, not CPU addressable)\n", + start, orig_end, end + 1, orig_end); + } res = &info->res[info->res_num]; res->name = info->name; @@ -261,23 +304,20 @@ static void add_resources(struct pci_root_info *info) "ignoring host bridge window %pR (conflicts with %s %pR)\n", res, conflict->name, conflict); else - pci_bus_add_resource(info->bus, res, 0); + pci_add_resource(info->resources, res); } } static void get_current_resources(struct acpi_device *device, int busnum, - int domain, struct pci_bus *bus) + int domain, struct list_head *resources) { struct pci_root_info info; size_t size; - if (pci_use_crs) - pci_bus_remove_resources(bus); - info.bridge = device; - info.bus = bus; info.res_num = 0; + info.resources = resources; acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, &info); if (!info.res_num) @@ -286,7 +326,7 @@ get_current_resources(struct acpi_device *device, int busnum, size = sizeof(*info.res) * info.res_num; info.res = kmalloc(size, GFP_KERNEL); if (!info.res) - goto res_alloc_fail; + return; info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum); if (!info.name) @@ -301,8 +341,6 @@ get_current_resources(struct acpi_device *device, int busnum, name_alloc_fail: kfree(info.res); -res_alloc_fail: - return; } struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) @@ -310,6 +348,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) struct acpi_device *device = root->device; int domain = root->segment; int busnum = root->secondary.start; + LIST_HEAD(resources); struct pci_bus *bus; struct pci_sysdata *sd; int node; @@ -364,11 +403,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) memcpy(bus->sysdata, sd, sizeof(*sd)); kfree(sd); } else { - bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd); - if (bus) { - get_current_resources(device, busnum, domain, bus); + get_current_resources(device, busnum, domain, &resources); + if (list_empty(&resources)) + x86_pci_root_bus_resources(busnum, &resources); + bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, + &resources); + if (bus) bus->subordinate = pci_scan_child_bus(bus); - } + else + pci_free_resource_list(&resources); } /* After the PCI-E bus has been walked and all devices discovered, diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 026e4931d16..0567df3890e 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c @@ -30,34 +30,6 @@ static struct pci_hostbridge_probe pci_probes[] __initdata = { { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 }, }; -static u64 __initdata fam10h_mmconf_start; -static u64 __initdata fam10h_mmconf_end; -static void __init get_pci_mmcfg_amd_fam10h_range(void) -{ - u32 address; - u64 base, msr; - unsigned segn_busn_bits; - - /* assume all cpus from fam10h have mmconf */ - if (boot_cpu_data.x86 < 0x10) - return; - - address = MSR_FAM10H_MMIO_CONF_BASE; - rdmsrl(address, msr); - - /* mmconfig is not enable */ - if (!(msr & FAM10H_MMIO_CONF_ENABLE)) - return; - - base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); - - segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & - FAM10H_MMIO_CONF_BUSRANGE_MASK; - - fam10h_mmconf_start = base; - fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; -} - #define RANGE_NUM 16 /** @@ -85,6 +57,9 @@ static int __init early_fill_mp_bus_info(void) u64 val; u32 address; bool found; + struct resource fam10h_mmconf_res, *fam10h_mmconf; + u64 fam10h_mmconf_start; + u64 fam10h_mmconf_end; if (!early_pci_allowed()) return -1; @@ -211,12 +186,17 @@ static int __init early_fill_mp_bus_info(void) subtract_range(range, RANGE_NUM, 0, end); /* get mmconfig */ - get_pci_mmcfg_amd_fam10h_range(); + fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res); /* need to take out mmconf range */ - if (fam10h_mmconf_end) { - printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end); + if (fam10h_mmconf) { + printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf); + fam10h_mmconf_start = fam10h_mmconf->start; + fam10h_mmconf_end = fam10h_mmconf->end; subtract_range(range, RANGE_NUM, fam10h_mmconf_start, fam10h_mmconf_end + 1); + } else { + fam10h_mmconf_start = 0; + fam10h_mmconf_end = 0; } /* mmio resource */ @@ -403,7 +383,6 @@ static void __init pci_enable_pci_io_ecs(void) ++n; } } - pr_info("Extended Config Space enabled on %u nodes\n", n); #endif } diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c index ab8269b0da2..f3a7c569a40 100644 --- a/arch/x86/pci/broadcom_bus.c +++ b/arch/x86/pci/broadcom_bus.c @@ -15,10 +15,11 @@ #include <linux/pci.h> #include <linux/init.h> #include <asm/pci_x86.h> +#include <asm/pci-direct.h> #include "bus_numa.h" -static void __devinit cnb20le_res(struct pci_dev *dev) +static void __init cnb20le_res(u8 bus, u8 slot, u8 func) { struct pci_root_info *info; struct resource res; @@ -26,21 +27,12 @@ static void __devinit cnb20le_res(struct pci_dev *dev) u8 fbus, lbus; int i; -#ifdef CONFIG_ACPI - /* - * We should get host bridge information from ACPI unless the BIOS - * doesn't support it. - */ - if (acpi_os_get_root_pointer()) - return; -#endif - info = &pci_root_info[pci_root_num]; pci_root_num++; /* read the PCI bus numbers */ - pci_read_config_byte(dev, 0x44, &fbus); - pci_read_config_byte(dev, 0x45, &lbus); + fbus = read_pci_config_byte(bus, slot, func, 0x44); + lbus = read_pci_config_byte(bus, slot, func, 0x45); info->bus_min = fbus; info->bus_max = lbus; @@ -59,8 +51,8 @@ static void __devinit cnb20le_res(struct pci_dev *dev) } /* read the non-prefetchable memory window */ - pci_read_config_word(dev, 0xc0, &word1); - pci_read_config_word(dev, 0xc2, &word2); + word1 = read_pci_config_16(bus, slot, func, 0xc0); + word2 = read_pci_config_16(bus, slot, func, 0xc2); if (word1 != word2) { res.start = (word1 << 16) | 0x0000; res.end = (word2 << 16) | 0xffff; @@ -69,8 +61,8 @@ static void __devinit cnb20le_res(struct pci_dev *dev) } /* read the prefetchable memory window */ - pci_read_config_word(dev, 0xc4, &word1); - pci_read_config_word(dev, 0xc6, &word2); + word1 = read_pci_config_16(bus, slot, func, 0xc4); + word2 = read_pci_config_16(bus, slot, func, 0xc6); if (word1 != word2) { res.start = (word1 << 16) | 0x0000; res.end = (word2 << 16) | 0xffff; @@ -79,8 +71,8 @@ static void __devinit cnb20le_res(struct pci_dev *dev) } /* read the IO port window */ - pci_read_config_word(dev, 0xd0, &word1); - pci_read_config_word(dev, 0xd2, &word2); + word1 = read_pci_config_16(bus, slot, func, 0xd0); + word2 = read_pci_config_16(bus, slot, func, 0xd2); if (word1 != word2) { res.start = word1; res.end = word2; @@ -92,13 +84,37 @@ static void __devinit cnb20le_res(struct pci_dev *dev) res.start = fbus; res.end = lbus; res.flags = IORESOURCE_BUS; - dev_info(&dev->dev, "CNB20LE PCI Host Bridge (domain %04x %pR)\n", - pci_domain_nr(dev->bus), &res); + printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res); for (i = 0; i < info->res_num; i++) - dev_info(&dev->dev, "host bridge window %pR\n", &info->res[i]); + printk(KERN_INFO "host bridge window %pR\n", &info->res[i]); } -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, - cnb20le_res); +static int __init broadcom_postcore_init(void) +{ + u8 bus = 0, slot = 0; + u32 id; + u16 vendor, device; + +#ifdef CONFIG_ACPI + /* + * We should get host bridge information from ACPI unless the BIOS + * doesn't support it. + */ + if (acpi_os_get_root_pointer()) + return 0; +#endif + + id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID); + vendor = id & 0xffff; + device = (id >> 16) & 0xffff; + + if (vendor == PCI_VENDOR_ID_SERVERWORKS && + device == PCI_DEVICE_ID_SERVERWORKS_LE) { + cnb20le_res(bus, slot, 0); + cnb20le_res(bus, slot, 1); + } + return 0; +} +postcore_initcall(broadcom_postcore_init); diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c index 64a12288389..fd3f65510e9 100644 --- a/arch/x86/pci/bus_numa.c +++ b/arch/x86/pci/bus_numa.c @@ -7,45 +7,50 @@ int pci_root_num; struct pci_root_info pci_root_info[PCI_ROOT_NR]; -void x86_pci_root_bus_res_quirks(struct pci_bus *b) +void x86_pci_root_bus_resources(int bus, struct list_head *resources) { int i; int j; struct pci_root_info *info; - /* don't go for it if _CRS is used already */ - if (b->resource[0] != &ioport_resource || - b->resource[1] != &iomem_resource) - return; - if (!pci_root_num) - return; + goto default_resources; for (i = 0; i < pci_root_num; i++) { - if (pci_root_info[i].bus_min == b->number) + if (pci_root_info[i].bus_min == bus) break; } if (i == pci_root_num) - return; + goto default_resources; - printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n", - b->number); + printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", + bus); - pci_bus_remove_resources(b); info = &pci_root_info[i]; for (j = 0; j < info->res_num; j++) { struct resource *res; struct resource *root; res = &info->res[j]; - pci_bus_add_resource(b, res, 0); + pci_add_resource(resources, res); if (res->flags & IORESOURCE_IO) root = &ioport_resource; else root = &iomem_resource; insert_resource(root, res); } + return; + +default_resources: + /* + * We don't have any host bridge aperture information from the + * "native host bridge drivers," e.g., amd_bus or broadcom_bus, + * so fall back to the defaults historically used by pci_create_bus(). + */ + printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus); + pci_add_resource(resources, &ioport_resource); + pci_add_resource(resources, &iomem_resource); } void __devinit update_res(struct pci_root_info *info, resource_size_t start, diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 7962ccb4d9b..323481e06ef 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -164,9 +164,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b) { struct pci_dev *dev; - /* root bus? */ - if (!b->parent) - x86_pci_root_bus_res_quirks(b); pci_read_bridge_bases(b); list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); @@ -433,6 +430,7 @@ void __init dmi_check_pciprobe(void) struct pci_bus * __devinit pcibios_scan_root(int busnum) { + LIST_HEAD(resources); struct pci_bus *bus = NULL; struct pci_sysdata *sd; @@ -456,9 +454,12 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) sd->node = get_mp_bus_to_node(busnum); printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); - bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); - if (!bus) + x86_pci_root_bus_resources(busnum, &resources); + bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources); + if (!bus) { + pci_free_resource_list(&resources); kfree(sd); + } return bus; } @@ -639,6 +640,7 @@ int pci_ext_cfg_avail(struct pci_dev *dev) struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) { + LIST_HEAD(resources); struct pci_bus *bus = NULL; struct pci_sysdata *sd; @@ -653,9 +655,12 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, return NULL; } sd->node = node; - bus = pci_scan_bus(busno, ops, sd); - if (!bus) + x86_pci_root_bus_resources(busno, &resources); + bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources); + if (!bus) { + pci_free_resource_list(&resources); kfree(sd); + } return bus; } diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 794b092d01a..91821a1a0c3 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -254,26 +254,6 @@ void __init pcibios_resource_survey(void) */ fs_initcall(pcibios_assign_resources); -/* - * If we set up a device for bus mastering, we need to check the latency - * timer as certain crappy BIOSes forget to set it properly. - */ -unsigned int pcibios_max_latency = 255; - -void pcibios_set_master(struct pci_dev *dev) -{ - u8 lat; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - if (lat < 16) - lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; - else if (lat > pcibios_max_latency) - lat = pcibios_max_latency; - else - return; - dev_printk(KERN_DEBUG, &dev->dev, "setting latency timer to %d\n", lat); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} - static const struct vm_operations_struct pci_mmap_ops = { .access = generic_access_phys, }; diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index 2c2aeabc260..a1df191129d 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c @@ -31,9 +31,6 @@ int __init pci_legacy_init(void) printk("PCI: Probing PCI hardware\n"); pci_root_bus = pcibios_scan_root(0); - if (pci_root_bus) - pci_bus_add_devices(pci_root_bus); - return 0; } diff --git a/arch/x86/pci/numaq_32.c b/arch/x86/pci/numaq_32.c index 51abf02f922..83e125b95ca 100644 --- a/arch/x86/pci/numaq_32.c +++ b/arch/x86/pci/numaq_32.c @@ -153,8 +153,6 @@ int __init pci_numaq_init(void) raw_pci_ops = &pci_direct_conf1_mq; pci_root_bus = pcibios_scan_root(0); - if (pci_root_bus) - pci_bus_add_devices(pci_root_bus); if (num_online_nodes() > 1) for_each_online_node(quad) { if (quad == 0) diff --git a/arch/xtensa/include/asm/pci.h b/arch/xtensa/include/asm/pci.h index 4609b0f15f1..05244f07dd3 100644 --- a/arch/xtensa/include/asm/pci.h +++ b/arch/xtensa/include/asm/pci.h @@ -22,11 +22,6 @@ extern struct pci_controller* pcibios_alloc_controller(void); -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - static inline void pcibios_penalize_isa_irq(int irq) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index cd102693120..61045c192e8 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -134,9 +134,46 @@ struct pci_controller * __init pcibios_alloc_controller(void) return pci_ctrl; } +static void __init pci_controller_apertures(struct pci_controller *pci_ctrl, + struct list_head *resources) +{ + struct resource *res; + unsigned long io_offset; + int i; + + io_offset = (unsigned long)pci_ctrl->io_space.base; + res = &pci_ctrl->io_resource; + if (!res->flags) { + if (io_offset) + printk (KERN_ERR "I/O resource not set for host" + " bridge %d\n", pci_ctrl->index); + res->start = 0; + res->end = IO_SPACE_LIMIT; + res->flags = IORESOURCE_IO; + } + res->start += io_offset; + res->end += io_offset; + pci_add_resource(resources, res); + + for (i = 0; i < 3; i++) { + res = &pci_ctrl->mem_resources[i]; + if (!res->flags) { + if (i > 0) + continue; + printk(KERN_ERR "Memory resource not set for " + "host bridge %d\n", pci_ctrl->index); + res->start = 0; + res->end = ~0U; + res->flags = IORESOURCE_MEM; + } + pci_add_resource(resources, res); + } +} + static int __init pcibios_init(void) { struct pci_controller *pci_ctrl; + struct list_head resources; struct pci_bus *bus; int next_busno = 0, i; @@ -145,19 +182,10 @@ static int __init pcibios_init(void) /* Scan all of the recorded PCI controllers. */ for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) { pci_ctrl->last_busno = 0xff; - bus = pci_scan_bus(pci_ctrl->first_busno, pci_ctrl->ops, - pci_ctrl); - if (pci_ctrl->io_resource.flags) { - unsigned long offs; - - offs = (unsigned long)pci_ctrl->io_space.base; - pci_ctrl->io_resource.start += offs; - pci_ctrl->io_resource.end += offs; - bus->resource[0] = &pci_ctrl->io_resource; - } - for (i = 0; i < 3; ++i) - if (pci_ctrl->mem_resources[i].flags) - bus->resource[i+1] =&pci_ctrl->mem_resources[i]; + INIT_LIST_HEAD(&resources); + pci_controller_apertures(pci_ctrl, &resources); + bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno, + pci_ctrl->ops, pci_ctrl, &resources); pci_ctrl->bus = bus; pci_ctrl->last_busno = bus->subordinate; if (next_busno <= pci_ctrl->last_busno) @@ -178,36 +206,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) int i; io_offset = (unsigned long)pci_ctrl->io_space.base; - if (bus->parent == NULL) { - /* this is a host bridge - fill in its resources */ - pci_ctrl->bus = bus; - - bus->resource[0] = res = &pci_ctrl->io_resource; - if (!res->flags) { - if (io_offset) - printk (KERN_ERR "I/O resource not set for host" - " bridge %d\n", pci_ctrl->index); - res->start = 0; - res->end = IO_SPACE_LIMIT; - res->flags = IORESOURCE_IO; - } - res->start += io_offset; - res->end += io_offset; - - for (i = 0; i < 3; i++) { - res = &pci_ctrl->mem_resources[i]; - if (!res->flags) { - if (i > 0) - continue; - printk(KERN_ERR "Memory resource not set for " - "host bridge %d\n", pci_ctrl->index); - res->start = 0; - res->end = ~0U; - res->flags = IORESOURCE_MEM; - } - bus->resource[i+1] = res; - } - } else { + if (bus->parent) { /* This is a subordinate bridge */ pci_read_bridge_bases(bus); @@ -227,6 +226,11 @@ char __init *pcibios_setup(char *str) return str; } +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} + /* the next one is stolen from the alpha port... */ void __init diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 7f9eba9a0b0..0eefa12e648 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -487,10 +487,10 @@ int acpi_pci_irq_enable(struct pci_dev *dev) else link_desc[0] = '\0'; - dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n", - pin_name(pin), link_desc, gsi, - (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", - (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); + dev_dbg(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n", + pin_name(pin), link_desc, gsi, + (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", + (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); return 0; } @@ -524,6 +524,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) * (e.g. PCI_UNDEFINED_IRQ). */ - dev_info(&dev->dev, "PCI INT %c disabled\n", pin_name(pin)); + dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin)); acpi_unregister_gsi(gsi); } diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index bcd5d54b7d4..7ff10c1e866 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -562,19 +562,6 @@ dino_fixup_bus(struct pci_bus *bus) /* Firmware doesn't set up card-mode dino, so we have to */ if (is_card_dino(&dino_dev->hba.dev->id)) { dino_card_setup(bus, dino_dev->hba.base_addr); - } else if(bus->parent == NULL) { - /* must have a dino above it, reparent the resources - * into the dino window */ - int i; - struct resource *res = &dino_dev->hba.lmmio_space; - - bus->resource[0] = &(dino_dev->hba.io_space); - for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) { - if(res[i].flags == 0) - break; - bus->resource[i+1] = &res[i]; - } - } else if (bus->parent) { int i; @@ -927,6 +914,7 @@ static int __init dino_probe(struct parisc_device *dev) const char *version = "unknown"; char *name; int is_cujo = 0; + LIST_HEAD(resources); struct pci_bus *bus; unsigned long hpa = dev->hpa.start; @@ -1003,26 +991,37 @@ static int __init dino_probe(struct parisc_device *dev) dev->dev.platform_data = dino_dev; + pci_add_resource(&resources, &dino_dev->hba.io_space); + if (dino_dev->hba.lmmio_space.flags) + pci_add_resource(&resources, &dino_dev->hba.lmmio_space); + if (dino_dev->hba.elmmio_space.flags) + pci_add_resource(&resources, &dino_dev->hba.elmmio_space); + if (dino_dev->hba.gmmio_space.flags) + pci_add_resource(&resources, &dino_dev->hba.gmmio_space); + /* ** It's not used to avoid chicken/egg problems ** with configuration accessor functions. */ - dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev, - dino_current_bus, &dino_cfg_ops, NULL); - - if(bus) { - /* This code *depends* on scanning being single threaded - * if it isn't, this global bus number count will fail - */ - dino_current_bus = bus->subordinate + 1; - pci_bus_assign_resources(bus); - pci_bus_add_devices(bus); - } else { + dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev, + dino_current_bus, &dino_cfg_ops, NULL, &resources); + if (!bus) { printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n", dev_name(&dev->dev), dino_current_bus); + pci_free_resource_list(&resources); /* increment the bus number in case of duplicates */ dino_current_bus++; + return 0; } + + bus->subordinate = pci_scan_child_bus(bus); + + /* This code *depends* on scanning being single threaded + * if it isn't, this global bus number count will fail + */ + dino_current_bus = bus->subordinate + 1; + pci_bus_assign_resources(bus); + pci_bus_add_devices(bus); return 0; } diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 3aeb3279c92..d5f3d753a10 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -653,7 +653,7 @@ lba_fixup_bus(struct pci_bus *bus) } } else { /* Host-PCI Bridge */ - int err, i; + int err; DBG("lba_fixup_bus() %s [%lx/%lx]/%lx\n", ldev->hba.io_space.name, @@ -669,9 +669,6 @@ lba_fixup_bus(struct pci_bus *bus) lba_dump_res(&ioport_resource, 2); BUG(); } - /* advertize Host bridge resources to PCI bus */ - bus->resource[0] = &(ldev->hba.io_space); - i = 1; if (ldev->hba.elmmio_space.start) { err = request_resource(&iomem_resource, @@ -685,35 +682,17 @@ lba_fixup_bus(struct pci_bus *bus) /* lba_dump_res(&iomem_resource, 2); */ /* BUG(); */ - } else - bus->resource[i++] = &(ldev->hba.elmmio_space); + } } - - /* Overlaps with elmmio can (and should) fail here. - * We will prune (or ignore) the distributed range. - * - * FIXME: SBA code should register all elmmio ranges first. - * that would take care of elmmio ranges routed - * to a different rope (already discovered) from - * getting registered *after* LBA code has already - * registered it's distributed lmmio range. - */ - if (truncate_pat_collision(&iomem_resource, - &(ldev->hba.lmmio_space))) { - - printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n", - (long)ldev->hba.lmmio_space.start, - (long)ldev->hba.lmmio_space.end); - } else { + if (ldev->hba.lmmio_space.flags) { err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space)); if (err < 0) { printk(KERN_ERR "FAILED: lba_fixup_bus() request for " "lmmio_space [%lx/%lx]\n", (long)ldev->hba.lmmio_space.start, (long)ldev->hba.lmmio_space.end); - } else - bus->resource[i++] = &(ldev->hba.lmmio_space); + } } #ifdef CONFIG_64BIT @@ -728,7 +707,6 @@ lba_fixup_bus(struct pci_bus *bus) lba_dump_res(&iomem_resource, 2); BUG(); } - bus->resource[i++] = &(ldev->hba.gmmio_space); } #endif @@ -1404,6 +1382,7 @@ static int __init lba_driver_probe(struct parisc_device *dev) { struct lba_device *lba_dev; + LIST_HEAD(resources); struct pci_bus *lba_bus; struct pci_ops *cfg_ops; u32 func_class; @@ -1518,10 +1497,41 @@ lba_driver_probe(struct parisc_device *dev) if (lba_dev->hba.bus_num.start < lba_next_bus) lba_dev->hba.bus_num.start = lba_next_bus; + /* Overlaps with elmmio can (and should) fail here. + * We will prune (or ignore) the distributed range. + * + * FIXME: SBA code should register all elmmio ranges first. + * that would take care of elmmio ranges routed + * to a different rope (already discovered) from + * getting registered *after* LBA code has already + * registered it's distributed lmmio range. + */ + if (truncate_pat_collision(&iomem_resource, + &(lba_dev->hba.lmmio_space))) { + printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n", + (long)lba_dev->hba.lmmio_space.start, + (long)lba_dev->hba.lmmio_space.end); + lba_dev->hba.lmmio_space.flags = 0; + } + + pci_add_resource(&resources, &lba_dev->hba.io_space); + if (lba_dev->hba.elmmio_space.start) + pci_add_resource(&resources, &lba_dev->hba.elmmio_space); + if (lba_dev->hba.lmmio_space.flags) + pci_add_resource(&resources, &lba_dev->hba.lmmio_space); + if (lba_dev->hba.gmmio_space.flags) + pci_add_resource(&resources, &lba_dev->hba.gmmio_space); + dev->dev.platform_data = lba_dev; lba_bus = lba_dev->hba.hba_bus = - pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start, - cfg_ops, NULL); + pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start, + cfg_ops, NULL, &resources); + if (!lba_bus) { + pci_free_resource_list(&resources); + return 0; + } + + lba_bus->subordinate = pci_scan_child_bus(lba_bus); /* This is in lieu of calling pci_assign_unassigned_resources() */ if (is_pdc_pat()) { @@ -1551,10 +1561,8 @@ lba_driver_probe(struct parisc_device *dev) lba_dev->flags |= LBA_FLAG_SKIP_PROBE; } - if (lba_bus) { - lba_next_bus = lba_bus->subordinate + 1; - pci_bus_add_devices(lba_bus); - } + lba_next_bus = lba_bus->subordinate + 1; + pci_bus_add_devices(lba_bus); /* Whew! Finally done! Tell services we got this one covered. */ return 0; diff --git a/drivers/pci/access.c b/drivers/pci/access.c index fdaa42aac7c..2a581642c23 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -13,7 +13,7 @@ * configuration space. */ -static DEFINE_RAW_SPINLOCK(pci_lock); +DEFINE_RAW_SPINLOCK(pci_lock); /* * Wrappers for all PCI configuration access functions. They just check @@ -127,20 +127,20 @@ EXPORT_SYMBOL(pci_write_vpd); * We have a bit per device to indicate it's blocked and a global wait queue * for callers to sleep on until devices are unblocked. */ -static DECLARE_WAIT_QUEUE_HEAD(pci_ucfg_wait); +static DECLARE_WAIT_QUEUE_HEAD(pci_cfg_wait); -static noinline void pci_wait_ucfg(struct pci_dev *dev) +static noinline void pci_wait_cfg(struct pci_dev *dev) { DECLARE_WAITQUEUE(wait, current); - __add_wait_queue(&pci_ucfg_wait, &wait); + __add_wait_queue(&pci_cfg_wait, &wait); do { set_current_state(TASK_UNINTERRUPTIBLE); raw_spin_unlock_irq(&pci_lock); schedule(); raw_spin_lock_irq(&pci_lock); - } while (dev->block_ucfg_access); - __remove_wait_queue(&pci_ucfg_wait, &wait); + } while (dev->block_cfg_access); + __remove_wait_queue(&pci_cfg_wait, &wait); } /* Returns 0 on success, negative values indicate error. */ @@ -153,7 +153,8 @@ int pci_user_read_config_##size \ if (PCI_##size##_BAD) \ return -EINVAL; \ raw_spin_lock_irq(&pci_lock); \ - if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev); \ + if (unlikely(dev->block_cfg_access)) \ + pci_wait_cfg(dev); \ ret = dev->bus->ops->read(dev->bus, dev->devfn, \ pos, sizeof(type), &data); \ raw_spin_unlock_irq(&pci_lock); \ @@ -172,7 +173,8 @@ int pci_user_write_config_##size \ if (PCI_##size##_BAD) \ return -EINVAL; \ raw_spin_lock_irq(&pci_lock); \ - if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev); \ + if (unlikely(dev->block_cfg_access)) \ + pci_wait_cfg(dev); \ ret = dev->bus->ops->write(dev->bus, dev->devfn, \ pos, sizeof(type), val); \ raw_spin_unlock_irq(&pci_lock); \ @@ -401,36 +403,56 @@ int pci_vpd_truncate(struct pci_dev *dev, size_t size) EXPORT_SYMBOL(pci_vpd_truncate); /** - * pci_block_user_cfg_access - Block userspace PCI config reads/writes + * pci_cfg_access_lock - Lock PCI config reads/writes * @dev: pci device struct * - * When user access is blocked, any reads or writes to config space will - * sleep until access is unblocked again. We don't allow nesting of - * block/unblock calls. + * When access is locked, any userspace reads or writes to config + * space and concurrent lock requests will sleep until access is + * allowed via pci_cfg_access_unlocked again. */ -void pci_block_user_cfg_access(struct pci_dev *dev) +void pci_cfg_access_lock(struct pci_dev *dev) +{ + might_sleep(); + + raw_spin_lock_irq(&pci_lock); + if (dev->block_cfg_access) + pci_wait_cfg(dev); + dev->block_cfg_access = 1; + raw_spin_unlock_irq(&pci_lock); +} +EXPORT_SYMBOL_GPL(pci_cfg_access_lock); + +/** + * pci_cfg_access_trylock - try to lock PCI config reads/writes + * @dev: pci device struct + * + * Same as pci_cfg_access_lock, but will return 0 if access is + * already locked, 1 otherwise. This function can be used from + * atomic contexts. + */ +bool pci_cfg_access_trylock(struct pci_dev *dev) { unsigned long flags; - int was_blocked; + bool locked = true; raw_spin_lock_irqsave(&pci_lock, flags); - was_blocked = dev->block_ucfg_access; - dev->block_ucfg_access = 1; + if (dev->block_cfg_access) + locked = false; + else + dev->block_cfg_access = 1; raw_spin_unlock_irqrestore(&pci_lock, flags); - /* If we BUG() inside the pci_lock, we're guaranteed to hose - * the machine */ - BUG_ON(was_blocked); + return locked; } -EXPORT_SYMBOL_GPL(pci_block_user_cfg_access); +EXPORT_SYMBOL_GPL(pci_cfg_access_trylock); /** - * pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes + * pci_cfg_access_unlock - Unlock PCI config reads/writes * @dev: pci device struct * - * This function allows userspace PCI config accesses to resume. + * This function allows PCI config accesses to resume. */ -void pci_unblock_user_cfg_access(struct pci_dev *dev) +void pci_cfg_access_unlock(struct pci_dev *dev) { unsigned long flags; @@ -438,10 +460,10 @@ void pci_unblock_user_cfg_access(struct pci_dev *dev) /* This indicates a problem in the caller, but we don't need * to kill them, unlike a double-block above. */ - WARN_ON(!dev->block_ucfg_access); + WARN_ON(!dev->block_cfg_access); - dev->block_ucfg_access = 0; - wake_up_all(&pci_ucfg_wait); + dev->block_cfg_access = 0; + wake_up_all(&pci_cfg_wait); raw_spin_unlock_irqrestore(&pci_lock, flags); } -EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access); +EXPORT_SYMBOL_GPL(pci_cfg_access_unlock); diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index 9dd90b30f91..95655d7c0d0 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -128,6 +128,23 @@ void pci_disable_ats(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_disable_ats); +void pci_restore_ats_state(struct pci_dev *dev) +{ + u16 ctrl; + + if (!pci_ats_enabled(dev)) + return; + if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS)) + BUG(); + + ctrl = PCI_ATS_CTRL_ENABLE; + if (!dev->is_virtfn) + ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU); + + pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); +} +EXPORT_SYMBOL_GPL(pci_restore_ats_state); + /** * pci_ats_queue_depth - query the ATS Invalidate Queue Depth * @dev: the PCI device diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 1e2ad92a475..398f5d85979 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -18,6 +18,32 @@ #include "pci.h" +void pci_add_resource(struct list_head *resources, struct resource *res) +{ + struct pci_bus_resource *bus_res; + + 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); + return; + } + + bus_res->res = res; + list_add_tail(&bus_res->list, resources); +} +EXPORT_SYMBOL(pci_add_resource); + +void pci_free_resource_list(struct list_head *resources) +{ + struct pci_bus_resource *bus_res, *tmp; + + list_for_each_entry_safe(bus_res, tmp, resources, list) { + list_del(&bus_res->list); + kfree(bus_res); + } +} +EXPORT_SYMBOL(pci_free_resource_list); + void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags) { @@ -52,16 +78,12 @@ EXPORT_SYMBOL_GPL(pci_bus_resource_n); void pci_bus_remove_resources(struct pci_bus *bus) { - struct pci_bus_resource *bus_res, *tmp; int i; for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) bus->resource[i] = NULL; - list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) { - list_del(&bus_res->list); - kfree(bus_res); - } + pci_free_resource_list(&bus->resources); } /** diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 1969a3ee305..0321fa3b422 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -347,11 +347,13 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) return rc; } + pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz); + iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; - pci_block_user_cfg_access(dev); + pci_cfg_access_lock(dev); pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); msleep(100); - pci_unblock_user_cfg_access(dev); + pci_cfg_access_unlock(dev); iov->initial = initial; if (nr_virtfn < initial) @@ -379,10 +381,10 @@ failed: virtfn_remove(dev, j, 0); iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); - pci_block_user_cfg_access(dev); + pci_cfg_access_lock(dev); pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); ssleep(1); - pci_unblock_user_cfg_access(dev); + pci_cfg_access_unlock(dev); if (iov->link != dev->devfn) sysfs_remove_link(&dev->dev.kobj, "dep_link"); @@ -405,10 +407,10 @@ static void sriov_disable(struct pci_dev *dev) virtfn_remove(dev, i, 0); iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); - pci_block_user_cfg_access(dev); + pci_cfg_access_lock(dev); pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); ssleep(1); - pci_unblock_user_cfg_access(dev); + pci_cfg_access_unlock(dev); if (iov->link != dev->devfn) sysfs_remove_link(&dev->dev.kobj, "dep_link"); @@ -452,7 +454,6 @@ static int sriov_init(struct pci_dev *dev, int pos) found: pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl); - pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total); pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset); pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride); if (!offset || (total > 1 && !stride)) @@ -465,7 +466,6 @@ found: return -EIO; pgsz &= ~(pgsz - 1); - pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz); nres = 0; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 337e16ab4a9..a825d78fd0a 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -86,6 +86,31 @@ void default_teardown_msi_irqs(struct pci_dev *dev) } #endif +#ifndef arch_restore_msi_irqs +# define arch_restore_msi_irqs default_restore_msi_irqs +# define HAVE_DEFAULT_MSI_RESTORE_IRQS +#endif + +#ifdef HAVE_DEFAULT_MSI_RESTORE_IRQS +void default_restore_msi_irqs(struct pci_dev *dev, int irq) +{ + struct msi_desc *entry; + + entry = NULL; + if (dev->msix_enabled) { + list_for_each_entry(entry, &dev->msi_list, list) { + if (irq == entry->irq) + break; + } + } else if (dev->msi_enabled) { + entry = irq_get_msi_desc(irq); + } + + if (entry) + write_msi_msg(irq, &entry->msg); +} +#endif + static void msi_set_enable(struct pci_dev *dev, int pos, int enable) { u16 control; @@ -323,8 +348,18 @@ static void free_msi_irqs(struct pci_dev *dev) if (list_is_last(&entry->list, &dev->msi_list)) iounmap(entry->mask_base); } - kobject_del(&entry->kobj); - kobject_put(&entry->kobj); + + /* + * Its possible that we get into this path + * When populate_msi_sysfs fails, which means the entries + * were not registered with sysfs. In that case don't + * unregister them. + */ + if (entry->kobj.parent) { + kobject_del(&entry->kobj); + kobject_put(&entry->kobj); + } + list_del(&entry->list); kfree(entry); } @@ -362,7 +397,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) pci_intx_for_msi(dev, 0); msi_set_enable(dev, pos, 0); - write_msi_msg(dev->irq, &entry->msg); + arch_restore_msi_irqs(dev, dev->irq); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); msi_mask_irq(entry, msi_capable_mask(control), entry->masked); @@ -390,7 +425,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); list_for_each_entry(entry, &dev->msi_list, list) { - write_msi_msg(entry->irq, &entry->msg); + arch_restore_msi_irqs(dev, entry->irq); msix_mask_irq(entry, entry->masked); } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 12d1e81a8ab..3623d65f8b8 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -604,7 +604,8 @@ static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) * supported as well. Drivers are supposed to support either the * former, or the latter, but not both at the same time. */ - WARN_ON(ret && drv->driver.pm); + WARN(ret && drv->driver.pm, "driver %s device %04x:%04x\n", + drv->name, pci_dev->vendor, pci_dev->device); return ret; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6d4a5319148..97fff785e97 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -88,6 +88,12 @@ enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF; u8 pci_dfl_cache_line_size __devinitdata = L1_CACHE_BYTES >> 2; u8 pci_cache_line_size; +/* + * If we set up a device for bus mastering, we need to check the latency + * timer as certain BIOSes forget to set it properly. + */ +unsigned int pcibios_max_latency = 255; + /** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search @@ -959,6 +965,7 @@ void pci_restore_state(struct pci_dev *dev) /* PCI Express register must be restored first */ pci_restore_pcie_state(dev); + pci_restore_ats_state(dev); /* * The Base Address register should be programmed before the command @@ -967,7 +974,7 @@ 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]) { - dev_printk(KERN_DEBUG, &dev->dev, "restoring config " + 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, @@ -1536,8 +1543,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable) } out: - dev_printk(KERN_DEBUG, &dev->dev, "PME# %s\n", - enable ? "enabled" : "disabled"); + dev_dbg(&dev->dev, "PME# %s\n", enable ? "enabled" : "disabled"); } /** @@ -2596,6 +2602,33 @@ static void __pci_set_master(struct pci_dev *dev, bool enable) } /** + * pcibios_set_master - enable PCI bus-mastering for device dev + * @dev: the PCI device to enable + * + * Enables PCI bus-mastering for the device. This is the default + * implementation. Architecture specific implementations can override + * this if necessary. + */ +void __weak pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + + /* The latency timer doesn't apply to PCIe (either Type 0 or Type 1) */ + if (pci_is_pcie(dev)) + return; + + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat < 16) + lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; + else if (lat > pcibios_max_latency) + lat = pcibios_max_latency; + else + return; + dev_printk(KERN_DEBUG, &dev->dev, "setting latency timer to %d\n", lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); +} + +/** * pci_set_master - enables bus-mastering for device dev * @dev: the PCI device to enable * @@ -2768,6 +2801,116 @@ pci_intx(struct pci_dev *pdev, int enable) } /** + * pci_intx_mask_supported - probe for INTx masking support + * @pdev: the PCI device to operate on + * + * Check if the device dev support INTx masking via the config space + * command word. + */ +bool pci_intx_mask_supported(struct pci_dev *dev) +{ + bool mask_supported = false; + u16 orig, new; + + pci_cfg_access_lock(dev); + + pci_read_config_word(dev, PCI_COMMAND, &orig); + pci_write_config_word(dev, PCI_COMMAND, + orig ^ PCI_COMMAND_INTX_DISABLE); + pci_read_config_word(dev, PCI_COMMAND, &new); + + /* + * There's no way to protect against hardware bugs or detect them + * reliably, but as long as we know what the value should be, let's + * go ahead and check it. + */ + if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) { + dev_err(&dev->dev, "Command register changed from " + "0x%x to 0x%x: driver or hardware bug?\n", orig, new); + } else if ((new ^ orig) & PCI_COMMAND_INTX_DISABLE) { + mask_supported = true; + pci_write_config_word(dev, PCI_COMMAND, orig); + } + + pci_cfg_access_unlock(dev); + return mask_supported; +} +EXPORT_SYMBOL_GPL(pci_intx_mask_supported); + +static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask) +{ + struct pci_bus *bus = dev->bus; + bool mask_updated = true; + u32 cmd_status_dword; + u16 origcmd, newcmd; + unsigned long flags; + bool irq_pending; + + /* + * We do a single dword read to retrieve both command and status. + * Document assumptions that make this possible. + */ + BUILD_BUG_ON(PCI_COMMAND % 4); + BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); + + raw_spin_lock_irqsave(&pci_lock, flags); + + bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword); + + irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT; + + /* + * Check interrupt status register to see whether our device + * triggered the interrupt (when masking) or the next IRQ is + * already pending (when unmasking). + */ + if (mask != irq_pending) { + mask_updated = false; + goto done; + } + + origcmd = cmd_status_dword; + newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE; + if (mask) + newcmd |= PCI_COMMAND_INTX_DISABLE; + if (newcmd != origcmd) + bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd); + +done: + raw_spin_unlock_irqrestore(&pci_lock, flags); + + return mask_updated; +} + +/** + * pci_check_and_mask_intx - mask INTx on pending interrupt + * @pdev: the PCI device to operate on + * + * Check if the device dev has its INTx line asserted, mask it and + * return true in that case. False is returned if not interrupt was + * pending. + */ +bool pci_check_and_mask_intx(struct pci_dev *dev) +{ + return pci_check_and_set_intx_mask(dev, true); +} +EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); + +/** + * pci_check_and_mask_intx - unmask INTx of no interrupt is pending + * @pdev: the PCI device to operate on + * + * Check if the device dev has its INTx line asserted, unmask it if not + * and return true. False is returned and the mask remains active if + * there was still an interrupt pending. + */ +bool pci_check_and_unmask_intx(struct pci_dev *dev) +{ + return pci_check_and_set_intx_mask(dev, false); +} +EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); + +/** * pci_msi_off - disables any msi or msix capabilities * @dev: the PCI device to operate on * @@ -2965,7 +3108,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) might_sleep(); if (!probe) { - pci_block_user_cfg_access(dev); + pci_cfg_access_lock(dev); /* block PM suspend, driver probe, etc. */ device_lock(&dev->dev); } @@ -2990,7 +3133,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) done: if (!probe) { device_unlock(&dev->dev); - pci_unblock_user_cfg_access(dev); + pci_cfg_access_unlock(dev); } return rc; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b74084e9ca1..1009a5e88e5 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -136,6 +136,8 @@ static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; } /* Lock for read/write access to pci device and bus lists */ extern struct rw_semaphore pci_bus_sem; +extern raw_spinlock_t pci_lock; + extern unsigned int pci_pm_d3_delay; #ifdef CONFIG_PCI_MSI @@ -249,6 +251,14 @@ struct pci_sriov { u8 __iomem *mstate; /* VF Migration State Array */ }; +#ifdef CONFIG_PCI_ATS +extern void pci_restore_ats_state(struct pci_dev *dev); +#else +static inline void pci_restore_ats_state(struct pci_dev *dev) +{ +} +#endif /* CONFIG_PCI_ATS */ + #ifdef CONFIG_PCI_IOV extern int pci_iov_init(struct pci_dev *dev); extern void pci_iov_release(struct pci_dev *dev); diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index dc29348264c..72962cc92e0 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -39,7 +39,7 @@ config PCIEASPM Power Management) and Clock Power Management. ASPM supports state L0/L0s/L1. - ASPM is initially set up the the firmware. With this option enabled, + ASPM is initially set up by the firmware. With this option enabled, Linux can modify this state in order to disable ASPM on known-bad hardware or configurations and enable it when known-safe. diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 04e74f48571..7cc9e2f0f47 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1522,19 +1522,21 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) return max; } -struct pci_bus * pci_create_bus(struct device *parent, - int bus, struct pci_ops *ops, void *sysdata) +struct pci_bus *pci_create_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, struct list_head *resources) { - int error; + int error, i; struct pci_bus *b, *b2; struct device *dev; + struct pci_bus_resource *bus_res, *n; + struct resource *res; b = pci_alloc_bus(); if (!b) return NULL; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev){ + if (!dev) { kfree(b); return NULL; } @@ -1577,8 +1579,20 @@ struct pci_bus * pci_create_bus(struct device *parent, pci_create_legacy_files(b); b->number = b->secondary = bus; - b->resource[0] = &ioport_resource; - b->resource[1] = &iomem_resource; + + /* Add initial resources to the bus */ + list_for_each_entry_safe(bus_res, n, resources, list) + list_move_tail(&bus_res->list, &b->resources); + + 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); + } return b; @@ -1594,18 +1608,58 @@ err_out: return NULL; } +struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, struct list_head *resources) +{ + struct pci_bus *b; + + b = pci_create_root_bus(parent, bus, ops, sysdata, resources); + if (!b) + return NULL; + + b->subordinate = pci_scan_child_bus(b); + pci_bus_add_devices(b); + return b; +} +EXPORT_SYMBOL(pci_scan_root_bus); + +/* Deprecated; use pci_scan_root_bus() instead */ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { + LIST_HEAD(resources); struct pci_bus *b; - b = pci_create_bus(parent, bus, ops, sysdata); + pci_add_resource(&resources, &ioport_resource); + pci_add_resource(&resources, &iomem_resource); + b = pci_create_root_bus(parent, bus, ops, sysdata, &resources); if (b) b->subordinate = pci_scan_child_bus(b); + else + pci_free_resource_list(&resources); return b; } EXPORT_SYMBOL(pci_scan_bus_parented); +struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, + void *sysdata) +{ + LIST_HEAD(resources); + struct pci_bus *b; + + pci_add_resource(&resources, &ioport_resource); + pci_add_resource(&resources, &iomem_resource); + b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources); + if (b) { + b->subordinate = pci_scan_child_bus(b); + pci_bus_add_devices(b); + } else { + pci_free_resource_list(&resources); + } + return b; +} +EXPORT_SYMBOL(pci_scan_bus); + #ifdef CONFIG_HOTPLUG /** * pci_rescan_bus - scan a PCI bus for devices. diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 7f87beed35a..6def3624c68 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -89,9 +89,8 @@ EXPORT_SYMBOL(pci_remove_bus); * device lists, remove the /proc entry, and notify userspace * (/sbin/hotplug). */ -void pci_remove_bus_device(struct pci_dev *dev) +static void __pci_remove_bus_device(struct pci_dev *dev) { - pci_stop_bus_device(dev); if (dev->subordinate) { struct pci_bus *b = dev->subordinate; @@ -102,6 +101,11 @@ void pci_remove_bus_device(struct pci_dev *dev) pci_destroy_dev(dev); } +void pci_remove_bus_device(struct pci_dev *dev) +{ + pci_stop_bus_device(dev); + __pci_remove_bus_device(dev); +} /** * pci_remove_behind_bridge - remove all devices behind a PCI bridge @@ -117,7 +121,7 @@ void pci_remove_behind_bridge(struct pci_dev *dev) if (dev->subordinate) list_for_each_safe(l, n, &dev->subordinate->devices) - pci_remove_bus_device(pci_dev_b(l)); + __pci_remove_bus_device(pci_dev_b(l)); } static void pci_stop_bus_devices(struct pci_bus *bus) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 5717509becb..b66bfdbd21f 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -85,9 +85,9 @@ void pci_update_resource(struct pci_dev *dev, int resno) } } res->flags &= ~IORESOURCE_UNSET; - dev_info(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n", - resno, res, (unsigned long long)region.start, - (unsigned long long)region.end); + dev_dbg(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n", + resno, res, (unsigned long long)region.start, + (unsigned long long)region.end); } int pci_claim_resource(struct pci_dev *dev, int resource) diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index dfbd5a6cc58..258fef272ea 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -295,6 +295,45 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) } } +#ifdef CONFIG_AMD_NB + +#include <asm/amd_nb.h> + +static void quirk_amd_mmconfig_area(struct pnp_dev *dev) +{ + resource_size_t start, end; + struct pnp_resource *pnp_res; + struct resource *res; + struct resource mmconfig_res, *mmconfig; + + mmconfig = amd_get_mmconfig_range(&mmconfig_res); + if (!mmconfig) + return; + + list_for_each_entry(pnp_res, &dev->resources, list) { + res = &pnp_res->res; + if (res->end < mmconfig->start || res->start > mmconfig->end || + (res->start == mmconfig->start && res->end == mmconfig->end)) + continue; + + dev_info(&dev->dev, FW_BUG + "%pR covers only part of AMD MMCONFIG area %pR; adding more reservations\n", + res, mmconfig); + if (mmconfig->start < res->start) { + start = mmconfig->start; + end = res->start - 1; + pnp_add_mem_resource(dev, start, end, 0); + } + if (mmconfig->end > res->end) { + start = res->end + 1; + end = mmconfig->end; + pnp_add_mem_resource(dev, start, end, 0); + } + break; + } +} +#endif + /* * PnP Quirks * Cards or devices that need some tweaking due to incomplete resource info @@ -322,6 +361,9 @@ static struct pnp_fixup pnp_fixups[] = { /* PnP resources that might overlap PCI BARs */ {"PNP0c01", quirk_system_pci_resources}, {"PNP0c02", quirk_system_pci_resources}, +#ifdef CONFIG_AMD_NB + {"PNP0c01", quirk_amd_mmconfig_area}, +#endif {""} }; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index fd860d952b2..67b169b7a5b 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7638,8 +7638,12 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) **/ static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd) { + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + ENTER; - pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); + if (ioa_cfg->cfg_locked) + pci_cfg_access_unlock(ioa_cfg->pdev); + ioa_cfg->cfg_locked = 0; ipr_cmd->job_step = ipr_reset_restore_cfg_space; LEAVE; return IPR_RC_JOB_CONTINUE; @@ -7660,8 +7664,6 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) int rc = PCIBIOS_SUCCESSFUL; ENTER; - pci_block_user_cfg_access(ioa_cfg->pdev); - if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO) writel(IPR_UPROCI_SIS64_START_BIST, ioa_cfg->regs.set_uproc_interrupt_reg32); @@ -7673,7 +7675,9 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; } else { - pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); + if (ioa_cfg->cfg_locked) + pci_cfg_access_unlock(ipr_cmd->ioa_cfg->pdev); + ioa_cfg->cfg_locked = 0; ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); rc = IPR_RC_JOB_CONTINUE; } @@ -7716,7 +7720,6 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd) struct pci_dev *pdev = ioa_cfg->pdev; ENTER; - pci_block_user_cfg_access(pdev); pci_set_pcie_reset_state(pdev, pcie_warm_reset); ipr_cmd->job_step = ipr_reset_slot_reset_done; ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT); @@ -7725,6 +7728,56 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd) } /** + * ipr_reset_block_config_access_wait - Wait for permission to block config access + * @ipr_cmd: ipr command struct + * + * Description: This attempts to block config access to the IOA. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_block_config_access_wait(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + int rc = IPR_RC_JOB_CONTINUE; + + if (pci_cfg_access_trylock(ioa_cfg->pdev)) { + ioa_cfg->cfg_locked = 1; + ipr_cmd->job_step = ioa_cfg->reset; + } else { + if (ipr_cmd->u.time_left) { + rc = IPR_RC_JOB_RETURN; + ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; + ipr_reset_start_timer(ipr_cmd, + IPR_CHECK_FOR_RESET_TIMEOUT); + } else { + ipr_cmd->job_step = ioa_cfg->reset; + dev_err(&ioa_cfg->pdev->dev, + "Timed out waiting to lock config access. Resetting anyway.\n"); + } + } + + return rc; +} + +/** + * ipr_reset_block_config_access - Block config access to the IOA + * @ipr_cmd: ipr command struct + * + * Description: This attempts to block config access to the IOA + * + * Return value: + * IPR_RC_JOB_CONTINUE + **/ +static int ipr_reset_block_config_access(struct ipr_cmnd *ipr_cmd) +{ + ipr_cmd->ioa_cfg->cfg_locked = 0; + ipr_cmd->job_step = ipr_reset_block_config_access_wait; + ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; + return IPR_RC_JOB_CONTINUE; +} + +/** * ipr_reset_allowed - Query whether or not IOA can be reset * @ioa_cfg: ioa config struct * @@ -7763,7 +7816,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd) ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); } else { - ipr_cmd->job_step = ioa_cfg->reset; + ipr_cmd->job_step = ipr_reset_block_config_access; rc = IPR_RC_JOB_CONTINUE; } @@ -7796,7 +7849,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd) writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg32); ipr_cmd->job_step = ipr_reset_wait_to_start_bist; } else { - ipr_cmd->job_step = ioa_cfg->reset; + ipr_cmd->job_step = ipr_reset_block_config_access; } ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index ac84736c1b9..b13f9cc1227 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1387,6 +1387,7 @@ struct ipr_ioa_cfg { u8 msi_received:1; u8 sis64:1; u8 dump_timeout:1; + u8 cfg_locked:1; u8 revid; diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index 02bd47bdee1..0bd08ef2b39 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c @@ -45,77 +45,12 @@ to_uio_pci_generic_dev(struct uio_info *info) static irqreturn_t irqhandler(int irq, struct uio_info *info) { struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); - struct pci_dev *pdev = gdev->pdev; - irqreturn_t ret = IRQ_NONE; - u32 cmd_status_dword; - u16 origcmd, newcmd, status; - - /* We do a single dword read to retrieve both command and status. - * Document assumptions that make this possible. */ - BUILD_BUG_ON(PCI_COMMAND % 4); - BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); - - pci_block_user_cfg_access(pdev); - - /* Read both command and status registers in a single 32-bit operation. - * Note: we could cache the value for command and move the status read - * out of the lock if there was a way to get notified of user changes - * to command register through sysfs. Should be good for shared irqs. */ - pci_read_config_dword(pdev, PCI_COMMAND, &cmd_status_dword); - origcmd = cmd_status_dword; - status = cmd_status_dword >> 16; - - /* Check interrupt status register to see whether our device - * triggered the interrupt. */ - if (!(status & PCI_STATUS_INTERRUPT)) - goto done; - - /* We triggered the interrupt, disable it. */ - newcmd = origcmd | PCI_COMMAND_INTX_DISABLE; - if (newcmd != origcmd) - pci_write_config_word(pdev, PCI_COMMAND, newcmd); - /* UIO core will signal the user process. */ - ret = IRQ_HANDLED; -done: - - pci_unblock_user_cfg_access(pdev); - return ret; -} + if (!pci_check_and_mask_intx(gdev->pdev)) + return IRQ_NONE; -/* Verify that the device supports Interrupt Disable bit in command register, - * per PCI 2.3, by flipping this bit and reading it back: this bit was readonly - * in PCI 2.2. */ -static int __devinit verify_pci_2_3(struct pci_dev *pdev) -{ - u16 orig, new; - int err = 0; - - pci_block_user_cfg_access(pdev); - pci_read_config_word(pdev, PCI_COMMAND, &orig); - pci_write_config_word(pdev, PCI_COMMAND, - orig ^ PCI_COMMAND_INTX_DISABLE); - pci_read_config_word(pdev, PCI_COMMAND, &new); - /* There's no way to protect against - * hardware bugs or detect them reliably, but as long as we know - * what the value should be, let's go ahead and check it. */ - if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) { - err = -EBUSY; - dev_err(&pdev->dev, "Command changed from 0x%x to 0x%x: " - "driver or HW bug?\n", orig, new); - goto err; - } - if (!((new ^ orig) & PCI_COMMAND_INTX_DISABLE)) { - dev_warn(&pdev->dev, "Device does not support " - "disabling interrupts: unable to bind.\n"); - err = -ENODEV; - goto err; - } - /* Now restore the original value. */ - pci_write_config_word(pdev, PCI_COMMAND, orig); -err: - pci_unblock_user_cfg_access(pdev); - return err; + /* UIO core will signal the user process. */ + return IRQ_HANDLED; } static int __devinit probe(struct pci_dev *pdev, @@ -138,9 +73,10 @@ static int __devinit probe(struct pci_dev *pdev, return -ENODEV; } - err = verify_pci_2_3(pdev); - if (err) + if (!pci_intx_mask_supported(pdev)) { + err = -ENODEV; goto err_verify; + } gdev = kzalloc(sizeof(struct uio_pci_generic_dev), GFP_KERNEL); if (!gdev) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 84225c756bd..a16b1df3def 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -111,7 +111,7 @@ enum { PCI_NUM_RESOURCES, /* preserve this for compatibility */ - DEVICE_COUNT_RESOURCE + DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES, }; typedef int __bitwise pci_power_t; @@ -308,7 +308,7 @@ struct pci_dev { unsigned int is_added:1; unsigned int is_busmaster:1; /* device is busmaster */ unsigned int no_msi:1; /* device may not use msi */ - unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ + unsigned int block_cfg_access:1; /* config space access is blocked */ unsigned int broken_parity_status:1; /* Device generates false positive parity */ unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ unsigned int msi_enabled:1; @@ -661,17 +661,13 @@ extern struct pci_bus *pci_find_bus(int domain, int busnr); void pci_bus_add_devices(const struct pci_bus *bus); struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata); -static inline struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, - void *sysdata) -{ - struct pci_bus *root_bus; - root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata); - if (root_bus) - pci_bus_add_devices(root_bus); - return root_bus; -} -struct pci_bus *pci_create_bus(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata); +struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata); +struct pci_bus *pci_create_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, + struct list_head *resources); +struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, + struct list_head *resources); struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); void pcie_update_link_speed(struct pci_bus *bus, u16 link_status); @@ -795,8 +791,11 @@ static inline int pci_is_managed(struct pci_dev *pdev) } void pci_disable_device(struct pci_dev *dev); + +extern unsigned int pcibios_max_latency; void pci_set_master(struct pci_dev *dev); void pci_clear_master(struct pci_dev *dev); + int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state); int pci_set_cacheline_size(struct pci_dev *dev); #define HAVE_PCI_SET_MWI @@ -804,6 +803,9 @@ int __must_check pci_set_mwi(struct pci_dev *dev); int pci_try_set_mwi(struct pci_dev *dev); void pci_clear_mwi(struct pci_dev *dev); void pci_intx(struct pci_dev *dev, int enable); +bool pci_intx_mask_supported(struct pci_dev *dev); +bool pci_check_and_mask_intx(struct pci_dev *dev); +bool pci_check_and_unmask_intx(struct pci_dev *dev); void pci_msi_off(struct pci_dev *dev); int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size); int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask); @@ -911,6 +913,8 @@ int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *); 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_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); void pci_bus_remove_resources(struct pci_bus *bus); @@ -1085,8 +1089,9 @@ int ht_create_irq(struct pci_dev *dev, int idx); void ht_destroy_irq(unsigned int irq); #endif /* CONFIG_HT_IRQ */ -extern void pci_block_user_cfg_access(struct pci_dev *dev); -extern void pci_unblock_user_cfg_access(struct pci_dev *dev); +extern void pci_cfg_access_lock(struct pci_dev *dev); +extern bool pci_cfg_access_trylock(struct pci_dev *dev); +extern void pci_cfg_access_unlock(struct pci_dev *dev); /* * PCI domain support. Sometimes called PCI segment (eg by ACPI), @@ -1283,10 +1288,13 @@ static inline void pci_release_regions(struct pci_dev *dev) #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0) -static inline void pci_block_user_cfg_access(struct pci_dev *dev) +static inline void pci_block_cfg_access(struct pci_dev *dev) { } -static inline void pci_unblock_user_cfg_access(struct pci_dev *dev) +static inline int pci_block_cfg_access_in_atomic(struct pci_dev *dev) +{ return 0; } + +static inline void pci_unblock_cfg_access(struct pci_dev *dev) { } static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from) @@ -1424,10 +1432,10 @@ static inline void pci_fixup_device(enum pci_fixup_pass pass, void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); void __iomem * const *pcim_iomap_table(struct pci_dev *pdev); -int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name); -int pcim_iomap_regions_request_all(struct pci_dev *pdev, u16 mask, +int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name); +int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask, const char *name); -void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask); +void pcim_iounmap_regions(struct pci_dev *pdev, int mask); extern int pci_pci_problems; #define PCIPCI_FAIL 1 /* No PCI PCI DMA */ @@ -1446,8 +1454,10 @@ extern u8 pci_cache_line_size; extern unsigned long pci_hotplug_io_size; extern unsigned long pci_hotplug_mem_size; +/* Architecture specific versions may override these (weak) */ int pcibios_add_platform_entries(struct pci_dev *dev); void pcibios_disable_device(struct pci_dev *dev); +void pcibios_set_master(struct pci_dev *dev); int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 2aaee0ca9da..31d77af2ef4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -776,6 +776,29 @@ #define PCI_DEVICE_ID_ELSA_QS3000 0x3000 #define PCI_VENDOR_ID_STMICRO 0x104A +#define PCI_DEVICE_ID_STMICRO_USB_HOST 0xCC00 +#define PCI_DEVICE_ID_STMICRO_USB_OHCI 0xCC01 +#define PCI_DEVICE_ID_STMICRO_USB_OTG 0xCC02 +#define PCI_DEVICE_ID_STMICRO_UART_HWFC 0xCC03 +#define PCI_DEVICE_ID_STMICRO_UART_NO_HWFC 0xCC04 +#define PCI_DEVICE_ID_STMICRO_SOC_DMA 0xCC05 +#define PCI_DEVICE_ID_STMICRO_SATA 0xCC06 +#define PCI_DEVICE_ID_STMICRO_I2C 0xCC07 +#define PCI_DEVICE_ID_STMICRO_SPI_HS 0xCC08 +#define PCI_DEVICE_ID_STMICRO_MAC 0xCC09 +#define PCI_DEVICE_ID_STMICRO_SDIO_EMMC 0xCC0A +#define PCI_DEVICE_ID_STMICRO_SDIO 0xCC0B +#define PCI_DEVICE_ID_STMICRO_GPIO 0xCC0C +#define PCI_DEVICE_ID_STMICRO_VIP 0xCC0D +#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_DMA 0xCC0E +#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_SRCS 0xCC0F +#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_MSPS 0xCC10 +#define PCI_DEVICE_ID_STMICRO_CAN 0xCC11 +#define PCI_DEVICE_ID_STMICRO_MLB 0xCC12 +#define PCI_DEVICE_ID_STMICRO_DBP 0xCC13 +#define PCI_DEVICE_ID_STMICRO_SATA_PHY 0xCC14 +#define PCI_DEVICE_ID_STMICRO_ESRAM 0xCC15 +#define PCI_DEVICE_ID_STMICRO_VIC 0xCC16 #define PCI_VENDOR_ID_BUSLOGIC 0x104B #define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 28fe380cb19..e41a10f5ae8 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -392,7 +392,7 @@ #define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ #define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ #define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ -#define PCI_EXP_TYPE_RC_EC 0x10 /* Root Complex Event Collector */ +#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ #define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ #define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ #define PCI_EXP_DEVCAP 4 /* Device capabilities */ diff --git a/lib/devres.c b/lib/devres.c index 4fbc09e6e9e..9676617b448 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -304,7 +304,7 @@ EXPORT_SYMBOL(pcim_iounmap); * * Request and iomap regions specified by @mask. */ -int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name) +int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name) { void __iomem * const *iomap; int i, rc; @@ -357,7 +357,7 @@ EXPORT_SYMBOL(pcim_iomap_regions); * * Request all PCI BARs and iomap regions specified by @mask. */ -int pcim_iomap_regions_request_all(struct pci_dev *pdev, u16 mask, +int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask, const char *name) { int request_mask = ((1 << 6) - 1) & ~mask; @@ -381,7 +381,7 @@ EXPORT_SYMBOL(pcim_iomap_regions_request_all); * * Unmap and release regions specified by @mask. */ -void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask) +void pcim_iounmap_regions(struct pci_dev *pdev, int mask) { void __iomem * const *iomap; int i; |