Merge branch 'pci/host-xgene' into next
authorBjorn Helgaas <bhelgaas@google.com>
Tue, 14 Nov 2017 18:11:37 +0000 (12:11 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 14 Nov 2017 18:11:37 +0000 (12:11 -0600)
* pci/host-xgene:
  PCI: xgene: Rename xgene_pcie_probe_bridge() to xgene_pcie_probe()

86 files changed:
Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
Documentation/devicetree/bindings/pci/designware-pcie-ecam.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/layerscape-pci.txt
Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt
Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt
MAINTAINERS
arch/alpha/include/asm/pci.h
arch/alpha/kernel/pci.c
arch/alpha/kernel/pci_impl.h
arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
arch/cris/include/asm/pci.h
arch/frv/include/asm/pci.h
arch/ia64/include/asm/pci.h
arch/mips/include/asm/pci.h
arch/mn10300/include/asm/pci.h
arch/mn10300/unit-asb2305/pci-asb2305.h
arch/parisc/include/asm/pci.h
arch/powerpc/include/asm/pci.h
arch/powerpc/kernel/eeh_driver.c
arch/sh/include/asm/pci.h
arch/sparc/include/asm/pci_32.h
arch/x86/include/asm/pci.h
arch/x86/pci/fixup.c
arch/x86/pci/intel_mid_pci.c
arch/xtensa/include/asm/pci.h
drivers/irqchip/irq-ls-scfg-msi.c
drivers/misc/pci_endpoint_test.c
drivers/of/address.c
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/dwc/Kconfig
drivers/pci/dwc/Makefile
drivers/pci/dwc/pci-dra7xx.c
drivers/pci/dwc/pci-layerscape.c
drivers/pci/dwc/pcie-histb.c [new file with mode: 0644]
drivers/pci/host/Kconfig
drivers/pci/host/Makefile
drivers/pci/host/pci-ftpci100.c
drivers/pci/host/pci-host-generic.c
drivers/pci/host/pci-hyperv.c
drivers/pci/host/pci-rcar-gen2.c
drivers/pci/host/pci-tegra.c
drivers/pci/host/pci-v3-semi.c [new file with mode: 0644]
drivers/pci/host/pci-xgene.c
drivers/pci/host/pcie-altera.c
drivers/pci/host/pcie-iproc-msi.c
drivers/pci/host/pcie-iproc.c
drivers/pci/host/pcie-rcar.c
drivers/pci/host/pcie-tango.c
drivers/pci/hotplug-pci.c [deleted file]
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/cpci_hotplug_pci.c
drivers/pci/hotplug/cpqphp.h
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/cpqphp_ctrl.c
drivers/pci/hotplug/ibmphp_pci.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/hotplug/shpchp_hpc.c
drivers/pci/hotplug/shpchp_pci.c
drivers/pci/iov.c
drivers/pci/pci-acpi.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/pme.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/rom.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pci/switch/switchtec.c
drivers/pcmcia/cardbus.c
include/linux/of_address.h
include/linux/pci.h
include/uapi/linux/pci_regs.h
init/Kconfig

index 49ccabbfa6f3dcd13634f52ef308d8251e163027..a4ff93d6b7f386454558035472e1a2aa0eca205d 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
               "fsl,ls1043a-msi"
               "fsl,ls1046a-msi"
               "fsl,ls1043a-v1.1-msi"
+              "fsl,ls1012a-msi"
 - msi-controller: indicates that this is a PCIe MSI controller node
 - reg: physical base address of the controller and length of memory mapped.
 - interrupts: an interrupt to the parent interrupt controller.
diff --git a/Documentation/devicetree/bindings/pci/designware-pcie-ecam.txt b/Documentation/devicetree/bindings/pci/designware-pcie-ecam.txt
new file mode 100644 (file)
index 0000000..515b2f9
--- /dev/null
@@ -0,0 +1,42 @@
+* Synopsys DesignWare PCIe root complex in ECAM shift mode
+
+In some cases, firmware may already have configured the Synopsys DesignWare
+PCIe controller in RC mode with static ATU window mappings that cover all
+config, MMIO and I/O spaces in a [mostly] ECAM compatible fashion.
+In this case, there is no need for the OS to perform any low level setup
+of clocks, PHYs or device registers, nor is there any reason for the driver
+to reconfigure ATU windows for config and/or IO space accesses at runtime.
+
+In cases where the IP was synthesized with a minimum ATU window size of
+64 KB, it cannot be supported by the generic ECAM driver, because it
+requires special config space accessors that filter accesses to device #1
+and beyond on the first bus.
+
+Required properties:
+- compatible: "marvell,armada8k-pcie-ecam" or
+              "socionext,synquacer-pcie-ecam" or
+              "snps,dw-pcie-ecam" (must be preceded by a more specific match)
+
+Please refer to the binding document of "pci-host-ecam-generic" in the
+file host-generic-pci.txt for a description of the remaining required
+and optional properties.
+
+Example:
+
+    pcie1: pcie@7f000000 {
+        compatible = "socionext,synquacer-pcie-ecam", "snps,dw-pcie-ecam";
+        device_type = "pci";
+        reg = <0x0 0x7f000000 0x0 0xf00000>;
+        bus-range = <0x0 0xe>;
+        #address-cells = <3>;
+        #size-cells = <2>;
+        ranges = <0x1000000 0x00 0x00010000 0x00 0x7ff00000 0x0 0x00010000>,
+                 <0x2000000 0x00 0x70000000 0x00 0x70000000 0x0 0x0f000000>,
+                 <0x3000000 0x3f 0x00000000 0x3f 0x00000000 0x1 0x00000000>;
+
+        #interrupt-cells = <0x1>;
+        interrupt-map-mask = <0x0 0x0 0x0 0x0>;
+        interrupt-map = <0x0 0x0 0x0 0x0 &gic 0x0 0x0 0x0 182 0x4>;
+        msi-map = <0x0 &its 0x0 0x10000>;
+        dma-coherent;
+    };
diff --git a/Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt b/Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt
new file mode 100644 (file)
index 0000000..c84bc02
--- /dev/null
@@ -0,0 +1,68 @@
+HiSilicon STB PCIe host bridge DT description
+
+The HiSilicon STB PCIe host controller is based on the DesignWare PCIe core.
+It shares common functions with the DesignWare PCIe core driver and inherits
+common properties defined in
+Documentation/devicetree/bindings/pci/designware-pcie.txt.
+
+Additional properties are described here:
+
+Required properties
+- compatible: Should be one of the following strings:
+               "hisilicon,hi3798cv200-pcie"
+- reg: Should contain sysctl, rc_dbi, config registers location and length.
+- reg-names: Must include the following entries:
+  "control": control registers of PCIe controller;
+  "rc-dbi": configuration space of PCIe controller;
+  "config": configuration transaction space of PCIe controller.
+- bus-range: PCI bus numbers covered.
+- interrupts: MSI interrupt.
+- interrupt-names: Must include "msi" entries.
+- clocks: List of phandle and clock specifier pairs as listed in clock-names
+  property.
+- clock-name: Must include the following entries:
+  "aux": auxiliary gate clock;
+  "pipe": pipe gate clock;
+  "sys": sys gate clock;
+  "bus": bus gate clock.
+- resets: List of phandle and reset specifier pairs as listed in reset-names
+  property.
+- reset-names: Must include the following entries:
+  "soft": soft reset;
+  "sys": sys reset;
+  "bus": bus reset.
+
+Optional properties:
+- reset-gpios: The gpio to generate PCIe PERST# assert and deassert signal.
+- phys: List of phandle and phy mode specifier, should be 0.
+- phy-names: Must be "phy".
+
+Example:
+       pcie@f9860000 {
+               compatible = "hisilicon,hi3798cv200-pcie";
+               reg = <0xf9860000 0x1000>,
+                     <0xf0000000 0x2000>,
+                     <0xf2000000 0x01000000>;
+               reg-names = "control", "rc-dbi", "config";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               bus-range = <0 15>;
+               num-lanes = <1>;
+               ranges=<0x81000000 0 0 0xf4000000 0 0x00010000
+                       0x82000000 0 0xf3000000 0xf3000000 0 0x01000000>;
+               interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "msi";
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&crg PCIE_AUX_CLK>,
+                        <&crg PCIE_PIPE_CLK>,
+                        <&crg PCIE_SYS_CLK>,
+                        <&crg PCIE_BUS_CLK>;
+               clock-names = "aux", "pipe", "sys", "bus";
+               resets = <&crg 0x18c 6>, <&crg 0x18c 5>, <&crg 0x18c 4>;
+               reset-names = "soft", "sys", "bus";
+               phys = <&combphy1 PHY_TYPE_PCIE>;
+               phy-names = "phy";
+       };
index c0484da0f20d9d87f3be44f9bfd844362820bb59..66df1e81e0b8d218ad39396e41be2c2d2e504f5c 100644 (file)
@@ -18,6 +18,7 @@ Required properties:
         "fsl,ls2088a-pcie"
         "fsl,ls1088a-pcie"
         "fsl,ls1046a-pcie"
+        "fsl,ls1012a-pcie"
 - reg: base addresses and lengths of the PCIe controller register blocks.
 - interrupts: A list of interrupt outputs of the controller. Must contain an
   entry for each entry in the interrupt-names property.
index 982a74ea6df9b31a2cbbb076e5359ae33026f506..33d2e21393331929a729d01ed2f98f8c88ba9de8 100644 (file)
@@ -1,10 +1,15 @@
 NVIDIA Tegra PCIe controller
 
 Required properties:
-- compatible: For Tegra20, must contain "nvidia,tegra20-pcie".  For Tegra30,
-  "nvidia,tegra30-pcie".  For Tegra124, must contain "nvidia,tegra124-pcie".
-  Otherwise, must contain "nvidia,<chip>-pcie", plus one of the above, where
-  <chip> is tegra132 or tegra210.
+- compatible: Must be:
+  - "nvidia,tegra20-pcie": for Tegra20
+  - "nvidia,tegra30-pcie": for Tegra30
+  - "nvidia,tegra124-pcie": for Tegra124 and Tegra132
+  - "nvidia,tegra210-pcie": for Tegra210
+  - "nvidia,tegra186-pcie": for Tegra186
+- power-domains: To ungate power partition by BPMP powergate driver. Must
+  contain BPMP phandle and PCIe power partition ID. This is required only
+  for Tegra186.
 - device_type: Must be "pci"
 - reg: A list of physical base address and length for each set of controller
   registers. Must contain an entry for each entry in the reg-names property.
@@ -124,6 +129,16 @@ Power supplies for Tegra210:
   - vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must
     supply 1.8 V.
 
+Power supplies for Tegra186:
+- Required:
+  - dvdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
+  - hvdd-pex-pll-supply: High-voltage supply for PLLE (shared with USB3). Must
+    supply 1.8 V.
+  - hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks.
+    Must supply 1.8 V.
+  - vddio-pexctl-aud-supply: Power supply for PCIe side band signals. Must
+    supply 1.8 V.
+
 Root ports are defined as subnodes of the PCIe controller node.
 
 Required properties:
@@ -546,3 +561,114 @@ Board DTS:
                        status = "okay";
                };
        };
+
+Tegra186:
+---------
+
+SoC DTSI:
+
+       pcie@10003000 {
+               compatible = "nvidia,tegra186-pcie";
+               power-domains = <&bpmp TEGRA186_POWER_DOMAIN_PCX>;
+               device_type = "pci";
+               reg = <0x0 0x10003000 0x0 0x00000800   /* PADS registers */
+                      0x0 0x10003800 0x0 0x00000800   /* AFI registers */
+                      0x0 0x40000000 0x0 0x10000000>; /* configuration space */
+               reg-names = "pads", "afi", "cs";
+
+               interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */
+                            <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */
+               interrupt-names = "intr", "msi";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+
+               bus-range = <0x00 0xff>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+
+               ranges = <0x82000000 0 0x10000000 0x0 0x10000000 0 0x00001000   /* port 0 configuration space */
+                         0x82000000 0 0x10001000 0x0 0x10001000 0 0x00001000   /* port 1 configuration space */
+                         0x82000000 0 0x10004000 0x0 0x10004000 0 0x00001000   /* port 2 configuration space */
+                         0x81000000 0 0x0        0x0 0x50000000 0 0x00010000   /* downstream I/O (64 KiB) */
+                         0x82000000 0 0x50100000 0x0 0x50100000 0 0x07F00000   /* non-prefetchable memory (127 MiB) */
+                         0xc2000000 0 0x58000000 0x0 0x58000000 0 0x28000000>; /* prefetchable memory (640 MiB) */
+
+               clocks = <&bpmp TEGRA186_CLK_AFI>,
+                        <&bpmp TEGRA186_CLK_PCIE>,
+                        <&bpmp TEGRA186_CLK_PLLE>;
+               clock-names = "afi", "pex", "pll_e";
+
+               resets = <&bpmp TEGRA186_RESET_AFI>,
+                        <&bpmp TEGRA186_RESET_PCIE>,
+                        <&bpmp TEGRA186_RESET_PCIEXCLK>;
+               reset-names = "afi", "pex", "pcie_x";
+
+               status = "disabled";
+
+               pci@1,0 {
+                       device_type = "pci";
+                       assigned-addresses = <0x82000800 0 0x10000000 0 0x1000>;
+                       reg = <0x000800 0 0 0 0>;
+                       status = "disabled";
+
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       nvidia,num-lanes = <2>;
+               };
+
+               pci@2,0 {
+                       device_type = "pci";
+                       assigned-addresses = <0x82001000 0 0x10001000 0 0x1000>;
+                       reg = <0x001000 0 0 0 0>;
+                       status = "disabled";
+
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       nvidia,num-lanes = <1>;
+               };
+
+               pci@3,0 {
+                       device_type = "pci";
+                       assigned-addresses = <0x82001800 0 0x10004000 0 0x1000>;
+                       reg = <0x001800 0 0 0 0>;
+                       status = "disabled";
+
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       nvidia,num-lanes = <1>;
+               };
+       };
+
+Board DTS:
+
+       pcie@10003000 {
+               status = "okay";
+
+               dvdd-pex-supply = <&vdd_pex>;
+               hvdd-pex-pll-supply = <&vdd_1v8>;
+               hvdd-pex-supply = <&vdd_1v8>;
+               vddio-pexctl-aud-supply = <&vdd_1v8>;
+
+               pci@1,0 {
+                       nvidia,num-lanes = <4>;
+                       status = "okay";
+               };
+
+               pci@2,0 {
+                       nvidia,num-lanes = <0>;
+                       status = "disabled";
+               };
+
+               pci@3,0 {
+                       nvidia,num-lanes = <1>;
+                       status = "disabled";
+               };
+       };
index 3d038638612b8ec2af704adaf6dcd5b0bc81b1e6..9fe7e12a7bf37b7c874a3e93bea590452845d093 100644 (file)
@@ -60,17 +60,15 @@ Example SoC configuration:
                                 0x0800 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
                                 0x1000 0 0 2 &gic 0 108 IRQ_TYPE_LEVEL_HIGH>;
 
-               pci@0,1 {
+               usb@1,0 {
                        reg = <0x800 0 0 0 0>;
-                       device_type = "pci";
-                       phys = <&usbphy 0 0>;
+                       phys = <&usb0 0>;
                        phy-names = "usb";
                };
 
-               pci@0,2 {
+               usb@2,0 {
                        reg = <0x1000 0 0 0 0>;
-                       device_type = "pci";
-                       phys = <&usbphy 0 0>;
+                       phys = <&usb0 0>;
                        phy-names = "usb";
                };
        };
index 30b364e504ba9942ac316eaf0afc1132a83cd255..11063293f76190dd9662849bf97c9abe5e61624d 100644 (file)
@@ -2,14 +2,75 @@ V3 Semiconductor V360 EPC PCI bridge
 
 This bridge is found in the ARM Integrator/AP (Application Platform)
 
-Integrator-specific notes:
+Required properties:
+- compatible: should be one of:
+  "v3,v360epc-pci"
+  "arm,integrator-ap-pci", "v3,v360epc-pci"
+- reg: should contain two register areas:
+  first the base address of the V3 host bridge controller, 64KB
+  second the configuration area register space, 16MB
+- interrupts: should contain a reference to the V3 error interrupt
+  as routed on the system.
+- bus-range: see pci.txt
+- ranges: this follows the standard PCI bindings in the IEEE Std
+  1275-1994 (see pci.txt) with the following restriction:
+  - The non-prefetchable and prefetchable memory windows must
+    each be exactly 256MB (0x10000000) in size.
+  - The prefetchable memory window must be immediately adjacent
+    to the non-prefetcable memory window
+- dma-ranges: three ranges for the inbound memory region. The ranges must
+  be aligned to a 1MB boundary, and may be 1MB, 2MB, 4MB, 8MB, 16MB, 32MB,
+  64MB, 128MB, 256MB, 512MB, 1GB or 2GB in size. The memory should be marked
+  as pre-fetchable. Two ranges are supported by the hardware.
 
-- syscon: should contain a link to the syscon device node (since
+Integrator-specific required properties:
+- syscon: should contain a link to the syscon device node, since
   on the Integrator, some registers in the syscon are required to
-  operate the V3).
+  operate the V3 host bridge.
 
-V360 EPC specific notes:
+Example:
 
-- reg: should contain the base address of the V3 adapter.
-- interrupts: should contain a reference to the V3 error interrupt
-  as routed on the system.
+pci: pciv3@62000000 {
+       compatible = "arm,integrator-ap-pci", "v3,v360epc-pci";
+       #interrupt-cells = <1>;
+       #size-cells = <2>;
+       #address-cells = <3>;
+       reg = <0x62000000 0x10000>, <0x61000000 0x01000000>;
+       interrupt-parent = <&pic>;
+       interrupts = <17>; /* Bus error IRQ */
+       clocks = <&pciclk>;
+       bus-range = <0x00 0xff>;
+       ranges = 0x01000000 0 0x00000000 /* I/O space @00000000 */
+               0x60000000 0 0x01000000 /* 16 MiB @ LB 60000000 */
+               0x02000000 0 0x40000000 /* non-prefectable memory @40000000 */
+               0x40000000 0 0x10000000 /* 256 MiB @ LB 40000000 1:1 */
+               0x42000000 0 0x50000000 /* prefetchable memory @50000000 */
+               0x50000000 0 0x10000000>; /* 256 MiB @ LB 50000000 1:1 */
+       dma-ranges = <0x02000000 0 0x20000000 /* EBI memory space */
+               0x20000000 0 0x20000000 /* 512 MB @ LB 20000000 1:1 */
+               0x02000000 0 0x80000000 /* Core module alias memory */
+               0x80000000 0 0x40000000>; /* 1GB @ LB 80000000 */
+       interrupt-map-mask = <0xf800 0 0 0x7>;
+       interrupt-map = <
+       /* IDSEL 9 */
+       0x4800 0 0 1 &pic 13 /* INT A on slot 9 is irq 13 */
+       0x4800 0 0 2 &pic 14 /* INT B on slot 9 is irq 14 */
+       0x4800 0 0 3 &pic 15 /* INT C on slot 9 is irq 15 */
+       0x4800 0 0 4 &pic 16 /* INT D on slot 9 is irq 16 */
+       /* IDSEL 10 */
+       0x5000 0 0 1 &pic 14 /* INT A on slot 10 is irq 14 */
+       0x5000 0 0 2 &pic 15 /* INT B on slot 10 is irq 15 */
+       0x5000 0 0 3 &pic 16 /* INT C on slot 10 is irq 16 */
+       0x5000 0 0 4 &pic 13 /* INT D on slot 10 is irq 13 */
+       /* IDSEL 11 */
+       0x5800 0 0 1 &pic 15 /* INT A on slot 11 is irq 15 */
+       0x5800 0 0 2 &pic 16 /* INT B on slot 11 is irq 16 */
+       0x5800 0 0 3 &pic 13 /* INT C on slot 11 is irq 13 */
+       0x5800 0 0 4 &pic 14 /* INT D on slot 11 is irq 14 */
+       /* IDSEL 12 */
+       0x6000 0 0 1 &pic 16 /* INT A on slot 12 is irq 16 */
+       0x6000 0 0 2 &pic 13 /* INT B on slot 12 is irq 13 */
+       0x6000 0 0 3 &pic 14 /* INT C on slot 12 is irq 14 */
+       0x6000 0 0 4 &pic 15 /* INT D on slot 12 is irq 15 */
+       >;
+};
index 65b0c88d5ee0d292914b85c9ba45b1fee5f466ff..ca456a8707314214052791f14b5836d8f3f50336 100644 (file)
@@ -10480,6 +10480,14 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/pci/pcie-kirin.txt
 F:     drivers/pci/dwc/pcie-kirin.c
 
+PCIE DRIVER FOR HISILICON STB
+M:     Jianguo Sun <sunjianguo1@huawei.com>
+M:     Shawn Guo <shawn.guo@linaro.org>
+L:     linux-pci@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt
+F:     drivers/pci/dwc/pcie-histb.c
+
 PCIE DRIVER FOR MEDIATEK
 M:     Ryder Lee <ryder.lee@mediatek.com>
 L:     linux-pci@vger.kernel.org
@@ -10503,6 +10511,13 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/pci/rockchip-pcie.txt
 F:     drivers/pci/host/pcie-rockchip.c
 
+PCI DRIVER FOR V3 SEMICONDUCTOR V360EPC
+M:     Linus Walleij <linus.walleij@linaro.org>
+L:     linux-pci@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt
+F:     drivers/pci/host/pci-v3-semi.c
+
 PCIE DRIVER FOR ST SPEAR13XX
 M:     Pratyush Anand <pratyush.anand@gmail.com>
 L:     linux-pci@vger.kernel.org
index a06c24b3a2e13baaca1a4f41f16544a012f009a9..0a10ff93b174e002355f92a3a578e699e14b5582 100644 (file)
@@ -12,9 +12,6 @@
  * The following structure is used to manage multiple PCI busses.
  */
 
-struct pci_dev;
-struct pci_bus;
-struct resource;
 struct pci_iommu_arena;
 struct page;
 
@@ -56,8 +53,6 @@ struct pci_controller {
 #define PCIBIOS_MIN_IO         alpha_mv.min_io_address
 #define PCIBIOS_MIN_MEM                alpha_mv.min_mem_address
 
-extern void pcibios_set_master(struct pci_dev *dev);
-
 /* IOMMU controls.  */
 
 /* The PCI address space does not equal the physical memory address space.
index 564114eb85e143f384d1b814cc29df48150ed933..16b67621a0d5fee5b88acae3bd4a527897ffae29 100644 (file)
@@ -196,9 +196,16 @@ pcibios_init(void)
 subsys_initcall(pcibios_init);
 
 #ifdef ALPHA_RESTORE_SRM_SETUP
+/* Store PCI device configuration left by SRM here. */
+struct pdev_srm_saved_conf
+{
+       struct pdev_srm_saved_conf *next;
+       struct pci_dev *dev;
+};
+
 static struct pdev_srm_saved_conf *srm_saved_configs;
 
-void pdev_save_srm_config(struct pci_dev *dev)
+static void pdev_save_srm_config(struct pci_dev *dev)
 {
        struct pdev_srm_saved_conf *tmp;
        static int printed = 0;
@@ -238,6 +245,8 @@ pci_restore_srm_config(void)
                pci_restore_state(tmp->dev);
        }
 }
+#else
+#define pdev_save_srm_config(dev)      do {} while (0)
 #endif
 
 void pcibios_fixup_bus(struct pci_bus *bus)
index 2b0ac429f5ebc4912e34b41029810fa914124479..65adea0d3d78905f34197d3d662a14990acbce44 100644 (file)
@@ -156,16 +156,8 @@ struct pci_iommu_arena
 #endif
 
 #ifdef ALPHA_RESTORE_SRM_SETUP
-/* Store PCI device configuration left by SRM here. */
-struct pdev_srm_saved_conf
-{
-       struct pdev_srm_saved_conf *next;
-       struct pci_dev *dev;
-};
-
 extern void pci_restore_srm_config(void);
 #else
-#define pdev_save_srm_config(dev)      do {} while (0)
 #define pci_restore_srm_config()       do {} while (0)
 #endif
 
index df83915d6ea629509b829d82061bd7c6019e790c..fe1ea5d707a8f7ec3dc0af3e66c05dd754f7528b 100644 (file)
                        dr_mode = "host";
                        phy_type = "ulpi";
                };
+
+               msi: msi-controller1@1572000 {
+                       compatible = "fsl,ls1012a-msi";
+                       reg = <0x0 0x1572000 0x0 0x8>;
+                       msi-controller;
+                       interrupts = <0 126 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               pcie@3400000 {
+                       compatible = "fsl,ls1012a-pcie", "snps,dw-pcie";
+                       reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
+                              0x40 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+                       interrupts = <0 118 0x4>, /* controller interrupt */
+                                    <0 117 0x4>; /* PME interrupt */
+                       interrupt-names = "aer", "pme";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       num-lanes = <4>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&msi>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 110 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 2 &gic 0 111 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 3 &gic 0 112 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 4 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>;
+               };
        };
 };
index c8ff0baddf1d06858091df65a66d60c348cc0e43..e8a478ca14858cb6f8d39672860964d4c06e0436 100644 (file)
                                     <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
                };
 
