Merge branches 'pci/demodularize-hosts' and 'pci/host-request-windows' into next
authorBjorn Helgaas <bhelgaas@google.com>
Mon, 1 Aug 2016 17:23:57 +0000 (12:23 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 1 Aug 2016 17:23:57 +0000 (12:23 -0500)
* pci/demodularize-hosts:
  PCI: xgene: Make explicitly non-modular
  PCI: thunder-pem: Make explicitly non-modular
  PCI: thunder-ecam: Make explicitly non-modular
  PCI: tegra: Make explicitly non-modular
  PCI: rcar-gen2: Make explicitly non-modular
  PCI: rcar: Make explicitly non-modular
  PCI: mvebu: Make explicitly non-modular
  PCI: layerscape: Make explicitly non-modular
  PCI: keystone: Make explicitly non-modular
  PCI: hisi: Make explicitly non-modular
  PCI: generic: Make explicitly non-modular
  PCI: designware-plat: Make it explicitly non-modular
  PCI: artpec6: Make explicitly non-modular
  PCI: armada8k: Make explicitly non-modular
  PCI: artpec: Add PCI_MSI_IRQ_DOMAIN dependency
  PCI: artpec: Add Axis ARTPEC-6 PCIe controller driver
  PCI: Add DT binding for Axis ARTPEC-6 PCIe controller
  PCI: generic: Select IRQ_DOMAIN

* pci/host-request-windows:
  PCI: versatile: Simplify host bridge window iteration
  PCI: versatile: Request host bridge window resources with core function
  PCI: tegra: Request host bridge window resources with core function
  PCI: tegra: Remove top-level resource from hierarchy
  PCI: rcar: Simplify host bridge window iteration
  PCI: rcar: Request host bridge window resources with core function
  PCI: rcar Gen2: Request host bridge window resources
  PCI: rcar: Drop gen2 dummy I/O port region
  ARM: Make PCI I/O space optional
  PCI: mvebu: Request host bridge window resources with core function
  PCI: generic: Simplify host bridge window iteration
  PCI: generic: Request host bridge window resources with core function
  PCI: altera: Simplify host bridge window iteration
  PCI: altera: Request host bridge window resources with core function
  PCI: xilinx-nwl: Use dev_printk() when possible
  PCI: xilinx-nwl: Request host bridge window resources
  PCI: xilinx-nwl: Free bridge resource list on failure
  PCI: xilinx: Request host bridge window resources
  PCI: xilinx: Free bridge resource list on failure
  PCI: xgene: Request host bridge window resources
  PCI: xgene: Free bridge resource list on failure
  PCI: iproc: Request host bridge window resources
  PCI: designware: Simplify host bridge window iteration
  PCI: designware: Request host bridge window resources
  PCI: designware: Free bridge resource list on failure
  PCI: Add devm_request_pci_bus_resources()

71 files changed:
Documentation/kernel-parameters.txt
MAINTAINERS
arch/arm/Kconfig
arch/arm/include/asm/mach/pci.h
arch/arm/kernel/bios32.c
arch/arm64/Kconfig
arch/arm64/kernel/pci.c
arch/microblaze/include/asm/pci.h
arch/microblaze/pci/pci-common.c
arch/mips/include/asm/pci.h
arch/mips/pci/pci.c
arch/powerpc/include/asm/pci.h
arch/powerpc/kernel/pci-common.c
arch/sparc/include/asm/pci_64.h
arch/sparc/kernel/pci.c
arch/unicore32/kernel/pci.c
arch/x86/pci/common.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/pci_mcfg.c [new file with mode: 0644]
drivers/acpi/pci_root.c
drivers/irqchip/Kconfig
drivers/misc/genwqe/card_base.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/fm10k/fm10k_pci.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/nvme/host/pci.c
drivers/pci/Kconfig
drivers/pci/bus.c
drivers/pci/ecam.c
drivers/pci/ecam.h [deleted file]
drivers/pci/host/Kconfig
drivers/pci/host/pci-host-common.c
drivers/pci/host/pci-host-generic.c
drivers/pci/host/pci-mvebu.c
drivers/pci/host/pci-rcar-gen2.c
drivers/pci/host/pci-tegra.c
drivers/pci/host/pci-thunder-ecam.c
drivers/pci/host/pci-thunder-pem.c
drivers/pci/host/pci-versatile.c
drivers/pci/host/pci-xgene.c
drivers/pci/host/pcie-altera.c
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-iproc.c
drivers/pci/host/pcie-rcar.c
drivers/pci/host/pcie-xilinx-nwl.c
drivers/pci/host/pcie-xilinx.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Kconfig
drivers/pci/pcie/aspm.c
drivers/pci/pcie/pcie-dpc.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/setup-bus.c
drivers/scsi/lpfc/lpfc_init.c
drivers/usb/host/xhci-pci.c
include/linux/pci-acpi.h
include/linux/pci-ecam.h [new file with mode: 0644]
include/linux/pci.h

index 82b42c958d1c7def4eac5c9931a0e8a6f9aab6c6..2102248005b5be5568aff5719c529c2374bb6f3f 100644 (file)
@@ -2998,6 +2998,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                resource_alignment=
                                Format:
                                [<order of align>@][<domain>:]<bus>:<slot>.<func>[; ...]
+                               [<order of align>@]pci:<vendor>:<device>\
+                                               [:<subvendor>:<subdevice>][; ...]
                                Specifies alignment and device to reassign
                                aligned memory resources.
                                If <order of align> is not specified,
@@ -3016,6 +3018,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                hpmemsize=nn[KMG]       The fixed amount of bus space which is
                                reserved for hotplug bridge's memory window.
                                Default size is 2 megabytes.
+               hpbussize=nn    The minimum amount of additional bus numbers
+                               reserved for buses below a hotplug bridge.
+                               Default is 1.
                realloc=        Enable/disable reallocating PCI bridge resources
                                if allocations done by BIOS are too small to
                                accommodate resources required by all child
@@ -3047,6 +3052,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                compat  Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
                        ports driver.
 
+       pcie_port_pm=   [PCIE] PCIe port power management handling:
+               off     Disable power management of all PCIe ports
+               force   Forcibly enable power management of all PCIe ports
+
        pcie_pme=       [PCIE,PM] Native PCIe PME signaling options:
                nomsi   Do not use MSI for native PCIe PME signaling (this makes
                        all PCIe root ports use INTx for all services).
index d26687f863ef2090e5fe8e58eb5064794f07c049..db492037ad7cf49bdb1d53a2e5f87e4aae9e8641 100644 (file)
@@ -8678,6 +8678,7 @@ L:        linux-pci@vger.kernel.org
 Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
 S:     Supported
+F:     Documentation/devicetree/bindings/pci/
 F:     Documentation/PCI/
 F:     drivers/pci/
 F:     include/linux/pci*
index 90542db1220dbcff5bc7f0d27ce233389a6d780d..354c167a2b42a645eb5d50e8a4bb74dd4e85af1d 100644 (file)
@@ -715,7 +715,7 @@ config ARCH_VIRT
        depends on ARCH_MULTI_V7
        select ARM_AMBA
        select ARM_GIC
-       select ARM_GIC_V2M if PCI_MSI
+       select ARM_GIC_V2M if PCI
        select ARM_GIC_V3
        select ARM_PSCI
        select HAVE_ARM_ARCH_TIMER
index 0070e8520cd447932ece57098d091c511ed1b895..2d88af5be45fd6313126b1a6001643bcdac117c9 100644 (file)
@@ -22,6 +22,7 @@ struct hw_pci {
        struct msi_controller *msi_ctrl;
        struct pci_ops  *ops;
        int             nr_controllers;
+       unsigned int    io_optional:1;
        void            **private_data;
        int             (*setup)(int nr, struct pci_sys_data *);
        struct pci_bus *(*scan)(int nr, struct pci_sys_data *);
index 05e61a2eeabe9e24aaa5011d2f05dd769019a485..2f0e07735d1d4715234d94d6bd0e0d7c49f442c0 100644 (file)
@@ -410,7 +410,8 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return irq;
 }
 
-static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
+static int pcibios_init_resource(int busnr, struct pci_sys_data *sys,
+                                int io_optional)
 {
        int ret;
        struct resource_entry *window;
@@ -420,6 +421,14 @@ static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
                         &iomem_resource, sys->mem_offset);
        }
 
+       /*
+        * If a platform says I/O port support is optional, we don't add
+        * the default I/O space.  The platform is responsible for adding
+        * any I/O space it needs.
+        */
+       if (io_optional)
+               return 0;
+
        resource_list_for_each_entry(window, &sys->resources)
                if (resource_type(window->res) == IORESOURCE_IO)
                        return 0;
@@ -466,7 +475,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
                if (ret > 0) {
                        struct pci_host_bridge *host_bridge;
 
-                       ret = pcibios_init_resources(nr, sys);
+                       ret = pcibios_init_resource(nr, sys, hw->io_optional);
                        if (ret)  {
                                kfree(sys);
                                break;
@@ -515,25 +524,23 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
        list_for_each_entry(sys, &head, node) {
                struct pci_bus *bus = sys->bus;
 
-               if (!pci_has_flag(PCI_PROBE_ONLY)) {
+               /*
+                * We insert PCI resources into the iomem_resource and
+                * ioport_resource trees in either pci_bus_claim_resources()
+                * or pci_bus_assign_resources().
+                */
+               if (pci_has_flag(PCI_PROBE_ONLY)) {
+                       pci_bus_claim_resources(bus);
+               } else {
                        struct pci_bus *child;
 
-                       /*
-                        * Size the bridge windows.
-                        */
                        pci_bus_size_bridges(bus);
-
-                       /*
-                        * Assign resources.
-                        */
                        pci_bus_assign_resources(bus);
 
                        list_for_each_entry(child, &bus->children, node)
                                pcie_bus_configure_settings(child);
                }
-               /*
-                * Tell drivers about devices found.
-                */
+
                pci_bus_add_devices(bus);
        }
 }
@@ -590,18 +597,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
        return start;
 }
 
-/**
- * pcibios_enable_device - Enable I/O and memory.
- * @dev: PCI device to be enabled
- */
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       if (pci_has_flag(PCI_PROBE_ONLY))
-               return 0;
-
-       return pci_enable_resources(dev, mask);
-}
-
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
index 5a0a691d4220a60aab7a1ef2251f8ba85ddffe2a..21d955de41812c1471e3e9b431853c76ee7a3c16 100644 (file)
@@ -3,6 +3,7 @@ config ARM64
        select ACPI_CCA_REQUIRED if ACPI
        select ACPI_GENERIC_GSI if ACPI
        select ACPI_REDUCED_HARDWARE_ONLY if ACPI
+       select ACPI_MCFG if ACPI
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select ARCH_HAS_ELF_RANDOMIZE
@@ -20,9 +21,9 @@ config ARM64
        select ARM_ARCH_TIMER
        select ARM_GIC
        select AUDIT_ARCH_COMPAT_GENERIC
-       select ARM_GIC_V2M if PCI_MSI
+       select ARM_GIC_V2M if PCI
        select ARM_GIC_V3
-       select ARM_GIC_V3_ITS if PCI_MSI
+       select ARM_GIC_V3_ITS if PCI
        select ARM_PSCI_FW
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
@@ -96,6 +97,7 @@ config ARM64
        select OF_EARLY_FLATTREE
        select OF_NUMA if NUMA && OF
        select OF_RESERVED_MEM
+       select PCI_ECAM if ACPI
        select PERF_USE_VMALLOC
        select POWER_RESET
        select POWER_SUPPLY
index 3c4e308b40a0ef53fb0e89303bfe75b3c2f0fb6a..acf38722457b1d24a4aad62f167cef415b1538c3 100644 (file)
@@ -17,6 +17,9 @@
 #include <linux/mm.h>
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/pci-acpi.h>
+#include <linux/pci-ecam.h>
 #include <linux/slab.h>
 
 /*
@@ -36,25 +39,17 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
        return res->start;
 }
 
-/**
- * pcibios_enable_device - Enable I/O and memory.
- * @dev: PCI device to be enabled
- * @mask: bitmask of BARs to enable
- */
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       if (pci_has_flag(PCI_PROBE_ONLY))
-               return 0;
-
-       return pci_enable_resources(dev, mask);
-}
-
 /*
- * Try to assign the IRQ number from DT when adding a new device
+ * Try to assign the IRQ number when probing a new device
  */
-int pcibios_add_device(struct pci_dev *dev)
+int pcibios_alloc_irq(struct pci_dev *dev)
 {
-       dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+       if (acpi_disabled)
+               dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+#ifdef CONFIG_ACPI
+       else
+               return acpi_pci_irq_enable(dev);
+#endif
 
        return 0;
 }
@@ -65,13 +60,21 @@ int pcibios_add_device(struct pci_dev *dev)
 int raw_pci_read(unsigned int domain, unsigned int bus,
                  unsigned int devfn, int reg, int len, u32 *val)
 {
-       return -ENXIO;
+       struct pci_bus *b = pci_find_bus(domain, bus);
+
+       if (!b)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       return b->ops->read(b, devfn, reg, len, val);
 }
 
 int raw_pci_write(unsigned int domain, unsigned int bus,
                unsigned int devfn, int reg, int len, u32 val)
 {
-       return -ENXIO;
+       struct pci_bus *b = pci_find_bus(domain, bus);
+
+       if (!b)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       return b->ops->write(b, devfn, reg, len, val);
 }
 
 #ifdef CONFIG_NUMA
@@ -85,10 +88,124 @@ EXPORT_SYMBOL(pcibus_to_node);
 #endif
 
 #ifdef CONFIG_ACPI
-/* Root bridge scanning */
+
+struct acpi_pci_generic_root_info {
+       struct acpi_pci_root_info       common;
+       struct pci_config_window        *cfg;   /* config space mapping */
+};
+
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+{
+       struct pci_config_window *cfg = bus->sysdata;
+       struct acpi_device *adev = to_acpi_device(cfg->parent);
+       struct acpi_pci_root *root = acpi_driver_data(adev);
+
+       return root->segment;
+}
+
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+       if (!acpi_disabled) {
+               struct pci_config_window *cfg = bridge->bus->sysdata;
+               struct acpi_device *adev = to_acpi_device(cfg->parent);
+               ACPI_COMPANION_SET(&bridge->dev, adev);
+       }
+
+       return 0;
+}
+
+/*
+ * Lookup the bus range for the domain in MCFG, and set up config space
+ * mapping.
+ */
+static struct pci_config_window *
+pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
+{
+       struct resource *bus_res = &root->secondary;
+       u16 seg = root->segment;
+       struct pci_config_window *cfg;
+       struct resource cfgres;
+       unsigned int bsz;
+
+       /* Use address from _CBA if present, otherwise lookup MCFG */
+       if (!root->mcfg_addr)
+               root->mcfg_addr = pci_mcfg_lookup(seg, bus_res);
+
+       if (!root->mcfg_addr) {
+               dev_err(&root->device->dev, "%04x:%pR ECAM region not found\n",
+                       seg, bus_res);
+               return NULL;
+       }
+
+       bsz = 1 << pci_generic_ecam_ops.bus_shift;
+       cfgres.start = root->mcfg_addr + bus_res->start * bsz;
+       cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1;
+       cfgres.flags = IORESOURCE_MEM;
+       cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res,
+                             &pci_generic_ecam_ops);
+       if (IS_ERR(cfg)) {
+               dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n",
+                       seg, bus_res, PTR_ERR(cfg));
+               return NULL;
+       }
+
+       return cfg;
+}
+
+/* release_info: free resources allocated by init_info */
+static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
+{
+       struct acpi_pci_generic_root_info *ri;
+
+       ri = container_of(ci, struct acpi_pci_generic_root_info, common);
+       pci_ecam_free(ri->cfg);
+       kfree(ri);
+}
+
+static struct acpi_pci_root_ops acpi_pci_root_ops = {
+       .release_info = pci_acpi_generic_release_info,
+};
+
+/* Interface called from ACPI code to setup PCI host controller */
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-       /* TODO: Should be revisited when implementing PCI on ACPI */
-       return NULL;
+       int node = acpi_get_node(root->device->handle);
+       struct acpi_pci_generic_root_info *ri;
+       struct pci_bus *bus, *child;
+
+       ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node);
+       if (!ri)
+               return NULL;
+
+       ri->cfg = pci_acpi_setup_ecam_mapping(root);
+       if (!ri->cfg) {
+               kfree(ri);
+               return NULL;
+       }
+
+       acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops;
+       bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common,
+                                  ri->cfg);
+       if (!bus)
+               return NULL;
+
+       pci_bus_size_bridges(bus);
+       pci_bus_assign_resources(bus);
+
+       list_for_each_entry(child, &bus->children, node)
+               pcie_bus_configure_settings(child);
+
+       return bus;
 }
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+       acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+       acpi_pci_remove_bus(bus);
+}
+
 #endif
index fc3ecb55f1b23130efa35233e08ee77153e4a237..2a120bb70e544a9502af6615fe7f65bf1f303a53 100644 (file)
@@ -82,9 +82,6 @@ extern pgprot_t       pci_phys_mem_access_prot(struct file *file,
                                         pgprot_t prot);
 
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
-extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                                const struct resource *rsrc,
-                                resource_size_t *start, resource_size_t *end);
 
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
 extern void pcibios_setup_bus_self(struct pci_bus *bus);
index 14cba600da7ae4fff9573cfcb27465e8f322e73d..81556b843a8ed24228cbf9ed768e9d67649085c8 100644 (file)
@@ -218,33 +218,6 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
        return NULL;
 }
 
-/*
- * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
-                                     pgprot_t protection,
-                                     enum pci_mmap_state mmap_state,
-                                     int write_combine)
-{
-       pgprot_t prot = protection;
-
-       /* Write combine is always 0 on non-memory space mappings. On
-        * memory space, if the user didn't pass 1, we check for a
-        * "prefetchable" resource. This is a bit hackish, but we use
-        * this to workaround the inability of /sysfs to provide a write
-        * combine bit
-        */
-       if (mmap_state != pci_mmap_mem)
-               write_combine = 0;
-       else if (write_combine == 0) {
-               if (rp->flags & IORESOURCE_PREFETCH)
-                       write_combine = 1;
-       }
-
-       return pgprot_noncached(prot);
-}
-
 /*
  * This one is used by /dev/mem and fbdev who have no clue about the
  * PCI device, it tries to find the PCI device first and calls the
@@ -317,9 +290,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        vma->vm_pgoff = offset >> PAGE_SHIFT;
-       vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
-                                                 vma->vm_page_prot,
-                                                 mmap_state, write_combine);
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
        ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                               vma->vm_end - vma->vm_start, vma->vm_page_prot);
@@ -473,39 +444,25 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
                          resource_size_t *start, resource_size_t *end)
 {
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       resource_size_t offset = 0;
+       struct pci_bus_region region;
 
-       if (hose == NULL)
+       if (rsrc->flags & IORESOURCE_IO) {
+               pcibios_resource_to_bus(dev->bus, &region,
+                                       (struct resource *) rsrc);
+               *start = region.start;
+               *end = region.end;
                return;
+       }
 
-       if (rsrc->flags & IORESOURCE_IO)
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-
-       /* We pass a fully fixed up address to userland for MMIO instead of
-        * a BAR value because X is lame and expects to be able to use that
-        * to pass to /dev/mem !
+       /* We pass a CPU physical address to userland for MMIO instead of a
+        * BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem!
         *
-        * That means that we'll have potentially 64 bits values where some
-        * userland apps only expect 32 (like X itself since it thinks only
-        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
-        * 32 bits CHRPs :-(
-        *
-        * Hopefully, the sysfs insterface is immune to that gunk. Once X
-        * has been fixed (and the fix spread enough), we can re-enable the
-        * 2 lines below and pass down a BAR value to userland. In that case
-        * we'll also have to re-enable the matching code in
-        * __pci_mmap_make_offset().
-        *
-        * BenH.
+        * That means we may have 64-bit values where some apps only expect
+        * 32 (like X itself since it thinks only Sparc has 64-bit MMIO).
         */
-#if 0
-       else if (rsrc->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-#endif
-
-       *start = rsrc->start - offset;
-       *end = rsrc->end - offset;
+       *start = rsrc->start;
+       *end = rsrc->end;
 }
 
 /**
index 86b239d9d75d3e6bfb75ec020d26e8e49bc4798b..9b63cd41213de1290e7a06c31791a2eae74d7487 100644 (file)
@@ -80,16 +80,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
 
-static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
-               const struct resource *rsrc, resource_size_t *start,
-               resource_size_t *end)
-{
-       phys_addr_t size = resource_size(rsrc);
-
-       *start = fixup_bigphys_addr(rsrc->start, size);
-       *end = rsrc->start + size;
-}
-
 /*
  * Dynamic DMA mapping stuff.
  * MIPS has everything mapped statically.
index f1b11f0dea2d8e71e8f5b6cbf65ad4d9e54d0501..b4c02f29663e180aeb5635aba2f4d9eabd24980c 100644 (file)
@@ -112,7 +112,14 @@ static void pcibios_scanbus(struct pci_controller *hose)
                need_domain_info = 1;
        }
 
-       if (!pci_has_flag(PCI_PROBE_ONLY)) {
+       /*
+        * We insert PCI resources into the iomem_resource and
+        * ioport_resource trees in either pci_bus_claim_resources()
+        * or pci_bus_assign_resources().
+        */
+       if (pci_has_flag(PCI_PROBE_ONLY)) {
+               pci_bus_claim_resources(bus);
+       } else {
                pci_bus_size_bridges(bus);
                pci_bus_assign_resources(bus);
        }
@@ -319,6 +326,16 @@ void pcibios_fixup_bus(struct pci_bus *bus)
 EXPORT_SYMBOL(PCIBIOS_MIN_IO);
 EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
 
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                         const struct resource *rsrc, resource_size_t *start,
+                         resource_size_t *end)
+{
+       phys_addr_t size = resource_size(rsrc);
+
+       *start = fixup_bigphys_addr(rsrc->start, size);
+       *end = rsrc->start + size;
+}
+
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
index a6f3ac0d4602fd8b0ecb2db73ea3d6b52ef46efe..e9bd6cf0212fdbc33e14b0b9b7a192dbc775b5b0 100644 (file)
@@ -136,9 +136,6 @@ extern pgprot_t     pci_phys_mem_access_prot(struct file *file,
                                         pgprot_t prot);
 
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
-extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                                const struct resource *rsrc,
-                                resource_size_t *start, resource_size_t *end);
 
 extern resource_size_t pcibios_io_space_offset(struct pci_controller *hose);
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
index 0f7a60f1e9f6292ceb9f1ade5c67d2617d1aefb9..6de6e0e96ce5d1c6dccf94654531c05a91f6e401 100644 (file)
@@ -355,36 +355,6 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
        return NULL;
 }
 
-/*
- * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
-                                     pgprot_t protection,
-                                     enum pci_mmap_state mmap_state,
-                                     int write_combine)
-{
-
-       /* Write combine is always 0 on non-memory space mappings. On
-        * memory space, if the user didn't pass 1, we check for a
-        * "prefetchable" resource. This is a bit hackish, but we use
-        * this to workaround the inability of /sysfs to provide a write
-        * combine bit
-        */
-       if (mmap_state != pci_mmap_mem)
-               write_combine = 0;
-       else if (write_combine == 0) {
-               if (rp->flags & IORESOURCE_PREFETCH)
-                       write_combine = 1;
-       }
-
-       /* XXX would be nice to have a way to ask for write-through */
-       if (write_combine)
-               return pgprot_noncached_wc(protection);
-       else
-               return pgprot_noncached(protection);
-}
-
 /*
  * This one is used by /dev/mem and fbdev who have no clue about the
  * PCI device, it tries to find the PCI device first and calls the
@@ -458,9 +428,10 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        vma->vm_pgoff = offset >> PAGE_SHIFT;
-       vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
-                                                 vma->vm_page_prot,
-                                                 mmap_state, write_combine);
+       if (write_combine)
+               vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot);
+       else
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
        ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                               vma->vm_end - vma->vm_start, vma->vm_page_prot);
@@ -610,39 +581,25 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
                          resource_size_t *start, resource_size_t *end)
 {
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       resource_size_t offset = 0;
+       struct pci_bus_region region;
 
-       if (hose == NULL)
+       if (rsrc->flags & IORESOURCE_IO) {
+               pcibios_resource_to_bus(dev->bus, &region,
+                                       (struct resource *) rsrc);
+               *start = region.start;
+               *end = region.end;
                return;
+       }
 
-       if (rsrc->flags & IORESOURCE_IO)
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-
-       /* We pass a fully fixed up address to userland for MMIO instead of
-        * a BAR value because X is lame and expects to be able to use that
-        * to pass to /dev/mem !
-        *
-        * That means that we'll have potentially 64 bits values where some
-        * userland apps only expect 32 (like X itself since it thinks only
-        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
-        * 32 bits CHRPs :-(
-        *
-        * Hopefully, the sysfs insterface is immune to that gunk. Once X
-        * has been fixed (and the fix spread enough), we can re-enable the
-        * 2 lines below and pass down a BAR value to userland. In that case
-        * we'll also have to re-enable the matching code in
-        * __pci_mmap_make_offset().
+       /* We pass a CPU physical address to userland for MMIO instead of a
+        * BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem!
         *
-        * BenH.
+        * That means we may have 64-bit values where some apps only expect
+        * 32 (like X itself since it thinks only Sparc has 64-bit MMIO).
         */
-#if 0
-       else if (rsrc->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-#endif
-
-       *start = rsrc->start - offset;
-       *end = rsrc->end - offset;
+       *start = rsrc->start;
+       *end = rsrc->end;
 }
 
 /**
index 022d16008a00d8a3c82de515f0e0ca8c6f7001c0..2303635158f56fc9b5653e5a5949642328d9cfe5 100644 (file)
@@ -55,9 +55,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 }
 
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
-void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                         const struct resource *rsrc,
-                         resource_size_t *start, resource_size_t *end);
 #endif /* __KERNEL__ */
 
 #endif /* __SPARC64_PCI_H */
index c2b202d763a16ae74d1d150ed6e7dd940341d7dd..9c1878f4fa9f31a69f0849252ef160550689fcd5 100644 (file)
@@ -986,16 +986,18 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
                          const struct resource *rp, resource_size_t *start,
                          resource_size_t *end)
 {
-       struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       unsigned long offset;
-
-       if (rp->flags & IORESOURCE_IO)
-               offset = pbm->io_space.start;
-       else
-               offset = pbm->mem_space.start;
+       struct pci_bus_region region;
 
-       *start = rp->start - offset;
-       *end = rp->end - offset;
+       /*
+        * "User" addresses are shown in /sys/devices/pci.../.../resource
+        * and /proc/bus/pci/devices and used as mmap offsets for
+        * /proc/bus/pci/BB/DD.F files (see proc_bus_pci_mmap()).
+        *
+        * On sparc, these are PCI bus addresses, i.e., raw BAR values.
+        */
+       pcibios_resource_to_bus(pdev->bus, &region, (struct resource *) rp);
+       *start = region.start;
+       *end = region.end;
 }
 
 void pcibios_set_master(struct pci_dev *dev)
index d45fa5f3e9c41dae187ebebf59f18c8b595cef9c..62137d13c6f9d2d75783dca25139217f23b09d54 100644 (file)
@@ -265,10 +265,8 @@ static int __init pci_common_init(void)
 
        pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
 
-       if (!pci_has_flag(PCI_PROBE_ONLY)) {
-               pci_bus_size_bridges(puv3_bus);
-               pci_bus_assign_resources(puv3_bus);
-       }
+       pci_bus_size_bridges(puv3_bus);
+       pci_bus_assign_resources(puv3_bus);
        pci_bus_add_devices(puv3_bus);
        return 0;
 }
@@ -279,9 +277,6 @@ char * __init pcibios_setup(char *str)
        if (!strcmp(str, "debug")) {
                debug_pci = 1;
                return NULL;
-       } else if (!strcmp(str, "firmware")) {
-               pci_add_flags(PCI_PROBE_ONLY);
-               return NULL;
        }
        return str;
 }