+               pcie@3400000 {
+                       compatible = "fsl,ls1046a-pcie", "snps,dw-pcie";
+                       reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
+                              0x40 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+                       interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */
+                                    <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; /* PME interrupt */
+                       interrupt-names = "aer", "pme";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
+                       num-lanes = <4>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&msi1>, <&msi2>, <&msi3>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 2 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 4 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               pcie@3500000 {
+                       compatible = "fsl,ls1046a-pcie", "snps,dw-pcie";
+                       reg = <0x00 0x03500000 0x0 0x00100000   /* controller registers */
+                              0x48 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */
+                                    <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>; /* PME interrupt */
+                       interrupt-names = "aer", "pme";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
+                       num-lanes = <2>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&msi2>, <&msi3>, <&msi1>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 2 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 3 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 4 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               pcie@3600000 {
+                       compatible = "fsl,ls1046a-pcie", "snps,dw-pcie";
+                       reg = <0x00 0x03600000 0x0 0x00100000   /* controller registers */
+                              0x50 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+                       interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */
+                                    <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>; /* PME interrupt */
+                       interrupt-names = "aer", "pme";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
+                       num-lanes = <2>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&msi3>, <&msi1>, <&msi2>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 2 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 3 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 4 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
        };
 
        reserved-memory {
index 6e505332b3e36d165a960e222e9593994c7eaf83..141337bf16bca0c7c881b911fd450c64f0b454c2 100644 (file)
 
 #define PCIBIOS_MIN_CARDBUS_IO 0x4000
 
-void pcibios_config_init(void);
-struct pci_bus * pcibios_scan_root(int bus);
-
-void pcibios_set_master(struct pci_dev *dev);
-struct irq_routing_table *pcibios_get_irq_routing_table(void);
-int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
-
 /* Dynamic DMA mapping stuff.
  * i386 has everything mapped statically.
  */
@@ -33,8 +26,6 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
 #include <linux/string.h>
 #include <asm/io.h>
 
-struct pci_dev;
-
 /* The PCI address space does equal the physical memory
  * address space.  The networking and block device layers use
  * this boolean for bounce buffer decisions.
index 809cfc6707abf4f2402c0ae1e856cbca76ca211b..895af9d558bacaebd9e9068c42212d709861bc3e 100644 (file)
 #include <linux/scatterlist.h>
 #include <asm-generic/pci.h>
 
-struct pci_dev;
-
 #define pcibios_assign_all_busses()    0
 
-extern void pcibios_set_master(struct pci_dev *dev);
-
 #ifdef CONFIG_MMU
 extern void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle);
 extern void consistent_free(void *vaddr);
index 6459f2d46200581b2b5288a54aab090cde2d20d1..915531ede6a5163296ed67c16d63d1e3584b4277 100644 (file)
@@ -29,10 +29,6 @@ struct pci_vector_struct {
 #define PCIBIOS_MIN_IO         0x1000
 #define PCIBIOS_MIN_MEM                0x10000000
 
-void pcibios_config_init(void);
-
-struct pci_dev;
-
 /*
  * PCI_DMA_BUS_IS_PHYS should be set to 1 if there is _necessarily_ a direct
  * correspondence between device bus addresses and CPU physical addresses.
index 52f551ee492de2e385d97c138cfd262f4b351af1..2339f42f047ac38097682dc9c82acd4da7c17f6f 100644 (file)
@@ -106,8 +106,6 @@ extern unsigned long PCIBIOS_MIN_MEM;
 
 #define PCIBIOS_MIN_CARDBUS_IO 0x4000
 
-extern void pcibios_set_master(struct pci_dev *dev);
-
 #define HAVE_PCI_MMAP
 #define ARCH_GENERIC_PCI_MMAP_RESOURCE
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
@@ -123,8 +121,6 @@ extern void pcibios_set_master(struct pci_dev *dev);
 #include <linux/string.h>
 #include <asm/io.h>
 
-struct pci_dev;
-
 /*
  * The PCI address space does equal the physical memory address space.
  * The networking and block device layers use this boolean for bounce
index d27654902f28bd5bd8f7b4acae66f744041d8700..5b75a1b2c4f6213bbf3b4a952c89689cb5b1dc8f 100644 (file)
@@ -47,8 +47,6 @@ extern void unit_pci_init(void);
 #define PCIBIOS_MIN_IO         0xBE000004
 #define PCIBIOS_MIN_MEM                0xB8000000
 
-void pcibios_set_master(struct pci_dev *dev);
-
 /* Dynamic DMA mapping stuff.
  * i386 has everything mapped statically.
  */
@@ -59,8 +57,6 @@ void pcibios_set_master(struct pci_dev *dev);
 #include <linux/string.h>
 #include <asm/io.h>
 
-struct pci_dev;
-
 /* The PCI address space does equal the physical memory
  * address space.  The networking and block device layers use
  * this boolean for bounce buffer decisions.
index 96c484b12226566999248042c6182eb9a4af66d4..0667f613b023cb29c733951854e6bd0891a761a8 100644 (file)
@@ -30,9 +30,6 @@ extern void pcibios_resource_survey(void);
 
 extern struct pci_ops *pci_root_ops;
 
-extern struct irq_routing_table *pcibios_get_irq_routing_table(void);
-extern int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
-
 /* pci-irq.c */
 
 struct irq_info {
index 1de1a3f412ec142514d76bbb0edfda171fb0f510..8cc009e26a28d3277b951e967cdaac6cc4e532eb 100644 (file)
@@ -86,13 +86,6 @@ struct pci_hba_data {
 #define PCI_F_EXTEND           0UL
 #endif /* !CONFIG_64BIT */
 
-/*
-** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus
-** (This eliminates some of the warnings).
-*/
-struct pci_bus;
-struct pci_dev;
-
 /*
  * If the PCI device's view of memory is the same as the CPU's view of memory,
  * PCI_DMA_BUS_IS_PHYS is true.  The networking and block device layers use
@@ -161,7 +154,6 @@ extern struct pci_bios_ops *pci_bios;
 
 #ifdef CONFIG_PCI
 extern void pcibios_register_hba(struct pci_hba_data *);
-extern void pcibios_set_master(struct pci_dev *);
 #else
 static inline void pcibios_register_hba(struct pci_hba_data *x)
 {
index c8975dac535fc7ea907bc7577b13aee8fd989a8a..8dc32eacc97c8acbebefeef081ccc5367c545cae 100644 (file)
@@ -28,8 +28,6 @@
 #define PCIBIOS_MIN_IO         0x1000
 #define PCIBIOS_MIN_MEM                0x10000000
 
-struct pci_dev;
-
 /* Values for the `which' argument to sys_pciconfig_iobase syscall.  */
 #define IOBASE_BRIDGE_NUMBER   0
 #define IOBASE_MEMORY          1
index 8b840191df59680b7030f3202d1b83571c7d8f6a..4e1b433f6cb558f178df597c05a115c267ca9329 100644 (file)
@@ -441,7 +441,7 @@ static void *eeh_add_virt_device(void *data, void *userdata)
        }
 
 #ifdef CONFIG_PPC_POWERNV
-       pci_iov_add_virtfn(edev->physfn, pdn->vf_index, 0);
+       pci_iov_add_virtfn(edev->physfn, pdn->vf_index);
 #endif
        return NULL;
 }
@@ -499,7 +499,7 @@ static void *eeh_rmv_device(void *data, void *userdata)
 #ifdef CONFIG_PPC_POWERNV
                struct pci_dn *pdn = eeh_dev_to_pdn(edev);
 
-               pci_iov_remove_virtfn(edev->physfn, pdn->vf_index, 0);
+               pci_iov_remove_virtfn(edev->physfn, pdn->vf_index);
                edev->pdev = NULL;
 
                /*
index 17fa69bc814d7967e33ba119202428142ab50343..6c2d68e08a57880de190c53058d4cabceeeb0ad9 100644 (file)
@@ -63,13 +63,9 @@ extern int pci_is_66mhz_capable(struct pci_channel *hose,
 
 extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;
 
-struct pci_dev;
-
 #define HAVE_PCI_MMAP
 #define ARCH_GENERIC_PCI_MMAP_RESOURCE
 
-extern void pcibios_set_master(struct pci_dev *dev);
-
 /* Dynamic DMA mapping stuff.
  * SuperH has everything mapped statically like x86.
  */
index b7c092df31340cf146c4301e4f8de1aa39d2a764..8b0e26232c78f3f68d8e3518d2af3927afa624d8 100644 (file)
@@ -20,8 +20,6 @@
  */
 #define PCI_DMA_BUS_IS_PHYS    (0)
 
-struct pci_dev;
-
 #endif /* __KERNEL__ */
 
 #ifndef CONFIG_LEON_PCI
index 473a7295ab1028cc82a105476c3fee2597fdaa3e..53873a875c0119dbd7cf002319937897bc4d6b9a 100644 (file)
@@ -88,10 +88,8 @@ extern unsigned long pci_mem_start;
 #define PCIBIOS_MIN_CARDBUS_IO 0x4000
 
 extern int pcibios_enabled;
-void pcibios_config_init(void);
 void pcibios_scan_root(int bus);
 
-void pcibios_set_master(struct pci_dev *dev);
 struct irq_routing_table *pcibios_get_irq_routing_table(void);
 int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
 
index f2228b150faa69caf10bc40574897597e3cd686a..e59378bf37d94936683229cd8cafc846a488c0b9 100644 (file)
@@ -635,3 +635,88 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2030, quirk_no_aersid);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2031, quirk_no_aersid);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2032, quirk_no_aersid);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2033, quirk_no_aersid);
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+
+#define AMD_141b_MMIO_BASE(x)  (0x80 + (x) * 0x8)
+#define AMD_141b_MMIO_BASE_RE_MASK             BIT(0)
+#define AMD_141b_MMIO_BASE_WE_MASK             BIT(1)
+#define AMD_141b_MMIO_BASE_MMIOBASE_MASK       GENMASK(31,8)
+
+#define AMD_141b_MMIO_LIMIT(x) (0x84 + (x) * 0x8)
+#define AMD_141b_MMIO_LIMIT_MMIOLIMIT_MASK     GENMASK(31,8)
+
+#define AMD_141b_MMIO_HIGH(x)  (0x180 + (x) * 0x4)
+#define AMD_141b_MMIO_HIGH_MMIOBASE_MASK       GENMASK(7,0)
+#define AMD_141b_MMIO_HIGH_MMIOLIMIT_SHIFT     16
+#define AMD_141b_MMIO_HIGH_MMIOLIMIT_MASK      GENMASK(23,16)
+
+/*
+ * The PCI Firmware Spec, rev 3.2, notes that ACPI should optionally allow
+ * configuring host bridge windows using the _PRS and _SRS methods.
+ *
+ * But this is rarely implemented, so we manually enable a large 64bit BAR for
+ * PCIe device on AMD Family 15h (Models 00h-1fh, 30h-3fh, 60h-7fh) Processors
+ * here.
+ */
+static void pci_amd_enable_64bit_bar(struct pci_dev *dev)
+{
+       unsigned i;
+       u32 base, limit, high;
+       struct resource *res, *conflict;
+
+       for (i = 0; i < 8; i++) {
+               pci_read_config_dword(dev, AMD_141b_MMIO_BASE(i), &base);
+               pci_read_config_dword(dev, AMD_141b_MMIO_HIGH(i), &high);
+
+               /* Is this slot free? */
+               if (!(base & (AMD_141b_MMIO_BASE_RE_MASK |
+                             AMD_141b_MMIO_BASE_WE_MASK)))
+                       break;
+
+               base >>= 8;
+               base |= high << 24;
+
+               /* Abort if a slot already configures a 64bit BAR. */
+               if (base > 0x10000)
+                       return;
+       }
+       if (i == 8)
+               return;
+
+       res = kzalloc(sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return;
+
+       res->name = "PCI Bus 0000:00";
+       res->flags = IORESOURCE_PREFETCH | IORESOURCE_MEM |
+               IORESOURCE_MEM_64 | IORESOURCE_WINDOW;
+       res->start = 0x100000000ull;
+       res->end = 0xfd00000000ull - 1;
+
+       /* Just grab the free area behind system memory for this */
+       while ((conflict = request_resource_conflict(&iomem_resource, res)))
+               res->start = conflict->end + 1;
+
+       dev_info(&dev->dev, "adding root bus resource %pR\n", res);
+
+       base = ((res->start >> 8) & AMD_141b_MMIO_BASE_MMIOBASE_MASK) |
+               AMD_141b_MMIO_BASE_RE_MASK | AMD_141b_MMIO_BASE_WE_MASK;
+       limit = ((res->end + 1) >> 8) & AMD_141b_MMIO_LIMIT_MMIOLIMIT_MASK;
+       high = ((res->start >> 40) & AMD_141b_MMIO_HIGH_MMIOBASE_MASK) |
+               ((((res->end + 1) >> 40) << AMD_141b_MMIO_HIGH_MMIOLIMIT_SHIFT)
+                & AMD_141b_MMIO_HIGH_MMIOLIMIT_MASK);
+
+       pci_write_config_dword(dev, AMD_141b_MMIO_HIGH(i), high);
+       pci_write_config_dword(dev, AMD_141b_MMIO_LIMIT(i), limit);
+       pci_write_config_dword(dev, AMD_141b_MMIO_BASE(i), base);
+
+       pci_bus_add_resource(dev->bus, res, 0);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1401, pci_amd_enable_64bit_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x141b, pci_amd_enable_64bit_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1571, pci_amd_enable_64bit_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x15b1, pci_amd_enable_64bit_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1601, pci_amd_enable_64bit_bar);
+
+#endif
index b901ece278dddb4f6aaf61c8b6479a26526af71a..63fbe8f5c70ef56260aa55fa2f2268bd3f9d6f41 100644 (file)
@@ -279,7 +279,7 @@ static void intel_mid_pci_irq_disable(struct pci_dev *dev)
        }
 }
 
-static struct pci_ops intel_mid_pci_ops = {
+static const struct pci_ops intel_mid_pci_ops __initconst = {
        .read = pci_read,
        .write = pci_write,
 };
index e4f366a488d3dc2fd7ba292d7ae4e2ccbe1fcae3..5c83798e3b2e2ca8c9173861a660bd6621567dd0 100644 (file)
@@ -37,8 +37,6 @@ extern struct pci_controller* pcibios_alloc_controller(void);
 #include <linux/string.h>
 #include <asm/io.h>
 
-struct pci_dev;
-
 /* The PCI address space does equal the physical memory address space.
  * The networking and block device layers use this boolean for bounce buffer
  * decisions.
index 119f4ef0d42175b01ea8247728e303b8697fc1b7..57e3d900f19e0ef7f6186411656f886b8744c5c6 100644 (file)
@@ -316,6 +316,7 @@ static const struct of_device_id ls_scfg_msi_id[] = {
        { .compatible = "fsl,1s1021a-msi", .data = &ls1021_msi_cfg},
        { .compatible = "fsl,1s1043a-msi", .data = &ls1021_msi_cfg},
 
+       { .compatible = "fsl,ls1012a-msi", .data = &ls1021_msi_cfg },
        { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg },
        { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg },
        { .compatible = "fsl,ls1043a-v1.1-msi", .data = &ls1043_v1_1_msi_cfg },
index deb20302649652d157529b82570dc45d913160c6..320276f4265381a8034e9e69e443213f6618be0c 100644 (file)
@@ -92,6 +92,7 @@ struct pci_endpoint_test {
        void __iomem    *bar[6];
        struct completion irq_raised;
        int             last_irq;
+       int             num_irqs;
        /* mutex to protect the ioctls */
        struct mutex    mutex;
        struct miscdevice miscdev;
@@ -226,6 +227,9 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
        u32 src_crc32;
        u32 dst_crc32;
 
+       if (size > SIZE_MAX - alignment)
+               goto err;
+
        orig_src_addr = dma_alloc_coherent(dev, size + alignment,
                                           &orig_src_phys_addr, GFP_KERNEL);
        if (!orig_src_addr) {
@@ -311,6 +315,9 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
        size_t alignment = test->alignment;
        u32 crc32;
 
+       if (size > SIZE_MAX - alignment)
+               goto err;
+
        orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
                                       GFP_KERNEL);
        if (!orig_addr) {
@@ -369,6 +376,9 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
        size_t alignment = test->alignment;
        u32 crc32;
 
+       if (size > SIZE_MAX - alignment)
+               goto err;
+
        orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
                                       GFP_KERNEL);
        if (!orig_addr) {
@@ -504,6 +514,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
                irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
                if (irq < 0)
                        dev_err(dev, "failed to get MSI interrupts\n");
+               test->num_irqs = irq;
        }
 
        err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
@@ -533,6 +544,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
 
        test->base = test->bar[test_reg_bar];
        if (!test->base) {
+               err = -ENOMEM;
                dev_err(dev, "Cannot perform PCI test without BAR%d\n",
                        test_reg_bar);
                goto err_iounmap;
@@ -542,6 +554,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
 
        id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL);
        if (id < 0) {
+               err = id;
                dev_err(dev, "unable to get id\n");
                goto err_iounmap;
        }
@@ -549,17 +562,24 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
        snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id);
        misc_device = &test->miscdev;
        misc_device->minor = MISC_DYNAMIC_MINOR;
-       misc_device->name = name;
+       misc_device->name = kstrdup(name, GFP_KERNEL);
+       if (!misc_device->name) {
+               err = -ENOMEM;
+               goto err_ida_remove;
+       }
        misc_device->fops = &pci_endpoint_test_fops,
 
        err = misc_register(misc_device);
        if (err) {
                dev_err(dev, "failed to register device\n");
-               goto err_ida_remove;
+               goto err_kfree_name;
        }
 
        return 0;
 
+err_kfree_name:
+       kfree(misc_device->name);
+
 err_ida_remove:
        ida_simple_remove(&pci_endpoint_test_ida, id);
 
@@ -569,6 +589,9 @@ err_iounmap:
                        pci_iounmap(pdev, test->bar[bar]);
        }
 
+       for (i = 0; i < irq; i++)
+               devm_free_irq(dev, pdev->irq + i, test);
+
 err_disable_msi:
        pci_disable_msi(pdev);
        pci_release_regions(pdev);
@@ -582,19 +605,25 @@ err_disable_pdev:
 static void pci_endpoint_test_remove(struct pci_dev *pdev)
 {
        int id;
+       int i;
        enum pci_barno bar;
        struct pci_endpoint_test *test = pci_get_drvdata(pdev);
        struct miscdevice *misc_device = &test->miscdev;
 
        if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1)
                return;
+       if (id < 0)
+               return;
 
        misc_deregister(&test->miscdev);
+       kfree(misc_device->name);
        ida_simple_remove(&pci_endpoint_test_ida, id);
        for (bar = BAR_0; bar <= BAR_5; bar++) {
                if (test->bar[bar])
                        pci_iounmap(pdev, test->bar[bar]);
        }
+       for (i = 0; i < test->num_irqs; i++)
+               devm_free_irq(&pdev->dev, pdev->irq + i, test);
        pci_disable_msi(pdev);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
index 792722e7d45884add844d9931ddef7dc5e816f0f..fa6cabfc3cb92e3e90cbcb08993d453a5516c8fd 100644 (file)
@@ -232,8 +232,8 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
 }
 EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
 
-int of_pci_range_parser_init(struct of_pci_range_parser *parser,
-                               struct device_node *node)
+static int parser_init(struct of_pci_range_parser *parser,
+                       struct device_node *node, const char *name)
 {
        const int na = 3, ns = 2;
        int rlen;
@@ -242,7 +242,7 @@ int of_pci_range_parser_init(struct of_pci_range_parser *parser,
        parser->pna = of_n_addr_cells(node);
        parser->np = parser->pna + na + ns;
 
-       parser->range = of_get_property(node, "ranges", &rlen);
+       parser->range = of_get_property(node, name, &rlen);
        if (parser->range == NULL)
                return -ENOENT;
 
@@ -250,8 +250,21 @@ int of_pci_range_parser_init(struct of_pci_range_parser *parser,
 
        return 0;
 }
+
+int of_pci_range_parser_init(struct of_pci_range_parser *parser,
+                               struct device_node *node)
+{
+       return parser_init(parser, node, "ranges");
+}
 EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
 
+int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
+                               struct device_node *node)
+{
+       return parser_init(parser, node, "dma-ranges");
+}
+EXPORT_SYMBOL_GPL(of_pci_dma_range_parser_init);
+
 struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
                                                struct of_pci_range *range)
 {
index c32a77fc8b03a5ff876768ade086c818dee3a116..90944667cceada37ea3e9176c9ac37f5413bc649 100644 (file)
@@ -29,6 +29,15 @@ config PCI_MSI_IRQ_DOMAIN
        depends on PCI_MSI
        select GENERIC_MSI_IRQ_DOMAIN
 
+config PCI_QUIRKS
+       default y
+       bool "Enable PCI quirk workarounds" if EXPERT
+       depends on PCI
+       help
+         This enables workarounds for various PCI chipset bugs/quirks.
+         Disable this only if your target machine is unaffected by PCI
+         quirks.
+
 config PCI_DEBUG
        bool "PCI Debugging"
        depends on PCI && DEBUG_KERNEL
@@ -42,13 +51,13 @@ config PCI_DEBUG
 config PCI_REALLOC_ENABLE_AUTO
        bool "Enable PCI resource re-allocation detection"
        depends on PCI
+       depends on PCI_IOV
        help
          Say Y here if you want the PCI core to detect if PCI resource
          re-allocation needs to be enabled. You can always use pci=realloc=on
-          or pci=realloc=off to override it.  Note this feature is a no-op
-          unless PCI_IOV support is also enabled; in that case it will
-          automatically re-allocate PCI resources if SR-IOV BARs have not
-          been allocated by the BIOS.
+         or pci=realloc=off to override it.  It will automatically
+         re-allocate PCI resources if SR-IOV BARs have not been allocated by
+         the BIOS.
 
          When in doubt, say N.
 
index 66a21acad95288be33076a9386359546e094dc20..fa56267fa2c0e49e17a435a9a6b628e8590effbd 100644 (file)
@@ -16,9 +16,6 @@ obj-$(CONFIG_PCIEPORTBUS) += pcie/
 
 # Build the PCI Hotplug drivers if we were asked to
 obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
-ifdef CONFIG_HOTPLUG_PCI
-obj-y += hotplug-pci.o
-endif
 
 # Build the PCI MSI interrupt support
 obj-$(CONFIG_PCI_MSI) += msi.o
index 22ec82fcdea24c7a76ceb97bf4f11ebf1408a0a2..113e09440f85c07815654e2eab80f999fc54e6fd 100644 (file)
@@ -169,4 +169,14 @@ config PCIE_KIRIN
          Say Y here if you want PCIe controller support
          on HiSilicon Kirin series SoCs.
 
+config PCIE_HISI_STB
+       bool "HiSilicon STB SoCs PCIe controllers"
+       depends on ARCH_HISI
+       depends on PCI
+       depends on PCI_MSI_IRQ_DOMAIN
+       select PCIEPORTBUS
+       select PCIE_DW_HOST
+       help
+          Say Y here if you want PCIe controller support on HiSilicon STB SoCs
+
 endmenu
index c61be9738ccecedfc99bf708fad9a62265e3c93b..54f56f6e9236c22d79c8b14da42b4f79103bf849 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
 obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
 obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
+obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
 
 # The following drivers are for devices that use the generic ACPI
 # pci_root.c driver but don't support standard ECAM config access.
index 34427a6a15afab94f2cd852ba8ea35babe22bc99..d0848006945a343f32a45fd10d650958a115acde 100644 (file)
@@ -794,6 +794,22 @@ static int dra7xx_pcie_resume_noirq(struct device *dev)
 }
 #endif
 
+void dra7xx_pcie_shutdown(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
+       int ret;
+
+       dra7xx_pcie_stop_link(dra7xx->pci);
+
+       ret = pm_runtime_put_sync(dev);
+       if (ret < 0)
+               dev_dbg(dev, "pm_runtime_put_sync failed\n");
+
+       pm_runtime_disable(dev);
+       dra7xx_pcie_disable_phy(dra7xx);
+}
+
 static const struct dev_pm_ops dra7xx_pcie_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(dra7xx_pcie_suspend, dra7xx_pcie_resume)
        SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dra7xx_pcie_suspend_noirq,
@@ -807,5 +823,6 @@ static struct platform_driver dra7xx_pcie_driver = {
                .suppress_bind_attrs = true,
                .pm     = &dra7xx_pcie_pm_ops,
        },
+       .shutdown = dra7xx_pcie_shutdown,
 };
 builtin_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe);
index 87fa486bee2cd4f56322115db2efcc1f4bb49e69..8f34c2fdc600692e8ac1b86578cace2a6082fcf2 100644 (file)
@@ -33,6 +33,8 @@
 
 /* PEX Internal Configuration Registers */
 #define PCIE_STRFMR1           0x71c /* Symbol Timer & Filter Mask Register1 */
+#define PCIE_ABSERR            0x8d0 /* Bridge Slave Error Response Register */
+#define PCIE_ABSERR_SETTING    0x9401 /* Forward error of non-posted request */
 
 #define PCIE_IATU_NUM          6
 
@@ -124,6 +126,14 @@ static int ls_pcie_link_up(struct dw_pcie *pci)
        return 1;
 }
 
+/* Forward error response of outbound non-posted requests */
+static void ls_pcie_fix_error_response(struct ls_pcie *pcie)
+{
+       struct dw_pcie *pci = pcie->pci;
+
+       iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR);
+}
+
 static int ls_pcie_host_init(struct pcie_port *pp)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -135,6 +145,7 @@ static int ls_pcie_host_init(struct pcie_port *pp)
         * dw_pcie_setup_rc() will reconfigure the outbound windows.
         */
        ls_pcie_disable_outbound_atus(pcie);
+       ls_pcie_fix_error_response(pcie);
 
        dw_pcie_dbi_ro_wr_en(pci);
        ls_pcie_clear_multifunction(pcie);