index 8196054fedb0450d56978936d769c7189a86ad85..7b6a9d14c8c0a27f6222982fd90d3224ae366c3e 100644 (file)
@@ -133,7 +133,7 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev)
        if (pci_probe & PCI_NOASSIGN_BARS) {
                /*
                * If the BIOS did not assign the BAR, zero out the
-               * resource so the kernel doesn't attmept to assign
+               * resource so the kernel doesn't attempt to assign
                * it later on in pci_assign_unassigned_resources
                */
                for (bar = 0; bar <= PCI_STD_RESOURCE_END; bar++) {
index b7e2e776397d8384dd6459c0a9e9f94b097c113f..f98c3287256e50a1137c800c6ca3a986581dbced 100644 (file)
@@ -217,6 +217,9 @@ config ACPI_PROCESSOR_IDLE
        bool
        select CPU_IDLE
 
+config ACPI_MCFG
+       bool
+
 config ACPI_CPPC_LIB
        bool
        depends on ACPI_PROCESSOR
index 251ce85a66fbb4460e6c379d39f7ddd0e2062ce8..632e81feef697551597f11bc8b975d1771748749 100644 (file)
@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y                         += ec.o
 acpi-$(CONFIG_ACPI_DOCK)       += dock.o
 acpi-y                         += pci_root.o pci_link.o pci_irq.o
+obj-$(CONFIG_ACPI_MCFG)                += pci_mcfg.o
 acpi-y                         += acpi_lpss.o acpi_apd.o
 acpi-y                         += acpi_platform.o
 acpi-y                         += acpi_pnp.o
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
new file mode 100644 (file)
index 0000000..b5b376e
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *     Author: Jayachandran C <jchandra@broadcom.com>
+ * Copyright (C) 2016 Semihalf
+ *     Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+#define pr_fmt(fmt) "ACPI: " fmt
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci-acpi.h>
+
+/* Structure to hold entries from the MCFG table */
+struct mcfg_entry {
+       struct list_head        list;
+       phys_addr_t             addr;
+       u16                     segment;
+       u8                      bus_start;
+       u8                      bus_end;
+};
+
+/* List to save MCFG entries */
+static LIST_HEAD(pci_mcfg_list);
+
+phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
+{
+       struct mcfg_entry *e;
+
+       /*
+        * We expect exact match, unless MCFG entry end bus covers more than
+        * specified by caller.
+        */
+       list_for_each_entry(e, &pci_mcfg_list, list) {
+               if (e->segment == seg && e->bus_start == bus_res->start &&
+                   e->bus_end >= bus_res->end)
+                       return e->addr;
+       }
+
+       return 0;
+}
+
+static __init int pci_mcfg_parse(struct acpi_table_header *header)
+{
+       struct acpi_table_mcfg *mcfg;
+       struct acpi_mcfg_allocation *mptr;
+       struct mcfg_entry *e, *arr;
+       int i, n;
+
+       if (header->length < sizeof(struct acpi_table_mcfg))
+               return -EINVAL;
+
+       n = (header->length - sizeof(struct acpi_table_mcfg)) /
+                                       sizeof(struct acpi_mcfg_allocation);
+       mcfg = (struct acpi_table_mcfg *)header;
+       mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
+
+       arr = kcalloc(n, sizeof(*arr), GFP_KERNEL);
+       if (!arr)
+               return -ENOMEM;
+
+       for (i = 0, e = arr; i < n; i++, mptr++, e++) {
+               e->segment = mptr->pci_segment;
+               e->addr =  mptr->address;
+               e->bus_start = mptr->start_bus_number;
+               e->bus_end = mptr->end_bus_number;
+               list_add(&e->list, &pci_mcfg_list);
+       }
+
+       pr_info("MCFG table detected, %d entries\n", n);
+       return 0;
+}
+
+/* Interface called by ACPI - parse and save MCFG table */
+void __init pci_mmcfg_late_init(void)
+{
+       int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
+       if (err)
+               pr_err("Failed to parse MCFG (%d)\n", err);
+}
index ae3fe4e642035b2d51b2e3f6c4d93e68a6cb1bcc..d144168d4ef9dbfb66f45383ee62ab9bf00c0438 100644 (file)
@@ -720,6 +720,36 @@ next:
        }
 }
 