@@ -253,6 +264,7 @@ static struct ls_pcie_drvdata ls2088_drvdata = {
 };
 
 static const struct of_device_id ls_pcie_of_match[] = {
+       { .compatible = "fsl,ls1012a-pcie", .data = &ls1046_drvdata },
        { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
        { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
        { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata },
diff --git a/drivers/pci/dwc/pcie-histb.c b/drivers/pci/dwc/pcie-histb.c
new file mode 100644 (file)
index 0000000..33b01b7
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * PCIe host controller driver for HiSilicon STB SoCs
+ *
+ * Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com
+ *
+ * Authors: Ruqiang Ju <juruqiang@hisilicon.com>
+ *          Jianguo Sun <sunjianguo1@huawei.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/reset.h>
+
+#include "pcie-designware.h"
+
+#define to_histb_pcie(x)       dev_get_drvdata((x)->dev)
+
+#define PCIE_SYS_CTRL0                 0x0000
+#define PCIE_SYS_CTRL1                 0x0004
+#define PCIE_SYS_CTRL7                 0x001C
+#define PCIE_SYS_CTRL13                        0x0034
+#define PCIE_SYS_CTRL15                        0x003C
+#define PCIE_SYS_CTRL16                        0x0040
+#define PCIE_SYS_CTRL17                        0x0044
+
+#define PCIE_SYS_STAT0                 0x0100
+#define PCIE_SYS_STAT4                 0x0110
+
+#define PCIE_RDLH_LINK_UP              BIT(5)
+#define PCIE_XMLH_LINK_UP              BIT(15)
+#define PCIE_ELBI_SLV_DBI_ENABLE       BIT(21)
+#define PCIE_APP_LTSSM_ENABLE          BIT(11)
+
+#define PCIE_DEVICE_TYPE_MASK          GENMASK(31, 28)
+#define PCIE_WM_EP                     0
+#define PCIE_WM_LEGACY                 BIT(1)
+#define PCIE_WM_RC                     BIT(30)
+
+#define PCIE_LTSSM_STATE_MASK          GENMASK(5, 0)
+#define PCIE_LTSSM_STATE_ACTIVE                0x11
+
+struct histb_pcie {
+       struct dw_pcie *pci;
+       struct clk *aux_clk;
+       struct clk *pipe_clk;
+       struct clk *sys_clk;
+       struct clk *bus_clk;
+       struct phy *phy;
+       struct reset_control *soft_reset;
+       struct reset_control *sys_reset;
+       struct reset_control *bus_reset;
+       void __iomem *ctrl;
+       int reset_gpio;
+};
+
+static u32 histb_pcie_readl(struct histb_pcie *histb_pcie, u32 reg)
+{
+       return readl(histb_pcie->ctrl + reg);
+}
+
+static void histb_pcie_writel(struct histb_pcie *histb_pcie, u32 reg, u32 val)
+{
+       writel(val, histb_pcie->ctrl + reg);
+}
+
+static void histb_pcie_dbi_w_mode(struct pcie_port *pp, bool enable)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct histb_pcie *hipcie = to_histb_pcie(pci);
+       u32 val;
+
+       val = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
+       if (enable)
+               val |= PCIE_ELBI_SLV_DBI_ENABLE;
+       else
+               val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
+       histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, val);
+}
+
+static void histb_pcie_dbi_r_mode(struct pcie_port *pp, bool enable)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct histb_pcie *hipcie = to_histb_pcie(pci);
+       u32 val;
+
+       val = histb_pcie_readl(hipcie, PCIE_SYS_CTRL1);
+       if (enable)
+               val |= PCIE_ELBI_SLV_DBI_ENABLE;
+       else
+               val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
+       histb_pcie_writel(hipcie, PCIE_SYS_CTRL1, val);
+}
+
+static u32 histb_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
+                              u32 reg, size_t size)
+{
+       u32 val;
+
+       histb_pcie_dbi_r_mode(&pci->pp, true);
+       dw_pcie_read(base + reg, size, &val);
+       histb_pcie_dbi_r_mode(&pci->pp, false);
+
+       return val;
+}
+
+static void histb_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
+                                u32 reg, size_t size, u32 val)
+{
+       histb_pcie_dbi_w_mode(&pci->pp, true);
+       dw_pcie_write(base + reg, size, val);
+       histb_pcie_dbi_w_mode(&pci->pp, false);
+}
+
+static int histb_pcie_rd_own_conf(struct pcie_port *pp, int where,
+                                 int size, u32 *val)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       int ret;
+
+       histb_pcie_dbi_r_mode(pp, true);
+       ret = dw_pcie_read(pci->dbi_base + where, size, val);
+       histb_pcie_dbi_r_mode(pp, false);
+
+       return ret;
+}
+
+static int histb_pcie_wr_own_conf(struct pcie_port *pp, int where,
+                                 int size, u32 val)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       int ret;
+
+       histb_pcie_dbi_w_mode(pp, true);
+       ret = dw_pcie_write(pci->dbi_base + where, size, val);
+       histb_pcie_dbi_w_mode(pp, false);
+
+       return ret;
+}
+
+static int histb_pcie_link_up(struct dw_pcie *pci)
+{
+       struct histb_pcie *hipcie = to_histb_pcie(pci);
+       u32 regval;
+       u32 status;
+
+       regval = histb_pcie_readl(hipcie, PCIE_SYS_STAT0);
+       status = histb_pcie_readl(hipcie, PCIE_SYS_STAT4);
+       status &= PCIE_LTSSM_STATE_MASK;
+       if ((regval & PCIE_XMLH_LINK_UP) && (regval & PCIE_RDLH_LINK_UP) &&
+           (status == PCIE_LTSSM_STATE_ACTIVE))
+               return 1;
+
+       return 0;
+}
+
+static int histb_pcie_establish_link(struct pcie_port *pp)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct histb_pcie *hipcie = to_histb_pcie(pci);
+       u32 regval;
+
+       if (dw_pcie_link_up(pci)) {
+               dev_info(pci->dev, "Link already up\n");
+               return 0;
+       }
+
+       /* PCIe RC work mode */
+       regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
+       regval &= ~PCIE_DEVICE_TYPE_MASK;
+       regval |= PCIE_WM_RC;
+       histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
+
+       /* setup root complex */
+       dw_pcie_setup_rc(pp);
+
+       /* assert LTSSM enable */
+       regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL7);
+       regval |= PCIE_APP_LTSSM_ENABLE;
+       histb_pcie_writel(hipcie, PCIE_SYS_CTRL7, regval);
+
+       return dw_pcie_wait_for_link(pci);
+}
+
+static int histb_pcie_host_init(struct pcie_port *pp)
+{
+       histb_pcie_establish_link(pp);
+
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               dw_pcie_msi_init(pp);
+
+       return 0;
+}
+
+static struct dw_pcie_host_ops histb_pcie_host_ops = {
+       .rd_own_conf = histb_pcie_rd_own_conf,
+       .wr_own_conf = histb_pcie_wr_own_conf,
+       .host_init = histb_pcie_host_init,
+};
+
+static irqreturn_t histb_pcie_msi_irq_handler(int irq, void *arg)
+{
+       struct pcie_port *pp = arg;
+
+       return dw_handle_msi_irq(pp);
+}
+
+static void histb_pcie_host_disable(struct histb_pcie *hipcie)
+{
+       reset_control_assert(hipcie->soft_reset);
+       reset_control_assert(hipcie->sys_reset);
+       reset_control_assert(hipcie->bus_reset);
+
+       clk_disable_unprepare(hipcie->aux_clk);
+       clk_disable_unprepare(hipcie->pipe_clk);
+       clk_disable_unprepare(hipcie->sys_clk);
+       clk_disable_unprepare(hipcie->bus_clk);
+
+       if (gpio_is_valid(hipcie->reset_gpio))
+               gpio_set_value_cansleep(hipcie->reset_gpio, 0);
+}
+
+static int histb_pcie_host_enable(struct pcie_port *pp)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct histb_pcie *hipcie = to_histb_pcie(pci);
+       struct device *dev = pci->dev;
+       int ret;
+
+       /* power on PCIe device if have */
+       if (gpio_is_valid(hipcie->reset_gpio))
+               gpio_set_value_cansleep(hipcie->reset_gpio, 1);
+
+       ret = clk_prepare_enable(hipcie->bus_clk);
+       if (ret) {
+               dev_err(dev, "cannot prepare/enable bus clk\n");
+               goto err_bus_clk;
+       }
+
+       ret = clk_prepare_enable(hipcie->sys_clk);
+       if (ret) {
+               dev_err(dev, "cannot prepare/enable sys clk\n");
+               goto err_sys_clk;
+       }
+
+       ret = clk_prepare_enable(hipcie->pipe_clk);
+       if (ret) {
+               dev_err(dev, "cannot prepare/enable pipe clk\n");
+               goto err_pipe_clk;
+       }
+
+       ret = clk_prepare_enable(hipcie->aux_clk);
+       if (ret) {
+               dev_err(dev, "cannot prepare/enable aux clk\n");
+               goto err_aux_clk;
+       }
+
+       reset_control_assert(hipcie->soft_reset);
+       reset_control_deassert(hipcie->soft_reset);
+
+       reset_control_assert(hipcie->sys_reset);
+       reset_control_deassert(hipcie->sys_reset);
+
+       reset_control_assert(hipcie->bus_reset);
+       reset_control_deassert(hipcie->bus_reset);
+
+       return 0;
+
+err_aux_clk:
+       clk_disable_unprepare(hipcie->aux_clk);
+err_pipe_clk:
+       clk_disable_unprepare(hipcie->pipe_clk);
+err_sys_clk:
+       clk_disable_unprepare(hipcie->sys_clk);
+err_bus_clk:
+       clk_disable_unprepare(hipcie->bus_clk);
+
+       return ret;
+}
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+       .read_dbi = histb_pcie_read_dbi,
+       .write_dbi = histb_pcie_write_dbi,
+       .link_up = histb_pcie_link_up,
+};
+
+static int histb_pcie_probe(struct platform_device *pdev)
+{
+       struct histb_pcie *hipcie;
+       struct dw_pcie *pci;
+       struct pcie_port *pp;
+       struct resource *res;
+       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       enum of_gpio_flags of_flags;
+       unsigned long flag = GPIOF_DIR_OUT;
+       int ret;
+
+       hipcie = devm_kzalloc(dev, sizeof(*hipcie), GFP_KERNEL);
+       if (!hipcie)
+               return -ENOMEM;
+
+       pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+       if (!pci)
+               return -ENOMEM;
+
+       hipcie->pci = pci;
+       pp = &pci->pp;
+       pci->dev = dev;
+       pci->ops = &dw_pcie_ops;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
+       hipcie->ctrl = devm_ioremap_resource(dev, res);
+       if (IS_ERR(hipcie->ctrl)) {
+               dev_err(dev, "cannot get control reg base\n");
+               return PTR_ERR(hipcie->ctrl);
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc-dbi");
+       pci->dbi_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(pci->dbi_base)) {
+               dev_err(dev, "cannot get rc-dbi base\n");
+               return PTR_ERR(pci->dbi_base);
+       }
+
+       hipcie->reset_gpio = of_get_named_gpio_flags(np,
+                               "reset-gpios", 0, &of_flags);
+       if (of_flags & OF_GPIO_ACTIVE_LOW)
+               flag |= GPIOF_ACTIVE_LOW;
+       if (gpio_is_valid(hipcie->reset_gpio)) {
+               ret = devm_gpio_request_one(dev, hipcie->reset_gpio,
+                               flag, "PCIe device power control");
+               if (ret) {
+                       dev_err(dev, "unable to request gpio\n");
+                       return ret;
+               }
+       }
+
+       hipcie->aux_clk = devm_clk_get(dev, "aux");
+       if (IS_ERR(hipcie->aux_clk)) {
+               dev_err(dev, "Failed to get PCIe aux clk\n");
+               return PTR_ERR(hipcie->aux_clk);
+       }
+
+       hipcie->pipe_clk = devm_clk_get(dev, "pipe");
+       if (IS_ERR(hipcie->pipe_clk)) {
+               dev_err(dev, "Failed to get PCIe pipe clk\n");
+               return PTR_ERR(hipcie->pipe_clk);
+       }
+
+       hipcie->sys_clk = devm_clk_get(dev, "sys");
+       if (IS_ERR(hipcie->sys_clk)) {
+               dev_err(dev, "Failed to get PCIEe sys clk\n");
+               return PTR_ERR(hipcie->sys_clk);
+       }
+
+       hipcie->bus_clk = devm_clk_get(dev, "bus");
+       if (IS_ERR(hipcie->bus_clk)) {
+               dev_err(dev, "Failed to get PCIe bus clk\n");
+               return PTR_ERR(hipcie->bus_clk);
+       }
+
+       hipcie->soft_reset = devm_reset_control_get(dev, "soft");
+       if (IS_ERR(hipcie->soft_reset)) {
+               dev_err(dev, "couldn't get soft reset\n");
+               return PTR_ERR(hipcie->soft_reset);
+       }
+
+       hipcie->sys_reset = devm_reset_control_get(dev, "sys");
+       if (IS_ERR(hipcie->sys_reset)) {
+               dev_err(dev, "couldn't get sys reset\n");
+               return PTR_ERR(hipcie->sys_reset);
+       }
+
+       hipcie->bus_reset = devm_reset_control_get(dev, "bus");
+       if (IS_ERR(hipcie->bus_reset)) {
+               dev_err(dev, "couldn't get bus reset\n");
+               return PTR_ERR(hipcie->bus_reset);
+       }
+
+       if (IS_ENABLED(CONFIG_PCI_MSI)) {
+               pp->msi_irq = platform_get_irq_byname(pdev, "msi");
+               if (pp->msi_irq < 0) {
+                       dev_err(dev, "Failed to get MSI IRQ\n");
+                       return pp->msi_irq;
+               }
+
+               ret = devm_request_irq(dev, pp->msi_irq,
+                                      histb_pcie_msi_irq_handler,
+                                      IRQF_SHARED, "histb-pcie-msi", pp);
+               if (ret) {
+                       dev_err(dev, "cannot request MSI IRQ\n");
+                       return ret;
+               }
+       }
+
+       hipcie->phy = devm_phy_get(dev, "phy");
+       if (IS_ERR(hipcie->phy)) {
+               dev_info(dev, "no pcie-phy found\n");
+               hipcie->phy = NULL;
+               /* fall through here!
+                * if no pcie-phy found, phy init
+                * should be done under boot!
+                */
+       } else {
+               phy_init(hipcie->phy);
+       }
+
+       pp->root_bus_nr = -1;
+       pp->ops = &histb_pcie_host_ops;
+
+       platform_set_drvdata(pdev, hipcie);
+
+       ret = histb_pcie_host_enable(pp);
+       if (ret) {
+               dev_err(dev, "failed to enable host\n");
+               return ret;
+       }
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(dev, "failed to initialize host\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int histb_pcie_remove(struct platform_device *pdev)
+{
+       struct histb_pcie *hipcie = platform_get_drvdata(pdev);
+
+       histb_pcie_host_disable(hipcie);
+
+       if (hipcie->phy)
+               phy_exit(hipcie->phy);
+
+       return 0;
+}
+
+static const struct of_device_id histb_pcie_of_match[] = {
+       { .compatible = "hisilicon,hi3798cv200-pcie", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, histb_pcie_of_match);
+
+static struct platform_driver histb_pcie_platform_driver = {
+       .probe  = histb_pcie_probe,
+       .remove = histb_pcie_remove,
+       .driver = {
+               .name = "histb-pcie",
+               .of_match_table = histb_pcie_of_match,
+       },
+};
+module_platform_driver(histb_pcie_platform_driver);
+
+MODULE_DESCRIPTION("HiSilicon STB PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
index b868803792d8c0e73938f19707b7a0d2402f224a..38d12980db0f0f3358030e419ed86400b7b275c3 100644 (file)
@@ -95,6 +95,12 @@ config PCI_XGENE_MSI
          Say Y here if you want PCIe MSI support for the APM X-Gene v1 SoC.
          This MSI driver supports 5 PCIe ports on the APM X-Gene v1 SoC.
 
+config PCI_V3_SEMI
+       bool "V3 Semiconductor PCI controller"
+       depends on OF
+       depends on ARM
+       default ARCH_INTEGRATOR_AP
+
 config PCI_VERSATILE
        bool "ARM Versatile PB PCI controller"
        depends on ARCH_VERSATILE
index 12382785e02a652637b64599e1b51c6a7b78206d..ee7cd492bb7f65e5bd945ec8262e8ee753da1e3d 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
 obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
 obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o
+obj-$(CONFIG_PCI_V3_SEMI) += pci-v3-semi.o
 obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
 obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
 obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
index 96028f01bc90142e50ef3b8ce5d85e6775f1e619..fae6bd19077046f37cbb2a84cba1440148f0fb69 100644 (file)
@@ -370,24 +370,6 @@ static int faraday_pci_setup_cascaded_irq(struct faraday_pci *p)
        return 0;
 }
 
-static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-                                    struct device_node *node)
-{
-       const int na = 3, ns = 2;
-       int rlen;
-
-       parser->node = node;
-       parser->pna = of_n_addr_cells(node);
-       parser->np = parser->pna + na + ns;
-
-       parser->range = of_get_property(node, "dma-ranges", &rlen);
-       if (!parser->range)
-               return -ENOENT;
-       parser->end = parser->range + rlen / sizeof(__be32);
-
-       return 0;
-}
-
 static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p,
                                            struct device_node *np)
 {
@@ -402,7 +384,7 @@ static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p,
        int i = 0;
        u32 val;
 
-       if (pci_dma_range_parser_init(&parser, np)) {
+       if (of_pci_dma_range_parser_init(&parser, np)) {
                dev_err(dev, "missing dma-ranges property\n");
                return -EINVAL;
        }
@@ -481,7 +463,7 @@ static int faraday_pci_probe(struct platform_device *pdev)
        }
        p->bus_clk = devm_clk_get(dev, "PCICLK");
        if (IS_ERR(p->bus_clk))
-               return PTR_ERR(clk);
+               return PTR_ERR(p->bus_clk);
        ret = clk_prepare_enable(p->bus_clk);
        if (ret) {
                dev_err(dev, "could not prepare PCICLK\n");
index 7d709a7e0aa8a7cf2e0bc55de059f1731d8adb27..2f05511ce718c147736927a0c3f76dae8c999140 100644 (file)
@@ -35,6 +35,40 @@ static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
        }
 };
 
+static bool pci_dw_valid_device(struct pci_bus *bus, unsigned int devfn)
+{
+       struct pci_config_window *cfg = bus->sysdata;
+
+       /*
+        * The Synopsys DesignWare PCIe controller in ECAM mode will not filter
+        * type 0 config TLPs sent to devices 1 and up on its downstream port,
+        * resulting in devices appearing multiple times on bus 0 unless we
+        * filter out those accesses here.
+        */
+       if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0)
+               return false;
+
+       return true;
+}
+
+static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus,
+                                        unsigned int devfn, int where)
+{
+       if (!pci_dw_valid_device(bus, devfn))
+               return NULL;
+
+       return pci_ecam_map_bus(bus, devfn, where);
+}
+
+static struct pci_ecam_ops pci_dw_ecam_bus_ops = {
+       .bus_shift      = 20,
+       .pci_ops        = {
+               .map_bus        = pci_dw_ecam_map_bus,
+               .read           = pci_generic_config_read,
+               .write          = pci_generic_config_write,
+       }
+};
+
 static const struct of_device_id gen_pci_of_match[] = {
        { .compatible = "pci-host-cam-generic",
          .data = &gen_pci_cfg_cam_bus_ops },
@@ -42,6 +76,15 @@ static const struct of_device_id gen_pci_of_match[] = {
        { .compatible = "pci-host-ecam-generic",
          .data = &pci_generic_ecam_ops },
 
+       { .compatible = "marvell,armada8k-pcie-ecam",
+         .data = &pci_dw_ecam_bus_ops },
+
+       { .compatible = "socionext,synquacer-pcie-ecam",
+         .data = &pci_dw_ecam_bus_ops },
+
+       { .compatible = "snps,dw-pcie-ecam",
+         .data = &pci_dw_ecam_bus_ops },
+
        { },
 };
 
index 0fe3ea164ee53321b2a23aded63eeac6c68684fa..04dac6a42c9f287519379757a0cefd3c08e14e11 100644 (file)
@@ -879,7 +879,7 @@ static void hv_irq_unmask(struct irq_data *data)
        int cpu;
        u64 res;
 
-       dest = irq_data_get_affinity_mask(data);
+       dest = irq_data_get_effective_affinity_mask(data);
        pdev = msi_desc_to_pci_dev(msi_desc);
        pbus = pdev->bus;
        hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
@@ -1042,6 +1042,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
        struct hv_pci_dev *hpdev;
        struct pci_bus *pbus;
        struct pci_dev *pdev;
+       struct cpumask *dest;
        struct compose_comp_ctxt comp;
        struct tran_int_desc *int_desc;
        struct {
@@ -1056,6 +1057,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
        int ret;
 
        pdev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data));
+       dest = irq_data_get_effective_affinity_mask(data);
        pbus = pdev->bus;
        hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
        hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
@@ -1081,14 +1083,14 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
        switch (pci_protocol_version) {
        case PCI_PROTOCOL_VERSION_1_1:
                size = hv_compose_msi_req_v1(&ctxt.int_pkts.v1,
-                                       irq_data_get_affinity_mask(data),
+                                       dest,
                                        hpdev->desc.win_slot.slot,
                                        cfg->vector);
                break;
 
        case PCI_PROTOCOL_VERSION_1_2:
                size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2,
-                                       irq_data_get_affinity_mask(data),
+                                       dest,
                                        hpdev->desc.win_slot.slot,
                                        cfg->vector);
                break;
index 6f879685fedd5dbec5aa5451bace961ec80fbeec..e46de69f03802b96b14502b204e5646c6963c365 100644 (file)
@@ -293,24 +293,6 @@ static struct pci_ops rcar_pci_ops = {
        .write  = pci_generic_config_write,
 };
 