+static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
+{
+#ifdef PCI_IOBASE
+       struct resource *res = entry->res;
+       resource_size_t cpu_addr = res->start;
+       resource_size_t pci_addr = cpu_addr - entry->offset;
+       resource_size_t length = resource_size(res);
+       unsigned long port;
+
+       if (pci_register_io_range(cpu_addr, length))
+               goto err;
+
+       port = pci_address_to_pio(cpu_addr);
+       if (port == (unsigned long)-1)
+               goto err;
+
+       res->start = port;
+       res->end = port + length - 1;
+       entry->offset = port - pci_addr;
+
+       if (pci_remap_iospace(res, cpu_addr) < 0)
+               goto err;
+
+       pr_info("Remapped I/O %pa to %pR\n", &cpu_addr, res);
+       return;
+err:
+       res->flags |= IORESOURCE_DISABLED;
+#endif
+}
+
 int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 {
        int ret;
@@ -740,6 +770,9 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
                        "no IO and memory resources present in _CRS\n");
        else {
                resource_list_for_each_entry_safe(entry, tmp, list) {
+                       if (entry->res->flags & IORESOURCE_IO)
+                               acpi_pci_root_remap_iospace(entry);
+
                        if (entry->res->flags & IORESOURCE_DISABLED)
                                resource_list_destroy_entry(entry);
                        else
@@ -811,6 +844,8 @@ static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
 
        resource_list_for_each_entry(entry, &bridge->windows) {
                res = entry->res;
+               if (res->flags & IORESOURCE_IO)
+                       pci_unmap_iospace(res);
                if (res->parent &&
                    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
                        release_resource(res);
index fa33c50b0e5a00cef1e560b0aa105034dd30e816..11ecb6cfb2e5cc853ca7ce5889910f65e5a718d1 100644 (file)
@@ -15,9 +15,9 @@ config ARM_GIC_MAX_NR
 
 config ARM_GIC_V2M
        bool
-       depends on ARM_GIC
-       depends on PCI && PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCI
+       select ARM_GIC
+       select PCI_MSI
 
 config GIC_NON_BANKED
        bool
@@ -31,7 +31,8 @@ config ARM_GIC_V3
 
 config ARM_GIC_V3_ITS
        bool
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCI
+       depends on PCI_MSI
 
 config ARM_NVIC
        bool
@@ -56,13 +57,13 @@ config ARM_VIC_NR
 config ARMADA_370_XP_IRQ
        bool
        select GENERIC_IRQ_CHIP
-       select PCI_MSI_IRQ_DOMAIN if PCI_MSI
+       select PCI_MSI if PCI
 
 config ALPINE_MSI
        bool
-       depends on PCI && PCI_MSI
+       depends on PCI
+       select PCI_MSI
        select GENERIC_IRQ_CHIP
-       select PCI_MSI_IRQ_DOMAIN
 
 config ATMEL_AIC_IRQ
        bool
@@ -111,7 +112,6 @@ config HISILICON_IRQ_MBIGEN
        bool
        select ARM_GIC_V3
        select ARM_GIC_V3_ITS
-       select GENERIC_MSI_IRQ_DOMAIN
 
 config IMGPDC_IRQ
        bool
@@ -244,12 +244,10 @@ config IRQ_MXS
 
 config MVEBU_ODMI
        bool
-       select GENERIC_MSI_IRQ_DOMAIN
 
 config LS_SCFG_MSI
        def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
        depends on PCI && PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
 
 config PARTITION_PERCPU
        bool
index 4cf8f82cfca2567bf7642d4c8ba7f8fafc2e8fea..a70b853fa2c99b330583189e5b4b103771531eed 100644 (file)
@@ -182,7 +182,7 @@ static void genwqe_dev_free(struct genwqe_dev *cd)
  */
 static int genwqe_bus_reset(struct genwqe_dev *cd)
 {
-       int bars, rc = 0;
+       int rc = 0;
        struct pci_dev *pci_dev = cd->pci_dev;
        void __iomem *mmio;
 
@@ -193,8 +193,7 @@ static int genwqe_bus_reset(struct genwqe_dev *cd)
        cd->mmio = NULL;
        pci_iounmap(pci_dev, mmio);
 
-       bars = pci_select_bars(pci_dev, IORESOURCE_MEM);
-       pci_release_selected_regions(pci_dev, bars);
+       pci_release_mem_regions(pci_dev);
 
        /*
         * Firmware/BIOS might change memory mapping during bus reset.
@@ -218,7 +217,7 @@ static int genwqe_bus_reset(struct genwqe_dev *cd)
                            GENWQE_INJECT_GFIR_FATAL |
                            GENWQE_INJECT_GFIR_INFO);
 
-       rc = pci_request_selected_regions(pci_dev, bars, genwqe_driver_name);
+       rc = pci_request_mem_regions(pci_dev, genwqe_driver_name);
        if (rc) {
                dev_err(&pci_dev->dev,
                        "[%s] err: request bars failed (%d)\n", __func__, rc);
@@ -1068,10 +1067,9 @@ static int genwqe_health_check_stop(struct genwqe_dev *cd)
  */
 static int genwqe_pci_setup(struct genwqe_dev *cd)
 {
-       int err, bars;
+       int err;
        struct pci_dev *pci_dev = cd->pci_dev;
 
-       bars = pci_select_bars(pci_dev, IORESOURCE_MEM);
        err = pci_enable_device_mem(pci_dev);
        if (err) {
                dev_err(&pci_dev->dev,
@@ -1080,7 +1078,7 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
        }
 
        /* Reserve PCI I/O and memory resources */
-       err = pci_request_selected_regions(pci_dev, bars, genwqe_driver_name);
+       err = pci_request_mem_regions(pci_dev, genwqe_driver_name);
        if (err) {
                dev_err(&pci_dev->dev,
                        "[%s] err: request bars failed (%d)\n", __func__, err);
@@ -1142,7 +1140,7 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
  out_iounmap:
        pci_iounmap(pci_dev, cd->mmio);
  out_release_resources:
-       pci_release_selected_regions(pci_dev, bars);
+       pci_release_mem_regions(pci_dev);
  err_disable_device:
        pci_disable_device(pci_dev);
  err_out:
@@ -1154,14 +1152,12 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
  */
 static void genwqe_pci_remove(struct genwqe_dev *cd)
 {
-       int bars;
        struct pci_dev *pci_dev = cd->pci_dev;
 
        if (cd->mmio)
                pci_iounmap(pci_dev, cd->mmio);
 
-       bars = pci_select_bars(pci_dev, IORESOURCE_MEM);
-       pci_release_selected_regions(pci_dev, bars);
+       pci_release_mem_regions(pci_dev);
        pci_disable_device(pci_dev);
 }
 
index c98acdc0d14f5304918d922372b635bf38c6f666..ec157a0c5d2a4a5d1a0a214957e8cb9dbd3e3f62 100644 (file)
@@ -1284,7 +1284,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct alx_priv *alx;
        struct alx_hw *hw;
        bool phy_configured;
-       int bars, err;
+       int err;
 
        err = pci_enable_device_mem(pdev);
        if (err)
@@ -1304,11 +1304,10 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       err = pci_request_selected_regions(pdev, bars, alx_drv_name);
+       err = pci_request_mem_regions(pdev, alx_drv_name);
        if (err) {
                dev_err(&pdev->dev,
-                       "pci_request_selected_regions failed(bars:%d)\n", bars);
+                       "pci_request_mem_regions failed\n");
                goto out_pci_disable;
        }
 
@@ -1434,7 +1433,7 @@ out_unmap:
 out_free_netdev:
        free_netdev(netdev);
 out_pci_release:
-       pci_release_selected_regions(pdev, bars);
+       pci_release_mem_regions(pdev);
 out_pci_disable:
        pci_disable_device(pdev);
        return err;
@@ -1453,8 +1452,7 @@ static void alx_remove(struct pci_dev *pdev)
 
        unregister_netdev(alx->dev);
        iounmap(hw->hw_addr);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        pci_disable_pcie_error_reporting(pdev);
        pci_disable_device(pdev);
index 75e60897b7e748bca73317ae0e6d9247e6a9bbf9..a2dfa2fbedd8c69326028a292c3c6481cb944213 100644 (file)
@@ -7321,8 +7321,7 @@ err_flashmap:
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -7389,8 +7388,7 @@ static void e1000_remove(struct pci_dev *pdev)
        if ((adapter->hw.flash_address) &&
            (adapter->hw.mac.type < e1000_pch_spt))
                iounmap(adapter->hw.flash_address);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        free_netdev(netdev);
 
index e05aca9bef0e635bd33e5a882e022ade06732aa0..a5bccc8011772f3d5bd99cbf3acd8d20a3351c48 100644 (file)
@@ -1869,10 +1869,7 @@ static int fm10k_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_dma;
        }
 
-       err = pci_request_selected_regions(pdev,
-                                          pci_select_bars(pdev,
-                                                          IORESOURCE_MEM),
-                                          fm10k_driver_name);
+       err = pci_request_mem_regions(pdev, fm10k_driver_name);
        if (err) {
                dev_err(&pdev->dev,
                        "pci_request_selected_regions failed: %d\n", err);
@@ -1976,8 +1973,7 @@ err_sw_init:
 err_ioremap:
        free_netdev(netdev);
 err_alloc_netdev:
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -2025,8 +2021,7 @@ static void fm10k_remove(struct pci_dev *pdev)
 
        free_netdev(netdev);
 
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        pci_disable_pcie_error_reporting(pdev);
 
index 5ea22008d721d0a0ad769f32b7ee74ef8b19249d..2e10d2341a299d2fd88d7f40864f14cbc5dcb119 100644 (file)
@@ -10769,8 +10769,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* set up pci connections */
-       err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
-                                          IORESOURCE_MEM), i40e_driver_name);
+       err = pci_request_mem_regions(pdev, i40e_driver_name);
        if (err) {
                dev_info(&pdev->dev,
                         "pci_request_selected_regions failed %d\n", err);
@@ -11267,8 +11266,7 @@ err_ioremap:
        kfree(pf);
 err_pf_alloc:
        pci_disable_pcie_error_reporting(pdev);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -11379,8 +11377,7 @@ static void i40e_remove(struct pci_dev *pdev)
 
        iounmap(hw->hw_addr);
        kfree(pf);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        pci_disable_pcie_error_reporting(pdev);
        pci_disable_device(pdev);
index ef3d642f5ff203234383d2b07403c209cd5d37d3..1c96fe83000a10ea7ce16d809b9009cf3fdb3a55 100644 (file)
@@ -2323,9 +2323,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
-                                          IORESOURCE_MEM),
-                                          igb_driver_name);
+       err = pci_request_mem_regions(pdev, igb_driver_name);
        if (err)
                goto err_pci_reg;
 
@@ -2749,8 +2747,7 @@ err_sw_init:
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -2915,8 +2912,7 @@ static void igb_remove(struct pci_dev *pdev)
        pci_iounmap(pdev, adapter->io_addr);
        if (hw->flash_address)
                iounmap(hw->flash_address);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        kfree(adapter->shadow_vfta);
        free_netdev(netdev);
index 088c47cf27d97d0f5a8a40992c95ec7c7a761947..1629468387729c55b30505326229cac952821de6 100644 (file)
@@ -9331,8 +9331,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                pci_using_dac = 0;
        }
 
-       err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
-                                          IORESOURCE_MEM), ixgbe_driver_name);
+       err = pci_request_mem_regions(pdev, ixgbe_driver_name);
        if (err) {
                dev_err(&pdev->dev,
                        "pci_request_selected_regions failed 0x%x\n", err);
@@ -9718,8 +9717,7 @@ err_ioremap:
        disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
        free_netdev(netdev);
 err_alloc_etherdev:
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        if (!adapter || disable_dev)
@@ -9786,8 +9784,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
 
 #endif
        iounmap(adapter->io_addr);
-       pci_release_selected_regions(pdev, pci_select_bars(pdev,
-                                    IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        e_dev_info("complete\n");
 
index 78dca3193ca4ccc61df9784ff7699834c61e08b2..7e4d81208da77dafa1a949c6b2b645ea01ea767b 100644 (file)
@@ -1681,7 +1681,7 @@ static void nvme_dev_unmap(struct nvme_dev *dev)
 {
        if (dev->bar)
                iounmap(dev->bar);
-       pci_release_regions(to_pci_dev(dev->dev));
+       pci_release_mem_regions(to_pci_dev(dev->dev));
 }
 
 static void nvme_pci_disable(struct nvme_dev *dev)
@@ -1909,13 +1909,9 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
 
 static int nvme_dev_map(struct nvme_dev *dev)
 {
-       int bars;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       if (!bars)
-               return -ENODEV;
-       if (pci_request_selected_regions(pdev, bars, "nvme"))
+       if (pci_request_mem_regions(pdev, "nvme"))
                return -ENODEV;
 
        dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
@@ -1924,7 +1920,7 @@ static int nvme_dev_map(struct nvme_dev *dev)
 
        return 0;
   release:
-       pci_release_regions(pdev);
+       pci_release_mem_regions(pdev);
        return -ENODEV;
 }
 
index 56389be5d08b666f9a5e57da836a709421c4237b..67f9916ff14d2bb168916b272e9e45aded4b5c7c 100644 (file)
@@ -25,7 +25,7 @@ config PCI_MSI
           If you don't know what to do here, say Y.
 
 config PCI_MSI_IRQ_DOMAIN
-       bool
+       def_bool ARM || ARM64 || X86
        depends on PCI_MSI
        select GENERIC_MSI_IRQ_DOMAIN
 
index dd7cdbee8029d5a51a60c63bb24a5772c0b84de9..c288e5a525754dbebe3165f44e5cbe0569d7ec21 100644 (file)
@@ -91,6 +91,35 @@ void pci_bus_remove_resources(struct pci_bus *bus)
        }
 }
 
+int devm_request_pci_bus_resources(struct device *dev,
+                                  struct list_head *resources)
+{
+       struct resource_entry *win;
+       struct resource *parent, *res;
+       int err;
+
+       resource_list_for_each_entry(win, resources) {
+               res = win->res;
+               switch (resource_type(res)) {
+               case IORESOURCE_IO:
+                       parent = &ioport_resource;
+                       break;
+               case IORESOURCE_MEM:
+                       parent = &iomem_resource;
+                       break;
+               default:
+                       continue;
+               }
+
+               err = devm_request_resource(dev, parent, res);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(devm_request_pci_bus_resources);
+
 static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL};
 #ifdef CONFIG_PCI_BUS_ADDR_T_64BIT
 static struct pci_bus_region pci_64_bit = {0,
@@ -291,6 +320,7 @@ void pci_bus_add_device(struct pci_dev *dev)
        pci_fixup_device(pci_fixup_final, dev);
        pci_create_sysfs_dev_files(dev);
        pci_proc_attach_device(dev);
+       pci_bridge_d3_device_changed(dev);
 
        dev->match_driver = true;
        retval = device_attach(&dev->dev);
@@ -397,4 +427,3 @@ void pci_bus_put(struct pci_bus *bus)
                put_device(&bus->dev);
 }
 EXPORT_SYMBOL(pci_bus_put);
-
index f9832ad8efe2fd4ded2e4d7b636cd05f7a80a520..66e0d718472f2de7ec8408b567908d13b824c93f 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/slab.h>
 
-#include "ecam.h"
-
 /*
  * On 64-bit systems, we do a single ioremap for the whole config space
  * since we have enough virtual address range available.  On 32-bit, we
@@ -52,6 +51,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
        if (!cfg)
                return ERR_PTR(-ENOMEM);
 
+       cfg->parent = dev;
        cfg->ops = ops;
        cfg->busr.start = busr->start;
        cfg->busr.end = busr->end;
@@ -95,7 +95,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
        }
 
        if (ops->init) {
-               err = ops->init(dev, cfg);
+               err = ops->init(cfg);
                if (err)
                        goto err_exit;
        }
diff --git a/drivers/pci/ecam.h b/drivers/pci/ecam.h
deleted file mode 100644 (file)
index 9878beb..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 Broadcom
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
- */
-#ifndef DRIVERS_PCI_ECAM_H
-#define DRIVERS_PCI_ECAM_H
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-/*
- * struct to hold pci ops and bus shift of the config window
- * for a PCI controller.
- */
-struct pci_config_window;
-struct pci_ecam_ops {
-       unsigned int                    bus_shift;
-       struct pci_ops                  pci_ops;
-       int                             (*init)(struct device *,
-                                               struct pci_config_window *);
-};
-
-/*
- * struct to hold the mappings of a config space window. This
- * is expected to be used as sysdata for PCI controllers that
- * use ECAM.
- */
-struct pci_config_window {
-       struct resource                 res;
-       struct resource                 busr;
-       void                            *priv;
-       struct pci_ecam_ops             *ops;
-       union {
-               void __iomem            *win;   /* 64-bit single mapping */
-               void __iomem            **winp; /* 32-bit per-bus mapping */
-       };
-};
-
-/* create and free pci_config_window */
-struct pci_config_window *pci_ecam_create(struct device *dev,
-               struct resource *cfgres, struct resource *busr,
-               struct pci_ecam_ops *ops);
-void pci_ecam_free(struct pci_config_window *cfg);
-
-/* map_bus when ->sysdata is an instance of pci_config_window */
-void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
-                              int where);
-/* default ECAM ops */
-extern struct pci_ecam_ops pci_generic_ecam_ops;
-
-#ifdef CONFIG_PCI_HOST_GENERIC
-/* for DT-based PCI controllers that support ECAM */
-int pci_host_common_probe(struct platform_device *pdev,
-                         struct pci_ecam_ops *ops);
-#endif
-#endif
index c3ebdfa7397b7664e9e6824221a08bf5666f14f8..a1ef0c06dbb49a5aeb4e46516e5f94f9878d17e9 100644 (file)
@@ -3,8 +3,9 @@ menu "PCI host controller drivers"
 
 config PCI_DRA7XX
        bool "TI DRA7xx PCIe controller"
-       select PCIE_DW
        depends on OF && HAS_IOMEM && TI_PIPE3
+       depends on PCI_MSI_IRQ_DOMAIN
+       select PCIE_DW
        help
         Enables support for the PCIe controller in the DRA7xx SoC.  There
         are two instances of PCIe controller in DRA7xx.  This controller can
@@ -20,7 +21,7 @@ config PCI_MVEBU
 config PCIE_XILINX_NWL
        bool "NWL PCIe Core"
        depends on ARCH_ZYNQMP
-       select PCI_MSI_IRQ_DOMAIN if PCI_MSI
+       depends on PCI_MSI_IRQ_DOMAIN
        help
         Say 'Y' here if you want kernel support for Xilinx
         NWL PCIe controller. The controller can act as Root Port
@@ -29,6 +30,7 @@ config PCIE_XILINX_NWL
 
 config PCIE_DW_PLAT
        bool "Platform bus based DesignWare PCIe Controller"
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        ---help---
         This selects the DesignWare PCIe controller support. Select this if
@@ -40,16 +42,19 @@ config PCIE_DW_PLAT
 
 config PCIE_DW
        bool
+       depends on PCI_MSI_IRQ_DOMAIN
 
 config PCI_EXYNOS
        bool "Samsung Exynos PCIe controller"
        depends on SOC_EXYNOS5440
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIEPORTBUS
        select PCIE_DW
 
 config PCI_IMX6
        bool "Freescale i.MX6 PCIe controller"
        depends on SOC_IMX6Q
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIEPORTBUS
        select PCIE_DW
 
@@ -72,8 +77,7 @@ config PCI_RCAR_GEN2
 config PCIE_RCAR
        bool "Renesas R-Car PCIe controller"
        depends on ARCH_RENESAS || (ARM && COMPILE_TEST)
-       select PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCI_MSI_IRQ_DOMAIN
        help
          Say Y here if you want PCIe controller support on R-Car SoCs.
 
@@ -93,6 +97,7 @@ config PCI_HOST_GENERIC
 config PCIE_SPEAR13XX
        bool "STMicroelectronics SPEAr PCIe controller"
        depends on ARCH_SPEAR13XX
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIEPORTBUS
        select PCIE_DW
        help
@@ -101,6 +106,7 @@ config PCIE_SPEAR13XX
 config PCI_KEYSTONE
        bool "TI Keystone PCIe controller"
        depends on ARCH_KEYSTONE
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        select PCIEPORTBUS
        help
@@ -121,7 +127,6 @@ config PCI_XGENE
        depends on ARCH_XGENE
        depends on OF
        select PCIEPORTBUS
-       select PCI_MSI_IRQ_DOMAIN if PCI_MSI
        help
          Say Y here if you want internal PCI support on APM X-Gene SoC.
          There are 5 internal PCIe ports available. Each port is GEN3 capable
@@ -129,7 +134,8 @@ config PCI_XGENE
 
 config PCI_XGENE_MSI
        bool "X-Gene v1 PCIe MSI feature"
-       depends on PCI_XGENE && PCI_MSI
+       depends on PCI_XGENE
+       depends on PCI_MSI_IRQ_DOMAIN
        default y
        help
          Say Y here if you want PCIe MSI support for the APM X-Gene v1 SoC.
@@ -138,6 +144,7 @@ config PCI_XGENE_MSI
 config PCI_LAYERSCAPE
        bool "Freescale Layerscape PCIe controller"
        depends on OF && (ARM || ARCH_LAYERSCAPE)
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        select MFD_SYSCON
        help
@@ -178,8 +185,7 @@ config PCIE_IPROC_BCMA
 config PCIE_IPROC_MSI
        bool "Broadcom iProc PCIe MSI support"
        depends on PCIE_IPROC_PLATFORM || PCIE_IPROC_BCMA
-       depends on PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCI_MSI_IRQ_DOMAIN
        default ARCH_BCM_IPROC
        help
          Say Y here if you want to enable MSI support for Broadcom's iProc
@@ -196,8 +202,8 @@ config PCIE_ALTERA
 
 config PCIE_ALTERA_MSI
        bool "Altera PCIe MSI feature"
-       depends on PCIE_ALTERA && PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCIE_ALTERA
+       depends on PCI_MSI_IRQ_DOMAIN
        help
          Say Y here if you want PCIe MSI support for the Altera FPGA.
          This MSI driver supports Altera MSI to GIC controller IP.
@@ -205,6 +211,7 @@ config PCIE_ALTERA_MSI
 config PCI_HISI
        depends on OF && ARM64
        bool "HiSilicon Hip05 and Hip06 SoCs PCIe controllers"
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIEPORTBUS
        select PCIE_DW
        help
@@ -214,6 +221,7 @@ config PCI_HISI
 config PCIE_QCOM
        bool "Qualcomm PCIe controller"
        depends on ARCH_QCOM && OF
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        select PCIEPORTBUS
        help
@@ -238,6 +246,7 @@ config PCI_HOST_THUNDER_ECAM
 config PCIE_ARMADA_8K
        bool "Marvell Armada-8K PCIe controller"
        depends on ARCH_MVEBU
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        select PCIEPORTBUS
        help
index 8cba7ab73df991aa6d299caf6668573486477c83..9d9d34e959b6a253814c6e7d931f6532e4f7887e 100644 (file)
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-#include "../ecam.h"
-
 static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
                       struct list_head *resources, struct resource **bus_range)
 {
@@ -36,44 +35,34 @@ static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
        if (err)
                return err;
 
+       err = devm_request_pci_bus_resources(dev, resources);
+       if (err)
+               return err;
+
        resource_list_for_each_entry(win, resources) {
-               struct resource *parent, *res = win->res;
+               struct resource *res = win->res;
 
                switch (resource_type(res)) {
                case IORESOURCE_IO:
-                       parent = &ioport_resource;
                        err = pci_remap_iospace(res, iobase);
-                       if (err) {
+                       if (err)
                                dev_warn(dev, "error %d: failed to map resource %pR\n",
                                         err, res);
-                               continue;
-                       }
                        break;
                case IORESOURCE_MEM:
-                       parent = &iomem_resource;
                        res_valid |= !(res->flags & IORESOURCE_PREFETCH);
                        break;
                case IORESOURCE_BUS:
                        *bus_range = res;
-               default:
-                       continue;
+                       break;
                }
-
-               err = devm_request_resource(dev, parent, res);
-               if (err)
-                       goto out_release_res;
-       }
-
-       if (!res_valid) {
-               dev_err(dev, "non-prefetchable memory resource required\n");
-               err = -EINVAL;
-               goto out_release_res;
        }
 
-       return 0;
+       if (res_valid)
+               return 0;
 
-out_release_res:
-       return err;
+       dev_err(dev, "non-prefetchable memory resource required\n");
+       return -EINVAL;
 }
 
 static void gen_pci_unmap_cfg(void *ptr)
@@ -155,7 +144,14 @@ int pci_host_common_probe(struct platform_device *pdev,
 
        pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
 
-       if (!pci_has_flag(PCI_PROBE_ONLY)) {
+       /*
+        * We insert PCI resources into the iomem_resource and
+        * ioport_resource trees in either pci_bus_claim_resources()
+        * or pci_bus_assign_resources().
+        */
+       if (pci_has_flag(PCI_PROBE_ONLY)) {
+               pci_bus_claim_resources(bus);
+       } else {
                pci_bus_size_bridges(bus);
                pci_bus_assign_resources(bus);
 
index c5cbaf1e60e01e86e38a58d7e42de6fa2df15da8..c05ea9d72f693f38203e98ae92c4c95df4dab661 100644 (file)
 #include <linux/init.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-#include "../ecam.h"
-
 static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
        .bus_shift      = 16,
        .pci_ops        = {
index a42443924c009284f06233980cc7458264827dfe..307f81d6b479af4e55ed4e1ab30ba1cfdfdf22d2 100644 (file)
@@ -841,25 +841,22 @@ static struct pci_ops mvebu_pcie_ops = {
 static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
 {
        struct mvebu_pcie *pcie = sys_to_pcie(sys);
-       int i;
+       int err, i;
 
        pcie->mem.name = "PCI MEM";
        pcie->realio.name = "PCI I/O";
 
-       if (request_resource(&iomem_resource, &pcie->mem))
-               return 0;
-
-       if (resource_size(&pcie->realio) != 0) {
-               if (request_resource(&ioport_resource, &pcie->realio)) {
-                       release_resource(&pcie->mem);
-                       return 0;
-               }
+       if (resource_size(&pcie->realio) != 0)
                pci_add_resource_offset(&sys->resources, &pcie->realio,
                                        sys->io_offset);
-       }
+
        pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
        pci_add_resource(&sys->resources, &pcie->busn);
 
+       err = devm_request_pci_bus_resources(&pcie->pdev->dev, &sys->resources);
+       if (err)
+               return 0;
+
        for (i = 0; i < pcie->nports; i++) {
                struct mvebu_pcie_port *port = &pcie->ports[i];
 
index 7bada8ee0adbcfbe6af72786cd8a20a59804d371..597566f96f5eb68afba8b234c91ae990ba9340f6 100644 (file)
@@ -98,7 +98,6 @@
 struct rcar_pci_priv {
        struct device *dev;
        void __iomem *reg;
-       struct resource io_res;
        struct resource mem_res;
        struct resource *cfg_res;
        unsigned busnr;
@@ -195,6 +194,7 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
        struct rcar_pci_priv *priv = sys->private_data;
        void __iomem *reg = priv->reg;
        u32 val;
+       int ret;
 
        pm_runtime_enable(priv->dev);
        pm_runtime_get_sync(priv->dev);
@@ -274,8 +274,10 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
                rcar_pci_setup_errirq(priv);
 
        /* Add PCI resources */
-       pci_add_resource(&sys->resources, &priv->io_res);
        pci_add_resource(&sys->resources, &priv->mem_res);
+       ret = devm_request_pci_bus_resources(priv->dev, &sys->resources);
+       if (ret < 0)
+               return ret;
 
        /* Setup bus number based on platform device id / of bus-range */
        sys->busnr = priv->busnr;
@@ -372,14 +374,6 @@ static int rcar_pci_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        priv->mem_res = *mem_res;
-       /*
-        * The controller does not support/use port I/O,
-        * so setup a dummy port I/O region here.
-        */
-       priv->io_res.start = priv->mem_res.start;
-       priv->io_res.end = priv->mem_res.end;
-       priv->io_res.flags = IORESOURCE_IO;
-
        priv->cfg_res = cfg_res;
 
        priv->irq = platform_get_irq(pdev, 0);
@@ -422,6 +416,7 @@ static int rcar_pci_probe(struct platform_device *pdev)
        hw_private[0] = priv;
        memset(&hw, 0, sizeof(hw));
        hw.nr_controllers = ARRAY_SIZE(hw_private);
+       hw.io_optional = 1;
        hw.private_data = hw_private;
        hw.map_irq = rcar_pci_map_irq;
        hw.ops = &rcar_pci_ops;
index 54098a822714735163232c6e23e88895b761c41f..584777e0ad79e8b337ade4ee5af9407ce7775794 100644 (file)
@@ -276,7 +276,6 @@ struct tegra_pcie {
        struct list_head buses;
        struct resource *cs;
 
-       struct resource all;
        struct resource io;
        struct resource pio;
        struct resource mem;
@@ -625,21 +624,11 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        sys->mem_offset = pcie->offset.mem;
        sys->io_offset = pcie->offset.io;
 
-       err = devm_request_resource(pcie->dev, &pcie->all, &pcie->io);
+       err = devm_request_resource(pcie->dev, &iomem_resource, &pcie->io);
        if (err < 0)
                return err;
 
-       err = devm_request_resource(pcie->dev, &ioport_resource, &pcie->pio);
-       if (err < 0)
-               return err;
-
-       err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem);
-       if (err < 0)
-               return err;
-
-       err = devm_request_resource(pcie->dev, &pcie->all, &pcie->prefetch);
-       if (err)
-               return err;
+       pci_ioremap_io(pcie->pio.start, pcie->io.start);
 
        pci_add_resource_offset(&sys->resources, &pcie->pio, sys->io_offset);
        pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
@@ -647,7 +636,9 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
                                sys->mem_offset);
        pci_add_resource(&sys->resources, &pcie->busn);
 
-       pci_ioremap_io(pcie->pio.start, pcie->io.start);
+       err = devm_request_pci_bus_resources(pcie->dev, &sys->resources);
+       if (err < 0)
+               return err;
 
        return 1;
 }
@@ -1824,12 +1815,6 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
        struct resource res;
        int err;
 
-       memset(&pcie->all, 0, sizeof(pcie->all));
-       pcie->all.flags = IORESOURCE_MEM;
-       pcie->all.name = np->full_name;
-       pcie->all.start = ~0;
-       pcie->all.end = 0;
-
        if (of_pci_range_parser_init(&parser, np)) {
                dev_err(pcie->dev, "missing \"ranges\" property\n");
                return -EINVAL;
@@ -1882,18 +1867,8 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
                        }
                        break;
                }
-
-               if (res.start <= pcie->all.start)
-                       pcie->all.start = res.start;
-
-               if (res.end >= pcie->all.end)
-                       pcie->all.end = res.end;
        }
 
-       err = devm_request_resource(pcie->dev, &iomem_resource, &pcie->all);
-       if (err < 0)
-               return err;
-
        err = of_pci_parse_bus_range(np, &pcie->busn);
        if (err < 0) {
                dev_err(pcie->dev, "failed to parse ranges property: %d\n",
index b8871be5c2691676b3e1b93575d996379e7e2bba..d50a3dc2d8db127e225df7bfd24dd435500526cc 100644 (file)
 #include <linux/ioport.h>
 #include <linux/of_pci.h>
 #include <linux/of.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-#include "../ecam.h"
-
 static void set_val(u32 v, int where, int size, u32 *val)
 {
        int shift = (where & 3) * 8;
index 7b335e62758502815571be5450fa07ae19bf2ca9..6abaf80ffb395d48668dc995782cdb4b53ff4067 100644 (file)
 #include <linux/init.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-#include "../ecam.h"
-
 #define PEM_CFG_WR 0x28
 #define PEM_CFG_RD 0x30
 
@@ -285,8 +284,9 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
        return pci_generic_config_write(bus, devfn, where, size, val);
 }
 
-static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg)
+static int thunder_pem_init(struct pci_config_window *cfg)
 {
+       struct device *dev = cfg->parent;
        resource_size_t bar4_start;
        struct resource *res_pem;
        struct thunder_pem_pci *pem_pci;
index f843a72dc51c268173c682a26a895a93e3c8d381..f234405770abf0c8dd1dd66a58687a4e182cdf05 100644 (file)
@@ -80,21 +80,21 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
        if (err)
                return err;
 
+       err = devm_request_pci_bus_resources(dev, res);
+       if (err)
+               goto out_release_res;
+
        resource_list_for_each_entry(win, res) {
-               struct resource *parent, *res = win->res;
+               struct resource *res = win->res;
 
                switch (resource_type(res)) {
                case IORESOURCE_IO:
-                       parent = &ioport_resource;
                        err = pci_remap_iospace(res, iobase);
-                       if (err) {
+                       if (err)
                                dev_warn(dev, "error %d: failed to map resource %pR\n",
                                         err, res);
-                               continue;
-                       }
                        break;
                case IORESOURCE_MEM:
-                       parent = &iomem_resource;
                        res_valid |= !(res->flags & IORESOURCE_PREFETCH);
 
                        writel(res->start >> 28, PCI_IMAP(mem));
@@ -102,23 +102,14 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
                        mem++;
 
                        break;
-               case IORESOURCE_BUS:
-               default:
-                       continue;
                }
-
-               err = devm_request_resource(dev, parent, res);
-               if (err)
-                       goto out_release_res;
        }
 
-       if (!res_valid) {
-               dev_err(dev, "non-prefetchable memory resource required\n");
-               err = -EINVAL;
-               goto out_release_res;
-       }
+       if (res_valid)
+               return 0;
 
-       return 0;
+       dev_err(dev, "non-prefetchable memory resource required\n");
+       err = -EINVAL;
 
 out_release_res:
        pci_free_resource_list(res);
index 3b473a036ca0690934b2e4bb3deb13e438a97711..a81273c23341a4738617a5db2473ae682a30388d 100644 (file)
@@ -540,14 +540,20 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       ret = devm_request_pci_bus_resources(&pdev->dev, &res);
+       if (ret)
+               goto error;
+
        ret = xgene_pcie_setup(port, &res, iobase);
        if (ret)
-               return ret;
+               goto error;
 
        bus = pci_create_root_bus(&pdev->dev, 0,
                                        &xgene_pcie_ops, port, &res);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               ret = -ENOMEM;
+               goto error;
+       }
 
        pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
@@ -555,6 +561,10 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, port);
        return 0;
+
+error:
+       pci_free_resource_list(&res);
+       return ret;
 }
 
 static const struct of_device_id xgene_pcie_match_table[] = {
index dbac6fb3f0bdfbccaaceefc0c1467e80ce0345df..cf20c67a48f8d677c2e4b4944fe33318092f6e2f 100644 (file)
@@ -415,11 +415,6 @@ static void altera_pcie_isr(struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
-static void altera_pcie_release_of_pci_ranges(struct altera_pcie *pcie)
-{
-       pci_free_resource_list(&pcie->resources);
-}
-
 static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie)
 {
        int err, res_valid = 0;
@@ -432,33 +427,25 @@ static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie)
        if (err)
                return err;
 
+       err = devm_request_pci_bus_resources(dev, &pcie->resources);
+       if (err)
+               goto out_release_res;
+
        resource_list_for_each_entry(win, &pcie->resources) {
-               struct resource *parent, *res = win->res;
+               struct resource *res = win->res;
 
-               switch (resource_type(res)) {
-               case IORESOURCE_MEM:
-                       parent = &iomem_resource;
+               if (resource_type(res) == IORESOURCE_MEM)
                        res_valid |= !(res->flags & IORESOURCE_PREFETCH);
-                       break;
-               default:
-                       continue;
-               }
-
-               err = devm_request_resource(dev, parent, res);
-               if (err)
-                       goto out_release_res;
        }
 
-       if (!res_valid) {
-               dev_err(dev, "non-prefetchable memory resource required\n");
-               err = -EINVAL;
-               goto out_release_res;
-       }
+       if (res_valid)
+               return 0;
 
-       return 0;
+       dev_err(dev, "non-prefetchable memory resource required\n");
+       err = -EINVAL;
 
 out_release_res:
-       altera_pcie_release_of_pci_ranges(pcie);
+       pci_free_resource_list(&pcie->resources);
        return err;
 }
 
index aafd766546f38737d3845339944bbaee29883ec5..12afce19890b747ae5cc42f00541a9b79884c312 100644 (file)
@@ -452,6 +452,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
        if (ret)
                return ret;
 
+       ret = devm_request_pci_bus_resources(&pdev->dev, &res);
+       if (ret)
+               goto error;
+
        /* Get the I/O and memory ranges from DT */
        resource_list_for_each_entry(win, &res) {
                switch (resource_type(win->res)) {
@@ -461,11 +465,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
                        pp->io_size = resource_size(pp->io);
                        pp->io_bus_addr = pp->io->start - win->offset;
                        ret = pci_remap_iospace(pp->io, pp->io_base);
-                       if (ret) {
+                       if (ret)
                                dev_warn(pp->dev, "error %d: failed to map resource %pR\n",
                                         ret, pp->io);
-                               continue;
-                       }
                        break;
                case IORESOURCE_MEM:
                        pp->mem = win->res;
@@ -483,8 +485,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
                case IORESOURCE_BUS:
                        pp->busn = win->res;
                        break;
-               default:
-                       continue;
                }
        }
 
@@ -493,7 +493,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                        resource_size(pp->cfg));
                if (!pp->dbi_base) {
                        dev_err(pp->dev, "error with ioremap\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error;
                }
        }
 
@@ -504,7 +505,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                                pp->cfg0_size);
                if (!pp->va_cfg0_base) {
                        dev_err(pp->dev, "error with ioremap in function\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error;
                }
        }
 
@@ -513,7 +515,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                                pp->cfg1_size);
                if (!pp->va_cfg1_base) {
                        dev_err(pp->dev, "error with ioremap\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error;
                }
        }
 
@@ -528,7 +531,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                                &dw_pcie_msi_chip);
                        if (!pp->irq_domain) {
                                dev_err(pp->dev, "irq domain init failed\n");
-                               return -ENXIO;
+                               ret = -ENXIO;
+                               goto error;
                        }
 
                        for (i = 0; i < MAX_MSI_IRQS; i++)