-static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-                                    struct device_node *node)
-{
-       const int na = 3, ns = 2;
-       int rlen;
-
-       parser->node = node;
-       parser->pna = of_n_addr_cells(node);
-       parser->np = parser->pna + na + ns;
-
-       parser->range = of_get_property(node, "dma-ranges", &rlen);
-       if (!parser->range)
-               return -ENOENT;
-
-       parser->end = parser->range + rlen / sizeof(__be32);
-       return 0;
-}
-
 static int rcar_pci_parse_map_dma_ranges(struct rcar_pci_priv *pci,
                                         struct device_node *np)
 {
@@ -320,7 +302,7 @@ static int rcar_pci_parse_map_dma_ranges(struct rcar_pci_priv *pci,
        int index = 0;
 
        /* Failure to parse is ok as we fall back to defaults */
-       if (pci_dma_range_parser_init(&parser, np))
+       if (of_pci_dma_range_parser_init(&parser, np))
                return 0;
 
        /* Get the dma-ranges from DT */
index 9c40da54f88a10aab4dde9ba705b187912101909..8dd3b3f7d1417f533b24801617cfb61551966638 100644 (file)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE    (0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420       (0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1     (0x0 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401       (0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL      (0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222       (0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1     (0x1 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211       (0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411       (0x2 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111       (0x2 << 20)
 
 #define AFI_FUSE                       0x104
 #define  AFI_FUSE_PCIE_T0_GEN2_DIS     (1 << 2)
@@ -252,6 +255,7 @@ struct tegra_pcie_soc {
        bool has_cml_clk;
        bool has_gen2;
        bool force_pca_enable;
+       bool program_uphy;
 };
 
 static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip)
@@ -491,12 +495,32 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
        return addr;
 }
 
+static int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 *value)
+{
+       if (bus->number == 0)
+               return pci_generic_config_read32(bus, devfn, where, size,
+                                                value);
+
+       return pci_generic_config_read(bus, devfn, where, size, value);
+}
+
+static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+                                  int where, int size, u32 value)
+{
+       if (bus->number == 0)
+               return pci_generic_config_write32(bus, devfn, where, size,
+                                                 value);
+
+       return pci_generic_config_write(bus, devfn, where, size, value);
+}
+
 static struct pci_ops tegra_pcie_ops = {
        .add_bus = tegra_pcie_add_bus,
        .remove_bus = tegra_pcie_remove_bus,
        .map_bus = tegra_pcie_map_bus,
-       .read = pci_generic_config_read32,
-       .write = pci_generic_config_write32,
+       .read = tegra_pcie_config_read,
+       .write = tegra_pcie_config_write,
 };
 
 static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
@@ -1012,10 +1036,12 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
                afi_writel(pcie, value, AFI_FUSE);
        }
 
-       err = tegra_pcie_phy_power_on(pcie);
-       if (err < 0) {
-               dev_err(dev, "failed to power on PHY(s): %d\n", err);
-               return err;
+       if (soc->program_uphy) {
+               err = tegra_pcie_phy_power_on(pcie);
+               if (err < 0) {
+                       dev_err(dev, "failed to power on PHY(s): %d\n", err);
+                       return err;
+               }
        }
 
        /* take the PCIe interface module out of reset */
@@ -1048,19 +1074,23 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 static void tegra_pcie_power_off(struct tegra_pcie *pcie)
 {
        struct device *dev = pcie->dev;
+       const struct tegra_pcie_soc *soc = pcie->soc;
        int err;
 
        /* TODO: disable and unprepare clocks? */
 
-       err = tegra_pcie_phy_power_off(pcie);
-       if (err < 0)
-               dev_err(dev, "failed to power off PHY(s): %d\n", err);
+       if (soc->program_uphy) {
+               err = tegra_pcie_phy_power_off(pcie);
+               if (err < 0)
+                       dev_err(dev, "failed to power off PHY(s): %d\n", err);
+       }
 
        reset_control_assert(pcie->pcie_xrst);
        reset_control_assert(pcie->afi_rst);
        reset_control_assert(pcie->pex_rst);
 
-       tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+       if (!dev->pm_domain)
+               tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
 
        err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
        if (err < 0)
@@ -1077,19 +1107,29 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
        reset_control_assert(pcie->afi_rst);
        reset_control_assert(pcie->pex_rst);
 
-       tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+       if (!dev->pm_domain)
+               tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
 
        /* enable regulators */
        err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
        if (err < 0)
                dev_err(dev, "failed to enable regulators: %d\n", err);
 
-       err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
-                                               pcie->pex_clk,
-                                               pcie->pex_rst);
-       if (err) {
-               dev_err(dev, "powerup sequence failed: %d\n", err);
-               return err;
+       if (dev->pm_domain) {
+               err = clk_prepare_enable(pcie->pex_clk);
+               if (err) {
+                       dev_err(dev, "failed to enable PEX clock: %d\n", err);
+                       return err;
+               }
+               reset_control_deassert(pcie->pex_rst);
+       } else {
+               err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
+                                                       pcie->pex_clk,
+                                                       pcie->pex_rst);
+               if (err) {
+                       dev_err(dev, "powerup sequence failed: %d\n", err);
+                       return err;
+               }
        }
 
        reset_control_deassert(pcie->afi_rst);
@@ -1262,6 +1302,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
        struct device *dev = pcie->dev;
        struct platform_device *pdev = to_platform_device(dev);
        struct resource *pads, *afi, *res;
+       const struct tegra_pcie_soc *soc = pcie->soc;
        int err;
 
        err = tegra_pcie_clocks_get(pcie);
@@ -1276,10 +1317,12 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
                return err;
        }
 
-       err = tegra_pcie_phys_get(pcie);
-       if (err < 0) {
-               dev_err(dev, "failed to get PHYs: %d\n", err);
-               return err;
+       if (soc->program_uphy) {
+               err = tegra_pcie_phys_get(pcie);
+               if (err < 0) {
+                       dev_err(dev, "failed to get PHYs: %d\n", err);
+                       return err;
+               }
        }
 
        err = tegra_pcie_power_on(pcie);
@@ -1341,6 +1384,7 @@ poweroff:
 static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
 {
        struct device *dev = pcie->dev;
+       const struct tegra_pcie_soc *soc = pcie->soc;
        int err;
 
        if (pcie->irq > 0)
@@ -1348,9 +1392,11 @@ static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
 
        tegra_pcie_power_off(pcie);
 
-       err = phy_exit(pcie->phy);
-       if (err < 0)
-               dev_err(dev, "failed to teardown PHY: %d\n", err);
+       if (soc->program_uphy) {
+               err = phy_exit(pcie->phy);
+               if (err < 0)
+                       dev_err(dev, "failed to teardown PHY: %d\n", err);
+       }
 
        return 0;
 }
@@ -1616,8 +1662,32 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
        struct device *dev = pcie->dev;
        struct device_node *np = dev->of_node;
 
-       if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
-           of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
+       if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
+               switch (lanes) {
+               case 0x010004:
+                       dev_info(dev, "4x1, 1x1 configuration\n");
+                       *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401;
+                       return 0;
+
+               case 0x010102:
+                       dev_info(dev, "2x1, 1X1, 1x1 configuration\n");
+                       *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
+                       return 0;
+
+               case 0x010101:
+                       dev_info(dev, "1x1, 1x1, 1x1 configuration\n");
+                       *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111;
+                       return 0;
+
+               default:
+                       dev_info(dev, "wrong configuration updated in DT, "
+                                "switching to default 2x1, 1x1, 1x1 "
+                                "configuration\n");
+                       *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
+                       return 0;
+               }
+       } else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
+                  of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
                switch (lanes) {
                case 0x0000104:
                        dev_info(dev, "4x1, 1x1 configuration\n");
@@ -1737,7 +1807,20 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
        struct device_node *np = dev->of_node;
        unsigned int i = 0;
 
-       if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
+       if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
+               pcie->num_supplies = 4;
+
+               pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
+                                             sizeof(*pcie->supplies),
+                                             GFP_KERNEL);
+               if (!pcie->supplies)
+                       return -ENOMEM;
+
+               pcie->supplies[i++].supply = "dvdd-pex";
+               pcie->supplies[i++].supply = "hvdd-pex-pll";
+               pcie->supplies[i++].supply = "hvdd-pex";
+               pcie->supplies[i++].supply = "vddio-pexctl-aud";
+       } else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
                pcie->num_supplies = 6;
 
                pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
@@ -2076,6 +2159,7 @@ static const struct tegra_pcie_soc tegra20_pcie = {
        .has_cml_clk = false,
        .has_gen2 = false,
        .force_pca_enable = false,
+       .program_uphy = true,
 };
 
 static const struct tegra_pcie_soc tegra30_pcie = {
@@ -2091,6 +2175,7 @@ static const struct tegra_pcie_soc tegra30_pcie = {
        .has_cml_clk = true,
        .has_gen2 = false,
        .force_pca_enable = false,
+       .program_uphy = true,
 };
 
 static const struct tegra_pcie_soc tegra124_pcie = {
@@ -2105,6 +2190,7 @@ static const struct tegra_pcie_soc tegra124_pcie = {
        .has_cml_clk = true,
        .has_gen2 = true,
        .force_pca_enable = false,
+       .program_uphy = true,
 };
 
 static const struct tegra_pcie_soc tegra210_pcie = {
@@ -2119,9 +2205,27 @@ static const struct tegra_pcie_soc tegra210_pcie = {
        .has_cml_clk = true,
        .has_gen2 = true,
        .force_pca_enable = true,
+       .program_uphy = true,
+};
+
+static const struct tegra_pcie_soc tegra186_pcie = {
+       .num_ports = 3,
+       .msi_base_shift = 8,
+       .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+       .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+       .pads_refclk_cfg0 = 0x80b880b8,
+       .pads_refclk_cfg1 = 0x000480b8,
+       .has_pex_clkreq_en = true,
+       .has_pex_bias_ctrl = true,
+       .has_intr_prsnt_sense = true,
+       .has_cml_clk = false,
+       .has_gen2 = true,
+       .force_pca_enable = false,
+       .program_uphy = false,
 };
 
 static const struct of_device_id tegra_pcie_of_match[] = {
+       { .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie },
        { .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie },
        { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie },
        { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie },
diff --git a/drivers/pci/host/pci-v3-semi.c b/drivers/pci/host/pci-v3-semi.c
new file mode 100644 (file)
index 0000000..02f6e1e
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * Support for V3 Semiconductor PCI Local Bus to PCI Bridge
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Based on the code from arch/arm/mach-integrator/pci_v3.c
+ * Copyright (C) 1999 ARM Limited
+ * Copyright (C) 2000-2001 Deep Blue Solutions Ltd
+ *
+ * Contributors to the old driver include:
+ * Russell King <linux@armlinux.org.uk>
+ * David A. Rusling <david.rusling@linaro.org> (uHAL, ARM Firmware suite)
+ * Rob Herring <robh@kernel.org>
+ * Liviu Dudau <Liviu.Dudau@arm.com>
+ * Grant Likely <grant.likely@secretlab.ca>
+ * Arnd Bergmann <arnd@arndb.de>
+ * Bjorn Helgaas <bhelgaas@google.com>
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+
+#define V3_PCI_VENDOR                  0x00000000
+#define V3_PCI_DEVICE                  0x00000002
+#define V3_PCI_CMD                     0x00000004
+#define V3_PCI_STAT                    0x00000006
+#define V3_PCI_CC_REV                  0x00000008
+#define V3_PCI_HDR_CFG                 0x0000000C
+#define V3_PCI_IO_BASE                 0x00000010
+#define V3_PCI_BASE0                   0x00000014
+#define V3_PCI_BASE1                   0x00000018
+#define V3_PCI_SUB_VENDOR              0x0000002C
+#define V3_PCI_SUB_ID                  0x0000002E
+#define V3_PCI_ROM                     0x00000030
+#define V3_PCI_BPARAM                  0x0000003C
+#define V3_PCI_MAP0                    0x00000040
+#define V3_PCI_MAP1                    0x00000044
+#define V3_PCI_INT_STAT                        0x00000048
+#define V3_PCI_INT_CFG                 0x0000004C
+#define V3_LB_BASE0                    0x00000054
+#define V3_LB_BASE1                    0x00000058
+#define V3_LB_MAP0                     0x0000005E
+#define V3_LB_MAP1                     0x00000062
+#define V3_LB_BASE2                    0x00000064
+#define V3_LB_MAP2                     0x00000066
+#define V3_LB_SIZE                     0x00000068
+#define V3_LB_IO_BASE                  0x0000006E
+#define V3_FIFO_CFG                    0x00000070
+#define V3_FIFO_PRIORITY               0x00000072
+#define V3_FIFO_STAT                   0x00000074
+#define V3_LB_ISTAT                    0x00000076
+#define V3_LB_IMASK                    0x00000077
+#define V3_SYSTEM                      0x00000078
+#define V3_LB_CFG                      0x0000007A
+#define V3_PCI_CFG                     0x0000007C
+#define V3_DMA_PCI_ADR0                        0x00000080
+#define V3_DMA_PCI_ADR1                        0x00000090
+#define V3_DMA_LOCAL_ADR0              0x00000084
+#define V3_DMA_LOCAL_ADR1              0x00000094
+#define V3_DMA_LENGTH0                 0x00000088
+#define V3_DMA_LENGTH1                 0x00000098
+#define V3_DMA_CSR0                    0x0000008B
+#define V3_DMA_CSR1                    0x0000009B
+#define V3_DMA_CTLB_ADR0               0x0000008C
+#define V3_DMA_CTLB_ADR1               0x0000009C
+#define V3_DMA_DELAY                   0x000000E0
+#define V3_MAIL_DATA                   0x000000C0
+#define V3_PCI_MAIL_IEWR               0x000000D0
+#define V3_PCI_MAIL_IERD               0x000000D2
+#define V3_LB_MAIL_IEWR                        0x000000D4
+#define V3_LB_MAIL_IERD                        0x000000D6
+#define V3_MAIL_WR_STAT                        0x000000D8
+#define V3_MAIL_RD_STAT                        0x000000DA
+#define V3_QBA_MAP                     0x000000DC
+
+/* PCI STATUS bits */
+#define V3_PCI_STAT_PAR_ERR            BIT(15)
+#define V3_PCI_STAT_SYS_ERR            BIT(14)
+#define V3_PCI_STAT_M_ABORT_ERR                BIT(13)
+#define V3_PCI_STAT_T_ABORT_ERR                BIT(12)
+
+/* LB ISTAT bits */
+#define V3_LB_ISTAT_MAILBOX            BIT(7)
+#define V3_LB_ISTAT_PCI_RD             BIT(6)
+#define V3_LB_ISTAT_PCI_WR             BIT(5)
+#define V3_LB_ISTAT_PCI_INT            BIT(4)
+#define V3_LB_ISTAT_PCI_PERR           BIT(3)
+#define V3_LB_ISTAT_I2O_QWR            BIT(2)
+#define V3_LB_ISTAT_DMA1               BIT(1)
+#define V3_LB_ISTAT_DMA0               BIT(0)
+
+/* PCI COMMAND bits */
+#define V3_COMMAND_M_FBB_EN            BIT(9)
+#define V3_COMMAND_M_SERR_EN           BIT(8)
+#define V3_COMMAND_M_PAR_EN            BIT(6)
+#define V3_COMMAND_M_MASTER_EN         BIT(2)
+#define V3_COMMAND_M_MEM_EN            BIT(1)
+#define V3_COMMAND_M_IO_EN             BIT(0)
+
+/* SYSTEM bits */
+#define V3_SYSTEM_M_RST_OUT            BIT(15)
+#define V3_SYSTEM_M_LOCK               BIT(14)
+#define V3_SYSTEM_UNLOCK               0xa05f
+
+/* PCI CFG bits */
+#define V3_PCI_CFG_M_I2O_EN            BIT(15)
+#define V3_PCI_CFG_M_IO_REG_DIS                BIT(14)
+#define V3_PCI_CFG_M_IO_DIS            BIT(13)
+#define V3_PCI_CFG_M_EN3V              BIT(12)
+#define V3_PCI_CFG_M_RETRY_EN          BIT(10)
+#define V3_PCI_CFG_M_AD_LOW1           BIT(9)
+#define V3_PCI_CFG_M_AD_LOW0           BIT(8)
+/*
+ * This is the value applied to C/BE[3:1], with bit 0 always held 0
+ * during DMA access.
+ */
+#define V3_PCI_CFG_M_RTYPE_SHIFT       5
+#define V3_PCI_CFG_M_WTYPE_SHIFT       1
+#define V3_PCI_CFG_TYPE_DEFAULT                0x3
+
+/* PCI BASE bits (PCI -> Local Bus) */
+#define V3_PCI_BASE_M_ADR_BASE         0xFFF00000U
+#define V3_PCI_BASE_M_ADR_BASEL                0x000FFF00U
+#define V3_PCI_BASE_M_PREFETCH         BIT(3)
+#define V3_PCI_BASE_M_TYPE             (3 << 1)
+#define V3_PCI_BASE_M_IO               BIT(0)
+
+/* PCI MAP bits (PCI -> Local bus) */
+#define V3_PCI_MAP_M_MAP_ADR           0xFFF00000U
+#define V3_PCI_MAP_M_RD_POST_INH       BIT(15)
+#define V3_PCI_MAP_M_ROM_SIZE          (3 << 10)
+#define V3_PCI_MAP_M_SWAP              (3 << 8)
+#define V3_PCI_MAP_M_ADR_SIZE          0x000000F0U
+#define V3_PCI_MAP_M_REG_EN            BIT(1)
+#define V3_PCI_MAP_M_ENABLE            BIT(0)
+
+/* LB_BASE0,1 bits (Local bus -> PCI) */
+#define V3_LB_BASE_ADR_BASE            0xfff00000U
+#define V3_LB_BASE_SWAP                        (3 << 8)
+#define V3_LB_BASE_ADR_SIZE            (15 << 4)
+#define V3_LB_BASE_PREFETCH            BIT(3)
+#define V3_LB_BASE_ENABLE              BIT(0)
+
+#define V3_LB_BASE_ADR_SIZE_1MB                (0 << 4)
+#define V3_LB_BASE_ADR_SIZE_2MB                (1 << 4)
+#define V3_LB_BASE_ADR_SIZE_4MB                (2 << 4)
+#define V3_LB_BASE_ADR_SIZE_8MB                (3 << 4)
+#define V3_LB_BASE_ADR_SIZE_16MB       (4 << 4)
+#define V3_LB_BASE_ADR_SIZE_32MB       (5 << 4)
+#define V3_LB_BASE_ADR_SIZE_64MB       (6 << 4)
+#define V3_LB_BASE_ADR_SIZE_128MB      (7 << 4)
+#define V3_LB_BASE_ADR_SIZE_256MB      (8 << 4)
+#define V3_LB_BASE_ADR_SIZE_512MB      (9 << 4)
+#define V3_LB_BASE_ADR_SIZE_1GB                (10 << 4)
+#define V3_LB_BASE_ADR_SIZE_2GB                (11 << 4)
+
+#define v3_addr_to_lb_base(a)  ((a) & V3_LB_BASE_ADR_BASE)
+
+/* LB_MAP0,1 bits (Local bus -> PCI) */
+#define V3_LB_MAP_MAP_ADR              0xfff0U
+#define V3_LB_MAP_TYPE                 (7 << 1)
+#define V3_LB_MAP_AD_LOW_EN            BIT(0)
+
+#define V3_LB_MAP_TYPE_IACK            (0 << 1)
+#define V3_LB_MAP_TYPE_IO              (1 << 1)
+#define V3_LB_MAP_TYPE_MEM             (3 << 1)
+#define V3_LB_MAP_TYPE_CONFIG          (5 << 1)
+#define V3_LB_MAP_TYPE_MEM_MULTIPLE    (6 << 1)
+
+#define v3_addr_to_lb_map(a)   (((a) >> 16) & V3_LB_MAP_MAP_ADR)
+
+/* LB_BASE2 bits (Local bus -> PCI IO) */
+#define V3_LB_BASE2_ADR_BASE           0xff00U
+#define V3_LB_BASE2_SWAP_AUTO          (3 << 6)
+#define V3_LB_BASE2_ENABLE             BIT(0)
+
+#define v3_addr_to_lb_base2(a) (((a) >> 16) & V3_LB_BASE2_ADR_BASE)
+
+/* LB_MAP2 bits (Local bus -> PCI IO) */
+#define V3_LB_MAP2_MAP_ADR             0xff00U
+
+#define v3_addr_to_lb_map2(a)  (((a) >> 16) & V3_LB_MAP2_MAP_ADR)
+
+/* FIFO priority bits */
+#define V3_FIFO_PRIO_LOCAL             BIT(12)
+#define V3_FIFO_PRIO_LB_RD1_FLUSH_EOB  BIT(10)
+#define V3_FIFO_PRIO_LB_RD1_FLUSH_AP1  BIT(11)
+#define V3_FIFO_PRIO_LB_RD1_FLUSH_ANY  (BIT(10)|BIT(11))
+#define V3_FIFO_PRIO_LB_RD0_FLUSH_EOB  BIT(8)
+#define V3_FIFO_PRIO_LB_RD0_FLUSH_AP1  BIT(9)
+#define V3_FIFO_PRIO_LB_RD0_FLUSH_ANY  (BIT(8)|BIT(9))
+#define V3_FIFO_PRIO_PCI               BIT(4)
+#define V3_FIFO_PRIO_PCI_RD1_FLUSH_EOB BIT(2)
+#define V3_FIFO_PRIO_PCI_RD1_FLUSH_AP1 BIT(3)
+#define V3_FIFO_PRIO_PCI_RD1_FLUSH_ANY (BIT(2)|BIT(3))
+#define V3_FIFO_PRIO_PCI_RD0_FLUSH_EOB BIT(0)
+#define V3_FIFO_PRIO_PCI_RD0_FLUSH_AP1 BIT(1)
+#define V3_FIFO_PRIO_PCI_RD0_FLUSH_ANY (BIT(0)|BIT(1))
+
+/* Local bus configuration bits */
+#define V3_LB_CFG_LB_TO_64_CYCLES      0x0000
+#define V3_LB_CFG_LB_TO_256_CYCLES     BIT(13)
+#define V3_LB_CFG_LB_TO_512_CYCLES     BIT(14)
+#define V3_LB_CFG_LB_TO_1024_CYCLES    (BIT(13)|BIT(14))
+#define V3_LB_CFG_LB_RST               BIT(12)
+#define V3_LB_CFG_LB_PPC_RDY           BIT(11)
+#define V3_LB_CFG_LB_LB_INT            BIT(10)
+#define V3_LB_CFG_LB_ERR_EN            BIT(9)
+#define V3_LB_CFG_LB_RDY_EN            BIT(8)
+#define V3_LB_CFG_LB_BE_IMODE          BIT(7)
+#define V3_LB_CFG_LB_BE_OMODE          BIT(6)
+#define V3_LB_CFG_LB_ENDIAN            BIT(5)
+#define V3_LB_CFG_LB_PARK_EN           BIT(4)
+#define V3_LB_CFG_LB_FBB_DIS           BIT(2)
+
+/* ARM Integrator-specific extended control registers */
+#define INTEGRATOR_SC_PCI_OFFSET       0x18
+#define INTEGRATOR_SC_PCI_ENABLE       BIT(0)
+#define INTEGRATOR_SC_PCI_INTCLR       BIT(1)
+#define INTEGRATOR_SC_LBFADDR_OFFSET   0x20
+#define INTEGRATOR_SC_LBFCODE_OFFSET   0x24
+
+struct v3_pci {
+       struct device *dev;
+       void __iomem *base;
+       void __iomem *config_base;
+       struct pci_bus *bus;
+       u32 config_mem;
+       u32 io_mem;
+       u32 non_pre_mem;
+       u32 pre_mem;
+       phys_addr_t io_bus_addr;
+       phys_addr_t non_pre_bus_addr;
+       phys_addr_t pre_bus_addr;
+       struct regmap *map;
+};
+
+/*
+ * The V3 PCI interface chip in Integrator provides several windows from
+ * local bus memory into the PCI memory areas. Unfortunately, there
+ * are not really enough windows for our usage, therefore we reuse
+ * one of the windows for access to PCI configuration space. On the
+ * Integrator/AP, the memory map is as follows:
+ *
+ * Local Bus Memory         Usage
+ *
+ * 40000000 - 4FFFFFFF      PCI memory.  256M non-prefetchable
+ * 50000000 - 5FFFFFFF      PCI memory.  256M prefetchable
+ * 60000000 - 60FFFFFF      PCI IO.  16M
+ * 61000000 - 61FFFFFF      PCI Configuration. 16M
+ *
+ * There are three V3 windows, each described by a pair of V3 registers.
+ * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
+ * Base0 and Base1 can be used for any type of PCI memory access.   Base2
+ * can be used either for PCI I/O or for I20 accesses.  By default, uHAL
+ * uses this only for PCI IO space.
+ *
+ * Normally these spaces are mapped using the following base registers:
+ *
+ * Usage Local Bus Memory         Base/Map registers used
+ *
+ * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
+ * Mem   50000000 - 5FFFFFFF      LB_BASE1/LB_MAP1
+ * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
+ * Cfg   61000000 - 61FFFFFF
+ *
+ * This means that I20 and PCI configuration space accesses will fail.
+ * When PCI configuration accesses are needed (via the uHAL PCI
+ * configuration space primitives) we must remap the spaces as follows:
+ *
+ * Usage Local Bus Memory         Base/Map registers used
+ *
+ * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
+ * Mem   50000000 - 5FFFFFFF      LB_BASE0/LB_MAP0
+ * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
+ * Cfg   61000000 - 61FFFFFF      LB_BASE1/LB_MAP1
+ *
+ * To make this work, the code depends on overlapping windows working.
+ * The V3 chip translates an address by checking its range within
+ * each of the BASE/MAP pairs in turn (in ascending register number
+ * order).  It will use the first matching pair.   So, for example,
+ * if the same address is mapped by both LB_BASE0/LB_MAP0 and
+ * LB_BASE1/LB_MAP1, the V3 will use the translation from
+ * LB_BASE0/LB_MAP0.
+ *
+ * To allow PCI Configuration space access, the code enlarges the
+ * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M.  This occludes
+ * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
+ * be remapped for use by configuration cycles.
+ *
+ * At the end of the PCI Configuration space accesses,
+ * LB_BASE1/LB_MAP1 is reset to map PCI Memory.  Finally the window
+ * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
+ * reveal the now restored LB_BASE1/LB_MAP1 window.
+ *
+ * NOTE: We do not set up I2O mapping.  I suspect that this is only
+ * for an intelligent (target) device.  Using I2O disables most of
+ * the mappings into PCI memory.
+ */
+static void __iomem *v3_map_bus(struct pci_bus *bus,
+                               unsigned int devfn, int offset)
+{
+       struct v3_pci *v3 = bus->sysdata;
+       unsigned int address, mapaddress, busnr;
+
+       busnr = bus->number;
+       if (busnr == 0) {
+               int slot = PCI_SLOT(devfn);
+
+               /*
+                * local bus segment so need a type 0 config cycle
+                *
+                * build the PCI configuration "address" with one-hot in
+                * A31-A11
+                *
+                * mapaddress:
+                *  3:1 = config cycle (101)
+                *  0   = PCI A1 & A0 are 0 (0)
+                */
+               address = PCI_FUNC(devfn) << 8;
+               mapaddress = V3_LB_MAP_TYPE_CONFIG;
+
+               if (slot > 12)
+                       /*
+                        * high order bits are handled by the MAP register
+                        */
+                       mapaddress |= BIT(slot - 5);
+               else
+                       /*
+                        * low order bits handled directly in the address
+                        */
+                       address |= BIT(slot + 11);
+       } else {
+               /*
+                * not the local bus segment so need a type 1 config cycle
+                *
+                * address:
+                *  23:16 = bus number
+                *  15:11 = slot number (7:3 of devfn)
+                *  10:8  = func number (2:0 of devfn)
+                *
+                * mapaddress:
+                *  3:1 = config cycle (101)
+                *  0   = PCI A1 & A0 from host bus (1)
+                */
+               mapaddress = V3_LB_MAP_TYPE_CONFIG | V3_LB_MAP_AD_LOW_EN;
+               address = (busnr << 16) | (devfn << 8);
+       }
+
+       /*
+        * Set up base0 to see all 512Mbytes of memory space (not
+        * prefetchable), this frees up base1 for re-use by
+        * configuration memory
+        */
+       writel(v3_addr_to_lb_base(v3->non_pre_mem) |
+              V3_LB_BASE_ADR_SIZE_512MB | V3_LB_BASE_ENABLE,
+              v3->base + V3_LB_BASE0);
+
+       /*
+        * Set up base1/map1 to point into configuration space.
+        * The config mem is always 16MB.
+        */
+       writel(v3_addr_to_lb_base(v3->config_mem) |
+              V3_LB_BASE_ADR_SIZE_16MB | V3_LB_BASE_ENABLE,
+              v3->base + V3_LB_BASE1);
+       writew(mapaddress, v3->base + V3_LB_MAP1);
+
+       return v3->config_base + address + offset;
+}
+
+static void v3_unmap_bus(struct v3_pci *v3)
+{
+       /*
+        * Reassign base1 for use by prefetchable PCI memory
+        */
+       writel(v3_addr_to_lb_base(v3->pre_mem) |
+              V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH |
+              V3_LB_BASE_ENABLE,
+              v3->base + V3_LB_BASE1);
+       writew(v3_addr_to_lb_map(v3->pre_bus_addr) |
+              V3_LB_MAP_TYPE_MEM, /* was V3_LB_MAP_TYPE_MEM_MULTIPLE */
+              v3->base + V3_LB_MAP1);
+
+       /*
+        * And shrink base0 back to a 256M window (NOTE: MAP0 already correct)
+        */
+       writel(v3_addr_to_lb_base(v3->non_pre_mem) |
+              V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE,
+              v3->base + V3_LB_BASE0);
+}
+
+static int v3_pci_read_config(struct pci_bus *bus, unsigned int fn,
+                             int config, int size, u32 *value)
+{
+       struct v3_pci *v3 = bus->sysdata;
+       int ret;
+
+       dev_dbg(&bus->dev,
+               "[read]  slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n",
+               PCI_SLOT(fn), PCI_FUNC(fn), config, size, *value);
+       ret = pci_generic_config_read(bus, fn, config, size, value);
+       v3_unmap_bus(v3);
+       return ret;
+}
+
+static int v3_pci_write_config(struct pci_bus *bus, unsigned int fn,
+                                   int config, int size, u32 value)
+{
+       struct v3_pci *v3 = bus->sysdata;
+       int ret;
+
+       dev_dbg(&bus->dev,
+               "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n",
+               PCI_SLOT(fn), PCI_FUNC(fn), config, size, value);
+       ret = pci_generic_config_write(bus, fn, config, size, value);
+       v3_unmap_bus(v3);
+       return ret;
+}
+
+static struct pci_ops v3_pci_ops = {
+       .map_bus = v3_map_bus,
+       .read = v3_pci_read_config,
+       .write = v3_pci_write_config,
+};
+
+static irqreturn_t v3_irq(int irq, void *data)
+{
+       struct v3_pci *v3 = data;
+       struct device *dev = v3->dev;
+       u32 status;
+
+       status = readw(v3->base + V3_PCI_STAT);
+       if (status & V3_PCI_STAT_PAR_ERR)
+               dev_err(dev, "parity error interrupt\n");
+       if (status & V3_PCI_STAT_SYS_ERR)
+               dev_err(dev, "system error interrupt\n");
+       if (status & V3_PCI_STAT_M_ABORT_ERR)
+               dev_err(dev, "master abort error interrupt\n");
+       if (status & V3_PCI_STAT_T_ABORT_ERR)
+               dev_err(dev, "target abort error interrupt\n");
+       writew(status, v3->base + V3_PCI_STAT);
+
+       status = readb(v3->base + V3_LB_ISTAT);
+       if (status & V3_LB_ISTAT_MAILBOX)
+               dev_info(dev, "PCI mailbox interrupt\n");
+       if (status & V3_LB_ISTAT_PCI_RD)
+               dev_err(dev, "PCI target LB->PCI READ abort interrupt\n");
+       if (status & V3_LB_ISTAT_PCI_WR)
+               dev_err(dev, "PCI target LB->PCI WRITE abort interrupt\n");
+       if (status &  V3_LB_ISTAT_PCI_INT)
+               dev_info(dev, "PCI pin interrupt\n");
+       if (status & V3_LB_ISTAT_PCI_PERR)
+               dev_err(dev, "PCI parity error interrupt\n");
+       if (status & V3_LB_ISTAT_I2O_QWR)
+               dev_info(dev, "I2O inbound post queue interrupt\n");
+       if (status & V3_LB_ISTAT_DMA1)
+               dev_info(dev, "DMA channel 1 interrupt\n");
+       if (status & V3_LB_ISTAT_DMA0)
+               dev_info(dev, "DMA channel 0 interrupt\n");
+       /* Clear all possible interrupts on the local bus */
+       writeb(0, v3->base + V3_LB_ISTAT);
+       if (v3->map)
+               regmap_write(v3->map, INTEGRATOR_SC_PCI_OFFSET,
+                            INTEGRATOR_SC_PCI_ENABLE |
+                            INTEGRATOR_SC_PCI_INTCLR);
+
+       return IRQ_HANDLED;
+}
+
+static int v3_integrator_init(struct v3_pci *v3)
+{
+       unsigned int val;
+
+       v3->map =
+               syscon_regmap_lookup_by_compatible("arm,integrator-ap-syscon");
+       if (IS_ERR(v3->map)) {
+               dev_err(v3->dev, "no syscon\n");
+               return -ENODEV;
+       }
+
+       regmap_read(v3->map, INTEGRATOR_SC_PCI_OFFSET, &val);
+       /* Take the PCI bridge out of reset, clear IRQs */
+       regmap_write(v3->map, INTEGRATOR_SC_PCI_OFFSET,
+                    INTEGRATOR_SC_PCI_ENABLE |
+                    INTEGRATOR_SC_PCI_INTCLR);
+
+       if (!(val & INTEGRATOR_SC_PCI_ENABLE)) {
+               /* If we were in reset we need to sleep a bit */
+               msleep(230);
+
+               /* Set the physical base for the controller itself */
+               writel(0x6200, v3->base + V3_LB_IO_BASE);
+
+               /* Wait for the mailbox to settle after reset */
+               do {
+                       writeb(0xaa, v3->base + V3_MAIL_DATA);
+                       writeb(0x55, v3->base + V3_MAIL_DATA + 4);
+               } while (readb(v3->base + V3_MAIL_DATA) != 0xaa &&
+                        readb(v3->base + V3_MAIL_DATA) != 0x55);
+       }
+
+       dev_info(v3->dev, "initialized PCI V3 Integrator/AP integration\n");
+
+       return 0;
+}
+
+static int v3_pci_setup_resource(struct v3_pci *v3,
+                                resource_size_t io_base,
+                                struct pci_host_bridge *host,
+                                struct resource_entry *win)
+{
+       struct device *dev = v3->dev;
+       struct resource *mem;
+       struct resource *io;
+       int ret;
+
+       switch (resource_type(win->res)) {
+       case IORESOURCE_IO:
+               io = win->res;
+               io->name = "V3 PCI I/O";
+               v3->io_mem = io_base;
+               v3->io_bus_addr = io->start - win->offset;
+               dev_dbg(dev, "I/O window %pR, bus addr %pap\n",
+                       io, &v3->io_bus_addr);
+               ret = pci_remap_iospace(io, io_base);
+               if (ret) {
+                       dev_warn(dev,
+                                "error %d: failed to map resource %pR\n",
+                                ret, io);
+                       return ret;
+               }
+               /* Setup window 2 - PCI I/O */
+               writel(v3_addr_to_lb_base2(v3->io_mem) |
+                      V3_LB_BASE2_ENABLE,
+                      v3->base + V3_LB_BASE2);
+               writew(v3_addr_to_lb_map2(v3->io_bus_addr),
+                      v3->base + V3_LB_MAP2);
+               break;
+       case IORESOURCE_MEM:
+               mem = win->res;
+               if (mem->flags & IORESOURCE_PREFETCH) {
+                       mem->name = "V3 PCI PRE-MEM";
+                       v3->pre_mem = mem->start;
+                       v3->pre_bus_addr = mem->start - win->offset;
+                       dev_dbg(dev, "PREFETCHABLE MEM window %pR, bus addr %pap\n",
+                               mem, &v3->pre_bus_addr);
+                       if (resource_size(mem) != SZ_256M) {
+                               dev_err(dev, "prefetchable memory range is not 256MB\n");
+                               return -EINVAL;
+                       }
+                       if (v3->non_pre_mem &&
+                           (mem->start != v3->non_pre_mem + SZ_256M)) {
+                               dev_err(dev,
+                                       "prefetchable memory is not adjacent to non-prefetchable memory\n");
+                               return -EINVAL;
+                       }
+                       /* Setup window 1 - PCI prefetchable memory */
+                       writel(v3_addr_to_lb_base(v3->pre_mem) |
+                              V3_LB_BASE_ADR_SIZE_256MB |
+                              V3_LB_BASE_PREFETCH |
+                              V3_LB_BASE_ENABLE,
+                              v3->base + V3_LB_BASE1);
+                       writew(v3_addr_to_lb_map(v3->pre_bus_addr) |
+                              V3_LB_MAP_TYPE_MEM, /* Was V3_LB_MAP_TYPE_MEM_MULTIPLE */
+                              v3->base + V3_LB_MAP1);
+               } else {
+                       mem->name = "V3 PCI NON-PRE-MEM";
+                       v3->non_pre_mem = mem->start;
+                       v3->non_pre_bus_addr = mem->start - win->offset;
+                       dev_dbg(dev, "NON-PREFETCHABLE MEM window %pR, bus addr %pap\n",
+                               mem, &v3->non_pre_bus_addr);
+                       if (resource_size(mem) != SZ_256M) {
+                               dev_err(dev,
+                                       "non-prefetchable memory range is not 256MB\n");
+                               return -EINVAL;
+                       }
+                       /* Setup window 0 - PCI non-prefetchable memory */
+                       writel(v3_addr_to_lb_base(v3->non_pre_mem) |
+                              V3_LB_BASE_ADR_SIZE_256MB |
+                              V3_LB_BASE_ENABLE,
+                              v3->base + V3_LB_BASE0);
+                       writew(v3_addr_to_lb_map(v3->non_pre_bus_addr) |
+                              V3_LB_MAP_TYPE_MEM,
+                              v3->base + V3_LB_MAP0);
+               }
+               break;
+       case IORESOURCE_BUS:
+               dev_dbg(dev, "BUS %pR\n", win->res);
+               host->busnr = win->res->start;
+               break;
+       default:
+               dev_info(dev, "Unknown resource type %lu\n",
+                        resource_type(win->res));
+               break;
+       }
+
+       return 0;
+}
+
+static int v3_get_dma_range_config(struct v3_pci *v3,
+                                  struct of_pci_range *range,
+                                  u32 *pci_base, u32 *pci_map)
+{
+       struct device *dev = v3->dev;
+       u64 cpu_end = range->cpu_addr + range->size - 1;
+       u64 pci_end = range->pci_addr + range->size - 1;
+       u32 val;
+
+       if (range->pci_addr & ~V3_PCI_BASE_M_ADR_BASE) {
+               dev_err(dev, "illegal range, only PCI bits 31..20 allowed\n");
+               return -EINVAL;
+       }
+       val = ((u32)range->pci_addr) & V3_PCI_BASE_M_ADR_BASE;
+       *pci_base = val;
+
+       if (range->cpu_addr & ~V3_PCI_MAP_M_MAP_ADR) {
+               dev_err(dev, "illegal range, only CPU bits 31..20 allowed\n");
+               return -EINVAL;
+       }
+       val = ((u32)range->cpu_addr) & V3_PCI_MAP_M_MAP_ADR;
+
+       switch (range->size) {
+       case SZ_1M:
+               val |= V3_LB_BASE_ADR_SIZE_1MB;
+               break;
+       case SZ_2M:
+               val |= V3_LB_BASE_ADR_SIZE_2MB;
+               break;
+       case SZ_4M:
+               val |= V3_LB_BASE_ADR_SIZE_4MB;
+               break;
+       case SZ_8M:
+               val |= V3_LB_BASE_ADR_SIZE_8MB;
+               break;
+       case SZ_16M:
+               val |= V3_LB_BASE_ADR_SIZE_16MB;
+               break;
+       case SZ_32M:
+               val |= V3_LB_BASE_ADR_SIZE_32MB;
+               break;
+       case SZ_64M:
+               val |= V3_LB_BASE_ADR_SIZE_64MB;
+               break;
+       case SZ_128M:
+               val |= V3_LB_BASE_ADR_SIZE_128MB;
+               break;
+       case SZ_256M:
+               val |= V3_LB_BASE_ADR_SIZE_256MB;
+               break;
+       case SZ_512M:
+               val |= V3_LB_BASE_ADR_SIZE_512MB;
+               break;
+       case SZ_1G:
+               val |= V3_LB_BASE_ADR_SIZE_1GB;
+               break;
+       case SZ_2G:
+               val |= V3_LB_BASE_ADR_SIZE_2GB;
+               break;
+       default:
+               dev_err(v3->dev, "illegal dma memory chunk size\n");
+               return -EINVAL;
+               break;
+       };
+       val |= V3_PCI_MAP_M_REG_EN | V3_PCI_MAP_M_ENABLE;
+       *pci_map = val;
+
+       dev_dbg(dev,
+               "DMA MEM CPU: 0x%016llx -> 0x%016llx => "
+               "PCI: 0x%016llx -> 0x%016llx base %08x map %08x\n",
+               range->cpu_addr, cpu_end,
+               range->pci_addr, pci_end,
+               *pci_base, *pci_map);
+
+       return 0;
+}
+
+static int v3_pci_parse_map_dma_ranges(struct v3_pci *v3,
+                                      struct device_node *np)
+{
+       struct of_pci_range range;
+       struct of_pci_range_parser parser;
+       struct device *dev = v3->dev;
+       int i = 0;
+
+       if (of_pci_dma_range_parser_init(&parser, np)) {
+               dev_err(dev, "missing dma-ranges property\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Get the dma-ranges from the device tree
+        */
+       for_each_of_pci_range(&parser, &range) {
+               int ret;
+               u32 pci_base, pci_map;
+
+               ret = v3_get_dma_range_config(v3, &range, &pci_base, &pci_map);
+               if (ret)
+                       return ret;
+
+               if (i == 0) {
+                       writel(pci_base, v3->base + V3_PCI_BASE0);
+                       writel(pci_map, v3->base + V3_PCI_MAP0);
+               } else if (i == 1) {
+                       writel(pci_base, v3->base + V3_PCI_BASE1);
+                       writel(pci_map, v3->base + V3_PCI_MAP1);
+               } else {
+                       dev_err(dev, "too many ranges, only two supported\n");
+                       dev_err(dev, "range %d ignored\n", i);
+               }
+               i++;
+       }
+       return 0;
+}
+
+static int v3_pci_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       resource_size_t io_base;
+       struct resource *regs;
+       struct resource_entry *win;
+       struct v3_pci *v3;
+       struct pci_host_bridge *host;
+       struct clk *clk;
+       u16 val;
+       int irq;
+       int ret;
+       LIST_HEAD(res);
+
+       host = pci_alloc_host_bridge(sizeof(*v3));
+       if (!host)
+               return -ENOMEM;
+
+       host->dev.parent = dev;
+       host->ops = &v3_pci_ops;
+       host->busnr = 0;
+       host->msi = NULL;
+       host->map_irq = of_irq_parse_and_map_pci;
+       host->swizzle_irq = pci_common_swizzle;
+       v3 = pci_host_bridge_priv(host);
+       host->sysdata = v3;
+       v3->dev = dev;
+
+       /* Get and enable host clock */
+       clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(dev, "clock not found\n");
+               return PTR_ERR(clk);
+       }
+       ret = clk_prepare_enable(clk);
+       if (ret) {
+               dev_err(dev, "unable to enable clock\n");
+               return ret;
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       v3->base = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(v3->base))
+               return PTR_ERR(v3->base);
+       /*
+        * The hardware has a register with the physical base address
+        * of the V3 controller itself, verify that this is the same
+        * as the physical memory we've remapped it from.
+        */
+       if (readl(v3->base + V3_LB_IO_BASE) != (regs->start >> 16))
+               dev_err(dev, "V3_LB_IO_BASE = %08x but device is @%pR\n",
+                       readl(v3->base + V3_LB_IO_BASE), regs);
+
+       /* Configuration space is 16MB directly mapped */
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (resource_size(regs) != SZ_16M) {
+               dev_err(dev, "config mem is not 16MB!\n");
+               return -EINVAL;
+       }
+       v3->config_mem = regs->start;
+       v3->config_base = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(v3->config_base))
+               return PTR_ERR(v3->config_base);
+
+       ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &io_base);
+       if (ret)
+               return ret;
+
+       ret = devm_request_pci_bus_resources(dev, &res);
+       if (ret)
+               return ret;
+
+       /* Get and request error IRQ resource */
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(dev, "unable to obtain PCIv3 error IRQ\n");
+               return -ENODEV;
+       }
+       ret = devm_request_irq(dev, irq, v3_irq, 0,
+                       "PCIv3 error", v3);
+       if (ret < 0) {
+               dev_err(dev,
+                       "unable to request PCIv3 error IRQ %d (%d)\n",
+                       irq, ret);
+               return ret;
+       }
+
+       /*
+        * Unlock V3 registers, but only if they were previously locked.
+        */
+       if (readw(v3->base + V3_SYSTEM) & V3_SYSTEM_M_LOCK)
+               writew(V3_SYSTEM_UNLOCK, v3->base + V3_SYSTEM);
+
+       /* Disable all slave access while we set up the windows */
+       val = readw(v3->base + V3_PCI_CMD);
+       val &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+       writew(val, v3->base + V3_PCI_CMD);
+
+       /* Put the PCI bus into reset */
+       val = readw(v3->base + V3_SYSTEM);
+       val &= ~V3_SYSTEM_M_RST_OUT;
+       writew(val, v3->base + V3_SYSTEM);
+
+       /* Retry until we're ready */
+       val = readw(v3->base + V3_PCI_CFG);
+       val |= V3_PCI_CFG_M_RETRY_EN;
+       writew(val, v3->base + V3_PCI_CFG);
+
+       /* Set up the local bus protocol */
+       val = readw(v3->base + V3_LB_CFG);
+       val |= V3_LB_CFG_LB_BE_IMODE; /* Byte enable input */
+       val |= V3_LB_CFG_LB_BE_OMODE; /* Byte enable output */
+       val &= ~V3_LB_CFG_LB_ENDIAN; /* Little endian */
+       val &= ~V3_LB_CFG_LB_PPC_RDY; /* TODO: when using on PPC403Gx, set to 1 */
+       writew(val, v3->base + V3_LB_CFG);
+
+       /* Enable the PCI bus master */
+       val = readw(v3->base + V3_PCI_CMD);
+       val |= PCI_COMMAND_MASTER;
+       writew(val, v3->base + V3_PCI_CMD);
+
+       /* Get the I/O and memory ranges from DT */
+       resource_list_for_each_entry(win, &res) {
+               ret = v3_pci_setup_resource(v3, io_base, host, win);
+               if (ret) {
+                       dev_err(dev, "error setting up resources\n");
+                       return ret;
+               }
+       }
+       ret = v3_pci_parse_map_dma_ranges(v3, np);
+       if (ret)
+               return ret;
+
+       /*
+        * Disable PCI to host IO cycles, enable I/O buffers @3.3V,
+        * set AD_LOW0 to 1 if one of the LB_MAP registers choose
+        * to use this (should be unused).
+        */
+       writel(0x00000000, v3->base + V3_PCI_IO_BASE);
+       val = V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS |
+               V3_PCI_CFG_M_EN3V | V3_PCI_CFG_M_AD_LOW0;
+       /*
+        * DMA read and write from PCI bus commands types
+        */
+       val |=  V3_PCI_CFG_TYPE_DEFAULT << V3_PCI_CFG_M_RTYPE_SHIFT;
+       val |=  V3_PCI_CFG_TYPE_DEFAULT << V3_PCI_CFG_M_WTYPE_SHIFT;
+       writew(val, v3->base + V3_PCI_CFG);
+
+       /*
+        * Set the V3 FIFO such that writes have higher priority than
+        * reads, and local bus write causes local bus read fifo flush
+        * on aperture 1. Same for PCI.
+        */
+       writew(V3_FIFO_PRIO_LB_RD1_FLUSH_AP1 |
+              V3_FIFO_PRIO_LB_RD0_FLUSH_AP1 |
+              V3_FIFO_PRIO_PCI_RD1_FLUSH_AP1 |
+              V3_FIFO_PRIO_PCI_RD0_FLUSH_AP1,
+              v3->base + V3_FIFO_PRIORITY);
+
+
+       /*
+        * Clear any error interrupts, and enable parity and write error
+        * interrupts
+        */
+       writeb(0, v3->base + V3_LB_ISTAT);
+       val = readw(v3->base + V3_LB_CFG);
+       val |= V3_LB_CFG_LB_LB_INT;
+       writew(val, v3->base + V3_LB_CFG);
+       writeb(V3_LB_ISTAT_PCI_WR | V3_LB_ISTAT_PCI_PERR,
+              v3->base + V3_LB_IMASK);
+
+       /* Special Integrator initialization */
+       if (of_device_is_compatible(np, "arm,integrator-ap-pci")) {
+               ret = v3_integrator_init(v3);
+               if (ret)
+                       return ret;
+       }
+
+       /* Post-init: enable PCI memory and invalidate (master already on) */
+       val = readw(v3->base + V3_PCI_CMD);
+       val |= PCI_COMMAND_MEMORY | PCI_COMMAND_INVALIDATE;
+       writew(val, v3->base + V3_PCI_CMD);
+
+       /* Clear pending interrupts */
+       writeb(0, v3->base + V3_LB_ISTAT);
+       /* Read or write errors and parity errors cause interrupts */
+       writeb(V3_LB_ISTAT_PCI_RD | V3_LB_ISTAT_PCI_WR | V3_LB_ISTAT_PCI_PERR,
+              v3->base + V3_LB_IMASK);
+
+       /* Take the PCI bus out of reset so devices can initialize */
+       val = readw(v3->base + V3_SYSTEM);
+       val |= V3_SYSTEM_M_RST_OUT;
+       writew(val, v3->base + V3_SYSTEM);
+
+       /*
+        * Re-lock the system register.
+        */
+       val = readw(v3->base + V3_SYSTEM);
+       val |= V3_SYSTEM_M_LOCK;
+       writew(val, v3->base + V3_SYSTEM);
+
+       list_splice_init(&res, &host->windows);
+       ret = pci_scan_root_bus_bridge(host);
+       if (ret) {
+               dev_err(dev, "failed to register host: %d\n", ret);
+               return ret;
+       }
+       v3->bus = host->bus;
+
+       pci_bus_assign_resources(v3->bus);
+       pci_bus_add_devices(v3->bus);
+
+       return 0;
+}
+
+static const struct of_device_id v3_pci_of_match[] = {
+       {
+               .compatible = "v3,v360epc-pci",
+       },
+       {},
+};
+
+static struct platform_driver v3_pci_driver = {
+       .driver = {
+               .name = "pci-v3-semi",
+               .of_match_table = of_match_ptr(v3_pci_of_match),
+               .suppress_bind_attrs = true,
+       },
+       .probe  = v3_pci_probe,
+};
+builtin_platform_driver(v3_pci_driver);
index 9f53612f6594cb9cb8b4190c8082d67213970c05..465aa2a1b38dbadf9e96493a1e5a58d1b9cb8cf6 100644 (file)
@@ -542,24 +542,6 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
        xgene_pcie_setup_pims(port, pim_reg, pci_addr, ~(size - 1));
 }
 
-static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-                                    struct device_node *node)
-{
-       const int na = 3, ns = 2;
-       int rlen;
-
-       parser->node = node;
-       parser->pna = of_n_addr_cells(node);
-       parser->np = parser->pna + na + ns;
-
-       parser->range = of_get_property(node, "dma-ranges", &rlen);
-       if (!parser->range)
-               return -ENOENT;
-       parser->end = parser->range + rlen / sizeof(__be32);
-
-       return 0;
-}
-
 static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port)
 {
        struct device_node *np = port->node;
@@ -568,7 +550,7 @@ static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port)
        struct device *dev = port->dev;
        u8 ib_reg_mask = 0;
 
-       if (pci_dma_range_parser_init(&parser, np)) {
+       if (of_pci_dma_range_parser_init(&parser, np)) {
                dev_err(dev, "missing dma-ranges property\n");
                return -EINVAL;
        }
index b468b8cccf8d120e6d84350510da22553627f88a..5cc4f594d79ae77c338cd236fdbfa41a5bc9bd2e 100644 (file)
@@ -105,7 +105,7 @@ static inline u32 cra_readl(struct altera_pcie *pcie, const u32 reg)
        return readl_relaxed(pcie->cra_base + reg);
 }
 
-static bool altera_pcie_link_is_up(struct altera_pcie *pcie)
+static bool altera_pcie_link_up(struct altera_pcie *pcie)
 {
        return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0);
 }
@@ -142,7 +142,7 @@ static bool altera_pcie_valid_device(struct altera_pcie *pcie,
 {
        /* If there is no link, then there is no device */
        if (bus->number != pcie->root_bus_nr) {
-               if (!altera_pcie_link_is_up(pcie))
+               if (!altera_pcie_link_up(pcie))
                        return false;
        }
 
@@ -412,7 +412,7 @@ static void altera_wait_link_retrain(struct altera_pcie *pcie)
        /* Wait for link is up */
        start_jiffies = jiffies;
        for (;;) {
-               if (altera_pcie_link_is_up(pcie))
+               if (altera_pcie_link_up(pcie))
                        break;
 
                if (time_after(jiffies, start_jiffies + LINK_UP_TIMEOUT)) {
@@ -427,7 +427,7 @@ static void altera_pcie_retrain(struct altera_pcie *pcie)
 {
        u16 linkcap, linkstat, linkctl;
 
-       if (!altera_pcie_link_is_up(pcie))
+       if (!altera_pcie_link_up(pcie))
                return;
 
        /*
index 2d0f535a2f69a462df8fede4de2e31b4a7333097..990fc906d73d952b0d2cea32f8f50e97a53670c1 100644 (file)
@@ -179,7 +179,7 @@ static struct irq_chip iproc_msi_irq_chip = {
 
 static struct msi_domain_info iproc_msi_domain_info = {
        .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-               MSI_FLAG_PCI_MSIX,
+               MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
        .chip = &iproc_msi_irq_chip,
 };
 
@@ -237,7 +237,7 @@ static void iproc_msi_irq_compose_msi_msg(struct irq_data *data,
        addr = msi->msi_addr + iproc_msi_addr_offset(msi, data->hwirq);
        msg->address_lo = lower_32_bits(addr);
        msg->address_hi = upper_32_bits(addr);
-       msg->data = data->hwirq;
+       msg->data = data->hwirq << 5;
 }
 
 static struct irq_chip iproc_msi_bottom_irq_chip = {
@@ -251,7 +251,7 @@ static int iproc_msi_irq_domain_alloc(struct irq_domain *domain,
                                      void *args)
 {
        struct iproc_msi *msi = domain->host_data;
-       int hwirq;
+       int hwirq, i;
 
        mutex_lock(&msi->bitmap_lock);
 
@@ -267,10 +267,14 @@ static int iproc_msi_irq_domain_alloc(struct irq_domain *domain,
 
        mutex_unlock(&msi->bitmap_lock);
 
-       irq_domain_set_info(domain, virq, hwirq, &iproc_msi_bottom_irq_chip,
-                           domain->host_data, handle_simple_irq, NULL, NULL);
+       for (i = 0; i < nr_irqs; i++) {
+               irq_domain_set_info(domain, virq + i, hwirq + i,
+                                   &iproc_msi_bottom_irq_chip,
+                                   domain->host_data, handle_simple_irq,
+                                   NULL, NULL);
+       }
 
-       return 0;
+       return hwirq;
 }
 
 static void iproc_msi_irq_domain_free(struct irq_domain *domain,
@@ -302,7 +306,8 @@ static inline u32 decode_msi_hwirq(struct iproc_msi *msi, u32 eq, u32 head)
 
        offs = iproc_msi_eq_offset(msi, eq) + head * sizeof(u32);
        msg = (u32 *)(msi->eq_cpu + offs);
-       hwirq = *msg & IPROC_MSI_EQ_MASK;
+       hwirq = readl(msg);
+       hwirq = (hwirq >> 5) + (hwirq & 0x1f);
 
        /*
         * Since we have multiple hwirq mapped to a single MSI vector,
index 3a8b9d20ee57b71358671ddcccb374e7333b754b..935909bbe5c45e381725cd34b0851858251c72c7 100644 (file)
@@ -1097,24 +1097,6 @@ err_ib:
        return ret;
 }
 
-static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-                                    struct device_node *node)
-{
-       const int na = 3, ns = 2;
-       int rlen;
-
-       parser->node = node;
-       parser->pna = of_n_addr_cells(node);
-       parser->np = parser->pna + na + ns;
-
-       parser->range = of_get_property(node, "dma-ranges", &rlen);
-       if (!parser->range)
-               return -ENOENT;
-
-       parser->end = parser->range + rlen / sizeof(__be32);
-       return 0;
-}
-
 static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
 {
        struct of_pci_range range;
@@ -1122,7 +1104,7 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
        int ret;
 
        /* Get the dma-ranges from DT */
-       ret = pci_dma_range_parser_init(&parser, pcie->dev->of_node);
+       ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node);
        if (ret)
                return ret;
 
index 4e0b25d09b0c72e73c720556bc7e0a066ff0094b..12796eccb2befd9170b1ba8119dc600ef356c7e8 100644 (file)
@@ -1027,24 +1027,6 @@ static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
        return 0;
 }
 
-static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-                                    struct device_node *node)
-{
-       const int na = 3, ns = 2;
-       int rlen;
-
-       parser->node = node;
-       parser->pna = of_n_addr_cells(node);
-       parser->np = parser->pna + na + ns;
-
-       parser->range = of_get_property(node, "dma-ranges", &rlen);
-       if (!parser->range)
-               return -ENOENT;
-
-       parser->end = parser->range + rlen / sizeof(__be32);
-       return 0;
-}
-
 static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
                                          struct device_node *np)
 {
@@ -1053,7 +1035,7 @@ static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
        int index = 0;
        int err;
 
-       if (pci_dma_range_parser_init(&parser, np))
+       if (of_pci_dma_range_parser_init(&parser, np))
                return -EINVAL;
 
        /* Get the dma-ranges from DT */
index 6bbb81f06a53c33bcd6acaee3cbb1bd92ecf7823..e23f7383ac33c25055edbb591ada8d4ff53302f9 100644 (file)
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
 #include <linux/pci-ecam.h>
 #include <linux/delay.h>
-#include <linux/of.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+
+#define MSI_MAX                        256
 
 #define SMP8759_MUX            0x48
 #define SMP8759_TEST_OUT       0x74
+#define SMP8759_DOORBELL       0x7c
+#define SMP8759_STATUS         0x80
+#define SMP8759_ENABLE         0xa0
 
 struct tango_pcie {
-       void __iomem *base;
+       DECLARE_BITMAP(used_msi, MSI_MAX);
+       u64                     msi_doorbell;
+       spinlock_t              used_msi_lock;
+       void __iomem            *base;
+       struct irq_domain       *dom;
+};
+
+static void tango_msi_isr(struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
+       unsigned long status, base, virq, idx, pos = 0;
+
+       chained_irq_enter(chip, desc);
+       spin_lock(&pcie->used_msi_lock);
+
+       while ((pos = find_next_bit(pcie->used_msi, MSI_MAX, pos)) < MSI_MAX) {
+               base = round_down(pos, 32);
+               status = readl_relaxed(pcie->base + SMP8759_STATUS + base / 8);
+               for_each_set_bit(idx, &status, 32) {
+                       virq = irq_find_mapping(pcie->dom, base + idx);
+                       generic_handle_irq(virq);
+               }
+               pos = base + 32;
+       }
+
+       spin_unlock(&pcie->used_msi_lock);
+       chained_irq_exit(chip, desc);
+}
+
+static void tango_ack(struct irq_data *d)
+{
+       struct tango_pcie *pcie = d->chip_data;
+       u32 offset = (d->hwirq / 32) * 4;
+       u32 bit = BIT(d->hwirq % 32);
+
+       writel_relaxed(bit, pcie->base + SMP8759_STATUS + offset);
+}
+
+static void update_msi_enable(struct irq_data *d, bool unmask)
+{
+       unsigned long flags;
+       struct tango_pcie *pcie = d->chip_data;
+       u32 offset = (d->hwirq / 32) * 4;
+       u32 bit = BIT(d->hwirq % 32);
+       u32 val;
+
+       spin_lock_irqsave(&pcie->used_msi_lock, flags);
+       val = readl_relaxed(pcie->base + SMP8759_ENABLE + offset);
+       val = unmask ? val | bit : val & ~bit;
+       writel_relaxed(val, pcie->base + SMP8759_ENABLE + offset);
+       spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+}
+
+static void tango_mask(struct irq_data *d)
+{
+       update_msi_enable(d, false);
+}
+
+static void tango_unmask(struct irq_data *d)
+{
+       update_msi_enable(d, true);
+}
+
+static int tango_set_affinity(struct irq_data *d, const struct cpumask *mask,
+                             bool force)
+{
+       return -EINVAL;
+}
+
+static void tango_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+       struct tango_pcie *pcie = d->chip_data;
+       msg->address_lo = lower_32_bits(pcie->msi_doorbell);
+       msg->address_hi = upper_32_bits(pcie->msi_doorbell);
+       msg->data = d->hwirq;
+}
+
+static struct irq_chip tango_chip = {
+       .irq_ack                = tango_ack,
+       .irq_mask               = tango_mask,
+       .irq_unmask             = tango_unmask,
+       .irq_set_affinity       = tango_set_affinity,
+       .irq_compose_msi_msg    = tango_compose_msi_msg,
+};
+
+static void msi_ack(struct irq_data *d)
+{
+       irq_chip_ack_parent(d);
+}
+
+static void msi_mask(struct irq_data *d)
+{
+       pci_msi_mask_irq(d);
+       irq_chip_mask_parent(d);
+}
+
+static void msi_unmask(struct irq_data *d)
+{
+       pci_msi_unmask_irq(d);
+       irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip msi_chip = {
+       .name = "MSI",
+       .irq_ack = msi_ack,
+       .irq_mask = msi_mask,
+       .irq_unmask = msi_unmask,
+};
+
+static struct msi_domain_info msi_dom_info = {
+       .flags  = MSI_FLAG_PCI_MSIX
+               | MSI_FLAG_USE_DEF_DOM_OPS
+               | MSI_FLAG_USE_DEF_CHIP_OPS,
+       .chip   = &msi_chip,
+};
+
+static int tango_irq_domain_alloc(struct irq_domain *dom, unsigned int virq,
+                                 unsigned int nr_irqs, void *args)
+{
+       struct tango_pcie *pcie = dom->host_data;
+       unsigned long flags;
+       int pos;
+
+       spin_lock_irqsave(&pcie->used_msi_lock, flags);
+       pos = find_first_zero_bit(pcie->used_msi, MSI_MAX);
+       if (pos >= MSI_MAX) {
+               spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+               return -ENOSPC;
+       }
+       __set_bit(pos, pcie->used_msi);
+       spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+       irq_domain_set_info(dom, virq, pos, &tango_chip,
+                       pcie, handle_edge_irq, NULL, NULL);
+
+       return 0;
+}
+
+static void tango_irq_domain_free(struct irq_domain *dom, unsigned int virq,
+                                 unsigned int nr_irqs)
+{
+       unsigned long flags;
+       struct irq_data *d = irq_domain_get_irq_data(dom, virq);
+       struct tango_pcie *pcie = d->chip_data;
+
+       spin_lock_irqsave(&pcie->used_msi_lock, flags);
+       __clear_bit(d->hwirq, pcie->used_msi);
+       spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+}
+
+static const struct irq_domain_ops dom_ops = {
+       .alloc  = tango_irq_domain_alloc,
+       .free   = tango_irq_domain_free,
 };
 
 static int smp8759_config_read(struct pci_bus *bus, unsigned int devfn,
@@ -76,7 +236,11 @@ static int tango_pcie_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct tango_pcie *pcie;
        struct resource *res;
-       int ret;
+       struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
+       struct irq_domain *msi_dom, *irq_dom;
+       struct of_pci_range_parser parser;
+       struct of_pci_range range;
+       int virq, offset;
 
        dev_warn(dev, "simultaneous PCI config and MMIO accesses may cause data corruption\n");
        add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
@@ -95,6 +259,41 @@ static int tango_pcie_probe(struct platform_device *pdev)
        if (!tango_pcie_link_up(pcie))
                return -ENODEV;
 
+       if (of_pci_dma_range_parser_init(&parser, dev->of_node) < 0)
+               return -ENOENT;
+
+       if (of_pci_range_parser_one(&parser, &range) == NULL)
+               return -ENOENT;
+
+       range.pci_addr += range.size;
+       pcie->msi_doorbell = range.pci_addr + res->start + SMP8759_DOORBELL;
+
+       for (offset = 0; offset < MSI_MAX / 8; offset += 4)
+               writel_relaxed(0, pcie->base + SMP8759_ENABLE + offset);
+
+       virq = platform_get_irq(pdev, 1);
+       if (virq <= 0) {
+               dev_err(dev, "Failed to map IRQ\n");
+               return -ENXIO;
+       }
+
+       irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &dom_ops, pcie);
+       if (!irq_dom) {
+               dev_err(dev, "Failed to create IRQ domain\n");
+               return -ENOMEM;
+       }
+
+       msi_dom = pci_msi_create_irq_domain(fwnode, &msi_dom_info, irq_dom);
+       if (!msi_dom) {
+               dev_err(dev, "Failed to create MSI domain\n");
+               irq_domain_remove(irq_dom);
+               return -ENOMEM;
+       }
+
+       pcie->dom = irq_dom;
+       spin_lock_init(&pcie->used_msi_lock);
+       irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie);
+
        return pci_host_common_probe(pdev, &smp8759_ecam_ops);
 }
 
diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c
deleted file mode 100644 (file)
index c68366c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Core PCI functionality used only by PCI hotplug */
-
-#include <linux/pci.h>
-#include <linux/export.h>
-#include "pci.h"
-
-int pci_hp_add_bridge(struct pci_dev *dev)
-{
-       struct pci_bus *parent = dev->bus;
-       int pass, busnr, start = parent->busn_res.start;
-       int end = parent->busn_res.end;
-
-       for (busnr = start; busnr <= end; busnr++) {
-               if (!pci_find_bus(pci_domain_nr(parent), busnr))
-                       break;
-       }
-       if (busnr-- > end) {
-               printk(KERN_ERR "No bus number available for hot-added bridge %s\n",
-                               pci_name(dev));
-               return -1;
-       }
-       for (pass = 0; pass < 2; pass++)
-               busnr = pci_scan_bridge(parent, dev, busnr, pass);
-       if (!dev->subordinate)
-               return -1;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(pci_hp_add_bridge);
index 5ed2dcaa8e27c0ebe0729c3f543a58261c86a651..5db6f1839dada041d5affbfedef46312360488e3 100644 (file)
@@ -462,18 +462,15 @@ static void enable_slot(struct acpiphp_slot *slot)
        acpiphp_rescan_slot(slot);
        max = acpiphp_max_busnr(bus);
        for (pass = 0; pass < 2; pass++) {
-               list_for_each_entry(dev, &bus->devices, bus_list) {
+               for_each_pci_bridge(dev, bus) {
                        if (PCI_SLOT(dev->devfn) != slot->device)
                                continue;
 
-                       if (pci_is_bridge(dev)) {
-                               max = pci_scan_bridge(bus, dev, max, pass);
-                               if (pass && dev->subordinate) {
-                                       check_hotplug_bridge(slot, dev);
-                                       pcibios_resource_survey_bus(dev->subordinate);
-                                       __pci_bus_size_bridges(dev->subordinate,
-                                                              &add_list);
-                               }
+                       max = pci_scan_bridge(bus, dev, max, pass);
+                       if (pass && dev->subordinate) {
+                               check_hotplug_bridge(slot, dev);
+                               pcibios_resource_survey_bus(dev->subordinate);
+                               __pci_bus_size_bridges(dev->subordinate, &add_list);
                        }
                }
        }
index 80c80017197daa8d2b128faf063b48d93eb05da0..f616358fa9382cc49eb7b515ebc5c29d224a2e8c 100644 (file)
@@ -286,14 +286,11 @@ int cpci_configure_slot(struct slot *slot)
        }
        parent = slot->dev->bus;
 
-       list_for_each_entry(dev, &parent->devices, bus_list) {
-               if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
-                       continue;
-               if (pci_is_bridge(dev))
+       for_each_pci_bridge(dev, parent) {
+               if (PCI_SLOT(dev->devfn) == PCI_SLOT(slot->devfn))
                        pci_hp_add_bridge(dev);
        }
 
-
        pci_assign_unassigned_bridge_resources(parent->self);
 
        pci_bus_add_devices(parent);
index 48c8a066a6b78fadd6cb3569036e26dcce47fee7..c2bbe6b65d06e444f60fb11ffd1fde4e6cd2753f 100644 (file)
@@ -410,7 +410,7 @@ void cpqhp_create_debugfs_files(struct controller *ctrl);
 void cpqhp_remove_debugfs_files(struct controller *ctrl);
 
 /* controller functions */
-void cpqhp_pushbutton_thread(unsigned long event_pointer);
+void cpqhp_pushbutton_thread(struct timer_list *t);
 irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data);
 int cpqhp_find_available_resources(struct controller *ctrl,
                                   void __iomem *rom_start);
index 4d06b84612559218233749d772d4c53dc1f0aaec..70967ac75265471dacc098abebd319b2699ecef4 100644 (file)
@@ -661,9 +661,8 @@ static int ctrl_slot_setup(struct controller *ctrl,
 
                slot->p_sm_slot = slot_entry;
 
-               init_timer(&slot->task_event);
+               timer_setup(&slot->task_event, cpqhp_pushbutton_thread, 0);
                slot->task_event.expires = jiffies + 5 * HZ;
-               slot->task_event.function = cpqhp_pushbutton_thread;
 
                /*FIXME: these capabilities aren't used but if they are
                 *       they need to be correctly implemented
index a55653b54eeddc5b53ac33bbd03f6e7d3f7dac79..a93069e739cb4d579f0a7aa14832529c0f023c7f 100644 (file)
@@ -47,7 +47,7 @@ static void interrupt_event_handler(struct controller *ctrl);
 
 
 static struct task_struct *cpqhp_event_thread;
-static unsigned long pushbutton_pending;       /* = 0 */
+static struct timer_list *pushbutton_pending;  /* = NULL */
 
 /* delay is in jiffies to wait for */
 static void long_delay(int delay)
@@ -1732,9 +1732,10 @@ static u32 remove_board(struct pci_func *func, u32 replace_flag, struct controll
        return 0;
 }
 
-static void pushbutton_helper_thread(unsigned long data)
+static void pushbutton_helper_thread(struct timer_list *t)
 {
-       pushbutton_pending = data;
+       pushbutton_pending = t;
+
        wake_up_process(cpqhp_event_thread);
 }
 
@@ -1883,13 +1884,13 @@ static void interrupt_event_handler(struct controller *ctrl)
                                        wait_for_ctrl_irq(ctrl);
 
                                        mutex_unlock(&ctrl->crit_sect);
-                                       init_timer(&p_slot->task_event);
+                                       timer_setup(&p_slot->task_event,
+                                                   pushbutton_helper_thread,
+                                                   0);
                                        p_slot->hp_slot = hp_slot;
                                        p_slot->ctrl = ctrl;
 /*                                     p_slot->physical_slot = physical_slot; */
                                        p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
-                                       p_slot->task_event.function = pushbutton_helper_thread;
-                                       p_slot->task_event.data = (u32) p_slot;
 
                                        dbg("add_timer p_slot = %p\n", p_slot);
                                        add_timer(&p_slot->task_event);
@@ -1920,15 +1921,15 @@ static void interrupt_event_handler(struct controller *ctrl)
  * Scheduled procedure to handle blocking stuff for the pushbuttons.
  * Handles all pending events and exits.
  */
-void cpqhp_pushbutton_thread(unsigned long slot)
+void cpqhp_pushbutton_thread(struct timer_list *t)
 {
        u8 hp_slot;
        u8 device;
        struct pci_func *func;
-       struct slot *p_slot = (struct slot *) slot;
+       struct slot *p_slot = from_timer(p_slot, t, task_event);
        struct controller *ctrl = (struct controller *) p_slot->ctrl;
 
-       pushbutton_pending = 0;
+       pushbutton_pending = NULL;
        hp_slot = p_slot->hp_slot;
 
        device = p_slot->device;
index dc1876feb06f9e4b12ebfb81c10ab4964394ef7a..25edd0b18b75186add7edf80fe274b4a93b36c8c 100644 (file)
@@ -1267,20 +1267,19 @@ static int unconfigure_boot_device(u8 busno, u8 device, u8 function)
                        size = size & 0xFFFFFFFC;
                        size = ~size + 1;
                        end_address = start_address + size - 1;
-                       if (ibmphp_find_resource(bus, start_address, &io, IO) < 0) {
-                               err("cannot find corresponding IO resource to remove\n");
-                               return -EIO;
-                       }
+                       if (ibmphp_find_resource(bus, start_address, &io, IO))
+                               goto report_search_failure;
+
                        debug("io->start = %x\n", io->start);
                        temp_end = io->end;
                        start_address = io->end + 1;
                        ibmphp_remove_resource(io);
                        /* This is needed b/c of the old I/O restrictions in the BIOS */
                        while (temp_end < end_address) {
-                               if (ibmphp_find_resource(bus, start_address, &io, IO) < 0) {
-                                       err("cannot find corresponding IO resource to remove\n");
-                                       return -EIO;
-                               }
+                               if (ibmphp_find_resource(bus, start_address,
+                                                        &io, IO))
+                                       goto report_search_failure;
+
                                debug("io->start = %x\n", io->start);
                                temp_end = io->end;
                                start_address = io->end + 1;
@@ -1327,6 +1326,10 @@ static int unconfigure_boot_device(u8 busno, u8 device, u8 function)
        }       /* end of for */
 
        return 0;
+
+report_search_failure:
+       err("cannot find corresponding IO resource to remove\n");
+       return -EIO;
 }
 
 static int unconfigure_boot_bridge(u8 busno, u8 device, u8 function)
index ec0b4c11ccd9dc95cdb738d03ae292744e34127e..83f3d4af3677537f282269ad1041f227f313f011 100644 (file)
@@ -113,10 +113,11 @@ static int board_added(struct slot *p_slot)
 
        retval = pciehp_configure_device(p_slot);
        if (retval) {
-               ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
-                        pci_domain_nr(parent), parent->number);
-               if (retval != -EEXIST)
+               if (retval != -EEXIST) {
+                       ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
+                                pci_domain_nr(parent), parent->number);
                        goto err_exit;
+               }
        }
 
        pciehp_green_led_on(p_slot);
index e5d5ce9e30106a8329e423bff084592c201606a7..7bab0606f1a9f1d04e9529a22b1354b1f73844c3 100644 (file)
@@ -50,14 +50,13 @@ static irqreturn_t pcie_isr(int irq, void *dev_id);
 static void start_int_poll_timer(struct controller *ctrl, int sec);
 
 /* This is the interrupt polling timeout function. */
-static void int_poll_timeout(unsigned long data)
+static void int_poll_timeout(struct timer_list *t)
 {
-       struct controller *ctrl = (struct controller *)data;
+       struct controller *ctrl = from_timer(ctrl, t, poll_timer);
 
        /* Poll for interrupt events.  regs == NULL => polling */
        pcie_isr(0, ctrl);
 
-       init_timer(&ctrl->poll_timer);
        if (!pciehp_poll_time)
                pciehp_poll_time = 2; /* default polling interval is 2 sec */
 
@@ -71,8 +70,6 @@ static void start_int_poll_timer(struct controller *ctrl, int sec)
        if ((sec <= 0) || (sec > 60))
                sec = 2;
 
-       ctrl->poll_timer.function = &int_poll_timeout;
-       ctrl->poll_timer.data = (unsigned long)ctrl;
        ctrl->poll_timer.expires = jiffies + sec * HZ;
        add_timer(&ctrl->poll_timer);
 }
@@ -83,7 +80,7 @@ static inline int pciehp_request_irq(struct controller *ctrl)
 
        /* Install interrupt polling timer. Start with 10 sec delay */
        if (pciehp_poll_mode) {
-               init_timer(&ctrl->poll_timer);
+               timer_setup(&ctrl->poll_timer, int_poll_timeout, 0);
                start_int_poll_timer(ctrl, 10);
                return 0;
        }
@@ -764,8 +761,7 @@ int pciehp_reset_slot(struct slot *slot, int probe)
        ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
                 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask);
        if (pciehp_poll_mode)
-               int_poll_timeout(ctrl->poll_timer.data);
-
+               int_poll_timeout(&ctrl->poll_timer);
        return 0;
 }
 
@@ -795,7 +791,7 @@ static int pcie_init_slot(struct controller *ctrl)
        if (!slot)
                return -ENOMEM;
 
-       slot->wq = alloc_workqueue("pciehp-%u", 0, 0, PSN(ctrl));
+       slot->wq = alloc_ordered_workqueue("pciehp-%u", 0, PSN(ctrl));
        if (!slot->wq)
                goto abort;
 
@@ -862,11 +858,16 @@ struct controller *pcie_init(struct pcie_device *dev)
        if (link_cap & PCI_EXP_LNKCAP_DLLLARC)
                ctrl->link_active_reporting = 1;
 
-       /* Clear all remaining event bits in Slot Status register */
+       /*
+        * Clear all remaining event bits in Slot Status register except
+        * Presence Detect Changed. We want to make sure possible
+        * hotplug event is triggered when the interrupt is unmasked so
+        * that we don't lose that event.
+        */
        pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
                PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
-               PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
-               PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
+               PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC |
+               PCI_EXP_SLTSTA_DLLSC);
 
        ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c LLActRep%c\n",
                (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,
index 19f30a9f461d50b3ec12847b67ed2eea251f16f5..2a1ca020cf5a792eac7103a19368b4883ab6a46e 100644 (file)
@@ -46,7 +46,11 @@ int pciehp_configure_device(struct slot *p_slot)
 
        dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
        if (dev) {
-               ctrl_err(ctrl, "Device %s already exists at %04x:%02x:00, cannot hot-add\n",
+               /*
+                * The device is already there. Either configured by the
+                * boot firmware or a previous hotplug event.
+                */
+               ctrl_dbg(ctrl, "Device %s already exists at %04x:%02x:00, skipping hot-add\n",
                         pci_name(dev), pci_domain_nr(parent), parent->number);
                pci_dev_put(dev);
                ret = -EEXIST;
@@ -60,9 +64,8 @@ int pciehp_configure_device(struct slot *p_slot)
                goto out;
        }
 
-       list_for_each_entry(dev, &parent->devices, bus_list)
-               if (pci_is_bridge(dev))
-                       pci_hp_add_bridge(dev);
+       for_each_pci_bridge(dev, parent)
+               pci_hp_add_bridge(dev);
 
        pci_assign_unassigned_bridge_resources(bridge);
        pcie_bus_configure_settings(parent);
index e5824c7b7b6b30195f46dd1d7a560021e55c11ae..4810e9626d9f12d64dcadba00da08dc2fc3526ce 100644 (file)
@@ -229,14 +229,13 @@ static inline int shpc_indirect_read(struct controller *ctrl, int index,
 /*
  * This is the interrupt polling timeout function.
  */
-static void int_poll_timeout(unsigned long data)
+static void int_poll_timeout(struct timer_list *t)
 {
-       struct controller *ctrl = (struct controller *)data;
+       struct controller *ctrl = from_timer(ctrl, t, poll_timer);
 
        /* Poll for interrupt events.  regs == NULL => polling */
        shpc_isr(0, ctrl);
 
-       init_timer(&ctrl->poll_timer);
        if (!shpchp_poll_time)
                shpchp_poll_time = 2; /* default polling interval is 2 sec */
 
@@ -252,8 +251,6 @@ static void start_int_poll_timer(struct controller *ctrl, int sec)
        if ((sec <= 0) || (sec > 60))
                sec = 2;
 
-       ctrl->poll_timer.function = &int_poll_timeout;
-       ctrl->poll_timer.data = (unsigned long)ctrl;
        ctrl->poll_timer.expires = jiffies + sec * HZ;
        add_timer(&ctrl->poll_timer);
 }
@@ -1054,7 +1051,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
 
        if (shpchp_poll_mode) {
                /* Install interrupt polling timer. Start with 10 sec delay */
-               init_timer(&ctrl->poll_timer);
+               timer_setup(&ctrl->poll_timer, int_poll_timeout, 0);
                start_int_poll_timer(ctrl, 10);
        } else {
                /* Installs the interrupt handler */
index f8cd3a27e3515e630639e86a8e58478517f5ec2a..ea63db58b4b136271ae1bed32ec5c668ccb40d69 100644 (file)
@@ -61,10 +61,8 @@ int shpchp_configure_device(struct slot *p_slot)
                goto out;
        }
 
-       list_for_each_entry(dev, &parent->devices, bus_list) {
-               if (PCI_SLOT(dev->devfn) != p_slot->device)
-                       continue;
-               if (pci_is_bridge(dev))
+       for_each_pci_bridge(dev, parent) {
+               if (PCI_SLOT(dev->devfn) == p_slot->device)
                        pci_hp_add_bridge(dev);
        }
 
index ac41c8be9200accd30e91938aea8ed896dac1ec0..6bacb8995e9641dfc0ab98d6a5e9f032bbd7f98e 100644 (file)
@@ -113,7 +113,7 @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
        return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
 }
 
-int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset)
+int pci_iov_add_virtfn(struct pci_dev *dev, int id)
 {
        int i;
        int rc = -ENOMEM;
@@ -134,7 +134,7 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset)
 
        virtfn->devfn = pci_iov_virtfn_devfn(dev, id);
        virtfn->vendor = dev->vendor;
-       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device);
+       virtfn->device = iov->vf_device;
        rc = pci_setup_device(virtfn);
        if (rc)
                goto failed0;
@@ -157,12 +157,8 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset)
                BUG_ON(rc);
        }
 