@@ -536,7 +540,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
                } else {
                        ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
                        if (ret < 0)
-                               return ret;
+                               goto error;
                }
        }
 
@@ -552,8 +556,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
        } else
                bus = pci_scan_root_bus(pp->dev, pp->root_bus_nr, &dw_pcie_ops,
                                        pp, &res);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               ret = -ENOMEM;
+               goto error;
+       }
 
        if (pp->ops->scan_bus)
                pp->ops->scan_bus(pp);
@@ -571,6 +577,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
        pci_bus_add_devices(bus);
        return 0;
+
+error:
+       pci_free_resource_list(&res);
+       return ret;
 }
 
 static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
index a576aeeb22da6cec1a01784328e209a66e96e8df..e167b2f0098d687c6a197b49e2b86e56dded9514 100644 (file)
@@ -462,6 +462,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
        if (!pcie || !pcie->dev || !pcie->base)
                return -EINVAL;
 
+       ret = devm_request_pci_bus_resources(pcie->dev, res);
+       if (ret)
+               return ret;
+
        ret = phy_init(pcie->phy);
        if (ret) {
                dev_err(pcie->dev, "unable to initialize PCIe PHY\n");
index 04b8357f48205bf995909ac3c31ad61d8981a87b..65db7a2215090ff4508141dc131fb37104b9a34b 100644 (file)
@@ -939,11 +939,6 @@ static const struct of_device_id rcar_pcie_of_match[] = {
        {},
 };
 
-static void rcar_pcie_release_of_pci_ranges(struct rcar_pcie *pci)
-{
-       pci_free_resource_list(&pci->resources);
-}
-
 static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
 {
        int err;
@@ -956,37 +951,25 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
        if (err)
                return err;
 
+       err = devm_request_pci_bus_resources(dev, &pci->resources);
+       if (err)
+               goto out_release_res;
+
        resource_list_for_each_entry(win, &pci->resources) {
-               struct resource *parent, *res = win->res;
+               struct resource *res = win->res;
 
-               switch (resource_type(res)) {
-               case IORESOURCE_IO:
-                       parent = &ioport_resource;
+               if (resource_type(res) == IORESOURCE_IO) {
                        err = pci_remap_iospace(res, iobase);
-                       if (err) {
+                       if (err)
                                dev_warn(dev, "error %d: failed to map resource %pR\n",
                                         err, res);
-                               continue;
-                       }
-                       break;
-               case IORESOURCE_MEM:
-                       parent = &iomem_resource;
-                       break;
-
-               case IORESOURCE_BUS:
-               default:
-                       continue;
                }
-
-               err = devm_request_resource(dev, parent, res);
-               if (err)
-                       goto out_release_res;
        }
 
        return 0;
 
 out_release_res:
-       rcar_pcie_release_of_pci_ranges(pci);
+       pci_free_resource_list(&pci->resources);
        return err;
 }
 
index 3479d30e2be86cbfccd108da69377899e1e1cd92..0b597d9190b4bd4811bc8559c2fec5c247cc8765 100644 (file)
@@ -825,27 +825,33 @@ static int nwl_pcie_probe(struct platform_device *pdev)
 
        err = of_pci_get_host_bridge_resources(node, 0, 0xff, &res, &iobase);
        if (err) {
-               pr_err("Getting bridge resources failed\n");
+               dev_err(pcie->dev, "Getting bridge resources failed\n");
                return err;
        }
 
+       err = devm_request_pci_bus_resources(pcie->dev, &res);
+       if (err)
+               goto error;
+
        err = nwl_pcie_init_irq_domain(pcie);
        if (err) {
                dev_err(pcie->dev, "Failed creating IRQ Domain\n");
-               return err;
+               goto error;
        }
 
        bus = pci_create_root_bus(&pdev->dev, pcie->root_busno,
                                  &nwl_pcie_ops, pcie, &res);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               err = -ENOMEM;
+               goto error;
+       }
 
        if (IS_ENABLED(CONFIG_PCI_MSI)) {
                err = nwl_pcie_enable_msi(pcie, bus);
                if (err < 0) {
                        dev_err(&pdev->dev,
                                "failed to enable MSI support: %d\n", err);
-                       return err;
+                       goto error;
                }
        }
        pci_scan_child_bus(bus);
@@ -855,6 +861,10 @@ static int nwl_pcie_probe(struct platform_device *pdev)
        pci_bus_add_devices(bus);
        platform_set_drvdata(pdev, pcie);
        return 0;
+
+error:
+       pci_free_resource_list(&res);
+       return err;
 }
 
 static int nwl_pcie_remove(struct platform_device *pdev)