-       if (reset)
-               __pci_reset_function(virtfn);
-
        pci_device_add(virtfn, virtfn->bus);
 
-       pci_bus_add_device(virtfn);
        sprintf(buf, "virtfn%u", id);
        rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
        if (rc)
@@ -173,6 +169,8 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset)
 
        kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
 
+       pci_bus_add_device(virtfn);
+
        return 0;
 
 failed2:
@@ -187,7 +185,7 @@ failed:
        return rc;
 }
 
-void pci_iov_remove_virtfn(struct pci_dev *dev, int id, int reset)
+void pci_iov_remove_virtfn(struct pci_dev *dev, int id)
 {
        char buf[VIRTFN_ID_LEN];
        struct pci_dev *virtfn;
@@ -198,11 +196,6 @@ void pci_iov_remove_virtfn(struct pci_dev *dev, int id, int reset)
        if (!virtfn)
                return;
 
-       if (reset) {
-               device_release_driver(&virtfn->dev);
-               __pci_reset_function(virtfn);
-       }
-
        sprintf(buf, "virtfn%u", id);
        sysfs_remove_link(&dev->dev.kobj, buf);
        /*
@@ -317,7 +310,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
        pci_cfg_access_unlock(dev);
 
        for (i = 0; i < initial; i++) {
-               rc = pci_iov_add_virtfn(dev, i, 0);
+               rc = pci_iov_add_virtfn(dev, i);
                if (rc)
                        goto failed;
        }
@@ -329,7 +322,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
 
 failed:
        while (i--)
-               pci_iov_remove_virtfn(dev, i, 0);
+               pci_iov_remove_virtfn(dev, i);
 
 err_pcibios:
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
@@ -356,7 +349,7 @@ static void sriov_disable(struct pci_dev *dev)
                return;
 
        for (i = 0; i < iov->num_VFs; i++)
-               pci_iov_remove_virtfn(dev, i, 0);
+               pci_iov_remove_virtfn(dev, i);
 
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
        pci_cfg_access_lock(dev);
@@ -449,6 +442,7 @@ found:
        iov->nres = nres;
        iov->ctrl = ctrl;
        iov->total_VFs = total;
+       pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &iov->vf_device);
        iov->pgsz = pgsz;
        iov->self = dev;
        iov->drivers_autoprobe = true;
@@ -504,6 +498,14 @@ static void sriov_restore_state(struct pci_dev *dev)
        if (ctrl & PCI_SRIOV_CTRL_VFE)
                return;
 
+       /*
+        * Restore PCI_SRIOV_CTRL_ARI before pci_iov_set_numvfs() because
+        * it reads offset & stride, which depend on PCI_SRIOV_CTRL_ARI.
+        */
+       ctrl &= ~PCI_SRIOV_CTRL_ARI;
+       ctrl |= iov->ctrl & PCI_SRIOV_CTRL_ARI;
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl);
+
        for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++)
                pci_update_resource(dev, i);
 