index 65f0fe0c2eafb67141fd84f84b31285ff038c868..4703aa336041e36453ccf96681521835241887b8 100644 (file)
@@ -660,7 +660,6 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
        struct xilinx_pcie_port *port;
        struct device *dev = &pdev->dev;
        struct pci_bus *bus;
-
        int err;
        resource_size_t iobase = 0;
        LIST_HEAD(res);
@@ -694,10 +693,17 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
                dev_err(dev, "Getting bridge resources failed\n");
                return err;
        }
+
+       err = devm_request_pci_bus_resources(dev, &res);
+       if (err)
+               goto error;
+
        bus = pci_create_root_bus(&pdev->dev, 0,
                                  &xilinx_pcie_ops, port, &res);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               err = -ENOMEM;
+               goto error;
+       }
 
 #ifdef CONFIG_PCI_MSI
        xilinx_pcie_msi_chip.dev = port->dev;
@@ -712,6 +718,10 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, port);
 
        return 0;
+
+error:
+       pci_free_resource_list(&res);
+       return err;
 }
 
 /**
index fa49f9143b80631108e10ef78e5e45e285c40cf8..6a33ddcfa20b45b7b5d7bbfdc04a2cf4288c8368 100644 (file)
@@ -675,6 +675,8 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
        if (bridge->is_going_away)
                return;
 
+       pm_runtime_get_sync(&bridge->pci_dev->dev);
+
        list_for_each_entry(slot, &bridge->slots, node) {
                struct pci_bus *bus = slot->bus;
                struct pci_dev *dev, *tmp;
@@ -694,6 +696,8 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
                        disable_slot(slot);
                }
        }
+
+       pm_runtime_put(&bridge->pci_dev->dev);
 }
 
 /*
index 5c24e938042fd6bccb4e207d58dcb988d7c62611..08e84d61874e104ac7479f132d830f5fca98861a 100644 (file)
@@ -546,6 +546,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
        u8 present;
        bool link;
 
+       /* Interrupts cannot originate from a controller that's asleep */
+       if (pdev->current_state == PCI_D3cold)
+               return IRQ_NONE;
+
        /*
         * In order to guarantee that all interrupt events are
         * serviced, we need to re-inspect Slot Status register after
index d7ffd66814bb51c14cbdf849fcd6a0a33f30dba7..e39a67c8ef397e7bd7511b266a533ab0cff817f8 100644 (file)
@@ -777,7 +777,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
 
        if (!pci_dev->state_saved) {
                pci_save_state(pci_dev);
-               if (!pci_has_subordinate(pci_dev))
+               if (pci_power_manageable(pci_dev))
                        pci_prepare_to_sleep(pci_dev);
        }
 
@@ -1144,7 +1144,6 @@ static int pci_pm_runtime_suspend(struct device *dev)
                return -ENOSYS;
 
        pci_dev->state_saved = false;
-       pci_dev->no_d3cold = false;
        error = pm->runtime_suspend(dev);
        if (error) {
                /*
@@ -1161,8 +1160,6 @@ static int pci_pm_runtime_suspend(struct device *dev)
 
                return error;
        }
-       if (!pci_dev->d3cold_allowed)
-               pci_dev->no_d3cold = true;
 
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
index d319a9ca9b7bf9a330620313ec1e5c89d819142c..bcd10c795284cff70a58e73aac8ce2810da6831e 100644 (file)
@@ -406,6 +406,11 @@ static ssize_t d3cold_allowed_store(struct device *dev,
                return -EINVAL;
 
        pdev->d3cold_allowed = !!val;
+       if (pdev->d3cold_allowed)
+               pci_d3cold_enable(pdev);
+       else
+               pci_d3cold_disable(pdev);
+
        pm_runtime_resume(dev);
 
        return count;
index c8b4dbdd1bddae95c214e92b52492b82364afcaf..9a6bc77ce3aa9137c9327eba06eb48117403de0f 100644 (file)
@@ -7,8 +7,10 @@
  *     Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
  */
 
+#include <linux/acpi.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/dmi.h>
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_pci.h>
@@ -25,7 +27,9 @@
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
 #include <linux/pci_hotplug.h>
+#include <linux/vmalloc.h>
 #include <asm/setup.h>
+#include <asm/dma.h>
 #include <linux/aer.h>
 #include "pci.h"
 
@@ -81,6 +85,9 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
 unsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;
 unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
 
+#define DEFAULT_HOTPLUG_BUS_SIZE       1
+unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
+
 enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT;
 
 /*
@@ -101,6 +108,21 @@ unsigned int pcibios_max_latency = 255;
 /* If set, the PCIe ARI capability will not be used. */
 static bool pcie_ari_disabled;
 
+/* Disable bridge_d3 for all PCIe ports */
+static bool pci_bridge_d3_disable;
+/* Force bridge_d3 for all PCIe ports */
+static bool pci_bridge_d3_force;
+
+static int __init pcie_port_pm_setup(char *str)
+{
+       if (!strcmp(str, "off"))
+               pci_bridge_d3_disable = true;
+       else if (!strcmp(str, "force"))
+               pci_bridge_d3_force = true;
+       return 1;
+}
+__setup("pcie_port_pm=", pcie_port_pm_setup);
+
 /**
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
  * @bus: pointer to PCI bus structure to search
@@ -2155,6 +2177,164 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev)
                pm_runtime_put_sync(parent);
 }
 
+/**
+ * pci_bridge_d3_possible - Is it possible to put the bridge into D3
+ * @bridge: Bridge to check
+ *
+ * This function checks if it is possible to move the bridge to D3.
+ * Currently we only allow D3 for recent enough PCIe ports.
+ */
+static bool pci_bridge_d3_possible(struct pci_dev *bridge)
+{
+       unsigned int year;
+
+       if (!pci_is_pcie(bridge))
+               return false;
+
+       switch (pci_pcie_type(bridge)) {
+       case PCI_EXP_TYPE_ROOT_PORT:
+       case PCI_EXP_TYPE_UPSTREAM:
+       case PCI_EXP_TYPE_DOWNSTREAM:
+               if (pci_bridge_d3_disable)
+                       return false;
+               if (pci_bridge_d3_force)
+                       return true;
+
+               /*
+                * It should be safe to put PCIe ports from 2015 or newer
+                * to D3.
+                */
+               if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+                   year >= 2015) {
+                       return true;
+               }
+               break;
+       }
+
+       return false;
+}
+
+static int pci_dev_check_d3cold(struct pci_dev *dev, void *data)
+{
+       bool *d3cold_ok = data;
+       bool no_d3cold;
+
+       /*
+        * The device needs to be allowed to go D3cold and if it is wake
+        * capable to do so from D3cold.
+        */
+       no_d3cold = dev->no_d3cold || !dev->d3cold_allowed ||
+               (device_may_wakeup(&dev->dev) && !pci_pme_capable(dev, PCI_D3cold)) ||
+               !pci_power_manageable(dev);
+
+       *d3cold_ok = !no_d3cold;
+
+       return no_d3cold;
+}
+
+/*
+ * pci_bridge_d3_update - Update bridge D3 capabilities
+ * @dev: PCI device which is changed
+ * @remove: Is the device being removed
+ *
+ * Update upstream bridge PM capabilities accordingly depending on if the
+ * device PM configuration was changed or the device is being removed.  The
+ * change is also propagated upstream.
+ */
+static void pci_bridge_d3_update(struct pci_dev *dev, bool remove)
+{
+       struct pci_dev *bridge;
+       bool d3cold_ok = true;
+
+       bridge = pci_upstream_bridge(dev);
+       if (!bridge || !pci_bridge_d3_possible(bridge))
+               return;
+
+       pci_dev_get(bridge);
+       /*
+        * If the device is removed we do not care about its D3cold
+        * capabilities.
+        */
+       if (!remove)
+               pci_dev_check_d3cold(dev, &d3cold_ok);
+
+       if (d3cold_ok) {
+               /*
+                * We need to go through all children to find out if all of
+                * them can still go to D3cold.
+                */
+               pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold,
+                            &d3cold_ok);
+       }
+
+       if (bridge->bridge_d3 != d3cold_ok) {
+               bridge->bridge_d3 = d3cold_ok;
+               /* Propagate change to upstream bridges */
+               pci_bridge_d3_update(bridge, false);
+       }
+
+       pci_dev_put(bridge);
+}
+
+/**
+ * pci_bridge_d3_device_changed - Update bridge D3 capabilities on change
+ * @dev: PCI device that was changed
+ *
+ * If a device is added or its PM configuration, such as is it allowed to
+ * enter D3cold, is changed this function updates upstream bridge PM
+ * capabilities accordingly.
+ */
+void pci_bridge_d3_device_changed(struct pci_dev *dev)
+{
+       pci_bridge_d3_update(dev, false);
+}
+
+/**
+ * pci_bridge_d3_device_removed - Update bridge D3 capabilities on remove
+ * @dev: PCI device being removed
+ *
+ * Function updates upstream bridge PM capabilities based on other devices
+ * still left on the bus.
+ */
+void pci_bridge_d3_device_removed(struct pci_dev *dev)
+{
+       pci_bridge_d3_update(dev, true);
+}
+
+/**
+ * pci_d3cold_enable - Enable D3cold for device
+ * @dev: PCI device to handle
+ *
+ * This function can be used in drivers to enable D3cold from the device
+ * they handle.  It also updates upstream PCI bridge PM capabilities
+ * accordingly.
+ */
+void pci_d3cold_enable(struct pci_dev *dev)
+{
+       if (dev->no_d3cold) {
+               dev->no_d3cold = false;
+               pci_bridge_d3_device_changed(dev);
+       }
+}
+EXPORT_SYMBOL_GPL(pci_d3cold_enable);
+
+/**
+ * pci_d3cold_disable - Disable D3cold for device
+ * @dev: PCI device to handle
+ *
+ * This function can be used in drivers to disable D3cold from the device
+ * they handle.  It also updates upstream PCI bridge PM capabilities
+ * accordingly.
+ */
+void pci_d3cold_disable(struct pci_dev *dev)
+{
+       if (!dev->no_d3cold) {
+               dev->no_d3cold = true;
+               pci_bridge_d3_device_changed(dev);
+       }
+}
+EXPORT_SYMBOL_GPL(pci_d3cold_disable);
+
 /**
  * pci_pm_init - Initialize PM functions of given PCI device
  * @dev: PCI device to handle.
@@ -2189,6 +2369,7 @@ void pci_pm_init(struct pci_dev *dev)
        dev->pm_cap = pm;
        dev->d3_delay = PCI_PM_D3_WAIT;
        dev->d3cold_delay = PCI_PM_D3COLD_WAIT;
+       dev->bridge_d3 = pci_bridge_d3_possible(dev);
        dev->d3cold_allowed = true;
 
        dev->d1_support = false;
@@ -3165,6 +3346,23 @@ int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
 #endif
 }
 
+/**
+ *     pci_unmap_iospace - Unmap the memory mapped I/O space
+ *     @res: resource to be unmapped
+ *
+ *     Unmap the CPU virtual address @res from virtual address space.
+ *     Only architectures that have memory mapped IO functions defined
+ *     (and the PCI_IOBASE value defined) should call this function.
+ */
+void pci_unmap_iospace(struct resource *res)
+{
+#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
+       unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
+
+       unmap_kernel_range(vaddr, resource_size(res));
+#endif
+}
+
 static void __pci_set_master(struct pci_dev *dev, bool enable)
 {
        u16 old_cmd, cmd;
@@ -4755,6 +4953,7 @@ static DEFINE_SPINLOCK(resource_alignment_lock);
 static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
 {
        int seg, bus, slot, func, align_order, count;
+       unsigned short vendor, device, subsystem_vendor, subsystem_device;
        resource_size_t align = 0;
        char *p;
 
@@ -4768,28 +4967,55 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
                } else {
                        align_order = -1;
                }
-               if (sscanf(p, "%x:%x:%x.%x%n",
-                       &seg, &bus, &slot, &func, &count) != 4) {
-                       seg = 0;
-                       if (sscanf(p, "%x:%x.%x%n",
-                                       &bus, &slot, &func, &count) != 3) {
-                               /* Invalid format */
-                               printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
-                                       p);
+               if (strncmp(p, "pci:", 4) == 0) {
+                       /* PCI vendor/device (subvendor/subdevice) ids are specified */
+                       p += 4;
+                       if (sscanf(p, "%hx:%hx:%hx:%hx%n",
+                               &vendor, &device, &subsystem_vendor, &subsystem_device, &count) != 4) {
+                               if (sscanf(p, "%hx:%hx%n", &vendor, &device, &count) != 2) {
+                                       printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: pci:%s\n",
+                                               p);
+                                       break;
+                               }
+                               subsystem_vendor = subsystem_device = 0;
+                       }
+                       p += count;
+                       if ((!vendor || (vendor == dev->vendor)) &&
+                               (!device || (device == dev->device)) &&
+                               (!subsystem_vendor || (subsystem_vendor == dev->subsystem_vendor)) &&
+                               (!subsystem_device || (subsystem_device == dev->subsystem_device))) {
+                               if (align_order == -1)
+                                       align = PAGE_SIZE;
+                               else
+                                       align = 1 << align_order;
+                               /* Found */
                                break;
                        }
                }
-               p += count;
-               if (seg == pci_domain_nr(dev->bus) &&
-                       bus == dev->bus->number &&
-                       slot == PCI_SLOT(dev->devfn) &&
-                       func == PCI_FUNC(dev->devfn)) {
-                       if (align_order == -1)
-                               align = PAGE_SIZE;
-                       else
-                               align = 1 << align_order;
-                       /* Found */
-                       break;
+               else {
+                       if (sscanf(p, "%x:%x:%x.%x%n",
+                               &seg, &bus, &slot, &func, &count) != 4) {
+                               seg = 0;
+                               if (sscanf(p, "%x:%x.%x%n",
+                                               &bus, &slot, &func, &count) != 3) {
+                                       /* Invalid format */
+                                       printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
+                                               p);
+                                       break;
+                               }
+                       }
+                       p += count;
+                       if (seg == pci_domain_nr(dev->bus) &&
+                               bus == dev->bus->number &&
+                               slot == PCI_SLOT(dev->devfn) &&
+                               func == PCI_FUNC(dev->devfn)) {
+                               if (align_order == -1)
+                                       align = PAGE_SIZE;
+                               else
+                                       align = 1 << align_order;
+                               /* Found */
+                               break;
+                       }
                }
                if (*p != ';' && *p != ',') {
                        /* End of param or invalid format */
@@ -4897,7 +5123,7 @@ static ssize_t pci_resource_alignment_store(struct bus_type *bus,
        return pci_set_resource_alignment_param(buf, count);
 }
 
-BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show,
+static BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show,
                                        pci_resource_alignment_store);
 
 static int __init pci_resource_alignment_sysfs_init(void)
@@ -4923,7 +5149,7 @@ int pci_get_new_domain_nr(void)
 }
 
 #ifdef CONFIG_PCI_DOMAINS_GENERIC
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+static int of_pci_bus_find_domain_nr(struct device *parent)
 {
        static int use_dt_domains = -1;
        int domain = -1;
@@ -4967,7 +5193,13 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
                domain = -1;
        }
 
-       bus->domain_nr = domain;
+       return domain;
+}
+
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
+{
+       return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
+                              acpi_pci_bus_find_domain_nr(bus);
 }
 #endif
 #endif
@@ -5021,6 +5253,11 @@ static int __init pci_setup(char *str)
                                pci_hotplug_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "hpmemsize=", 10)) {
                                pci_hotplug_mem_size = memparse(str + 10, &str);
+                       } else if (!strncmp(str, "hpbussize=", 10)) {
+                               pci_hotplug_bus_size =
+                                       simple_strtoul(str + 10, &str, 0);
+                               if (pci_hotplug_bus_size > 0xff)
+                                       pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
                        } else if (!strncmp(str, "pcie_bus_tune_off", 17)) {
                                pcie_bus_config = PCIE_BUS_TUNE_OFF;
                        } else if (!strncmp(str, "pcie_bus_safe", 13)) {
index a814bbb80fcb3d1ddbf35508b7dcf5808f3d0e5d..9730c474b0163ccab1d9aa8027cf1c00d6ca823a 100644 (file)
@@ -82,6 +82,8 @@ void pci_pm_init(struct pci_dev *dev);
 void pci_ea_init(struct pci_dev *dev);
 void pci_allocate_cap_save_buffers(struct pci_dev *dev);
 void pci_free_cap_save_buffers(struct pci_dev *dev);
+void pci_bridge_d3_device_changed(struct pci_dev *dev);
+void pci_bridge_d3_device_removed(struct pci_dev *dev);
 
 static inline void pci_wakeup_event(struct pci_dev *dev)
 {
@@ -94,6 +96,15 @@ static inline bool pci_has_subordinate(struct pci_dev *pci_dev)
        return !!(pci_dev->subordinate);
 }
 
+static inline bool pci_power_manageable(struct pci_dev *pci_dev)
+{
+       /*
+        * Currently we allow normal PCI devices and PCI bridges transition
+        * into D3 if their bridge_d3 is set.
+        */
+       return !pci_has_subordinate(pci_dev) || pci_dev->bridge_d3;
+}
+
 struct pci_vpd_ops {
        ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
        ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
index 22ca6412bd15c5e36d8965783f79531c58907cf6..7fcea75afa4cf9a3b702c2773ead13c75a65de80 100644 (file)
@@ -83,7 +83,7 @@ config PCIE_PME
        depends on PCIEPORTBUS && PM
 
 config PCIE_DPC
-       tristate "PCIe Downstream Port Containment support"
+       bool "PCIe Downstream Port Containment support"
        depends on PCIEPORTBUS
        default n
        help
@@ -92,6 +92,3 @@ config PCIE_DPC
          will be handled by the DPC driver.  If your system doesn't
          have this capability or you do not want to use this feature,
          it is safe to answer N.
-
-         To compile this driver as a module, choose M here: the module
-         will be called pcie-dpc.
index 2dfe7fdb77e7fe95d6b22d1cc925fe24a06c685b..0ec649d961d7a6ee515747c3458a8ce1df108099 100644 (file)
@@ -139,7 +139,7 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
 static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
 {
        /* Don't enable Clock PM if the link is not Clock PM capable */
-       if (!link->clkpm_capable && enable)
+       if (!link->clkpm_capable)
                enable = 0;
        /* Need nothing if the specified equals to current state */
        if (link->clkpm_enabled == enable)
index ab552f1bc08fae0c113085f739fc01ebc1cb2b77..250f878617863e1452f95d57e5055f8599a1e2b5 100644 (file)
@@ -15,8 +15,8 @@
 
 struct dpc_dev {
        struct pcie_device      *dev;
-       struct work_struct      work;
-       int                     cap_pos;
+       struct work_struct      work;
+       int                     cap_pos;
 };
 
 static void dpc_wait_link_inactive(struct pci_dev *pdev)
@@ -89,7 +89,7 @@ static int dpc_probe(struct pcie_device *dev)
        int status;
        u16 ctl, cap;
 
-       dpc = kzalloc(sizeof(*dpc), GFP_KERNEL);
+       dpc = devm_kzalloc(&dev->device, sizeof(*dpc), GFP_KERNEL);
        if (!dpc)
                return -ENOMEM;
 
@@ -98,11 +98,12 @@ static int dpc_probe(struct pcie_device *dev)
        INIT_WORK(&dpc->work, interrupt_event_handler);
        set_service_data(dev, dpc);
 
-       status = request_irq(dev->irq, dpc_irq, IRQF_SHARED, "pcie-dpc", dpc);
+       status = devm_request_irq(&dev->device, dev->irq, dpc_irq, IRQF_SHARED,
+                                 "pcie-dpc", dpc);
        if (status) {
                dev_warn(&dev->device, "request IRQ%d failed: %d\n", dev->irq,
                         status);
-               goto out;
+               return status;
        }
 
        pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap);
@@ -117,9 +118,6 @@ static int dpc_probe(struct pcie_device *dev)
                FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), (cap >> 8) & 0xf,
                FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE));
        return status;
- out:
-       kfree(dpc);
-       return status;
 }
 
 static void dpc_remove(struct pcie_device *dev)
@@ -131,14 +129,11 @@ static void dpc_remove(struct pcie_device *dev)
        pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl);
        ctl &= ~(PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN);
        pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
-
-       free_irq(dev->irq, dpc);
-       kfree(dpc);
 }
 
 static struct pcie_port_service_driver dpcdriver = {
        .name           = "dpc",
-       .port_type      = PCI_EXP_TYPE_ROOT_PORT | PCI_EXP_TYPE_DOWNSTREAM,
+       .port_type      = PCIE_ANY_PORT,
        .service        = PCIE_PORT_SERVICE_DPC,
        .probe          = dpc_probe,
        .remove         = dpc_remove,
index 32d4d0a3d20e5f2b5b2e78a90adc77081ad451be..e9270b4026f3c05ff43959c8945efef3e63ae1de 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
@@ -342,6 +343,8 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
                return retval;
        }
 
+       pm_runtime_no_callbacks(device);
+
        return 0;
 }
 
index be35da2e105e0b39449244416f8ba8934446f58a..70d7ad8c6d17d95ba07ae6cbc7458b3b3efacac0 100644 (file)
@@ -93,6 +93,26 @@ static int pcie_port_resume_noirq(struct device *dev)
        return 0;
 }
 
+static int pcie_port_runtime_suspend(struct device *dev)
+{
+       return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
+}
+
+static int pcie_port_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+static int pcie_port_runtime_idle(struct device *dev)
+{
+       /*
+        * Assume the PCI core has set bridge_d3 whenever it thinks the port
+        * should be good to go to D3.  Everything else, including moving
+        * the port to D3, is handled by the PCI core.
+        */
+       return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
+}
+
 static const struct dev_pm_ops pcie_portdrv_pm_ops = {
        .suspend        = pcie_port_device_suspend,
        .resume         = pcie_port_device_resume,
@@ -101,6 +121,9 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
        .poweroff       = pcie_port_device_suspend,
        .restore        = pcie_port_device_resume,
        .resume_noirq   = pcie_port_resume_noirq,
+       .runtime_suspend = pcie_port_runtime_suspend,
+       .runtime_resume = pcie_port_runtime_resume,
+       .runtime_idle   = pcie_port_runtime_idle,
 };
 
 #define PCIE_PORTDRV_PM_OPS    (&pcie_portdrv_pm_ops)
@@ -134,16 +157,39 @@ static int pcie_portdrv_probe(struct pci_dev *dev,
                return status;
 
        pci_save_state(dev);
+
        /*
-        * D3cold may not work properly on some PCIe port, so disable
-        * it by default.
+        * Prevent runtime PM if the port is advertising support for PCIe
+        * hotplug.  Otherwise the BIOS hotplug SMI code might not be able
+        * to enumerate devices behind this port properly (the port is
+        * powered down preventing all config space accesses to the
+        * subordinate devices).  We can't be sure for native PCIe hotplug
+        * either so prevent that as well.
         */
-       dev->d3cold_allowed = false;
+       if (!dev->is_hotplug_bridge) {
+               /*
+                * Keep the port resumed 100ms to make sure things like
+                * config space accesses from userspace (lspci) will not
+                * cause the port to repeatedly suspend and resume.
+                */
+               pm_runtime_set_autosuspend_delay(&dev->dev, 100);
+               pm_runtime_use_autosuspend(&dev->dev);
+               pm_runtime_mark_last_busy(&dev->dev);
+               pm_runtime_put_autosuspend(&dev->dev);
+               pm_runtime_allow(&dev->dev);
+       }
+
        return 0;
 }
 
 static void pcie_portdrv_remove(struct pci_dev *dev)
 {
+       if (!dev->is_hotplug_bridge) {
+               pm_runtime_forbid(&dev->dev);
+               pm_runtime_get_noresume(&dev->dev);
+               pm_runtime_dont_use_autosuspend(&dev->dev);
+       }
+
        pcie_port_device_remove(dev);
 }
 
index 8e3ef720997dfba2858c4dae77b2a0651f678c2d..93f280df342824fd89c5206f99ff2733fd7e7044 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/aer.h>
 #include <linux/acpi.h>
 #include <linux/irqdomain.h>
+#include <linux/pm_runtime.h>
 #include "pci.h"
 
 #define CARDBUS_LATENCY_TIMER  176     /* secondary latency timer */
@@ -832,6 +833,12 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
        u8 primary, secondary, subordinate;
        int broken = 0;
 
+       /*
+        * Make sure the bridge is powered on to be able to access config
+        * space of devices below it.
+        */
+       pm_runtime_get_sync(&dev->dev);
+
        pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
        primary = buses & 0xFF;
        secondary = (buses >> 8) & 0xFF;
@@ -1012,6 +1019,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
 out:
        pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
 
+       pm_runtime_put(&dev->dev);
+
        return max;
 }
 EXPORT_SYMBOL(pci_scan_bridge);
@@ -2076,6 +2085,15 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
                                max = pci_scan_bridge(bus, dev, max, pass);
                }
 
+       /*
+        * Make sure a hotplug bridge has at least the minimum requested
+        * number of buses.
+        */
+       if (bus->self && bus->self->is_hotplug_bridge && pci_hotplug_bus_size) {
+               if (max - bus->busn_res.start < pci_hotplug_bus_size - 1)
+                       max = bus->busn_res.start + pci_hotplug_bus_size - 1;
+       }
+
        /*
         * We've scanned the bus and so we know all about what's on
         * the other side of any bridges that may be on this bus plus
@@ -2127,7 +2145,9 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
        b->sysdata = sysdata;
        b->ops = ops;
        b->number = b->busn_res.start = bus;
-       pci_bus_assign_domain_nr(b, parent);
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+       b->domain_nr = pci_bus_find_domain_nr(b, parent);
+#endif
        b2 = pci_find_bus(pci_domain_nr(b), bus);
        if (b2) {
                /* If we already got to this bus through a different bridge, ignore it */
index 3f155e78513fd4171dc4b57c5b7b3b41e7afea20..2408abe4ee8c68919d8a79465e62ab16f3c8660e 100644 (file)
@@ -231,7 +231,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct pci_dev *dev = PDE_DATA(file_inode(file));
        struct pci_filp_private *fpriv = file->private_data;
-       int i, ret;
+       int i, ret, write_combine;
 
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
@@ -245,9 +245,12 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
        if (i >= PCI_ROM_RESOURCE)
                return -ENODEV;
 
+       if (fpriv->mmap_state == pci_mmap_mem)
+               write_combine = fpriv->write_combine;
+       else
+               write_combine = 0;
        ret = pci_mmap_page_range(dev, vma,
-                                 fpriv->mmap_state,
-                                 fpriv->write_combine);
+                                 fpriv->mmap_state, write_combine);
        if (ret < 0)
                return ret;
 