@@ -724,7 +726,7 @@ int pci_vfs_assigned(struct pci_dev *dev)
         * determine the device ID for the VFs, the vendor ID will be the
         * same as the PF so there is no need to check for that one
         */
-       pci_read_config_word(dev, dev->sriov->pos + PCI_SRIOV_VF_DID, &dev_id);
+       dev_id = dev->sriov->vf_device;
 
        /* loop through all the VFs to see if we own any that are assigned */
        vfdev = pci_get_device(dev->vendor, dev_id, NULL);
index a8da543b3814b312a99af0ef1f3c3ef18e089478..4708eb9df71b0ebb7548b87e4cb4238a0b900b6a 100644 (file)
@@ -624,7 +624,7 @@ void acpi_pci_add_bus(struct pci_bus *bus)
        union acpi_object *obj;
        struct pci_host_bridge *bridge;
 
-       if (acpi_pci_disabled || !bus->bridge)
+       if (acpi_pci_disabled || !bus->bridge || !ACPI_HANDLE(bus->bridge))
                return;
 
        acpi_pci_slot_enumerate(bus);
index 8e075ea2743ef41b4ed08065f502527cbe804c82..7200909674442245e274b7fd038de56d7227131c 100644 (file)
@@ -648,6 +648,33 @@ exit:
        return count;
 }
 
+static ssize_t sriov_offset_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n", pdev->sriov->offset);
+}
+
+static ssize_t sriov_stride_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n", pdev->sriov->stride);
+}
+
+static ssize_t sriov_vf_device_show(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%x\n", pdev->sriov->vf_device);
+}
+
 static ssize_t sriov_drivers_autoprobe_show(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
@@ -676,6 +703,9 @@ static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs);
 static struct device_attribute sriov_numvfs_attr =
                __ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP),
                       sriov_numvfs_show, sriov_numvfs_store);
+static struct device_attribute sriov_offset_attr = __ATTR_RO(sriov_offset);
+static struct device_attribute sriov_stride_attr = __ATTR_RO(sriov_stride);
+static struct device_attribute sriov_vf_device_attr = __ATTR_RO(sriov_vf_device);
 static struct device_attribute sriov_drivers_autoprobe_attr =
                __ATTR(sriov_drivers_autoprobe, (S_IRUGO|S_IWUSR|S_IWGRP),
                       sriov_drivers_autoprobe_show, sriov_drivers_autoprobe_store);
@@ -1748,6 +1778,9 @@ static const struct attribute_group pci_dev_hp_attr_group = {
 static struct attribute *sriov_dev_attrs[] = {
        &sriov_totalvfs_attr.attr,
        &sriov_numvfs_attr.attr,
+       &sriov_offset_attr.attr,
+       &sriov_stride_attr.attr,
+       &sriov_vf_device_attr.attr,
        &sriov_drivers_autoprobe_attr.attr,
        NULL,
 };
@@ -1795,6 +1828,6 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
        NULL,
 };
 