index ee72ebe18f4b5a6510d043da9abcee50cbada987..37ff0158e45f1a3aa453e5da757d21a11e1c3267 100644 (file)
@@ -3189,13 +3189,15 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
 }
 
 /*
- * Atheros AR93xx chips do not behave after a bus reset.  The device will
- * throw a Link Down error on AER-capable systems and regardless of AER,
- * config space of the device is never accessible again and typically
- * causes the system to hang or reset when access is attempted.
+ * Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
+ * The device will throw a Link Down error on AER-capable systems and
+ * regardless of AER, config space of the device is never accessible again
+ * and typically causes the system to hang or reset when access is attempted.
  * http://www.spinics.net/lists/linux-pci/msg34797.html
  */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
 
 static void quirk_no_pm_reset(struct pci_dev *dev)
 {
@@ -3711,6 +3713,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9172,
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c59 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x917a,
                         quirk_dma_func1_alias);
+/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c78 */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9182,
+                        quirk_dma_func1_alias);
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0,
                         quirk_dma_func1_alias);
@@ -3747,6 +3752,9 @@ static const struct pci_device_id fixed_dma_alias_tbl[] = {
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285,
                         PCI_VENDOR_ID_ADAPTEC2, 0x02bb), /* Adaptec 3405 */
          .driver_data = PCI_DEVFN(1, 0) },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285,
+                        PCI_VENDOR_ID_ADAPTEC2, 0x02bc), /* Adaptec 3805 */
+         .driver_data = PCI_DEVFN(1, 0) },
        { 0 }
 };
 
@@ -4087,6 +4095,7 @@ static const struct pci_dev_acs_enabled {
        { PCI_VENDOR_ID_AMD, 0x7809, pci_quirk_amd_sb_acs },
        { PCI_VENDOR_ID_SOLARFLARE, 0x0903, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_SOLARFLARE, 0x0923, pci_quirk_mf_endpoint_acs },
+       { PCI_VENDOR_ID_SOLARFLARE, 0x0A03, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_INTEL, 0x10C6, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_INTEL, 0x10DB, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_INTEL, 0x10DD, pci_quirk_mf_endpoint_acs },
index 8982026637d5598a27c9a36d3b265c6b74cb4a0d..d1ef7acf69307f1377782544bde6011af4e54df2 100644 (file)
@@ -96,6 +96,8 @@ static void pci_remove_bus_device(struct pci_dev *dev)
                dev->subordinate = NULL;
        }
 
+       pci_bridge_d3_device_removed(dev);
+
        pci_destroy_dev(dev);
 }
 
index 55641a39a3e94f3eab29a5494d943afc9614d3e6..1d1a2c952c351e308cc2aefe7ffd4de82d528488 100644 (file)
@@ -1423,6 +1423,74 @@ void pci_bus_assign_resources(const struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_assign_resources);
 
+static void pci_claim_device_resources(struct pci_dev *dev)
+{
+       int i;
+
+       for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
+               struct resource *r = &dev->resource[i];
+
+               if (!r->flags || r->parent)
+                       continue;
+
+               pci_claim_resource(dev, i);
+       }
+}
+
+static void pci_claim_bridge_resources(struct pci_dev *dev)
+{
+       int i;
+
+       for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+               struct resource *r = &dev->resource[i];
+
+               if (!r->flags || r->parent)
+                       continue;
+
+               pci_claim_bridge_resource(dev, i);
+       }
+}
+
+static void pci_bus_allocate_dev_resources(struct pci_bus *b)
+{
+       struct pci_dev *dev;
+       struct pci_bus *child;
+
+       list_for_each_entry(dev, &b->devices, bus_list) {
+               pci_claim_device_resources(dev);
+
+               child = dev->subordinate;
+               if (child)
+                       pci_bus_allocate_dev_resources(child);
+       }
+}
+
+static void pci_bus_allocate_resources(struct pci_bus *b)
+{
+       struct pci_bus *child;
+
+       /*
+        * Carry out a depth-first search on the PCI bus
+        * tree to allocate bridge apertures. Read the
+        * programmed bridge bases and recursively claim
+        * the respective bridge resources.
+        */
+       if (b->self) {
+               pci_read_bridge_bases(b);
+               pci_claim_bridge_resources(b->self);
+       }
+
+       list_for_each_entry(child, &b->children, node)
+               pci_bus_allocate_resources(child);
+}
+
+void pci_bus_claim_resources(struct pci_bus *b)
+{
+       pci_bus_allocate_resources(b);
+       pci_bus_allocate_dev_resources(b);
+}
+EXPORT_SYMBOL(pci_bus_claim_resources);
+
 static void __pci_bridge_assign_resources(const struct pci_dev *bridge,
                                          struct list_head *add_head,
                                          struct list_head *fail_head)
index b43f7ac9812c3473b0bb04c227bfc7c38e09175e..3a0f3a4ee944fb2982e55d3416407030cea89400 100644 (file)
@@ -4775,20 +4775,17 @@ static int
 lpfc_enable_pci_dev(struct lpfc_hba *phba)
 {
        struct pci_dev *pdev;
-       int bars = 0;
 
        /* Obtain PCI device reference */
        if (!phba->pcidev)
                goto out_error;
        else
                pdev = phba->pcidev;
-       /* Select PCI BARs */
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
        /* Enable PCI device */
        if (pci_enable_device_mem(pdev))
                goto out_error;
        /* Request PCI resource for the device */
-       if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
+       if (pci_request_mem_regions(pdev, LPFC_DRIVER_NAME))
                goto out_disable_device;
        /* Set up device as PCI master and save state for EEH */
        pci_set_master(pdev);
@@ -4805,7 +4802,7 @@ out_disable_device:
        pci_disable_device(pdev);
 out_error:
        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                       "1401 Failed to enable pci device, bars:x%x\n", bars);
+                       "1401 Failed to enable pci device\n");
        return -ENODEV;
 }
 
@@ -4820,17 +4817,14 @@ static void
 lpfc_disable_pci_dev(struct lpfc_hba *phba)
 {
        struct pci_dev *pdev;
-       int bars;
 
        /* Obtain PCI device reference */
        if (!phba->pcidev)
                return;
        else
                pdev = phba->pcidev;
-       /* Select PCI BARs */
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
        /* Release PCI resource and disable PCI device */
-       pci_release_selected_regions(pdev, bars);
+       pci_release_mem_regions(pdev);
        pci_disable_device(pdev);
 
        return;
@@ -9722,7 +9716,6 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
        struct lpfc_vport **vports;
        struct lpfc_hba   *phba = vport->phba;
        int i;
-       int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 
        spin_lock_irq(&phba->hbalock);
        vport->load_flag |= FC_UNLOADING;
@@ -9797,7 +9790,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
 
        lpfc_hba_free(phba);
 
-       pci_release_selected_regions(pdev, bars);
+       pci_release_mem_regions(pdev);
        pci_disable_device(pdev);
 }
 
index 48672fac7ff3eb22389acfb4889a513e8ac79948..ac352fe391f402ea8ce02e0474b77a8429931d98 100644 (file)
@@ -382,7 +382,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
         * need to have the registers polled during D3, so avoid D3cold.
         */
        if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
-               pdev->no_d3cold = true;
+               pci_d3cold_disable(pdev);
 
        if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
                xhci_pme_quirk(hcd);
index 89ab0572dbc63cfe4375cdae9528809b3b0bdd62..7d63a66e8ed43a7b696f0e061a0d9a8d051b98fc 100644 (file)
@@ -24,6 +24,8 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
 }
 extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
 
+extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res);
+
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 {
        struct pci_bus *pbus = pdev->bus;
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
new file mode 100644 (file)
index 0000000..7adad20
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+#ifndef DRIVERS_PCI_ECAM_H
+#define DRIVERS_PCI_ECAM_H
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+/*
+ * struct to hold pci ops and bus shift of the config window
+ * for a PCI controller.
+ */
+struct pci_config_window;
+struct pci_ecam_ops {
+       unsigned int                    bus_shift;
+       struct pci_ops                  pci_ops;
+       int                             (*init)(struct pci_config_window *);
+};
+
+/*
+ * struct to hold the mappings of a config space window. This
+ * is expected to be used as sysdata for PCI controllers that
+ * use ECAM.
+ */
+struct pci_config_window {
+       struct resource                 res;
+       struct resource                 busr;
+       void                            *priv;
+       struct pci_ecam_ops             *ops;
+       union {
+               void __iomem            *win;   /* 64-bit single mapping */
+               void __iomem            **winp; /* 32-bit per-bus mapping */
+       };
+       struct device                   *parent;/* ECAM res was from this dev */
+};
+
+/* create and free pci_config_window */
+struct pci_config_window *pci_ecam_create(struct device *dev,
+               struct resource *cfgres, struct resource *busr,
+               struct pci_ecam_ops *ops);
+void pci_ecam_free(struct pci_config_window *cfg);
+
+/* map_bus when ->sysdata is an instance of pci_config_window */
+void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
+                              int where);
+/* default ECAM ops */
+extern struct pci_ecam_ops pci_generic_ecam_ops;
+
+#ifdef CONFIG_PCI_HOST_GENERIC
+/* for DT-based PCI controllers that support ECAM */
+int pci_host_common_probe(struct platform_device *pdev,
+                         struct pci_ecam_ops *ops);
+#endif
+#endif
index b67e4df2080130b75b8c925921fa5f13e464496c..1fed5927b08a4e1ae5452dc86b79d994e325d24f 100644 (file)
@@ -101,6 +101,10 @@ enum {
        DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES,
 };
 
+/*
+ * pci_power_t values must match the bits in the Capabilities PME_Support
+ * and Control/Status PowerState fields in the Power Management capability.
+ */
 typedef int __bitwise pci_power_t;
 
 #define PCI_D0         ((pci_power_t __force) 0)
@@ -116,7 +120,7 @@ extern const char *pci_power_names[];
 
 static inline const char *pci_power_name(pci_power_t state)
 {
-       return pci_power_names[1 + (int) state];
+       return pci_power_names[1 + (__force int) state];
 }
 
 #define PCI_PM_D2_DELAY                200
@@ -294,6 +298,7 @@ struct pci_dev {
        unsigned int    d2_support:1;   /* Low power state D2 is supported */
        unsigned int    no_d1d2:1;      /* D1 and D2 are forbidden */
        unsigned int    no_d3cold:1;    /* D3cold is forbidden */
+       unsigned int    bridge_d3:1;    /* Allow D3 for bridge */
        unsigned int    d3cold_allowed:1;       /* D3cold is allowed by user */
        unsigned int    mmio_always_on:1;       /* disallow turning off io/mem
                                                   decoding during bar sizing */
@@ -1083,6 +1088,8 @@ int pci_back_from_sleep(struct pci_dev *dev);
 bool pci_dev_run_wake(struct pci_dev *dev);
 bool pci_check_pme_status(struct pci_dev *dev);
 void pci_pme_wakeup_bus(struct pci_bus *bus);
+void pci_d3cold_enable(struct pci_dev *dev);
+void pci_d3cold_disable(struct pci_dev *dev);
 
 static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
                                  bool enable)
@@ -1114,6 +1121,7 @@ int pci_set_vpd_size(struct pci_dev *dev, size_t len);
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
 resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
 void pci_bus_assign_resources(const struct pci_bus *bus);
+void pci_bus_claim_resources(struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 int pci_claim_bridge_resource(struct pci_dev *bridge, int i);
@@ -1143,9 +1151,12 @@ void pci_add_resource(struct list_head *resources, struct resource *res);
 void pci_add_resource_offset(struct list_head *resources, struct resource *res,
                             resource_size_t offset);
 void pci_free_resource_list(struct list_head *resources);
-void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
+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);
+int devm_request_pci_bus_resources(struct device *dev,
+                                  struct list_head *resources);
 
 #define pci_bus_for_each_resource(bus, res, i)                         \
        for (i = 0;                                                     \
@@ -1167,6 +1178,7 @@ int pci_register_io_range(phys_addr_t addr, resource_size_t size);
 unsigned long pci_address_to_pio(phys_addr_t addr);
 phys_addr_t pci_pio_to_address(unsigned long pio);
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
+void pci_unmap_iospace(struct resource *res);
 
 static inline pci_bus_addr_t pci_bus_address(struct pci_dev *pdev, int bar)
 {
@@ -1389,12 +1401,13 @@ static inline int pci_domain_nr(struct pci_bus *bus)
 {
        return bus->domain_nr;
 }
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
+#ifdef CONFIG_ACPI
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus);
 #else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
-                                       struct device *parent)
-{
-}
+static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+{ return 0; }
+#endif
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent);
 #endif
 
 /* some architectures require additional setup to direct VGA traffic */
@@ -1402,6 +1415,34 @@ typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
                      unsigned int command_bits, u32 flags);
 void pci_register_set_vga_state(arch_set_vga_state_t func);
 
+static inline int
+pci_request_io_regions(struct pci_dev *pdev, const char *name)
+{
+       return pci_request_selected_regions(pdev,
+                           pci_select_bars(pdev, IORESOURCE_IO), name);
+}
+
+static inline void
+pci_release_io_regions(struct pci_dev *pdev)
+{
+       return pci_release_selected_regions(pdev,
+                           pci_select_bars(pdev, IORESOURCE_IO));
+}
+
+static inline int
+pci_request_mem_regions(struct pci_dev *pdev, const char *name)
+{
+       return pci_request_selected_regions(pdev,
+                           pci_select_bars(pdev, IORESOURCE_MEM), name);
+}
+
+static inline void
+pci_release_mem_regions(struct pci_dev *pdev)
+{
+       return pci_release_selected_regions(pdev,
+                           pci_select_bars(pdev, IORESOURCE_MEM));
+}
+
 #else /* CONFIG_PCI is not enabled */
 
 static inline void pci_set_flags(int flags) { }
@@ -1554,7 +1595,11 @@ static inline const char *pci_name(const struct pci_dev *pdev)
 /* Some archs don't want to expose struct resource to userland as-is
  * in sysfs and /proc
  */
-#ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER
+#ifdef HAVE_ARCH_PCI_RESOURCE_TO_USER
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                         const struct resource *rsrc,
+                         resource_size_t *start, resource_size_t *end);
+#else
 static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
                const struct resource *rsrc, resource_size_t *start,
                resource_size_t *end)
@@ -1706,6 +1751,7 @@ extern u8 pci_cache_line_size;
 
 extern unsigned long pci_hotplug_io_size;
 extern unsigned long pci_hotplug_mem_size;
+extern unsigned long pci_hotplug_bus_size;
 
 /* Architecture-specific versions may override these (weak) */
 void pcibios_disable_device(struct pci_dev *dev);
@@ -1722,7 +1768,7 @@ void pcibios_free_irq(struct pci_dev *dev);
 extern struct dev_pm_ops pcibios_pm_ops;
 #endif
 
-#ifdef CONFIG_PCI_MMCONFIG
+#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG)
 void __init pci_mmcfg_early_init(void);
 void __init pci_mmcfg_late_init(void);
 #else