-struct device_type pci_dev_type = {
+const struct device_type pci_dev_type = {
        .groups = pci_dev_attr_groups,
 };
index 6078dfc11b112a88aec1c58eb911de9f996b6644..b03e91aa8fec5b92e27a22458ab40aada62eb744 100644 (file)
@@ -2965,6 +2965,107 @@ bool pci_acs_path_enabled(struct pci_dev *start,
        return true;
 }
 
+/**
+ * pci_rebar_find_pos - find position of resize ctrl reg for BAR
+ * @pdev: PCI device
+ * @bar: BAR to find
+ *
+ * Helper to find the position of the ctrl register for a BAR.
+ * Returns -ENOTSUPP if resizable BARs are not supported at all.
+ * Returns -ENOENT if no ctrl register for the BAR could be found.
+ */
+static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
+{
+       unsigned int pos, nbars, i;
+       u32 ctrl;
+
+       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
+       if (!pos)
+               return -ENOTSUPP;
+
+       pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
+       nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >>
+                   PCI_REBAR_CTRL_NBAR_SHIFT;
+
+       for (i = 0; i < nbars; i++, pos += 8) {
+               int bar_idx;
+
+               pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
+               bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
+               if (bar_idx == bar)
+                       return pos;
+       }
+
+       return -ENOENT;
+}
+
+/**
+ * pci_rebar_get_possible_sizes - get possible sizes for BAR
+ * @pdev: PCI device
+ * @bar: BAR to query
+ *
+ * Get the possible sizes of a resizable BAR as bitmask defined in the spec
+ * (bit 0=1MB, bit 19=512GB). Returns 0 if BAR isn't resizable.
+ */
+u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar)
+{
+       int pos;
+       u32 cap;
+
+       pos = pci_rebar_find_pos(pdev, bar);
+       if (pos < 0)
+               return 0;
+
+       pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap);
+       return (cap & PCI_REBAR_CAP_SIZES) >> 4;
+}
+
+/**
+ * pci_rebar_get_current_size - get the current size of a BAR
+ * @pdev: PCI device
+ * @bar: BAR to set size to
+ *
+ * Read the size of a BAR from the resizable BAR config.
+ * Returns size if found or negative error code.
+ */
+int pci_rebar_get_current_size(struct pci_dev *pdev, int bar)
+{
+       int pos;
+       u32 ctrl;
+
+       pos = pci_rebar_find_pos(pdev, bar);
+       if (pos < 0)
+               return pos;
+
+       pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
+       return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> 8;
+}
+
+/**
+ * pci_rebar_set_size - set a new size for a BAR
+ * @pdev: PCI device
+ * @bar: BAR to set size to
+ * @size: new size as defined in the spec (0=1MB, 19=512GB)
+ *
+ * Set the new size of a BAR as defined in the spec.
+ * Returns zero if resizing was successful, error code otherwise.
+ */
+int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size)
+{
+       int pos;
+       u32 ctrl;
+
+       pos = pci_rebar_find_pos(pdev, bar);
+       if (pos < 0)
+               return pos;
+
+       pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
+       ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
+       ctrl |= size << 8;
+       pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
+       return 0;
+}
+
 /**
  * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
  * @dev: the PCI device
@@ -3471,7 +3572,7 @@ EXPORT_SYMBOL(devm_pci_remap_cfgspace);
  * All operations are managed and will be undone on driver detach.
  *
  * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
- * on failure. Usage example:
+ * on failure. Usage example::
  *
  *     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  *     base = devm_pci_remap_cfg_resource(&pdev->dev, res);
@@ -4145,35 +4246,6 @@ static void pci_dev_restore(struct pci_dev *dev)
                err_handler->reset_done(dev);
 }
 
-/**
- * __pci_reset_function - reset a PCI device function
- * @dev: PCI device to reset
- *
- * Some devices allow an individual function to be reset without affecting
- * other functions in the same device.  The PCI device must be responsive
- * to PCI config space in order to use this function.
- *
- * The device function is presumed to be unused when this function is called.
- * Resetting the device will make the contents of PCI configuration space
- * random, so any caller of this must be prepared to reinitialise the
- * device including MSI, bus mastering, BARs, decoding IO and memory spaces,
- * etc.
- *
- * Returns 0 if the device function was successfully reset or negative if the
- * device doesn't support resetting a single function.
- */
-int __pci_reset_function(struct pci_dev *dev)
-{
-       int ret;
-
-       pci_dev_lock(dev);
-       ret = __pci_reset_function_locked(dev);
-       pci_dev_unlock(dev);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(__pci_reset_function);
-
 /**
  * __pci_reset_function_locked - reset a PCI device function while holding
  * the @dev mutex lock.
@@ -4199,6 +4271,14 @@ int __pci_reset_function_locked(struct pci_dev *dev)
 
        might_sleep();
 
+       /*
+        * A reset method returns -ENOTTY if it doesn't support this device
+        * and we should try the next method.
+        *
+        * If it returns 0 (success), we're finished.  If it returns any
+        * other error, we're also finished: this indicates that further
+        * reset mechanisms might be broken on the device.
+        */
        rc = pci_dev_specific_reset(dev, 0);
        if (rc != -ENOTTY)
                return rc;
@@ -4264,8 +4344,8 @@ int pci_probe_reset_function(struct pci_dev *dev)
  *
  * This function does not just reset the PCI portion of a device, but
  * clears all the state associated with the device.  This function differs
- * from __pci_reset_function in that it saves and restores device state
- * over the reset.
+ * from __pci_reset_function_locked() in that it saves and restores device state
+ * over the reset and takes the PCI device lock.
  *
  * Returns 0 if the device function was successfully reset or negative if the
  * device doesn't support resetting a single function.
@@ -4300,7 +4380,7 @@ EXPORT_SYMBOL_GPL(pci_reset_function);
  *
  * This function does not just reset the PCI portion of a device, but
  * clears all the state associated with the device.  This function differs
- * from __pci_reset_function() in that it saves and restores device state
+ * from __pci_reset_function_locked() in that it saves and restores device state
  * over the reset.  It also differs from pci_reset_function() in that it
  * requires the PCI device lock to be held.
  *
@@ -4356,6 +4436,10 @@ static bool pci_bus_resetable(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
+
+       if (bus->self && (bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
+               return false;
+
        list_for_each_entry(dev, &bus->devices, bus_list) {
                if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
                    (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
@@ -4420,6 +4504,10 @@ static bool pci_slot_resetable(struct pci_slot *slot)
 {
        struct pci_dev *dev;
 
+       if (slot->bus->self &&
+           (slot->bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
+               return false;
+
        list_for_each_entry(dev, &slot->bus->devices, bus_list) {
                if (!dev->slot || dev->slot != slot)
                        continue;
index a6560c9baa52acb766ade748a0473cf74af6cd77..39eaacd122d8bd59040ca35b6c54e6383fa6739f 100644 (file)
@@ -192,7 +192,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
 }
 extern const struct attribute_group *pci_dev_groups[];
 extern const struct attribute_group *pcibus_groups[];
-extern struct device_type pci_dev_type;
+extern const struct device_type pci_dev_type;
 extern const struct attribute_group *pci_bus_groups[];
 
 
@@ -263,6 +263,7 @@ struct pci_sriov {
        u16 num_VFs;            /* number of VFs available */
        u16 offset;             /* first VF Routing ID offset */
        u16 stride;             /* following VF stride */
+       u16 vf_device;          /* VF device ID */
        u32 pgsz;               /* page size for BAR alignment */
        u8 link;                /* Function Dependency Link */
        u8 max_VF_buses;        /* max buses consumed by VFs */
@@ -366,4 +367,12 @@ int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
                          struct resource *res);
 #endif
 
+u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar);
+int pci_rebar_get_current_size(struct pci_dev *pdev, int bar);
+int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size);
+static inline u64 pci_rebar_size_to_bytes(int size)
+{
+       return 1ULL << (size + 20);
+}
+
 #endif /* DRIVERS_PCI_H */
index 890efcc574cbb98599d24cc400cc5323c6bcafeb..744805232155ccb15c7020ca3fdcab08bd50af7c 100644 (file)
@@ -390,7 +390,14 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
                 * If the error is reported by an end point, we think this
                 * error is related to the upstream link of the end point.
                 */
-               pci_walk_bus(dev->bus, cb, &result_data);
+               if (state == pci_channel_io_normal)
+                       /*
+                        * the error is non fatal so the bus is ok, just invoke
+                        * the callback for the function that logged the error.
+                        */
+                       cb(dev, &result_data);
+               else
+                       pci_walk_bus(dev->bus, cb, &result_data);
        }
 
        return result_data.result;
index 1dfa10cc566bebed005c2fe11a72c85a37036c32..d240ffab24c1326eaa7e44f054682ed881fafe26 100644 (file)
@@ -450,24 +450,25 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
        if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
                return;
 
-       /* Choose the greater of the two T_cmn_mode_rstr_time */
-       val1 = (upreg->l1ss_cap >> 8) & 0xFF;
-       val2 = (upreg->l1ss_cap >> 8) & 0xFF;
+       /* Choose the greater of the two Port Common_Mode_Restore_Times */
+       val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
+       val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
        if (val1 > val2)
                link->l1ss.ctl1 |= val1 << 8;
        else
                link->l1ss.ctl1 |= val2 << 8;
+
        /*
         * We currently use LTR L1.2 threshold to be fixed constant picked from
         * Intel's coreboot.
         */
        link->l1ss.ctl1 |= LTR_L1_2_THRESHOLD_BITS;
 
-       /* Choose the greater of the two T_pwr_on */
-       val1 = (upreg->l1ss_cap >> 19) & 0x1F;
-       scale1 = (upreg->l1ss_cap >> 16) & 0x03;
-       val2 = (dwreg->l1ss_cap >> 19) & 0x1F;
-       scale2 = (dwreg->l1ss_cap >> 16) & 0x03;
+       /* Choose the greater of the two Port T_POWER_ON times */
+       val1   = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
+       scale1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
+       val2   = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
+       scale2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
 
        if (calc_l1ss_pwron(link->pdev, scale1, val1) >
            calc_l1ss_pwron(link->downstream, scale2, val2))
@@ -646,21 +647,26 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
 
        if (enable_req & ASPM_STATE_L1_2_MASK) {
 
-               /* Program T_pwr_on in both ports */
+               /* Program T_POWER_ON times in both ports */
                pci_write_config_dword(parent, up_cap_ptr + PCI_L1SS_CTL2,
                                       link->l1ss.ctl2);
                pci_write_config_dword(child, dw_cap_ptr + PCI_L1SS_CTL2,
                                       link->l1ss.ctl2);
 
-               /* Program T_cmn_mode in parent */
+               /* Program Common_Mode_Restore_Time in upstream device */
                pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
-                                       0xFF00, link->l1ss.ctl1);
-
-               /* Program LTR L1.2 threshold in both ports */
-               pci_clear_and_set_dword(parent, dw_cap_ptr + PCI_L1SS_CTL1,
-                                       0xE3FF0000, link->l1ss.ctl1);
+                                       PCI_L1SS_CTL1_CM_RESTORE_TIME,
+                                       link->l1ss.ctl1);
+
+               /* Program LTR_L1.2_THRESHOLD time in both ports */
+               pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+                                       PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
+                                       PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
+                                       link->l1ss.ctl1);
                pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
-                                       0xE3FF0000, link->l1ss.ctl1);
+                                       PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
+                                       PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
+                                       link->l1ss.ctl1);
        }
 
        val = 0;
@@ -802,10 +808,14 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
 
        /*
         * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe
-        * hierarchies.
+        * hierarchies.  Note that some PCIe host implementations omit
+        * the root ports entirely, in which case a downstream port on
+        * a switch may become the root of the link state chain for all
+        * its subordinate endpoints.
         */
        if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
-           pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) {
+           pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE ||
+           !pdev->bus->parent->self) {
                link->root = link;
        } else {
                struct pcie_link_state *parent;
index fafdb165dd2ed663779f77bc59b3da3fb32af5c4..df290aa58dce93fd1889d3f0a6740003852b3023 100644 (file)
@@ -226,6 +226,9 @@ static void pcie_pme_work_fn(struct work_struct *work)
                        break;
 
                pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
+               if (rtsta == (u32) ~0)
+                       break;
+
                if (rtsta & PCI_EXP_RTSTA_PME) {
                        /*
                         * Clear PME status of the port.  If there are other
@@ -273,7 +276,7 @@ static irqreturn_t pcie_pme_irq(int irq, void *context)
        spin_lock_irqsave(&data->lock, flags);
        pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
 
-       if (!(rtsta & PCI_EXP_RTSTA_PME)) {
+       if (rtsta == (u32) ~0 || !(rtsta & PCI_EXP_RTSTA_PME)) {
                spin_unlock_irqrestore(&data->lock, flags);
                return IRQ_NONE;
        }
index 313a21df1692fa62f2330e55121aa0788e48ce29..3cd5eb48644a5aad141d59acbebeeb87f97e4b2f 100644 (file)
@@ -43,134 +43,113 @@ static void release_pcie_device(struct device *dev)
        kfree(to_pcie_device(dev));
 }
 
-/**
- * pcie_port_enable_irq_vec - try to set up MSI-X or MSI as interrupt mode
- * for given port
- * @dev: PCI Express port to handle
- * @irqs: Array of interrupt vectors to populate
- * @mask: Bitmask of port capabilities returned by get_port_device_capability()
- *
- * Return value: 0 on success, error code on failure
+/*
+ * Fill in *pme, *aer, *dpc with the relevant Interrupt Message Numbers if
+ * services are enabled in "mask".  Return the number of MSI/MSI-X vectors
+ * required to accommodate the largest Message Number.
  */
-static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
+static int pcie_message_numbers(struct pci_dev *dev, int mask,
+                               u32 *pme, u32 *aer, u32 *dpc)
 {
-       int nr_entries, entry, nvec = 0;
+       u32 nvec = 0, pos, reg32;
+       u16 reg16;
 
        /*
-        * Allocate as many entries as the port wants, so that we can check
-        * which of them will be useful.  Moreover, if nr_entries is correctly
-        * equal to the number of entries this port actually uses, we'll happily
-        * go through without any tricks.
+        * The Interrupt Message Number indicates which vector is used, i.e.,
+        * the MSI-X table entry or the MSI offset between the base Message
+        * Data and the generated interrupt message.  See PCIe r3.1, sec
+        * 7.8.2, 7.10.10, 7.31.2.
         */
-       nr_entries = pci_alloc_irq_vectors(dev, 1, PCIE_PORT_MAX_MSI_ENTRIES,
-                       PCI_IRQ_MSIX | PCI_IRQ_MSI);
-       if (nr_entries < 0)
-               return nr_entries;
 
        if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
-               u16 reg16;
-
-               /*
-                * Per PCIe r3.1, sec 6.1.6, "PME and Hot-Plug Event
-                * interrupts (when both are implemented) always share the
-                * same MSI or MSI-X vector, as indicated by the Interrupt
-                * Message Number field in the PCI Express Capabilities
-                * register".
-                *
-                * Per sec 7.8.2, "For MSI, the [Interrupt Message Number]
-                * indicates the offset between the base Message Data and
-                * the interrupt message that is generated."
-                *
-                * "For MSI-X, the [Interrupt Message Number] indicates
-                * which MSI-X Table entry is used to generate the
-                * interrupt message."
-                */
                pcie_capability_read_word(dev, PCI_EXP_FLAGS, &reg16);
-               entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
-               if (entry >= nr_entries)
-                       goto out_free_irqs;
-
-               irqs[PCIE_PORT_SERVICE_PME_SHIFT] = pci_irq_vector(dev, entry);
-               irqs[PCIE_PORT_SERVICE_HP_SHIFT] = pci_irq_vector(dev, entry);
-
-               nvec = max(nvec, entry + 1);
+               *pme = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
+               nvec = *pme + 1;
        }
 
        if (mask & PCIE_PORT_SERVICE_AER) {
-               u32 reg32, pos;
-
-               /*
-                * Per PCIe r3.1, sec 7.10.10, the Advanced Error Interrupt
-                * Message Number in the Root Error Status register
-                * indicates which MSI/MSI-X vector is used for AER.
-                *
-                * "For MSI, the [Advanced Error Interrupt Message Number]
-                * indicates the offset between the base Message Data and
-                * the interrupt message that is generated."
-                *
-                * "For MSI-X, the [Advanced Error Interrupt Message
-                * Number] indicates which MSI-X Table entry is used to
-                * generate the interrupt message."
-                */
                pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
-               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
-               entry = reg32 >> 27;
-               if (entry >= nr_entries)
-                       goto out_free_irqs;
-
-               irqs[PCIE_PORT_SERVICE_AER_SHIFT] = pci_irq_vector(dev, entry);
-
-               nvec = max(nvec, entry + 1);
+               if (pos) {
+                       pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS,
+                                             &reg32);
+                       *aer = (reg32 & PCI_ERR_ROOT_AER_IRQ) >> 27;
+                       nvec = max(nvec, *aer + 1);
+               }
        }
 
        if (mask & PCIE_PORT_SERVICE_DPC) {
-               u16 reg16, pos;
-
-               /*
-                * Per PCIe r4.0 (v0.9), sec 7.9.15.2, the DPC Interrupt
-                * Message Number in the DPC Capability register indicates
-                * which MSI/MSI-X vector is used for DPC.
-                *
-                * "For MSI, the [DPC Interrupt Message Number] indicates
-                * the offset between the base Message Data and the
-                * interrupt message that is generated."
-                *
-                * "For MSI-X, the [DPC Interrupt Message Number] indicates
-                * which MSI-X Table entry is used to generate the
-                * interrupt message."
-                */
                pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC);
-               pci_read_config_word(dev, pos + PCI_EXP_DPC_CAP, &reg16);
-               entry = reg16 & 0x1f;
-               if (entry >= nr_entries)
-                       goto out_free_irqs;
+               if (pos) {
+                       pci_read_config_word(dev, pos + PCI_EXP_DPC_CAP,
+                                            &reg16);
+                       *dpc = reg16 & PCI_EXP_DPC_IRQ;
+                       nvec = max(nvec, *dpc + 1);
+               }
+       }
+
+       return nvec;
+}
 
-               irqs[PCIE_PORT_SERVICE_DPC_SHIFT] = pci_irq_vector(dev, entry);
+/**
+ * pcie_port_enable_irq_vec - try to set up MSI-X or MSI as interrupt mode
+ * for given port
+ * @dev: PCI Express port to handle
+ * @irqs: Array of interrupt vectors to populate
+ * @mask: Bitmask of port capabilities returned by get_port_device_capability()
+ *
+ * Return value: 0 on success, error code on failure
+ */
+static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
+{
+       int nr_entries, nvec;
+       u32 pme = 0, aer = 0, dpc = 0;
 
-               nvec = max(nvec, entry + 1);
+       /* Allocate the maximum possible number of MSI/MSI-X vectors */
+       nr_entries = pci_alloc_irq_vectors(dev, 1, PCIE_PORT_MAX_MSI_ENTRIES,
+                       PCI_IRQ_MSIX | PCI_IRQ_MSI);
+       if (nr_entries < 0)
+               return nr_entries;
+
+       /* See how many and which Interrupt Message Numbers we actually use */
+       nvec = pcie_message_numbers(dev, mask, &pme, &aer, &dpc);
+       if (nvec > nr_entries) {
+               pci_free_irq_vectors(dev);
+               return -EIO;
        }
 
        /*
-        * If nvec is equal to the allocated number of entries, we can just use
-        * what we have.  Otherwise, the port has some extra entries not for the
-        * services we know and we need to work around that.
+        * If we allocated more than we need, free them and reallocate fewer.
+        *
+        * Reallocating may change the specific vectors we get, so
+        * pci_irq_vector() must be done *after* the reallocation.
+        *
+        * If we're using MSI, hardware is *allowed* to change the Interrupt
+        * Message Numbers when we free and reallocate the vectors, but we
+        * assume it won't because we allocate enough vectors for the
+        * biggest Message Number we found.
         */
        if (nvec != nr_entries) {
-               /* Drop the temporary MSI-X setup */
                pci_free_irq_vectors(dev);
 
-               /* Now allocate the MSI-X vectors for real */
                nr_entries = pci_alloc_irq_vectors(dev, nvec, nvec,
                                PCI_IRQ_MSIX | PCI_IRQ_MSI);
                if (nr_entries < 0)
                        return nr_entries;
        }
 
-       return 0;
+       /* PME and hotplug share an MSI/MSI-X vector */
+       if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
+               irqs[PCIE_PORT_SERVICE_PME_SHIFT] = pci_irq_vector(dev, pme);
+               irqs[PCIE_PORT_SERVICE_HP_SHIFT] = pci_irq_vector(dev, pme);
+       }
 
-out_free_irqs:
-       pci_free_irq_vectors(dev);
-       return -EIO;
+       if (mask & PCIE_PORT_SERVICE_AER)
+               irqs[PCIE_PORT_SERVICE_AER_SHIFT] = pci_irq_vector(dev, aer);
+
+       if (mask & PCIE_PORT_SERVICE_DPC)
+               irqs[PCIE_PORT_SERVICE_DPC_SHIFT] = pci_irq_vector(dev, dpc);
+
+       return 0;
 }
 
 /**
index 083276e03c38d924886a9e1d386deaee5b9e06e5..b350d12b39e33b9fec942a0654ca3f7def5c8d6e 100644 (file)
@@ -246,6 +246,7 @@ static struct pci_driver pcie_portdriver = {
 
        .probe          = pcie_portdrv_probe,
        .remove         = pcie_portdrv_remove,
+       .shutdown       = pcie_portdrv_remove,
 
        .err_handler    = &pcie_portdrv_err_handler,
 
index ff94b69738a87a8ec5b77e57624e1412c7ab4916..14e0ea1ff38b3745111ead4fba31a9fc124c1235 100644 (file)
@@ -959,7 +959,21 @@ static void pci_enable_crs(struct pci_dev *pdev)
                                         PCI_EXP_RTCTL_CRSSVE);
 }
 
+static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
+                                             unsigned int available_buses);
+
 /*
+ * pci_scan_bridge_extend() - Scan buses behind a bridge
+ * @bus: Parent bus the bridge is on
+ * @dev: Bridge itself
+ * @max: Starting subordinate number of buses behind this bridge
+ * @available_buses: Total number of buses available for this bridge and
+ *                  the devices below. After the minimal bus space has
+ *                  been allocated the remaining buses will be
+ *                  distributed equally between hotplug-capable bridges.
+ * @pass: Either %0 (scan already configured bridges) or %1 (scan bridges
+ *        that need to be reconfigured.
+ *
  * If it's a bridge, configure it and scan the bus behind it.
  * For CardBus bridges, we don't scan behind as the devices will
  * be handled by the bridge driver itself.
@@ -969,7 +983,9 @@ static void pci_enable_crs(struct pci_dev *pdev)
  * them, we proceed to assigning numbers to the remaining buses in
  * order to avoid overlaps between old and new bus numbers.
  */
-int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
+static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
+                                 int max, unsigned int available_buses,
+                                 int pass)
 {
        struct pci_bus *child;
        int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
@@ -1076,9 +1092,13 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
                        child = pci_add_new_bus(bus, dev, max+1);
                        if (!child)
                                goto out;
-                       pci_bus_insert_busn_res(child, max+1, 0xff);
+                       pci_bus_insert_busn_res(child, max+1,
+                                               bus->busn_res.end);
                }
                max++;
+               if (available_buses)
+                       available_buses--;
+
                buses = (buses & 0xff000000)
                      | ((unsigned int)(child->primary)     <<  0)
                      | ((unsigned int)(child->busn_res.start)   <<  8)
@@ -1100,7 +1120,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
 
                if (!is_cardbus) {
                        child->bridge_ctl = bctl;
-                       max = pci_scan_child_bus(child);
+                       max = pci_scan_child_bus_extend(child, available_buses);
                } else {
                        /*
                         * For CardBus bridges, we leave 4 bus numbers
@@ -1168,6 +1188,28 @@ out:
 
        return max;
 }
+
+/*
+ * pci_scan_bridge() - Scan buses behind a bridge
+ * @bus: Parent bus the bridge is on
+ * @dev: Bridge itself
+ * @max: Starting subordinate number of buses behind this bridge
+ * @pass: Either %0 (scan already configured bridges) or %1 (scan bridges
+ *        that need to be reconfigured.
+ *
+ * If it's a bridge, configure it and scan the bus behind it.
+ * For CardBus bridges, we don't scan behind as the devices will
+ * be handled by the bridge driver itself.
+ *
+ * We need to process bridges in two passes -- first we scan those
+ * already configured by the BIOS and after we are done with all of
+ * them, we proceed to assigning numbers to the remaining buses in
+ * order to avoid overlaps between old and new bus numbers.
+ */
+int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
+{
+       return pci_scan_bridge_extend(bus, dev, max, 0, pass);
+}
 EXPORT_SYMBOL(pci_scan_bridge);
 
 /*
@@ -2396,9 +2438,24 @@ void __weak pcibios_fixup_bus(struct pci_bus *bus)
        /* nothing to do, expected to be removed in the future */
 }
 
-unsigned int pci_scan_child_bus(struct pci_bus *bus)
+/**
+ * pci_scan_child_bus_extend() - Scan devices below a bus
+ * @bus: Bus to scan for devices
+ * @available_buses: Total number of buses available (%0 does not try to
+ *                  extend beyond the minimal)
+ *
+ * Scans devices below @bus including subordinate buses. Returns new
+ * subordinate number including all the found devices. Passing
+ * @available_buses causes the remaining bus space to be distributed
+ * equally between hotplug-capable bridges to allow future extension of the
+ * hierarchy.
+ */
+static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
+                                             unsigned int available_buses)
 {
-       unsigned int devfn, pass, max = bus->busn_res.start;
+       unsigned int used_buses, normal_bridges = 0, hotplug_bridges = 0;
+       unsigned int start = bus->busn_res.start;
+       unsigned int devfn, cmax, max = start;
        struct pci_dev *dev;
 
        dev_dbg(&bus->dev, "scanning bus\n");
@@ -2408,7 +2465,8 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
                pci_scan_slot(bus, devfn);
 
        /* Reserve buses for SR-IOV capability. */
-       max += pci_iov_bus_range(bus);
+       used_buses = pci_iov_bus_range(bus);
+       max += used_buses;
 
        /*
         * After performing arch-dependent fixup of the bus, look behind
@@ -2420,19 +2478,73 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
                bus->is_added = 1;
        }
 
-       for (pass = 0; pass < 2; pass++)
-               list_for_each_entry(dev, &bus->devices, bus_list) {
-                       if (pci_is_bridge(dev))
-                               max = pci_scan_bridge(bus, dev, max, pass);
+       /*
+        * Calculate how many hotplug bridges and normal bridges there
+        * are on this bus. We will distribute the additional available
+        * buses between hotplug bridges.
+        */
+       for_each_pci_bridge(dev, bus) {
+               if (dev->is_hotplug_bridge)
+                       hotplug_bridges++;
+               else
+                       normal_bridges++;
+       }
+
+       /*
+        * Scan bridges that are already configured. We don't touch them
+        * unless they are misconfigured (which will be done in the second
+        * scan below).
+        */
+       for_each_pci_bridge(dev, bus) {
+               cmax = max;
+               max = pci_scan_bridge_extend(bus, dev, max, 0, 0);
+               used_buses += cmax - max;
+       }
+
+       /* Scan bridges that need to be reconfigured */
+       for_each_pci_bridge(dev, bus) {
+               unsigned int buses = 0;
+
+               if (!hotplug_bridges && normal_bridges == 1) {
+                       /*
+                        * There is only one bridge on the bus (upstream
+                        * port) so it gets all available buses which it
+                        * can then distribute to the possible hotplug
+                        * bridges below.
+                        */
+                       buses = available_buses;
+               } else if (dev->is_hotplug_bridge) {
+                       /*
+                        * Distribute the extra buses between hotplug
+                        * bridges if any.
+                        */
+                       buses = available_buses / hotplug_bridges;
+                       buses = min(buses, available_buses - used_buses);
                }
 
+               cmax = max;
+               max = pci_scan_bridge_extend(bus, dev, cmax, buses, 1);
+               used_buses += max - cmax;
+       }
+
        /*
         * Make sure a hotplug bridge has at least the minimum requested
-        * number of buses.
+        * number of buses but allow it to grow up to the maximum available
+        * bus number of there is room.
         */
-       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;
+       if (bus->self && bus->self->is_hotplug_bridge) {
+               used_buses = max_t(unsigned int, available_buses,
+                                  pci_hotplug_bus_size - 1);
+               if (max - start < used_buses) {
+                       max = start + used_buses;
+
+                       /* Do not allocate more buses than we have room left */
+                       if (max > bus->busn_res.end)
+                               max = bus->busn_res.end;
+
+                       dev_dbg(&bus->dev, "%pR extended by %#02x\n",
+                               &bus->busn_res, max - start);
+               }
        }
 
        /*
@@ -2445,6 +2557,18 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
        dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max);
        return max;
 }
+
+/**
+ * pci_scan_child_bus() - Scan devices below a bus
+ * @bus: Bus to scan for devices
+ *
+ * Scans devices below @bus including subordinate buses. Returns new
+ * subordinate number including all the found devices.
+ */
+unsigned int pci_scan_child_bus(struct pci_bus *bus)
+{
+       return pci_scan_child_bus_extend(bus, 0);
+}
 EXPORT_SYMBOL_GPL(pci_scan_child_bus);
 
 /**
@@ -2737,3 +2861,38 @@ void __init pci_sort_breadthfirst(void)
 {
        bus_sort_breadthfirst(&pci_bus_type, &pci_sort_bf_cmp);
 }
+
+int pci_hp_add_bridge(struct pci_dev *dev)
+{
+       struct pci_bus *parent = dev->bus;
+       int busnr, start = parent->busn_res.start;
+       unsigned int available_buses = 0;
+       int end = parent->busn_res.end;
+
+       for (busnr = start; busnr <= end; busnr++) {
+               if (!pci_find_bus(pci_domain_nr(parent), busnr))
+                       break;
+       }
+       if (busnr-- > end) {
+               dev_err(&dev->dev, "No bus number available for hot-added bridge\n");
+               return -1;
+       }
+
+       /* Scan bridges that are already configured */
+       busnr = pci_scan_bridge(parent, dev, busnr, 0);
+
+       /*
+        * Distribute the available bus numbers between hotplug-capable
+        * bridges to make extending the chain later possible.
+        */
+       available_buses = end - busnr;
+
+       /* Scan bridges that need to be reconfigured */
+       pci_scan_bridge_extend(parent, dev, busnr, available_buses, 1);
+
+       if (!dev->subordinate)
+               return -1;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pci_hp_add_bridge);
index a4d33619a7bb67157f128f0009a58f9d21c7c727..cb89ff5f9cb452bf33704513e219a90d3a4e3511 100644 (file)
@@ -3365,6 +3365,13 @@ 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);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
 
+/*
+ * Root port on some Cavium CN8xxx chips do not successfully complete a bus
+ * reset when used with certain child devices.  After the reset, config
+ * accesses to the child may fail.
+ */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CAVIUM, 0xa100, quirk_no_bus_reset);
+
 static void quirk_no_pm_reset(struct pci_dev *dev)
 {
        /*
@@ -4211,17 +4218,32 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
 #endif
 }
 
+static bool pci_quirk_cavium_acs_match(struct pci_dev *dev)
+{
+       /*
+        * Effectively selects all downstream ports for whole ThunderX 1
+        * family by 0xf800 mask (which represents 8 SoCs), while the lower
+        * bits of device ID are used to indicate which subdevice is used
+        * within the SoC.
+        */
+       return (pci_is_pcie(dev) &&
+               (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) &&
+               ((dev->device & 0xf800) == 0xa000));
+}
+
 static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
 {
        /*
-        * Cavium devices matching this quirk do not perform peer-to-peer
-        * with other functions, allowing masking out these bits as if they
-        * were unimplemented in the ACS capability.
+        * Cavium root ports don't advertise an ACS capability.  However,
+        * the RTL internally implements similar protection as if ACS had
+        * Request Redirection, Completion Redirection, Source Validation,
+        * and Upstream Forwarding features enabled.  Assert that the
+        * hardware implements and enables equivalent ACS functionality for
+        * these flags.
         */
-       acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
-                      PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
+       acs_flags &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_SV | PCI_ACS_UF);
 
-       if (!((dev->device >= 0xa000) && (dev->device <= 0xa0ff)))
+       if (!pci_quirk_cavium_acs_match(dev))
                return -ENOTTY;
 
        return acs_flags ? 0 : 1;
@@ -4799,3 +4821,11 @@ static void quirk_no_ats(struct pci_dev *pdev)
 /* AMD Stoney platform GPU */
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_no_ats);
 #endif /* CONFIG_PCI_ATS */
+
+/* Freescale PCIe doesn't support MSI in RC mode */
+static void quirk_fsl_no_msi(struct pci_dev *pdev)
+{
+       if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
+               pdev->no_msi = 1;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
index 73a03d3825903b4cf8674c727d5eac8cf2cb082c..2fa0dbde36b7ab5a711c1b9b0b24052e286b9010 100644 (file)
@@ -19,9 +19,9 @@ static void pci_stop_dev(struct pci_dev *dev)
        pci_pme_active(dev, false);
 
        if (dev->is_added) {
+               device_release_driver(&dev->dev);
                pci_proc_detach_device(dev);
                pci_remove_sysfs_dev_files(dev);
-               device_release_driver(&dev->dev);
                dev->is_added = 0;
        }
 
index b6edb187d160c6dda3fb4bbccb5b0b85877ec4f5..1f5e6af96c834307c8acf0afcab4b8b437fb3226 100644 (file)
@@ -147,12 +147,8 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
                return NULL;
 
        rom = ioremap(start, *size);
-       if (!rom) {
-               /* restore enable if ioremap fails */
-               if (!(res->flags & IORESOURCE_ROM_ENABLE))
-                       pci_disable_rom(pdev);
-               return NULL;
-       }
+       if (!rom)
+               goto err_ioremap;
 
        /*
         * Try to find the true size of the ROM since sometimes the PCI window
@@ -160,7 +156,18 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
         * True size is important if the ROM is going to be copied.
         */
        *size = pci_get_rom_size(pdev, rom, *size);
+       if (!*size)
+               goto invalid_rom;
+
        return rom;
+
+invalid_rom:
+       iounmap(rom);
+err_ioremap:
+       /* restore enable if ioremap fails */
+       if (!(res->flags & IORESOURCE_ROM_ENABLE))
+               pci_disable_rom(pdev);
+       return NULL;
 }
 EXPORT_SYMBOL(pci_map_rom);
 
index 958da7db90331c44315f95ab90553c586d918c46..b1ad466199ad74d207b0c46c01c0d0d19adde44a 100644 (file)
@@ -1518,13 +1518,16 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge,
                break;
        }
 }
+
+#define PCI_RES_TYPE_MASK \
+       (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH |\
+        IORESOURCE_MEM_64)
+
 static void pci_bridge_release_resources(struct pci_bus *bus,
                                          unsigned long type)
 {
        struct pci_dev *dev = bus->self;
        struct resource *r;
-       unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
-                                 IORESOURCE_PREFETCH | IORESOURCE_MEM_64;
        unsigned old_flags = 0;
        struct resource *b_res;
        int idx = 1;
@@ -1567,7 +1570,7 @@ static void pci_bridge_release_resources(struct pci_bus *bus,
         */
        release_child_resources(r);
        if (!release_resource(r)) {
-               type = old_flags = r->flags & type_mask;
+               type = old_flags = r->flags & PCI_RES_TYPE_MASK;
                dev_printk(KERN_DEBUG, &dev->dev, "resource %d %pR released\n",
                                        PCI_BRIDGE_RESOURCES + idx, r);
                /* keep the old size */
@@ -1758,8 +1761,6 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
        enum release_type rel_type = leaf_only;
        LIST_HEAD(fail_head);
        struct pci_dev_resource *fail_res;
-       unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
-                                 IORESOURCE_PREFETCH | IORESOURCE_MEM_64;
        int pci_try_num = 1;
        enum enable_type enable_local;
 
@@ -1818,7 +1819,7 @@ again:
         */
        list_for_each_entry(fail_res, &fail_head, list)
                pci_bus_release_bridge_resources(fail_res->dev->bus,
-                                                fail_res->flags & type_mask,
+                                                fail_res->flags & PCI_RES_TYPE_MASK,
                                                 rel_type);
 
        /* restore size and flags */
@@ -1853,6 +1854,175 @@ void __init pci_assign_unassigned_resources(void)
        }
 }
 
+static void extend_bridge_window(struct pci_dev *bridge, struct resource *res,
+                       struct list_head *add_list, resource_size_t available)
+{
+       struct pci_dev_resource *dev_res;
+
+       if (res->parent)
+               return;
+
+       if (resource_size(res) >= available)
+               return;
+
+       dev_res = res_to_dev_res(add_list, res);
+       if (!dev_res)
+               return;
+
+       /* Is there room to extend the window? */
+       if (available - resource_size(res) <= dev_res->add_size)
+               return;
+
+       dev_res->add_size = available - resource_size(res);
+       dev_dbg(&bridge->dev, "bridge window %pR extended by %pa\n", res,
+               &dev_res->add_size);
+}
+
+static void pci_bus_distribute_available_resources(struct pci_bus *bus,
+       struct list_head *add_list, resource_size_t available_io,
+       resource_size_t available_mmio, resource_size_t available_mmio_pref)
+{
+       resource_size_t remaining_io, remaining_mmio, remaining_mmio_pref;
+       unsigned int normal_bridges = 0, hotplug_bridges = 0;
+       struct resource *io_res, *mmio_res, *mmio_pref_res;
+       struct pci_dev *dev, *bridge = bus->self;
+
+       io_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
+       mmio_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
+       mmio_pref_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
+
+       /*
+        * Update additional resource list (add_list) to fill all the
+        * extra resource space available for this port except the space
+        * calculated in __pci_bus_size_bridges() which covers all the
+        * devices currently connected to the port and below.
+        */
+       extend_bridge_window(bridge, io_res, add_list, available_io);
+       extend_bridge_window(bridge, mmio_res, add_list, available_mmio);
+       extend_bridge_window(bridge, mmio_pref_res, add_list,
+                            available_mmio_pref);
+
+       /*
+        * Calculate the total amount of extra resource space we can
+        * pass to bridges below this one. This is basically the
+        * extra space reduced by the minimal required space for the
+        * non-hotplug bridges.
+        */
+       remaining_io = available_io;
+       remaining_mmio = available_mmio;
+       remaining_mmio_pref = available_mmio_pref;
+
+       /*
+        * Calculate how many hotplug bridges and normal bridges there
+        * are on this bus. We will distribute the additional available
+        * resources between hotplug bridges.
+        */
+       for_each_pci_bridge(dev, bus) {
+               if (dev->is_hotplug_bridge)
+                       hotplug_bridges++;
+               else
+                       normal_bridges++;
+       }
+
+       for_each_pci_bridge(dev, bus) {
+               const struct resource *res;
+
+               if (dev->is_hotplug_bridge)
+                       continue;
+
+               /*
+                * Reduce the available resource space by what the
+                * bridge and devices below it occupy.
+                */
+               res = &dev->resource[PCI_BRIDGE_RESOURCES + 0];
+               if (!res->parent && available_io > resource_size(res))
+                       remaining_io -= resource_size(res);
+
+               res = &dev->resource[PCI_BRIDGE_RESOURCES + 1];
+               if (!res->parent && available_mmio > resource_size(res))
+                       remaining_mmio -= resource_size(res);
+
+               res = &dev->resource[PCI_BRIDGE_RESOURCES + 2];
+               if (!res->parent && available_mmio_pref > resource_size(res))
+                       remaining_mmio_pref -= resource_size(res);
+       }
+
+       /*
+        * Go over devices on this bus and distribute the remaining
+        * resource space between hotplug bridges.
+        */
+       for_each_pci_bridge(dev, bus) {
+               struct pci_bus *b;
+
+               b = dev->subordinate;
+               if (!b)
+                       continue;
+
+               if (!hotplug_bridges && normal_bridges == 1) {
+                       /*
+                        * There is only one bridge on the bus (upstream
+                        * port) so it gets all available resources
+                        * which it can then distribute to the possible
+                        * hotplug bridges below.
+                        */
+                       pci_bus_distribute_available_resources(b, add_list,
+                               available_io, available_mmio,
+                               available_mmio_pref);
+               } else if (dev->is_hotplug_bridge) {
+                       resource_size_t align, io, mmio, mmio_pref;
+
+                       /*
+                        * Distribute available extra resources equally
+                        * between hotplug-capable downstream ports
+                        * taking alignment into account.
+                        *
+                        * Here hotplug_bridges is always != 0.
+                        */
+                       align = pci_resource_alignment(bridge, io_res);
+                       io = div64_ul(available_io, hotplug_bridges);
+                       io = min(ALIGN(io, align), remaining_io);
+                       remaining_io -= io;
+
+                       align = pci_resource_alignment(bridge, mmio_res);
+                       mmio = div64_ul(available_mmio, hotplug_bridges);
+                       mmio = min(ALIGN(mmio, align), remaining_mmio);
+                       remaining_mmio -= mmio;
+
+                       align = pci_resource_alignment(bridge, mmio_pref_res);
+                       mmio_pref = div64_ul(available_mmio_pref,
+                                            hotplug_bridges);
+                       mmio_pref = min(ALIGN(mmio_pref, align),
+                                       remaining_mmio_pref);
+                       remaining_mmio_pref -= mmio_pref;
+
+                       pci_bus_distribute_available_resources(b, add_list, io,
+                                                              mmio, mmio_pref);
+               }
+       }
+}
+
+static void
+pci_bridge_distribute_available_resources(struct pci_dev *bridge,
+                                         struct list_head *add_list)
+{
+       resource_size_t available_io, available_mmio, available_mmio_pref;
+       const struct resource *res;
+
+       if (!bridge->is_hotplug_bridge)
+               return;
+
+       /* Take the initial extra resources from the hotplug port */
+       res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
+       available_io = resource_size(res);
+       res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
+       available_mmio = resource_size(res);
+       res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
+       available_mmio_pref = resource_size(res);
+
+       pci_bus_distribute_available_resources(bridge->subordinate,
+               add_list, available_io, available_mmio, available_mmio_pref);
+}
+
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
 {
        struct pci_bus *parent = bridge->subordinate;
@@ -1862,11 +2032,17 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
        LIST_HEAD(fail_head);
        struct pci_dev_resource *fail_res;
        int retval;
-       unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
-                                 IORESOURCE_PREFETCH | IORESOURCE_MEM_64;
 
 again:
        __pci_bus_size_bridges(parent, &add_list);
+
+       /*
+        * Distribute remaining resources (if any) equally between
+        * hotplug bridges below. This makes it possible to extend the
+        * hierarchy later without running out of resources.
+        */
+       pci_bridge_distribute_available_resources(bridge, &add_list);
+
        __pci_bridge_assign_resources(bridge, &add_list, &fail_head);
        BUG_ON(!list_empty(&add_list));
        tried_times++;
@@ -1889,7 +2065,7 @@ again:
         */
        list_for_each_entry(fail_res, &fail_head, list)
                pci_bus_release_bridge_resources(fail_res->dev->bus,
-                                                fail_res->flags & type_mask,
+                                                fail_res->flags & PCI_RES_TYPE_MASK,
                                                 whole_subtree);
 
        /* restore size and flags */
@@ -1914,6 +2090,104 @@ enable_all:
 }
 EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
 
+int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
+{
+       struct pci_dev_resource *dev_res;
+       struct pci_dev *next;
+       LIST_HEAD(saved);
+       LIST_HEAD(added);
+       LIST_HEAD(failed);
+       unsigned int i;
+       int ret;
+
+       /* Walk to the root hub, releasing bridge BARs when possible */
+       next = bridge;
+       do {
+               bridge = next;
+               for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCE_END;
+                    i++) {
+                       struct resource *res = &bridge->resource[i];
+
+                       if ((res->flags ^ type) & PCI_RES_TYPE_MASK)
+                               continue;
+
+                       /* Ignore BARs which are still in use */
+                       if (res->child)
+                               continue;
+
+                       ret = add_to_list(&saved, bridge, res, 0, 0);
+                       if (ret)
+                               goto cleanup;
+
+                       dev_info(&bridge->dev, "BAR %d: releasing %pR\n",
+                                i, res);
+
+                       if (res->parent)
+                               release_resource(res);
+                       res->start = 0;
+                       res->end = 0;
+                       break;
+               }
+               if (i == PCI_BRIDGE_RESOURCE_END)
+                       break;
+
+               next = bridge->bus ? bridge->bus->self : NULL;
+       } while (next);
+
+       if (list_empty(&saved))
+               return -ENOENT;
+
+       __pci_bus_size_bridges(bridge->subordinate, &added);
+       __pci_bridge_assign_resources(bridge, &added, &failed);
+       BUG_ON(!list_empty(&added));
+
+       if (!list_empty(&failed)) {
+               ret = -ENOSPC;
+               goto cleanup;
+       }
+
+       list_for_each_entry(dev_res, &saved, list) {
+               /* Skip the bridge we just assigned resources for. */
+               if (bridge == dev_res->dev)
+                       continue;
+
+               bridge = dev_res->dev;
+               pci_setup_bridge(bridge->subordinate);
+       }
+
+       free_list(&saved);
+       return 0;
+
+cleanup:
+       /* restore size and flags */
+       list_for_each_entry(dev_res, &failed, list) {
+               struct resource *res = dev_res->res;
+
+               res->start = dev_res->start;
+               res->end = dev_res->end;
+               res->flags = dev_res->flags;
+       }
+       free_list(&failed);
+
+       /* Revert to the old configuration */
+       list_for_each_entry(dev_res, &saved, list) {
+               struct resource *res = dev_res->res;
+
+               bridge = dev_res->dev;
+               i = res - bridge->resource;
+
+               res->start = dev_res->start;
+               res->end = dev_res->end;
+               res->flags = dev_res->flags;
+
+               pci_claim_resource(bridge, i);
+               pci_setup_bridge(bridge->subordinate);
+       }
+       free_list(&saved);
+
+       return ret;
+}
+
 void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
 {
        struct pci_dev *dev;
@@ -1921,10 +2195,9 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
                                        want additional resources */
 
        down_read(&pci_bus_sem);
-       list_for_each_entry(dev, &bus->devices, bus_list)
-               if (pci_is_bridge(dev) && pci_has_subordinate(dev))
-                               __pci_bus_size_bridges(dev->subordinate,
-                                                        &add_list);
+       for_each_pci_bridge(dev, bus)
+               if (pci_has_subordinate(dev))
+                       __pci_bus_size_bridges(dev->subordinate, &add_list);
        up_read(&pci_bus_sem);
        __pci_bus_assign_resources(bus, &add_list, NULL);
        BUG_ON(!list_empty(&add_list));
index e576e1a8d9782627642ace274b456a86772732a9..bf0089ef2177e5c251c0840fda8d5b7743a67525 100644 (file)
@@ -396,6 +396,64 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
        return 0;
 }
 
+void pci_release_resource(struct pci_dev *dev, int resno)
+{
+       struct resource *res = dev->resource + resno;
+
+       dev_info(&dev->dev, "BAR %d: releasing %pR\n", resno, res);
+       release_resource(res);
+       res->end = resource_size(res) - 1;
+       res->start = 0;
+       res->flags |= IORESOURCE_UNSET;
+}
+EXPORT_SYMBOL(pci_release_resource);
+
+int pci_resize_resource(struct pci_dev *dev, int resno, int size)
+{
+       struct resource *res = dev->resource + resno;
+       int old, ret;
+       u32 sizes;
+       u16 cmd;
+
+       /* Make sure the resource isn't assigned before resizing it. */
+       if (!(res->flags & IORESOURCE_UNSET))
+               return -EBUSY;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       if (cmd & PCI_COMMAND_MEMORY)
+               return -EBUSY;
+
+       sizes = pci_rebar_get_possible_sizes(dev, resno);
+       if (!sizes)
+               return -ENOTSUPP;
+
+       if (!(sizes & BIT(size)))
+               return -EINVAL;
+
+       old = pci_rebar_get_current_size(dev, resno);
+       if (old < 0)
+               return old;
+
+       ret = pci_rebar_set_size(dev, resno, size);
+       if (ret)
+               return ret;
+
+       res->end = res->start + pci_rebar_size_to_bytes(size) - 1;
+
+       /* Check if the new config works by trying to assign everything. */
+       ret = pci_reassign_bridge_resources(dev->bus->self, res->flags);
+       if (ret)
+               goto error_resize;
+
+       return 0;
+
+error_resize:
+       pci_rebar_set_size(dev, resno, old);
+       res->end = res->start + pci_rebar_size_to_bytes(old) - 1;
+       return ret;
+}
+EXPORT_SYMBOL(pci_resize_resource);
+
 int pci_enable_resources(struct pci_dev *dev, int mask)
 {
        u16 cmd, old_cmd;
index af81b2dec42e954692fe85ef2992ecf82fc44cb3..da45dbea20ce6af4d15ed8b758c13b4437b093f8 100644 (file)
@@ -943,7 +943,7 @@ static u32 __iomem *pff_ev_reg(struct switchtec_dev *stdev,
 #define EV_PAR(i, r)[i] = {offsetof(struct part_cfg_regs, r), part_ev_reg}
 #define EV_PFF(i, r)[i] = {offsetof(struct pff_csr_regs, r), pff_ev_reg}
 
-const struct event_reg {
+static const struct event_reg {
        size_t offset;
        u32 __iomem *(*map_reg)(struct switchtec_dev *stdev,
                                size_t offset, int index);
index 4fe4cc4ae19a297a0d0553e48e613cd50bc6e891..5c0170597037e4e98a6e61b6bc06b91fc0c15145 100644 (file)
@@ -77,9 +77,8 @@ int __ref cb_alloc(struct pcmcia_socket *s)
 
        max = bus->busn_res.start;
        for (pass = 0; pass < 2; pass++)
-               list_for_each_entry(dev, &bus->devices, bus_list)
-                       if (pci_is_bridge(dev))
-                               max = pci_scan_bridge(bus, dev, max, pass);
+               for_each_pci_bridge(dev, bus)
+                       max = pci_scan_bridge(bus, dev, max, pass);
 
        /*
         * Size all resources below the CardBus controller.
index 37864734ca50f76838cc1e95ea92f8d37bbdc856..8beed2de98e9deebc1f8ed99c694a5f581585846 100644 (file)
@@ -49,6 +49,8 @@ extern const __be32 *of_get_address(struct device_node *dev, int index,
 
 extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
                        struct device_node *node);
+extern int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
+                       struct device_node *node);
 extern struct of_pci_range *of_pci_range_parser_one(
                                        struct of_pci_range_parser *parser,
                                        struct of_pci_range *range);
@@ -85,7 +87,13 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index,
 static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
                        struct device_node *node)
 {
-       return -1;
+       return -ENOSYS;
+}
+
+static inline int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
+                       struct device_node *node)
+{
+       return -ENOSYS;
 }
 
 static inline struct of_pci_range *of_pci_range_parser_one(
index f4f8ee5a7362e982c0084d619c8ed1996a38f770..d85c626e12285e02e4536d4e578b69e4a02af694 100644 (file)
@@ -596,6 +596,10 @@ static inline bool pci_is_bridge(struct pci_dev *dev)
                dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
 }
 
+#define for_each_pci_bridge(dev, bus)                          \
+       list_for_each_entry(dev, &bus->devices, bus_list)       \
+               if (!pci_is_bridge(dev)) {} else
+
 static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev)
 {
        dev = pci_physfn(dev);
@@ -1089,7 +1093,6 @@ int pcie_set_mps(struct pci_dev *dev, int mps);
 int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
                          enum pcie_link_width *width);
 void pcie_flr(struct pci_dev *dev);
-int __pci_reset_function(struct pci_dev *dev);
 int __pci_reset_function_locked(struct pci_dev *dev);
 int pci_reset_function(struct pci_dev *dev);
 int pci_reset_function_locked(struct pci_dev *dev);
@@ -1106,6 +1109,8 @@ void pci_reset_bridge_secondary_bus(struct pci_dev *dev);
 void pci_update_resource(struct pci_dev *dev, int resno);
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
 int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
+void pci_release_resource(struct pci_dev *dev, int resno);
+int __must_check pci_resize_resource(struct pci_dev *dev, int i, int size);
 int pci_select_bars(struct pci_dev *dev, unsigned long flags);
 bool pci_device_is_present(struct pci_dev *pdev);
 void pci_ignore_hotplug(struct pci_dev *dev);
@@ -1185,6 +1190,7 @@ void pci_assign_unassigned_resources(void);
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
 void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
 void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus);
+int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type);
 void pdev_enable_device(struct pci_dev *);
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_assign_irq(struct pci_dev *dev);
@@ -1958,8 +1964,8 @@ int pci_iov_virtfn_devfn(struct pci_dev *dev, int id);
 
 int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
 void pci_disable_sriov(struct pci_dev *dev);
-int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset);
-void pci_iov_remove_virtfn(struct pci_dev *dev, int id, int reset);
+int pci_iov_add_virtfn(struct pci_dev *dev, int id);
+void pci_iov_remove_virtfn(struct pci_dev *dev, int id);
 int pci_num_vf(struct pci_dev *dev);
 int pci_vfs_assigned(struct pci_dev *dev);
 int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
@@ -1976,12 +1982,12 @@ static inline int pci_iov_virtfn_devfn(struct pci_dev *dev, int id)
 }
 static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
 { return -ENODEV; }
-static inline int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset)
+static inline int pci_iov_add_virtfn(struct pci_dev *dev, int id)
 {
        return -ENOSYS;
 }
 static inline void pci_iov_remove_virtfn(struct pci_dev *dev,
-                                        int id, int reset) { }
+                                        int id) { }
 static inline void pci_disable_sriov(struct pci_dev *dev) { }
 static inline int pci_num_vf(struct pci_dev *dev) { return 0; }
 static inline int pci_vfs_assigned(struct pci_dev *dev)
index f8d58045926ff11d23cd8e575e550badd78e3237..66cd64595d7ed661406e93367175c474734e39f6 100644 (file)
 #define PCI_ERR_ROOT_FIRST_FATAL       0x00000010 /* First UNC is Fatal */
 #define PCI_ERR_ROOT_NONFATAL_RCV      0x00000020 /* Non-Fatal Received */
 #define PCI_ERR_ROOT_FATAL_RCV         0x00000040 /* Fatal Received */
+#define PCI_ERR_ROOT_AER_IRQ           0xf8000000 /* Advanced Error Interrupt Message Number */
 #define PCI_ERR_ROOT_ERR_SRC   52      /* Error Source Identification */
 
 /* Virtual Channel */
 #define PCI_SATA_SIZEOF_LONG   16
 
 /* Resizable BARs */
+#define PCI_REBAR_CAP          4       /* capability register */
+#define  PCI_REBAR_CAP_SIZES           0x00FFFFF0  /* supported BAR sizes */
 #define PCI_REBAR_CTRL         8       /* control register */
-#define  PCI_REBAR_CTRL_NBAR_MASK      (7 << 5)        /* mask for # bars */
-#define  PCI_REBAR_CTRL_NBAR_SHIFT     5       /* shift for # bars */
+#define  PCI_REBAR_CTRL_BAR_IDX                0x00000007  /* BAR index */
+#define  PCI_REBAR_CTRL_NBAR_MASK      0x000000E0  /* # of resizable BARs */
+#define  PCI_REBAR_CTRL_NBAR_SHIFT     5           /* shift for # of BARs */
+#define  PCI_REBAR_CTRL_BAR_SIZE       0x00001F00  /* BAR size */
 
 /* Dynamic Power Allocation */
 #define PCI_DPA_CAP            4       /* capability register */
 
 /* Downstream Port Containment */
 #define PCI_EXP_DPC_CAP                        4       /* DPC Capability */
+#define PCI_EXP_DPC_IRQ                        0x1f    /* DPC Interrupt Message Number */
 #define  PCI_EXP_DPC_CAP_RP_EXT                0x20    /* Root Port Extensions for DPC */
 #define  PCI_EXP_DPC_CAP_POISONED_TLP  0x40    /* Poisoned TLP Egress Blocking Supported */
 #define  PCI_EXP_DPC_CAP_SW_TRIGGER    0x80    /* Software Triggering Supported */
 #define  PCI_PTM_CTRL_ENABLE           0x00000001  /* PTM enable */
 #define  PCI_PTM_CTRL_ROOT             0x00000002  /* Root select */
 
-/* L1 PM Substates */
-#define PCI_L1SS_CAP               4   /* capability register */
-#define  PCI_L1SS_CAP_PCIPM_L1_2        1      /* PCI PM L1.2 Support */
-#define  PCI_L1SS_CAP_PCIPM_L1_1        2      /* PCI PM L1.1 Support */
-#define  PCI_L1SS_CAP_ASPM_L1_2                 4      /* ASPM L1.2 Support */
-#define  PCI_L1SS_CAP_ASPM_L1_1                 8      /* ASPM L1.1 Support */
-#define  PCI_L1SS_CAP_L1_PM_SS         16      /* L1 PM Substates Support */
-#define PCI_L1SS_CTL1              8   /* Control Register 1 */
-#define  PCI_L1SS_CTL1_PCIPM_L1_2      1       /* PCI PM L1.2 Enable */
-#define  PCI_L1SS_CTL1_PCIPM_L1_1      2       /* PCI PM L1.1 Support */
-#define  PCI_L1SS_CTL1_ASPM_L1_2       4       /* ASPM L1.2 Support */
-#define  PCI_L1SS_CTL1_ASPM_L1_1       8       /* ASPM L1.1 Support */
-#define  PCI_L1SS_CTL1_L1SS_MASK       0x0000000F
-#define PCI_L1SS_CTL2              0xC /* Control Register 2 */
+/* ASPM L1 PM Substates */
+#define PCI_L1SS_CAP           0x04    /* Capabilities Register */
+#define  PCI_L1SS_CAP_PCIPM_L1_2       0x00000001  /* PCI-PM L1.2 Supported */
+#define  PCI_L1SS_CAP_PCIPM_L1_1       0x00000002  /* PCI-PM L1.1 Supported */
+#define  PCI_L1SS_CAP_ASPM_L1_2                0x00000004  /* ASPM L1.2 Supported */
+#define  PCI_L1SS_CAP_ASPM_L1_1                0x00000008  /* ASPM L1.1 Supported */
+#define  PCI_L1SS_CAP_L1_PM_SS         0x00000010  /* L1 PM Substates Supported */
+#define  PCI_L1SS_CAP_CM_RESTORE_TIME  0x0000ff00  /* Port Common_Mode_Restore_Time */
+#define  PCI_L1SS_CAP_P_PWR_ON_SCALE   0x00030000  /* Port T_POWER_ON scale */
+#define  PCI_L1SS_CAP_P_PWR_ON_VALUE   0x00f80000  /* Port T_POWER_ON value */
+#define PCI_L1SS_CTL1          0x08    /* Control 1 Register */
+#define  PCI_L1SS_CTL1_PCIPM_L1_2      0x00000001  /* PCI-PM L1.2 Enable */
+#define  PCI_L1SS_CTL1_PCIPM_L1_1      0x00000002  /* PCI-PM L1.1 Enable */
+#define  PCI_L1SS_CTL1_ASPM_L1_2       0x00000004  /* ASPM L1.2 Enable */
+#define  PCI_L1SS_CTL1_ASPM_L1_1       0x00000008  /* ASPM L1.1 Enable */
+#define  PCI_L1SS_CTL1_L1SS_MASK       0x0000000f
+#define  PCI_L1SS_CTL1_CM_RESTORE_TIME 0x0000ff00  /* Common_Mode_Restore_Time */
+#define  PCI_L1SS_CTL1_LTR_L12_TH_VALUE        0x03ff0000  /* LTR_L1.2_THRESHOLD_Value */
+#define  PCI_L1SS_CTL1_LTR_L12_TH_SCALE        0xe0000000  /* LTR_L1.2_THRESHOLD_Scale */
+#define PCI_L1SS_CTL2          0x0c    /* Control 2 Register */
 
 #endif /* LINUX_PCI_REGS_H */
index 78cb2461012ef530f2755a0a6a8458428ed19043..b5a1cb415f465f480c4569609d911763e350a39d 100644 (file)
@@ -1379,15 +1379,6 @@ config USERFAULTFD
          Enable the userfaultfd() system call that allows to intercept and
          handle page faults in userland.
 
-config PCI_QUIRKS
-       default y
-       bool "Enable PCI quirk workarounds" if EXPERT
-       depends on PCI
-       help
-         This enables workarounds for various PCI chipset
-         bugs/quirks. Disable this only if your target machine is
-         unaffected by PCI quirks.
-
 config MEMBARRIER
        bool "Enable membarrier() system call" if EXPERT
        default y