]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Merge tag 'pci-v5.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Oct 2020 19:41:00 +0000 (12:41 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Oct 2020 19:41:00 +0000 (12:41 -0700)
Pull PCI updates from Bjorn Helgaas:
 "Enumeration:
   - Print IRQ number used by PCIe Link Bandwidth Notification (Dongdong
     Liu)
   - Add schedule point in pci_read_config() to reduce max latency
     (Jiang Biao)
   - Add Kconfig options for MPS/MRRS strategy (Jim Quinlan)

  Resource management:
   - Fix pci_iounmap() memory leak when !CONFIG_GENERIC_IOMAP (Lorenzo
     Pieralisi)

  PCIe native device hotplug:
   - Reduce noisiness on hot removal (Lukas Wunner)

  Power management:
   - Revert "PCI/PM: Apply D2 delay as milliseconds, not microseconds"
     that was done on the basis of spec typo (Bjorn Helgaas)
   - Rename pci_dev.d3_delay to d3hot_delay to remove D3hot/D3cold
     ambiguity (Krzysztof Wilczyński)
   - Remove unused pcibios_pm_ops (Vaibhav Gupta)

  IOMMU:
   - Enable Translation Blocking for external devices to harden against
     DMA attacks (Rajat Jain)

  Error handling:
   - Add an ACPI APEI notifier chain for vendor CPER records to enable
     device-specific error handling (Shiju Jose)

  ASPM:
   - Remove struct aspm_register_info to simplify code (Saheed O.
     Bolarinwa)

  Amlogic Meson PCIe controller driver:
   - Build as module by default (Kevin Hilman)

  Ampere Altra PCIe controller driver:
   - Add MCFG quirk to work around non-standard ECAM implementation
     (Tuan Phan)

  Broadcom iProc PCIe controller driver:
   - Set affinity mask on MSI interrupts (Mark Tomlinson)

  Broadcom STB PCIe controller driver:
   - Make PCIE_BRCMSTB depend on ARCH_BRCMSTB (Jim Quinlan)
   - Add DT bindings for more Brcmstb chips (Jim Quinlan)
   - Add bcm7278 register info (Jim Quinlan)
   - Add bcm7278 PERST# support (Jim Quinlan)
   - Add suspend and resume pm_ops (Jim Quinlan)
   - Add control of rescal reset (Jim Quinlan)
   - Set additional internal memory DMA viewport sizes (Jim Quinlan)
   - Accommodate MSI for older chips (Jim Quinlan)
   - Set bus max burst size by chip type (Jim Quinlan)
   - Add support for bcm7211, bcm7216, bcm7445, bcm7278 (Jim Quinlan)

  Freescale i.MX6 PCIe controller driver:
   - Use dev_err_probe() to reduce redundant messages (Anson Huang)

  Freescale Layerscape PCIe controller driver:
   - Enforce 4K DMA buffer alignment in endpoint test (Hou Zhiqiang)
   - Add DT compatible strings for ls1088a, ls2088a (Xiaowei Bao)
   - Add endpoint support for ls1088a, ls2088a (Xiaowei Bao)
   - Add endpoint test support for lS1088a (Xiaowei Bao)
   - Add MSI-X support for ls1088a (Xiaowei Bao)

  HiSilicon HIP PCIe controller driver:
   - Handle HIP-specific errors via ACPI APEI (Yicong Yang)

  HiSilicon Kirin PCIe controller driver:
   - Return -EPROBE_DEFER if the GPIO isn't ready (Bean Huo)

  Intel VMD host bridge driver:
   - Factor out physical offset, bus offset, IRQ domain, IRQ allocation
     (Jon Derrick)
   - Use generic PCI PM correctly (Jon Derrick)

  Marvell Aardvark PCIe controller driver:
   - Fix compilation on s390 (Pali Rohár)
   - Implement driver 'remove' function and allow to build it as module
     (Pali Rohár)
   - Move PCIe reset card code to advk_pcie_train_link() (Pali Rohár)
   - Convert mvebu a3700 internal SMCC firmware return codes to errno
     (Pali Rohár)
   - Fix initialization with old Marvell's Arm Trusted Firmware (Pali
     Rohár)

  Microsoft Hyper-V host bridge driver:
   - Fix hibernation in case interrupts are not re-created (Dexuan Cui)

  NVIDIA Tegra PCIe controller driver:
   - Stop checking return value of debugfs_create() functions (Greg
     Kroah-Hartman)
   - Convert to use DEFINE_SEQ_ATTRIBUTE macro (Liu Shixin)

  Qualcomm PCIe controller driver:
   - Reset PCIe to work around Qsdk U-Boot issue (Ansuel Smith)

  Renesas R-Car PCIe controller driver:
   - Add DT documentation for r8a774a1, r8a774b1, r8a774e1 endpoints
     (Lad Prabhakar)
   - Add RZ/G2M, RZ/G2N, RZ/G2H IDs to endpoint test (Lad Prabhakar)
   - Add DT support for r8a7742 (Lad Prabhakar)

  Socionext UniPhier Pro5 controller driver:
   - Add DT descriptions of iATU register (host and endpoint) (Kunihiko
     Hayashi)

  Synopsys DesignWare PCIe controller driver:
   - Add link up check in dw_child_pcie_ops.map_bus() (racy, but seems
     unavoidable) (Hou Zhiqiang)
   - Fix endpoint Header Type check so multi-function devices work (Hou
     Zhiqiang)
   - Skip PCIE_MSI_INTR0* programming if MSI is disabled (Jisheng Zhang)
   - Stop leaking MSI page in suspend/resume (Jisheng Zhang)
   - Add common iATU register support instead of keystone-specific code
     (Kunihiko Hayashi)
   - Major config space access and other cleanups in dwc core and
     drivers that use it (al, exynos, histb, imx6, intel-gw, keystone,
     kirin, meson, qcom, tegra) (Rob Herring)
   - Add multiple PFs support for endpoint (Xiaowei Bao)
   - Add MSI-X doorbell mode in endpoint mode (Xiaowei Bao)

  Miscellaneous:
   - Use fallthrough pseudo-keyword (Gustavo A. R. Silva)
   - Fix "0 used as NULL pointer" warnings (Gustavo Pimentel)
   - Fix "cast truncates bits from constant value" warnings (Gustavo
     Pimentel)
   - Remove redundant zeroing for sg_init_table() (Julia Lawall)
   - Use scnprintf(), not snprintf(), in sysfs "show" functions
     (Krzysztof Wilczyński)
   - Remove unused assignments (Krzysztof Wilczyński)
   - Fix "0 used as NULL pointer" warning (Krzysztof Wilczyński)
   - Simplify bool comparisons (Krzysztof Wilczyński)
   - Use for_each_child_of_node() and for_each_node_by_name() (Qinglang
     Miao)
   - Simplify return expressions (Qinglang Miao)"

* tag 'pci-v5.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (147 commits)
  PCI: vmd: Update VMD PM to correctly use generic PCI PM
  PCI: vmd: Create IRQ allocation helper
  PCI: vmd: Create IRQ Domain configuration helper
  PCI: vmd: Create bus offset configuration helper
  PCI: vmd: Create physical offset helper
  PCI: v3-semi: Remove unneeded break
  PCI: dwc: Add link up check in dw_child_pcie_ops.map_bus()
  PCI/ASPM: Remove struct pcie_link_state.l1ss
  PCI/ASPM: Remove struct aspm_register_info.l1ss_cap
  PCI/ASPM: Pass L1SS Capabilities value, not struct aspm_register_info
  PCI/ASPM: Remove struct aspm_register_info.l1ss_ctl1
  PCI/ASPM: Remove struct aspm_register_info.l1ss_ctl2 (unused)
  PCI/ASPM: Remove struct aspm_register_info.l1ss_cap_ptr
  PCI/ASPM: Remove struct aspm_register_info.latency_encoding
  PCI/ASPM: Remove struct aspm_register_info.enabled
  PCI/ASPM: Remove struct aspm_register_info.support
  PCI/ASPM: Use 'parent' and 'child' for readability
  PCI/ASPM: Move LTR path check to where it's used
  PCI/ASPM: Move pci_clear_and_set_dword() earlier
  PCI: dwc: Fix MSI page leakage in suspend/resume
  ...

85 files changed:
Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
Documentation/devicetree/bindings/pci/layerscape-pci.txt
Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml
Documentation/devicetree/bindings/pci/rcar-pci.txt
Documentation/devicetree/bindings/pci/socionext,uniphier-pcie-ep.yaml
Documentation/devicetree/bindings/pci/uniphier-pcie.txt
Documentation/power/pci.rst
arch/arm/include/asm/mach/pci.h
arch/arm/kernel/bios32.c
arch/sparc/include/asm/io_32.h
arch/x86/pci/fixup.c
arch/x86/pci/intel_mid_pci.c
drivers/acpi/apei/ghes.c
drivers/acpi/pci_mcfg.c
drivers/hid/intel-ish-hid/ipc/ipc.c
drivers/misc/pci_endpoint_test.c
drivers/net/ethernet/marvell/sky2.c
drivers/pci/Kconfig
drivers/pci/controller/Kconfig
drivers/pci/controller/Makefile
drivers/pci/controller/cadence/pcie-cadence-ep.c
drivers/pci/controller/cadence/pcie-cadence-host.c
drivers/pci/controller/dwc/Kconfig
drivers/pci/controller/dwc/pci-dra7xx.c
drivers/pci/controller/dwc/pci-exynos.c
drivers/pci/controller/dwc/pci-imx6.c
drivers/pci/controller/dwc/pci-keystone.c
drivers/pci/controller/dwc/pci-layerscape-ep.c
drivers/pci/controller/dwc/pci-meson.c
drivers/pci/controller/dwc/pcie-al.c
drivers/pci/controller/dwc/pcie-artpec6.c
drivers/pci/controller/dwc/pcie-designware-ep.c
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-designware-plat.c
drivers/pci/controller/dwc/pcie-designware.c
drivers/pci/controller/dwc/pcie-designware.h
drivers/pci/controller/dwc/pcie-histb.c
drivers/pci/controller/dwc/pcie-intel-gw.c
drivers/pci/controller/dwc/pcie-kirin.c
drivers/pci/controller/dwc/pcie-qcom.c
drivers/pci/controller/dwc/pcie-spear13xx.c
drivers/pci/controller/dwc/pcie-tegra194.c
drivers/pci/controller/dwc/pcie-uniphier.c
drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
drivers/pci/controller/pci-aardvark.c
drivers/pci/controller/pci-hyperv.c
drivers/pci/controller/pci-loongson.c
drivers/pci/controller/pci-mvebu.c
drivers/pci/controller/pci-tegra.c
drivers/pci/controller/pci-v3-semi.c
drivers/pci/controller/pci-xgene-msi.c
drivers/pci/controller/pcie-brcmstb.c
drivers/pci/controller/pcie-hisi-error.c [new file with mode: 0644]
drivers/pci/controller/pcie-iproc-bcma.c
drivers/pci/controller/pcie-iproc-msi.c
drivers/pci/controller/pcie-iproc-platform.c
drivers/pci/controller/pcie-xilinx-cpm.c
drivers/pci/controller/vmd.c
drivers/pci/ecam.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/rpadlpar_core.c
drivers/pci/hotplug/shpchp_ctrl.c
drivers/pci/p2pdma.c
drivers/pci/pci-acpi.c
drivers/pci/pci-bridge-emul.c
drivers/pci/pci-driver.c
drivers/pci/pci-pf-stub.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aspm.c
drivers/pci/pcie/bw_notification.c
drivers/pci/pcie/dpc.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/phy/marvell/phy-mvebu-a3700-comphy.c
drivers/phy/marvell/phy-mvebu-cp110-comphy.c
drivers/staging/media/atomisp/pci/atomisp_v4l2.c
include/acpi/ghes.h
include/asm-generic/io.h
include/linux/pci-ecam.h
include/linux/pci-ep-cfs.h
include/linux/pci.h
include/uapi/linux/pci_regs.h

index 8680a0f86c5a7017082b6e5781d6a3550d7f53d1..807694b4f41f68b37aab27cb205299e7aa005631 100644 (file)
@@ -9,12 +9,15 @@ title: Brcmstb PCIe Host Controller Device Tree Bindings
 maintainers:
   - Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
 
-allOf:
-  - $ref: /schemas/pci/pci-bus.yaml#
-
 properties:
   compatible:
-    const: brcm,bcm2711-pcie # The Raspberry Pi 4
+    items:
+      - enum:
+          - brcm,bcm2711-pcie # The Raspberry Pi 4
+          - brcm,bcm7211-pcie # Broadcom STB version of RPi4
+          - brcm,bcm7278-pcie # Broadcom 7278 Arm
+          - brcm,bcm7216-pcie # Broadcom 7216 Arm
+          - brcm,bcm7445-pcie # Broadcom 7445 Arm
 
   reg:
     maxItems: 1
@@ -34,10 +37,12 @@ properties:
       - const: msi
 
   ranges:
-    maxItems: 1
+    minItems: 1
+    maxItems: 4
 
   dma-ranges:
-    maxItems: 1
+    minItems: 1
+    maxItems: 6
 
   clocks:
     maxItems: 1
@@ -58,8 +63,31 @@ properties:
 
   aspm-no-l0s: true
 
+  resets:
+    description: for "brcm,bcm7216-pcie", must be a valid reset
+      phandle pointing to the RESCAL reset controller provider node.
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+
+  reset-names:
+    items:
+      - const: rescal
+
+  brcm,scb-sizes:
+    description: u64 giving the 64bit PCIe memory
+      viewport size of a memory controller.  There may be up to
+      three controllers, and each size must be a power of two
+      with a size greater or equal to the amount of memory the
+      controller supports.  Note that each memory controller
+      may have two component regions -- base and extended -- so
+      this information cannot be deduced from the dma-ranges.
+    $ref: /schemas/types.yaml#/definitions/uint64-array
+    items:
+      minItems: 1
+      maxItems: 3
+
 required:
   - reg
+  - ranges
   - dma-ranges
   - "#interrupt-cells"
   - interrupts
@@ -68,6 +96,18 @@ required:
   - interrupt-map
   - msi-controller
 
+allOf:
+  - $ref: /schemas/pci/pci-bus.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: brcm,bcm7216-pcie
+    then:
+      required:
+        - resets
+        - reset-names
+
 unevaluatedProperties: false
 
 examples:
@@ -93,7 +133,9 @@ examples:
                     msi-parent = <&pcie0>;
                     msi-controller;
                     ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 0x0 0x04000000>;
-                    dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 0x0 0x80000000>;
+                    dma-ranges = <0x42000000 0x1 0x00000000 0x0 0x40000000 0x0 0x80000000>,
+                                 <0x42000000 0x1 0x80000000 0x3 0x00000000 0x0 0x80000000>;
                     brcm,enable-ssc;
+                    brcm,scb-sizes =  <0x0000000080000000 0x0000000080000000>;
             };
     };
index 99a386ea691c2b89e8f3abef701ee3621885bd1d..daa99f7d4c3fb4637f5b6d9dbb4c901543af1dec 100644 (file)
@@ -24,6 +24,8 @@ Required properties:
         "fsl,ls1028a-pcie"
   EP mode:
        "fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep"
+       "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"
+       "fsl,ls2088a-pcie-ep", "fsl,ls-pcie-ep"
 - 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 53d5952b7e57fc8064a6bb0b720781245ab8bd35..84eeb7fe6e0141fc64cf121a0f7a1e481cf784b7 100644 (file)
@@ -14,8 +14,12 @@ maintainers:
 properties:
   compatible:
     items:
-      - const: renesas,r8a774c0-pcie-ep
-      - const: renesas,rcar-gen3-pcie-ep
+      - enum:
+          - renesas,r8a774a1-pcie-ep     # RZ/G2M
+          - renesas,r8a774b1-pcie-ep     # RZ/G2N
+          - renesas,r8a774c0-pcie-ep     # RZ/G2E
+          - renesas,r8a774e1-pcie-ep     # RZ/G2H
+      - const: renesas,rcar-gen3-pcie-ep # R-Car Gen3 and RZ/G2
 
   reg:
     maxItems: 5
index 1041c44a614f5ae8694cd02533c8f7aaa60190a1..14d307deff061d5b3665265a5130b1e7f89eca35 100644 (file)
@@ -1,7 +1,8 @@
 * Renesas R-Car PCIe interface
 
 Required properties:
-compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC;
+compatible: "renesas,pcie-r8a7742" for the R8A7742 SoC;
+           "renesas,pcie-r8a7743" for the R8A7743 SoC;
            "renesas,pcie-r8a7744" for the R8A7744 SoC;
            "renesas,pcie-r8a774a1" for the R8A774A1 SoC;
            "renesas,pcie-r8a774b1" for the R8A774B1 SoC;
index f0558b9cf9e98d8933987435782a019594b44373..f4292d2c54e3c4201561e2828a6b285926e0e4ec 100644 (file)
@@ -23,14 +23,22 @@ properties:
     const: socionext,uniphier-pro5-pcie-ep
 
   reg:
-    maxItems: 4
+    minItems: 4
+    maxItems: 5
 
   reg-names:
-    items:
-      - const: dbi
-      - const: dbi2
-      - const: link
-      - const: addr_space
+    oneOf:
+      - items:
+        - const: dbi
+        - const: dbi2
+        - const: link
+        - const: addr_space
+      - items:
+        - const: dbi
+        - const: dbi2
+        - const: link
+        - const: addr_space
+        - const: atu
 
   clocks:
     maxItems: 2
index 1fa2c5906d4d7edd0681c797413a7c6e4af8035d..c4b7381733a0fda5c1a71d9f542b68497921f439 100644 (file)
@@ -16,6 +16,7 @@ Required properties:
     "dbi"    - controller configuration registers
     "link"   - SoC-specific glue layer registers
     "config" - PCIe configuration space
+    "atu"    - iATU registers for DWC version 4.80 or later
 - clocks: A phandle to the clock gate for PCIe glue layer including
        the host controller.
 - resets: A phandle to the reset line for PCIe glue layer including
index 1831e431f7259973126bf72edc5a3b6adb5d4350..b04fb18cc4e2826a2800fd36087a5d00b3a31dcc 100644 (file)
@@ -320,7 +320,7 @@ that these callbacks operate on::
        unsigned int    d2_support:1;   /* Low power state D2 is supported */
        unsigned int    no_d1d2:1;      /* D1 and D2 are forbidden */
        unsigned int    wakeup_prepared:1;  /* Device prepared for wake up */
-       unsigned int    d3_delay;       /* D3->D0 transition time in ms */
+       unsigned int    d3hot_delay;    /* D3hot->D0 transition time in ms */
        ...
   };
 
index 83d340702680da5209a53a78166088cdac414a27..ea9bd08895b7f5bb8f6a65a30eaddfcdfeac9f65 100644 (file)
@@ -17,10 +17,8 @@ struct pci_host_bridge;
 struct device;
 
 struct hw_pci {
-       struct msi_controller *msi_ctrl;
        struct pci_ops  *ops;
        int             nr_controllers;
-       unsigned int    io_optional:1;
        void            **private_data;
        int             (*setup)(int nr, struct pci_sys_data *);
        int             (*scan)(int nr, struct pci_host_bridge *);
@@ -28,11 +26,6 @@ struct hw_pci {
        void            (*postinit)(void);
        u8              (*swizzle)(struct pci_dev *dev, u8 *pin);
        int             (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
-       resource_size_t (*align_resource)(struct pci_dev *dev,
-                                         const struct resource *res,
-                                         resource_size_t start,
-                                         resource_size_t size,
-                                         resource_size_t align);
 };
 
 /*
index eecec16aa708fff9d3cac98091e4631637a866cb..e7ef2b5bea9c224b4a3d6c6812b70a9404cf3818 100644 (file)
@@ -394,8 +394,7 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return irq;
 }
 
-static int pcibios_init_resource(int busnr, struct pci_sys_data *sys,
-                                int io_optional)
+static int pcibios_init_resource(int busnr, struct pci_sys_data *sys)
 {
        int ret;
        struct resource_entry *window;
@@ -405,14 +404,6 @@ static int pcibios_init_resource(int busnr, struct pci_sys_data *sys,
                         &iomem_resource, sys->mem_offset);
        }
 
-       /*
-        * If a platform says I/O port support is optional, we don't add
-        * the default I/O space.  The platform is responsible for adding
-        * any I/O space it needs.
-        */
-       if (io_optional)
-               return 0;
-
        resource_list_for_each_entry(window, &sys->resources)
                if (resource_type(window->res) == IORESOURCE_IO)
                        return 0;
@@ -462,7 +453,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
 
                if (ret > 0) {
 
-                       ret = pcibios_init_resource(nr, sys, hw->io_optional);
+                       ret = pcibios_init_resource(nr, sys);
                        if (ret)  {
                                pci_free_host_bridge(bridge);
                                break;
@@ -480,9 +471,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
                                bridge->sysdata = sys;
                                bridge->busnr = sys->busnr;
                                bridge->ops = hw->ops;
-                               bridge->msi = hw->msi_ctrl;
-                               bridge->align_resource =
-                                               hw->align_resource;
 
                                ret = pci_scan_root_bus_bridge(bridge);
                        }
index 9a52d9506f80b7d58cb14a60ee6784d377348229..549f0a72280d337bcd537122bf4a5851ab2e11a4 100644 (file)
 #define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz)
 #define memcpy_toio(d,s,sz)   _memcpy_toio(d,s,sz)
 
+/*
+ * Bus number may be embedded in the higher bits of the physical address.
+ * This is why we have no bus number argument to ioremap().
+ */
+void __iomem *ioremap(phys_addr_t offset, size_t size);
+void iounmap(volatile void __iomem *addr);
+
 #include <asm-generic/io.h>
 
 static inline void _memset_io(volatile void __iomem *dst,
@@ -121,14 +128,6 @@ static inline void sbus_memcpy_toio(volatile void __iomem *dst,
        }
 }
 
-#ifdef __KERNEL__
-
-/*
- * Bus number may be embedded in the higher bits of the physical address.
- * This is why we have no bus number argument to ioremap().
- */
-void __iomem *ioremap(phys_addr_t offset, size_t size);
-void iounmap(volatile void __iomem *addr);
 /* Create a virtual mapping cookie for an IO port range */
 void __iomem *ioport_map(unsigned long port, unsigned int nr);
 void ioport_unmap(void __iomem *);
@@ -148,8 +147,6 @@ static inline int sbus_can_burst64(void)
 struct device;
 void sbus_set_sbus64(struct device *, int);
 
-#endif
-
 #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED         1
 
 
index b8c9a5b87f3728c0777b8907ffe12bbd466a5079..0a0e168be1cbec0da9bad7cf2266d11118eae977 100644 (file)
@@ -587,7 +587,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa26d, pci_invalid_bar);
 static void pci_fixup_amd_ehci_pme(struct pci_dev *dev)
 {
        dev_info(&dev->dev, "PME# does not work under D3, disabling it\n");
-       dev->pme_support &= ~((PCI_PM_CAP_PME_D3 | PCI_PM_CAP_PME_D3cold)
+       dev->pme_support &= ~((PCI_PM_CAP_PME_D3hot | PCI_PM_CAP_PME_D3cold)
                >> PCI_PM_CAP_PME_SHIFT);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x7808, pci_fixup_amd_ehci_pme);
index 00c62115f39cd8a6d38e0d136e6edd57e503e5d6..24ca4ee2802fbb2422b31c98cdbe96a2e0d37d1c 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/hw_irq.h>
 #include <asm/io_apic.h>
 #include <asm/intel-mid.h>
+#include <asm/acpi.h>
 
 #define PCIE_CAP_OFFSET        0x100
 
@@ -322,7 +323,7 @@ static void pci_d3delay_fixup(struct pci_dev *dev)
         */
        if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
                return;
-       dev->d3_delay = 0;
+       dev->d3hot_delay = 0;
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
 
index 81bf71b10d44fc2acf43a14312bc9e56985ed9ec..99df00f643061690645f8040f037dbd38fd8a893 100644 (file)
        ((struct acpi_hest_generic_status *)                            \
         ((struct ghes_estatus_node *)(estatus_node) + 1))
 
+#define GHES_VENDOR_ENTRY_LEN(gdata_len)                               \
+       (sizeof(struct ghes_vendor_record_entry) + (gdata_len))
+#define GHES_GDATA_FROM_VENDOR_ENTRY(vendor_entry)                     \
+       ((struct acpi_hest_generic_data *)                              \
+       ((struct ghes_vendor_record_entry *)(vendor_entry) + 1))
+
 /*
  *  NMI-like notifications vary by architecture, before the compiler can prune
  *  unused static functions it needs a value for these enums.
@@ -123,6 +129,12 @@ static DEFINE_MUTEX(ghes_list_mutex);
  */
 static DEFINE_SPINLOCK(ghes_notify_lock_irq);
 
+struct ghes_vendor_record_entry {
+       struct work_struct work;
+       int error_severity;
+       char vendor_record[];
+};
+
 static struct gen_pool *ghes_estatus_pool;
 static unsigned long ghes_estatus_pool_size_request;
 
@@ -511,6 +523,56 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
 #endif
 }
 
+static BLOCKING_NOTIFIER_HEAD(vendor_record_notify_list);
+
+int ghes_register_vendor_record_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&vendor_record_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(ghes_register_vendor_record_notifier);
+
+void ghes_unregister_vendor_record_notifier(struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&vendor_record_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(ghes_unregister_vendor_record_notifier);
+
+static void ghes_vendor_record_work_func(struct work_struct *work)
+{
+       struct ghes_vendor_record_entry *entry;
+       struct acpi_hest_generic_data *gdata;
+       u32 len;
+
+       entry = container_of(work, struct ghes_vendor_record_entry, work);
+       gdata = GHES_GDATA_FROM_VENDOR_ENTRY(entry);
+
+       blocking_notifier_call_chain(&vendor_record_notify_list,
+                                    entry->error_severity, gdata);
+
+       len = GHES_VENDOR_ENTRY_LEN(acpi_hest_get_record_size(gdata));
+       gen_pool_free(ghes_estatus_pool, (unsigned long)entry, len);
+}
+
+static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
+                                         int sev)
+{
+       struct acpi_hest_generic_data *copied_gdata;
+       struct ghes_vendor_record_entry *entry;
+       u32 len;
+
+       len = GHES_VENDOR_ENTRY_LEN(acpi_hest_get_record_size(gdata));
+       entry = (void *)gen_pool_alloc(ghes_estatus_pool, len);
+       if (!entry)
+               return;
+
+       copied_gdata = GHES_GDATA_FROM_VENDOR_ENTRY(entry);
+       memcpy(copied_gdata, gdata, acpi_hest_get_record_size(gdata));
+       entry->error_severity = sev;
+
+       INIT_WORK(&entry->work, ghes_vendor_record_work_func);
+       schedule_work(&entry->work);
+}
+
 static bool ghes_do_proc(struct ghes *ghes,
                         const struct acpi_hest_generic_status *estatus)
 {
@@ -549,6 +611,7 @@ static bool ghes_do_proc(struct ghes *ghes,
                } else {
                        void *err = acpi_hest_get_payload(gdata);
 
+                       ghes_defer_non_standard_event(gdata, sev);
                        log_non_standard_event(sec_type, fru_id, fru_text,
                                               sec_sev, err,
                                               gdata->error_data_length);
index 54b36b7ad47d95269e445cc11eb47039962fdc47..7ddd57abadd1da36cf559db61e7df4343b74b584 100644 (file)
@@ -142,6 +142,26 @@ static struct mcfg_fixup mcfg_quirks[] = {
        XGENE_V2_ECAM_MCFG(4, 0),
        XGENE_V2_ECAM_MCFG(4, 1),
        XGENE_V2_ECAM_MCFG(4, 2),
+
+#define ALTRA_ECAM_QUIRK(rev, seg) \
+       { "Ampere", "Altra   ", rev, seg, MCFG_BUS_ANY, &pci_32b_read_ops }
+
+       ALTRA_ECAM_QUIRK(1, 0),
+       ALTRA_ECAM_QUIRK(1, 1),
+       ALTRA_ECAM_QUIRK(1, 2),
+       ALTRA_ECAM_QUIRK(1, 3),
+       ALTRA_ECAM_QUIRK(1, 4),
+       ALTRA_ECAM_QUIRK(1, 5),
+       ALTRA_ECAM_QUIRK(1, 6),
+       ALTRA_ECAM_QUIRK(1, 7),
+       ALTRA_ECAM_QUIRK(1, 8),
+       ALTRA_ECAM_QUIRK(1, 9),
+       ALTRA_ECAM_QUIRK(1, 10),
+       ALTRA_ECAM_QUIRK(1, 11),
+       ALTRA_ECAM_QUIRK(1, 12),
+       ALTRA_ECAM_QUIRK(1, 13),
+       ALTRA_ECAM_QUIRK(1, 14),
+       ALTRA_ECAM_QUIRK(1, 15),
 };
 
 static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
@@ -280,5 +300,5 @@ void __init pci_mmcfg_late_init(void)
 {
        int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
        if (err)
-               pr_err("Failed to parse MCFG (%d)\n", err);
+               pr_debug("Failed to parse MCFG (%d)\n", err);
 }
index 8f8dfdf64833e2d56a7fd41d0d0a82f58e1b065d..a45ac7fa417b9aa97e673603bd166dda77c5379d 100644 (file)
@@ -755,7 +755,7 @@ static int _ish_hw_reset(struct ishtp_device *dev)
        csr |= PCI_D3hot;
        pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
 
-       mdelay(pdev->d3_delay);
+       mdelay(pdev->d3hot_delay);
 
        csr &= ~PCI_PM_CTRL_STATE_MASK;
        csr |= PCI_D0;
index e060796f9caa6c3d3d4158c2deeba1cd7eb46460..146ca6fb3260f32a581ae942da98cddb0dce9baf 100644 (file)
 
 #define PCI_DEVICE_ID_TI_J721E                 0xb00d
 #define PCI_DEVICE_ID_TI_AM654                 0xb00c
+#define PCI_DEVICE_ID_LS1088A                  0x80c0
 
 #define is_am654_pci_dev(pdev)         \
                ((pdev)->device == PCI_DEVICE_ID_TI_AM654)
 
+#define PCI_DEVICE_ID_RENESAS_R8A774A1         0x0028
+#define PCI_DEVICE_ID_RENESAS_R8A774B1         0x002b
 #define PCI_DEVICE_ID_RENESAS_R8A774C0         0x002d
+#define PCI_DEVICE_ID_RENESAS_R8A774E1         0x0025
 
 static DEFINE_IDA(pci_endpoint_test_ida);
 
@@ -945,13 +949,20 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x),
          .driver_data = (kernel_ulong_t)&default_data,
        },
-       { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
+       { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0),
+         .driver_data = (kernel_ulong_t)&default_data,
+       },
+       { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A),
+         .driver_data = (kernel_ulong_t)&default_data,
+       },
        { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
          .driver_data = (kernel_ulong_t)&am654_data
        },
-       { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),
-       },
+       { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774A1),},
+       { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),},
+       { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),},
+       { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),},
        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
          .driver_data = (kernel_ulong_t)&j721e_data,
        },
index 344864275ed56a6a323a19645f8a13d62b39db02..25981a7a43b5d3508688ffe369624a0de15977b3 100644 (file)
@@ -5105,7 +5105,7 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        INIT_WORK(&hw->restart_work, sky2_restart);
 
        pci_set_drvdata(pdev, hw);
-       pdev->d3_delay = 300;
+       pdev->d3hot_delay = 300;
 
        return 0;
 
index 438a792d2cf7715fcb992871e322768d328d8521..0c473d75e625c5bdd187d19f984b841803a6a656 100644 (file)
@@ -190,6 +190,68 @@ config PCI_HYPERV
          The PCI device frontend driver allows the kernel to import arbitrary
          PCI devices from a PCI backend to support PCI driver domains.
 
+choice
+       prompt "PCI Express hierarchy optimization setting"
+       default PCIE_BUS_DEFAULT
+       depends on PCI && EXPERT
+       help
+         MPS (Max Payload Size) and MRRS (Max Read Request Size) are PCIe
+         device parameters that affect performance and the ability to
+         support hotplug and peer-to-peer DMA.
+
+         The following choices set the MPS and MRRS optimization strategy
+         at compile-time.  The choices are the same as those offered for
+         the kernel command-line parameter 'pci', i.e.,
+         'pci=pcie_bus_tune_off', 'pci=pcie_bus_safe',
+         'pci=pcie_bus_perf', and 'pci=pcie_bus_peer2peer'.
+
+         This is a compile-time setting and can be overridden by the above
+         command-line parameters.  If unsure, choose PCIE_BUS_DEFAULT.
+
+config PCIE_BUS_TUNE_OFF
+       bool "Tune Off"
+       depends on PCI
+       help
+         Use the BIOS defaults; don't touch MPS at all.  This is the same
+         as booting with 'pci=pcie_bus_tune_off'.
+
+config PCIE_BUS_DEFAULT
+       bool "Default"
+       depends on PCI
+       help
+         Default choice; ensure that the MPS matches upstream bridge.
+
+config PCIE_BUS_SAFE
+       bool "Safe"
+       depends on PCI
+       help
+         Use largest MPS that boot-time devices support.  If you have a
+         closed system with no possibility of adding new devices, this
+         will use the largest MPS that's supported by all devices.  This
+         is the same as booting with 'pci=pcie_bus_safe'.
+
+config PCIE_BUS_PERFORMANCE
+       bool "Performance"
+       depends on PCI
+       help
+         Use MPS and MRRS for best performance.  Ensure that a given
+         device's MPS is no larger than its parent MPS, which allows us to
+         keep all switches/bridges to the max MPS supported by their
+         parent.  This is the same as booting with 'pci=pcie_bus_perf'.
+
+config PCIE_BUS_PEER2PEER
+       bool "Peer2peer"
+       depends on PCI
+       help
+         Set MPS = 128 for all devices.  MPS configuration effected by the
+         other options could cause the MPS on one root port to be
+         different than that of the MPS on another, which may cause
+         hot-added devices or peer-to-peer DMA to fail.  Set MPS to the
+         smallest possible value (128B) system-wide to avoid these issues.
+         This is the same as booting with 'pci=pcie_bus_peer2peer'.
+
+endchoice
+
 source "drivers/pci/hotplug/Kconfig"
 source "drivers/pci/controller/Kconfig"
 source "drivers/pci/endpoint/Kconfig"
index 4a7afbe189f8c9f87798d419d659f9e7f1a38ef0..64e2f5e379aa390229e2557ac15d09dc6b4fc402 100644 (file)
@@ -12,7 +12,7 @@ config PCI_MVEBU
        select PCI_BRIDGE_EMUL
 
 config PCI_AARDVARK
-       bool "Aardvark PCIe controller"
+       tristate "Aardvark PCIe controller"
        depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST
        depends on OF
        depends on PCI_MSI_IRQ_DOMAIN
@@ -273,9 +273,10 @@ config VMD
 
 config PCIE_BRCMSTB
        tristate "Broadcom Brcmstb PCIe host controller"
-       depends on ARCH_BCM2835 || COMPILE_TEST
+       depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
        depends on OF
        depends on PCI_MSI_IRQ_DOMAIN
+       default ARCH_BRCMSTB
        help
          Say Y here to enable PCIe host controller support for
          Broadcom STB based SoCs, like the Raspberry Pi 4.
@@ -297,6 +298,13 @@ config PCI_LOONGSON
          Say Y here if you want to enable PCI controller support on
          Loongson systems.
 
+config PCIE_HISI_ERR
+       depends on ACPI_APEI_GHES && (ARM64 || COMPILE_TEST)
+       bool "HiSilicon HIP PCIe controller error handling driver"
+       help
+         Say Y here if you want error handling support
+         for the PCIe controller's errors on HiSilicon HIP SoCs
+
 source "drivers/pci/controller/dwc/Kconfig"
 source "drivers/pci/controller/mobiveil/Kconfig"
 source "drivers/pci/controller/cadence/Kconfig"
index bcdbf49ab1e40738270cd8020153cf5ee4022931..04c6edc285c511a8f470bdcf721ff4b5eeb65327 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
 obj-$(CONFIG_VMD) += vmd.o
 obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
 obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o
+obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o
 # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
 obj-y                          += dwc/
 obj-y                          += mobiveil/
index 254a3e1eff50e5198a23d28c871bf3eb0e054b36..84cc58dc8512cde3a57af11422f2ed2e9ed1ec44 100644 (file)
@@ -328,7 +328,6 @@ static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx)
        cdns_pcie_ep_assert_intx(ep, fn, intx, true);
        /*
         * The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq()
-        * from drivers/pci/dwc/pci-dra7xx.c
         */
        mdelay(1);
        cdns_pcie_ep_assert_intx(ep, fn, intx, false);
index 4550e0d469ca8f9f73cd63dc5571845237b9093e..811c1cb2e8deb5211ade382daae684df50f11d00 100644 (file)
@@ -337,7 +337,7 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
        struct resource_entry *entry;
        u64 cpu_addr = cfg_res->start;
        u32 addr0, addr1, desc1;
-       int r, err, busnr = 0;
+       int r, busnr = 0;
 
        entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
        if (entry)
@@ -383,11 +383,7 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
                r++;
        }
 
-       err = cdns_pcie_host_map_dma_ranges(rc);
-       if (err)
-               return err;
-
-       return 0;
+       return cdns_pcie_host_map_dma_ranges(rc);
 }
 
 static int cdns_pcie_host_init(struct device *dev,
index 044a3761c44f2e4cef306287bf580f0529681293..bc049865f8e0539cf6554e7ef1c0162c6a5c73c2 100644 (file)
@@ -237,8 +237,9 @@ config PCIE_HISI_STB
          Say Y here if you want PCIe controller support on HiSilicon STB SoCs
 
 config PCI_MESON
-       bool "MESON PCIe controller"
+       tristate "MESON PCIe controller"
        depends on PCI_MSI_IRQ_DOMAIN
+       default m if ARCH_MESON
        select PCIE_DW_HOST
        help
          Say Y here if you want to enable PCI controller support on Amlogic
index dc387724cf08fe74f0a2d1c15c116e7fffa8e232..6d012d2b1e90d75ddb321e2e4c4c540685ba582d 100644 (file)
@@ -73,8 +73,6 @@
 #define        LINK_UP                                         BIT(16)
 #define        DRA7XX_CPU_TO_BUS_ADDR                          0x0FFFFFFF
 
-#define EXP_CAP_ID_OFFSET                              0x70
-
 #define        PCIECTRL_TI_CONF_INTX_ASSERT                    0x0124
 #define        PCIECTRL_TI_CONF_INTX_DEASSERT                  0x0128
 
@@ -91,7 +89,6 @@ struct dra7xx_pcie {
        void __iomem            *base;          /* DT ti_conf */
        int                     phy_count;      /* DT phy-names count */
        struct phy              **phy;
-       int                     link_gen;
        struct irq_domain       *irq_domain;
        enum dw_pcie_device_mode mode;
 };
@@ -142,33 +139,12 @@ static int dra7xx_pcie_establish_link(struct dw_pcie *pci)
        struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
        struct device *dev = pci->dev;
        u32 reg;
-       u32 exp_cap_off = EXP_CAP_ID_OFFSET;
 
        if (dw_pcie_link_up(pci)) {
                dev_err(dev, "link is already up\n");
                return 0;
        }
 
-       if (dra7xx->link_gen == 1) {
-               dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
-                            4, &reg);
-               if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
-                       reg &= ~((u32)PCI_EXP_LNKCAP_SLS);
-                       reg |= PCI_EXP_LNKCAP_SLS_2_5GB;
-                       dw_pcie_write(pci->dbi_base + exp_cap_off +
-                                     PCI_EXP_LNKCAP, 4, reg);
-               }
-
-               dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
-                            2, &reg);
-               if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
-                       reg &= ~((u32)PCI_EXP_LNKCAP_SLS);
-                       reg |= PCI_EXP_LNKCAP_SLS_2_5GB;
-                       dw_pcie_write(pci->dbi_base + exp_cap_off +
-                                     PCI_EXP_LNKCTL2, 2, reg);
-               }
-       }
-
        reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
        reg |= LTSSM_EN;
        dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
@@ -490,7 +466,9 @@ static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = {
 static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct device *dev = pci->dev;
        u32 ctrl, num_ctrls;
+       int ret;
 
        pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip;
 
@@ -506,7 +484,21 @@ static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
                                    ~0);
        }
 
-       return dw_pcie_allocate_domains(pp);
+       ret = dw_pcie_allocate_domains(pp);
+       if (ret)
+               return ret;
+
+       pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg,
+                                          sizeof(pp->msi_msg),
+                                          DMA_FROM_DEVICE,
+                                          DMA_ATTR_SKIP_CPU_SYNC);
+       ret = dma_mapping_error(dev, pp->msi_data);
+       if (ret) {
+               dev_err(dev, "Failed to map MSI data\n");
+               pp->msi_data = 0;
+               dw_pcie_free_msi(pp);
+       }
+       return ret;
 }
 
 static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
@@ -937,10 +929,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
        reg &= ~LTSSM_EN;
        dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
 
-       dra7xx->link_gen = of_pci_get_max_link_speed(np);
-       if (dra7xx->link_gen < 0 || dra7xx->link_gen > 2)
-               dra7xx->link_gen = 2;
-
        switch (mode) {
        case DW_PCIE_RC_TYPE:
                if (!IS_ENABLED(CONFIG_PCI_DRA7XX_HOST)) {
index 8d82c43ae299845770c704bfca2385b74a3b8c76..242683cde04a5d62e7b19121fea1ed52daadd6c4 100644 (file)
@@ -336,32 +336,37 @@ static void exynos_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
        exynos_pcie_sideband_dbi_w_mode(ep, false);
 }
 
-static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
-                               u32 *val)
+static int exynos_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
+                                  int where, int size, u32 *val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct exynos_pcie *ep = to_exynos_pcie(pci);
-       int ret;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
 
-       exynos_pcie_sideband_dbi_r_mode(ep, true);
-       ret = dw_pcie_read(pci->dbi_base + where, size, val);
-       exynos_pcie_sideband_dbi_r_mode(ep, false);
-       return ret;
+       if (PCI_SLOT(devfn)) {
+               *val = ~0;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       *val = dw_pcie_read_dbi(pci, where, size);
+       return PCIBIOS_SUCCESSFUL;
 }
 
-static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
-                               u32 val)
+static int exynos_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
+                                  int where, int size, u32 val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct exynos_pcie *ep = to_exynos_pcie(pci);
-       int ret;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
 
-       exynos_pcie_sideband_dbi_w_mode(ep, true);
-       ret = dw_pcie_write(pci->dbi_base + where, size, val);
-       exynos_pcie_sideband_dbi_w_mode(ep, false);
-       return ret;
+       if (PCI_SLOT(devfn))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       dw_pcie_write_dbi(pci, where, size, val);
+       return PCIBIOS_SUCCESSFUL;
 }
 
+static struct pci_ops exynos_pci_ops = {
+       .read = exynos_pcie_rd_own_conf,
+       .write = exynos_pcie_wr_own_conf,
+};
+
 static int exynos_pcie_link_up(struct dw_pcie *pci)
 {
        struct exynos_pcie *ep = to_exynos_pcie(pci);
@@ -379,6 +384,8 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct exynos_pcie *ep = to_exynos_pcie(pci);
 
+       pp->bridge->ops = &exynos_pci_ops;
+
        exynos_pcie_establish_link(ep);
        exynos_pcie_enable_interrupts(ep);
 
@@ -386,8 +393,6 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
 }
 
 static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
-       .rd_own_conf = exynos_pcie_rd_own_conf,
-       .wr_own_conf = exynos_pcie_wr_own_conf,
        .host_init = exynos_pcie_host_init,
 };
 
index 5fef2613b223ad2188b833f29f7db850b3ebc8b2..5cf1ef12fb9b05f892cfed3aa84db05e99dc7bcd 100644 (file)
@@ -79,7 +79,6 @@ struct imx6_pcie {
        u32                     tx_deemph_gen2_6db;
        u32                     tx_swing_full;
        u32                     tx_swing_low;
-       int                     link_gen;
        struct regulator        *vpcie;
        void __iomem            *phy_base;
 
@@ -94,15 +93,6 @@ struct imx6_pcie {
 #define PHY_PLL_LOCK_WAIT_USLEEP_MAX   200
 #define PHY_PLL_LOCK_WAIT_TIMEOUT      (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX)
 
-/* PCIe Root Complex registers (memory-mapped) */
-#define PCIE_RC_IMX6_MSI_CAP                   0x50
-#define PCIE_RC_LCR                            0x7c
-#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1       0x1
-#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2       0x2
-#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK       0xf
-
-#define PCIE_RC_LCSR                           0x80
-
 /* PCIe Port Logic registers (memory-mapped) */
 #define PL_OFFSET 0x700
 
@@ -116,8 +106,6 @@ struct imx6_pcie {
 #define PCIE_PHY_STAT (PL_OFFSET + 0x110)
 #define PCIE_PHY_STAT_ACK              BIT(16)
 
-#define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
-
 /* PHY registers (not memory-mapped) */
 #define PCIE_PHY_ATEOVRD                       0x10
 #define  PCIE_PHY_ATEOVRD_EN                   BIT(2)
@@ -761,6 +749,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 {
        struct dw_pcie *pci = imx6_pcie->pci;
        struct device *dev = pci->dev;
+       u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        u32 tmp;
        int ret;
 
@@ -769,10 +758,10 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
         * started in Gen2 mode, there is a possibility the devices on the
         * bus will not be detected at all.  This happens with PCIe switches.
         */
-       tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
-       tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
-       tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
-       dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
+       tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
+       tmp &= ~PCI_EXP_LNKCAP_SLS;
+       tmp |= PCI_EXP_LNKCAP_SLS_2_5GB;
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
 
        /* Start LTSSM. */
        imx6_pcie_ltssm_enable(dev);
@@ -781,12 +770,12 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
        if (ret)
                goto err_reset_phy;
 
-       if (imx6_pcie->link_gen == 2) {
+       if (pci->link_gen == 2) {
                /* Allow Gen2 mode after the link is up. */
-               tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
-               tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
-               tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
-               dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
+               tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
+               tmp &= ~PCI_EXP_LNKCAP_SLS;
+               tmp |= PCI_EXP_LNKCAP_SLS_5_0GB;
+               dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
 
                /*
                 * Start Directed Speed Change so the best possible
@@ -824,8 +813,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
                dev_info(dev, "Link: Gen2 disabled\n");
        }
 
-       tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR);
-       dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf);
+       tmp = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
+       dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS);
        return 0;
 
 err_reset_phy:
@@ -847,9 +836,7 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
        imx6_setup_phy_mpll(imx6_pcie);
        dw_pcie_setup_rc(pp);
        imx6_pcie_establish_link(imx6_pcie);
-
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(pp);
+       dw_pcie_msi_init(pp);
 
        return 0;
 }
@@ -1073,38 +1060,33 @@ static int imx6_pcie_probe(struct platform_device *pdev)
 
        /* Fetch clocks */
        imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy");
-       if (IS_ERR(imx6_pcie->pcie_phy)) {
-               dev_err(dev, "pcie_phy clock source missing or invalid\n");
-               return PTR_ERR(imx6_pcie->pcie_phy);
-       }
+       if (IS_ERR(imx6_pcie->pcie_phy))
+               return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy),
+                                    "pcie_phy clock source missing or invalid\n");
 
        imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus");
-       if (IS_ERR(imx6_pcie->pcie_bus)) {
-               dev_err(dev, "pcie_bus clock source missing or invalid\n");
-               return PTR_ERR(imx6_pcie->pcie_bus);
-       }
+       if (IS_ERR(imx6_pcie->pcie_bus))
+               return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_bus),
+                                    "pcie_bus clock source missing or invalid\n");
 
        imx6_pcie->pcie = devm_clk_get(dev, "pcie");
-       if (IS_ERR(imx6_pcie->pcie)) {
-               dev_err(dev, "pcie clock source missing or invalid\n");
-               return PTR_ERR(imx6_pcie->pcie);
-       }
+       if (IS_ERR(imx6_pcie->pcie))
+               return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie),
+                                    "pcie clock source missing or invalid\n");
 
        switch (imx6_pcie->drvdata->variant) {
        case IMX6SX:
                imx6_pcie->pcie_inbound_axi = devm_clk_get(dev,
                                                           "pcie_inbound_axi");
-               if (IS_ERR(imx6_pcie->pcie_inbound_axi)) {
-                       dev_err(dev, "pcie_inbound_axi clock missing or invalid\n");
-                       return PTR_ERR(imx6_pcie->pcie_inbound_axi);
-               }
+               if (IS_ERR(imx6_pcie->pcie_inbound_axi))
+                       return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_inbound_axi),
+                                            "pcie_inbound_axi clock missing or invalid\n");
                break;
        case IMX8MQ:
                imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
-               if (IS_ERR(imx6_pcie->pcie_aux)) {
-                       dev_err(dev, "pcie_aux clock source missing or invalid\n");
-                       return PTR_ERR(imx6_pcie->pcie_aux);
-               }
+               if (IS_ERR(imx6_pcie->pcie_aux))
+                       return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux),
+                                            "pcie_aux clock source missing or invalid\n");
                fallthrough;
        case IMX7D:
                if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
@@ -1165,10 +1147,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
                imx6_pcie->tx_swing_low = 127;
 
        /* Limit link speed */
-       ret = of_property_read_u32(node, "fsl,max-link-speed",
-                                  &imx6_pcie->link_gen);
-       if (ret)
-               imx6_pcie->link_gen = 1;
+       pci->link_gen = 1;
+       ret = of_property_read_u32(node, "fsl,max-link-speed", &pci->link_gen);
 
        imx6_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie");
        if (IS_ERR(imx6_pcie->vpcie)) {
@@ -1188,11 +1168,10 @@ static int imx6_pcie_probe(struct platform_device *pdev)
                return ret;
 
        if (pci_msi_enabled()) {
-               val = dw_pcie_readw_dbi(pci, PCIE_RC_IMX6_MSI_CAP +
-                                       PCI_MSI_FLAGS);
+               u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
+               val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS);
                val |= PCI_MSI_FLAGS_ENABLE;
-               dw_pcie_writew_dbi(pci, PCIE_RC_IMX6_MSI_CAP + PCI_MSI_FLAGS,
-                                  val);
+               dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val);
        }
 
        return 0;
index c8c9d6a75f17fc491f81cfec3a4f66bc3b0b9d24..a222728238caeb9e9afd71e8dde7258559c50df4 100644 (file)
@@ -96,8 +96,6 @@
 #define LEG_EP                         0x1
 #define RC                             0x2
 
-#define EXP_CAP_ID_OFFSET              0x70
-
 #define KS_PCIE_SYSCLOCKOUTEN          BIT(0)
 
 #define AM654_PCIE_DEV_TYPE_MASK       0x3
@@ -123,7 +121,6 @@ struct keystone_pcie {
 
        int                     msi_host_irq;
        int                     num_lanes;
-       u32                     num_viewport;
        struct phy              **phy;
        struct device_link      **link;
        struct                  device_node *msi_intc_np;
@@ -397,13 +394,17 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie)
 static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
 {
        u32 val;
-       u32 num_viewport = ks_pcie->num_viewport;
        struct dw_pcie *pci = ks_pcie->pci;
        struct pcie_port *pp = &pci->pp;
-       u64 start = pp->mem->start;
-       u64 end = pp->mem->end;
+       u32 num_viewport = pci->num_viewport;
+       u64 start, end;
+       struct resource *mem;
        int i;
 
+       mem = resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM)->res;
+       start = mem->start;
+       end = mem->end;
+
        /* Disable BARs for inbound access */
        ks_pcie_set_dbi_mode(ks_pcie);
        dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
@@ -430,10 +431,10 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
        ks_pcie_app_writel(ks_pcie, CMD_STATUS, val);
 }
 
-static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-                                unsigned int devfn, int where, int size,
-                                u32 *val)
+static void __iomem *ks_pcie_other_map_bus(struct pci_bus *bus,
+                                          unsigned int devfn, int where)
 {
+       struct pcie_port *pp = bus->sysdata;
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
        u32 reg;
@@ -444,36 +445,29 @@ static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
                reg |= CFG_TYPE1;
        ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
 
-       return dw_pcie_read(pp->va_cfg0_base + where, size, val);
+       return pp->va_cfg0_base + where;
 }
 
-static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-                                unsigned int devfn, int where, int size,
-                                u32 val)
-{
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-       u32 reg;
-
-       reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) |
-               CFG_FUNC(PCI_FUNC(devfn));
-       if (!pci_is_root_bus(bus->parent))
-               reg |= CFG_TYPE1;
-       ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
-
-       return dw_pcie_write(pp->va_cfg0_base + where, size, val);
-}
+static struct pci_ops ks_child_pcie_ops = {
+       .map_bus = ks_pcie_other_map_bus,
+       .read = pci_generic_config_read,
+       .write = pci_generic_config_write,
+};
 
 /**
- * ks_pcie_v3_65_scan_bus() - keystone scan_bus post initialization
+ * ks_pcie_v3_65_add_bus() - keystone add_bus post initialization
  *
  * This sets BAR0 to enable inbound access for MSI_IRQ register
  */
-static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp)
+static int ks_pcie_v3_65_add_bus(struct pci_bus *bus)
 {
+       struct pcie_port *pp = bus->sysdata;
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
 
+       if (!pci_is_root_bus(bus))
+               return 0;
+
        /* Configure and set up BAR0 */
        ks_pcie_set_dbi_mode(ks_pcie);
 
@@ -488,8 +482,17 @@ static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp)
          * be sufficient.  Use physical address to avoid any conflicts.
          */
        dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start);
+
+       return 0;
 }
 
+static struct pci_ops ks_pcie_ops = {
+       .map_bus = dw_pcie_own_conf_map_bus,
+       .read = pci_generic_config_read,
+       .write = pci_generic_config_write,
+       .add_bus = ks_pcie_v3_65_add_bus,
+};
+
 /**
  * ks_pcie_link_up() - Check if link up
  */
@@ -807,6 +810,9 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
        struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
        int ret;
 
+       pp->bridge->ops = &ks_pcie_ops;
+       pp->bridge->child_ops = &ks_child_pcie_ops;
+
        ret = ks_pcie_config_legacy_irq(ks_pcie);
        if (ret)
                return ret;
@@ -842,11 +848,8 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
 }
 
 static const struct dw_pcie_host_ops ks_pcie_host_ops = {
-       .rd_other_conf = ks_pcie_rd_other_conf,
-       .wr_other_conf = ks_pcie_wr_other_conf,
        .host_init = ks_pcie_host_init,
        .msi_host_init = ks_pcie_msi_host_init,
-       .scan_bus = ks_pcie_v3_65_scan_bus,
 };
 
 static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
@@ -867,16 +870,8 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
        struct dw_pcie *pci = ks_pcie->pci;
        struct pcie_port *pp = &pci->pp;
        struct device *dev = &pdev->dev;
-       struct resource *res;
        int ret;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
-       pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res);
-       if (IS_ERR(pp->va_cfg0_base))
-               return PTR_ERR(pp->va_cfg0_base);
-
-       pp->va_cfg1_base = pp->va_cfg0_base;
-
        ret = dw_pcie_host_init(pp);
        if (ret) {
                dev_err(dev, "failed to initialize host\n");
@@ -886,18 +881,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
        return 0;
 }
 
-static u32 ks_pcie_am654_read_dbi2(struct dw_pcie *pci, void __iomem *base,
-                                  u32 reg, size_t size)
-{
-       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-       u32 val;
-
-       ks_pcie_set_dbi_mode(ks_pcie);
-       dw_pcie_read(base + reg, size, &val);
-       ks_pcie_clear_dbi_mode(ks_pcie);
-       return val;
-}
-
 static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base,
                                     u32 reg, size_t size, u32 val)
 {
@@ -912,7 +895,6 @@ static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = {
        .start_link = ks_pcie_start_link,
        .stop_link = ks_pcie_stop_link,
        .link_up = ks_pcie_link_up,
-       .read_dbi2 = ks_pcie_am654_read_dbi2,
        .write_dbi2 = ks_pcie_am654_write_dbi2,
 };
 
@@ -1125,31 +1107,6 @@ static int ks_pcie_am654_set_mode(struct device *dev,
        return 0;
 }
 
-static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed)
-{
-       u32 val;
-
-       dw_pcie_dbi_ro_wr_en(pci);
-
-       val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP);
-       if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) {
-               val &= ~((u32)PCI_EXP_LNKCAP_SLS);
-               val |= link_speed;
-               dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP,
-                                  val);
-       }
-
-       val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2);
-       if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) {
-               val &= ~((u32)PCI_EXP_LNKCAP_SLS);
-               val |= link_speed;
-               dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2,
-                                  val);
-       }
-
-       dw_pcie_dbi_ro_wr_dis(pci);
-}
-
 static const struct ks_pcie_of_data ks_pcie_rc_of_data = {
        .host_ops = &ks_pcie_host_ops,
        .version = 0x365A,
@@ -1197,13 +1154,10 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
        struct keystone_pcie *ks_pcie;
        struct device_link **link;
        struct gpio_desc *gpiod;
-       void __iomem *atu_base;
        struct resource *res;
        unsigned int version;
        void __iomem *base;
-       u32 num_viewport;
        struct phy **phy;
-       int link_speed;
        u32 num_lanes;
        char name[10];
        int ret;
@@ -1320,29 +1274,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
                goto err_get_sync;
        }
 
-       if (pci->version >= 0x480A) {
-               atu_base = devm_platform_ioremap_resource_byname(pdev, "atu");
-               if (IS_ERR(atu_base)) {
-                       ret = PTR_ERR(atu_base);
-                       goto err_get_sync;
-               }
-
-               pci->atu_base = atu_base;
-
+       if (pci->version >= 0x480A)
                ret = ks_pcie_am654_set_mode(dev, mode);
-               if (ret < 0)
-                       goto err_get_sync;
-       } else {
+       else
                ret = ks_pcie_set_mode(dev);
-               if (ret < 0)
-                       goto err_get_sync;
-       }
-
-       link_speed = of_pci_get_max_link_speed(np);
-       if (link_speed < 0)
-               link_speed = 2;
-
-       ks_pcie_set_link_speed(pci, link_speed);
+       if (ret < 0)
+               goto err_get_sync;
 
        switch (mode) {
        case DW_PCIE_RC_TYPE:
@@ -1351,12 +1288,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
                        goto err_get_sync;
                }
 
-               ret = of_property_read_u32(np, "num-viewport", &num_viewport);
-               if (ret < 0) {
-                       dev_err(dev, "unable to read *num-viewport* property\n");
-                       goto err_get_sync;
-               }
-
                /*
                 * "Power Sequencing and Reset Signal Timings" table in
                 * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0
@@ -1370,7 +1301,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
                        gpiod_set_value_cansleep(gpiod, 1);
                }
 
-               ks_pcie->num_viewport = num_viewport;
                pci->pp.ops = host_ops;
                ret = ks_pcie_add_pcie_port(ks_pcie, pdev);
                if (ret < 0)
index 0d151cead1b72ee2c03305f43a4f90b7cb8fe00f..84206f265e54453b4954ab8fc31ff9fcb7197582 100644 (file)
 
 #define PCIE_DBI2_OFFSET               0x1000  /* DBI2 base address*/
 
-struct ls_pcie_ep {
-       struct dw_pcie          *pci;
+#define to_ls_pcie_ep(x)       dev_get_drvdata((x)->dev)
+
+struct ls_pcie_ep_drvdata {
+       u32                             func_offset;
+       const struct dw_pcie_ep_ops     *ops;
+       const struct dw_pcie_ops        *dw_pcie_ops;
 };
 
-#define to_ls_pcie_ep(x)       dev_get_drvdata((x)->dev)
+struct ls_pcie_ep {
+       struct dw_pcie                  *pci;
+       struct pci_epc_features         *ls_epc;
+       const struct ls_pcie_ep_drvdata *drvdata;
+};
 
 static int ls_pcie_establish_link(struct dw_pcie *pci)
 {
        return 0;
 }
 
-static const struct dw_pcie_ops ls_pcie_ep_ops = {
+static const struct dw_pcie_ops dw_ls_pcie_ep_ops = {
        .start_link = ls_pcie_establish_link,
 };
 
-static const struct of_device_id ls_pcie_ep_of_match[] = {
-       { .compatible = "fsl,ls-pcie-ep",},
-       { },
-};
-
-static const struct pci_epc_features ls_pcie_epc_features = {
-       .linkup_notifier = false,
-       .msi_capable = true,
-       .msix_capable = false,
-       .bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4),
-};
-
 static const struct pci_epc_features*
 ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
 {
-       return &ls_pcie_epc_features;
+       struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
+
+       return pcie->ls_epc;
 }
 
 static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
 {
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
+       struct dw_pcie_ep_func *ep_func;
        enum pci_barno bar;
 
+       ep_func = dw_pcie_ep_get_func_from_ep(ep, 0);
+       if (!ep_func)
+               return;
+
        for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
                dw_pcie_ep_reset_bar(pci, bar);
+
+       pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false;
+       pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false;
 }
 
 static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
-                                 enum pci_epc_irq_type type, u16 interrupt_num)
+                               enum pci_epc_irq_type type, u16 interrupt_num)
 {
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 
@@ -73,21 +81,51 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
        case PCI_EPC_IRQ_MSI:
                return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
        case PCI_EPC_IRQ_MSIX:
-               return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
+               return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no,
+                                                         interrupt_num);
        default:
                dev_err(pci->dev, "UNKNOWN IRQ type\n");
                return -EINVAL;
        }
 }
 
-static const struct dw_pcie_ep_ops pcie_ep_ops = {
+static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
+                                               u8 func_no)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
+
+       WARN_ON(func_no && !pcie->drvdata->func_offset);
+       return pcie->drvdata->func_offset * func_no;
+}
+
+static const struct dw_pcie_ep_ops ls_pcie_ep_ops = {
        .ep_init = ls_pcie_ep_init,
        .raise_irq = ls_pcie_ep_raise_irq,
        .get_features = ls_pcie_ep_get_features,
+       .func_conf_select = ls_pcie_ep_func_conf_select,
+};
+
+static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = {
+       .ops = &ls_pcie_ep_ops,
+       .dw_pcie_ops = &dw_ls_pcie_ep_ops,
+};
+
+static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = {
+       .func_offset = 0x20000,
+       .ops = &ls_pcie_ep_ops,
+       .dw_pcie_ops = &dw_ls_pcie_ep_ops,
+};
+
+static const struct of_device_id ls_pcie_ep_of_match[] = {
+       { .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata },
+       { .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata },
+       { .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata },
+       { },
 };
 
 static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
-                                       struct platform_device *pdev)
+                                struct platform_device *pdev)
 {
        struct dw_pcie *pci = pcie->pci;
        struct device *dev = pci->dev;
@@ -96,7 +134,7 @@ static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
        int ret;
 
        ep = &pci->ep;
-       ep->ops = &pcie_ep_ops;
+       ep->ops = pcie->drvdata->ops;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
        if (!res)
@@ -119,6 +157,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct dw_pcie *pci;
        struct ls_pcie_ep *pcie;
+       struct pci_epc_features *ls_epc;
        struct resource *dbi_base;
        int ret;
 
@@ -130,15 +169,26 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
        if (!pci)
                return -ENOMEM;
 
+       ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL);
+       if (!ls_epc)
+               return -ENOMEM;
+
+       pcie->drvdata = of_device_get_match_data(dev);
+
+       pci->dev = dev;
+       pci->ops = pcie->drvdata->dw_pcie_ops;
+
+       ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4),
+
+       pcie->pci = pci;
+       pcie->ls_epc = ls_epc;
+
        dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
        pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
        if (IS_ERR(pci->dbi_base))
                return PTR_ERR(pci->dbi_base);
 
        pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET;
-       pci->dev = dev;
-       pci->ops = &ls_pcie_ep_ops;
-       pcie->pci = pci;
 
        platform_set_drvdata(pdev, pcie);
 
index 4f183b96afbbfe2de9bb79fac7d95c7a691d9676..1913dc2c8fa0864d6d266842a18f68f220a69214 100644 (file)
 #include <linux/resource.h>
 #include <linux/types.h>
 #include <linux/phy/phy.h>
+#include <linux/module.h>
 
 #include "pcie-designware.h"
 
 #define to_meson_pcie(x) dev_get_drvdata((x)->dev)
 
-/* External local bus interface registers */
-#define PLR_OFFSET                     0x700
-#define PCIE_PORT_LINK_CTRL_OFF                (PLR_OFFSET + 0x10)
-#define FAST_LINK_MODE                 BIT(7)
-#define LINK_CAPABLE_MASK              GENMASK(21, 16)
-#define LINK_CAPABLE_X1                        BIT(16)
-
-#define PCIE_GEN2_CTRL_OFF             (PLR_OFFSET + 0x10c)
-#define NUM_OF_LANES_MASK              GENMASK(12, 8)
-#define NUM_OF_LANES_X1                        BIT(8)
-#define DIRECT_SPEED_CHANGE            BIT(17)
-
-#define TYPE1_HDR_OFFSET               0x0
-#define PCIE_STATUS_COMMAND            (TYPE1_HDR_OFFSET + 0x04)
-#define PCI_IO_EN                      BIT(0)
-#define PCI_MEM_SPACE_EN               BIT(1)
-#define PCI_BUS_MASTER_EN              BIT(2)
-
-#define PCIE_BASE_ADDR0                        (TYPE1_HDR_OFFSET + 0x10)
-#define PCIE_BASE_ADDR1                        (TYPE1_HDR_OFFSET + 0x14)
-
-#define PCIE_CAP_OFFSET                        0x70
-#define PCIE_DEV_CTRL_DEV_STUS         (PCIE_CAP_OFFSET + 0x08)
-#define PCIE_CAP_MAX_PAYLOAD_MASK      GENMASK(7, 5)
 #define PCIE_CAP_MAX_PAYLOAD_SIZE(x)   ((x) << 5)
-#define PCIE_CAP_MAX_READ_REQ_MASK     GENMASK(14, 12)
 #define PCIE_CAP_MAX_READ_REQ_SIZE(x)  ((x) << 12)
 
 /* PCIe specific config registers */
@@ -77,11 +53,6 @@ enum pcie_data_rate {
        PCIE_GEN4
 };
 
-struct meson_pcie_mem_res {
-       void __iomem *elbi_base;
-       void __iomem *cfg_base;
-};
-
 struct meson_pcie_clk_res {
        struct clk *clk;
        struct clk *port_clk;
@@ -95,7 +66,7 @@ struct meson_pcie_rc_reset {
 
 struct meson_pcie {
        struct dw_pcie pci;
-       struct meson_pcie_mem_res mem_res;
+       void __iomem *cfg_base;
        struct meson_pcie_clk_res clk_res;
        struct meson_pcie_rc_reset mrst;
        struct gpio_desc *reset_gpio;
@@ -134,28 +105,18 @@ static int meson_pcie_get_resets(struct meson_pcie *mp)
        return 0;
 }
 
-static void __iomem *meson_pcie_get_mem(struct platform_device *pdev,
-                                       struct meson_pcie *mp,
-                                       const char *id)
-{
-       struct device *dev = mp->pci.dev;
-       struct resource *res;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
-
-       return devm_ioremap_resource(dev, res);
-}
-
 static int meson_pcie_get_mems(struct platform_device *pdev,
                               struct meson_pcie *mp)
 {
-       mp->mem_res.elbi_base = meson_pcie_get_mem(pdev, mp, "elbi");
-       if (IS_ERR(mp->mem_res.elbi_base))
-               return PTR_ERR(mp->mem_res.elbi_base);
+       struct dw_pcie *pci = &mp->pci;
+
+       pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
+       if (IS_ERR(pci->dbi_base))
+               return PTR_ERR(pci->dbi_base);
 
-       mp->mem_res.cfg_base = meson_pcie_get_mem(pdev, mp, "cfg");
-       if (IS_ERR(mp->mem_res.cfg_base))
-               return PTR_ERR(mp->mem_res.cfg_base);
+       mp->cfg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
+       if (IS_ERR(mp->cfg_base))
+               return PTR_ERR(mp->cfg_base);
 
        return 0;
 }
@@ -253,24 +214,14 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
        return 0;
 }
 
-static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg)
-{
-       writel(val, mp->mem_res.elbi_base + reg);
-}
-
-static inline u32 meson_elb_readl(struct meson_pcie *mp, u32 reg)
-{
-       return readl(mp->mem_res.elbi_base + reg);
-}
-
 static inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg)
 {
-       return readl(mp->mem_res.cfg_base + reg);
+       return readl(mp->cfg_base + reg);
 }
 
 static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg)
 {
-       writel(val, mp->mem_res.cfg_base + reg);
+       writel(val, mp->cfg_base + reg);
 }
 
 static void meson_pcie_assert_reset(struct meson_pcie *mp)
@@ -287,25 +238,6 @@ static void meson_pcie_init_dw(struct meson_pcie *mp)
        val = meson_cfg_readl(mp, PCIE_CFG0);
        val |= APP_LTSSM_ENABLE;
        meson_cfg_writel(mp, val, PCIE_CFG0);
-
-       val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
-       val &= ~(LINK_CAPABLE_MASK | FAST_LINK_MODE);
-       meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
-
-       val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
-       val |= LINK_CAPABLE_X1;
-       meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
-
-       val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
-       val &= ~NUM_OF_LANES_MASK;
-       meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
-
-       val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
-       val |= NUM_OF_LANES_X1 | DIRECT_SPEED_CHANGE;
-       meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
-
-       meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0);
-       meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1);
 }
 
 static int meson_size_to_payload(struct meson_pcie *mp, int size)
@@ -327,37 +259,34 @@ static int meson_size_to_payload(struct meson_pcie *mp, int size)
 
 static void meson_set_max_payload(struct meson_pcie *mp, int size)
 {
+       struct dw_pcie *pci = &mp->pci;
        u32 val;
+       u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        int max_payload_size = meson_size_to_payload(mp, size);
 
-       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
-       val &= ~PCIE_CAP_MAX_PAYLOAD_MASK;
-       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+       val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
+       val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
 
-       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+       val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
        val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
-       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
 }
 
 static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
 {
+       struct dw_pcie *pci = &mp->pci;
        u32 val;
+       u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        int max_rd_req_size = meson_size_to_payload(mp, size);
 
-       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
-       val &= ~PCIE_CAP_MAX_READ_REQ_MASK;
-       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+       val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
+       val &= ~PCI_EXP_DEVCTL_READRQ;
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
 
-       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+       val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
        val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
-       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
-}
-
-static inline void meson_enable_memory_space(struct meson_pcie *mp)
-{
-       /* Set the RC Bus Master, Memory Space and I/O Space enables */
-       meson_elb_writel(mp, PCI_IO_EN | PCI_MEM_SPACE_EN | PCI_BUS_MASTER_EN,
-                        PCIE_STATUS_COMMAND);
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
 }
 
 static int meson_pcie_establish_link(struct meson_pcie *mp)
@@ -370,26 +299,18 @@ static int meson_pcie_establish_link(struct meson_pcie *mp)
        meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
 
        dw_pcie_setup_rc(pp);
-       meson_enable_memory_space(mp);
 
        meson_pcie_assert_reset(mp);
 
        return dw_pcie_wait_for_link(pci);
 }
 
-static void meson_pcie_enable_interrupts(struct meson_pcie *mp)
+static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
+                                 int where, int size, u32 *val)
 {
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(&mp->pci.pp);
-}
-
-static int meson_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;
 
-       ret = dw_pcie_read(pci->dbi_base + where, size, val);
+       ret = pci_generic_config_read(bus, devfn, where, size, val);
        if (ret != PCIBIOS_SUCCESSFUL)
                return ret;
 
@@ -410,13 +331,11 @@ static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
        return PCIBIOS_SUCCESSFUL;
 }
 
-static int meson_pcie_wr_own_conf(struct pcie_port *pp, int where,
-                                 int size, u32 val)
-{
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-
-       return dw_pcie_write(pci->dbi_base + where, size, val);
-}
+static struct pci_ops meson_pci_ops = {
+       .map_bus = dw_pcie_own_conf_map_bus,
+       .read = meson_pcie_rd_own_conf,
+       .write = pci_generic_config_write,
+};
 
 static int meson_pcie_link_up(struct dw_pcie *pci)
 {
@@ -463,18 +382,18 @@ static int meson_pcie_host_init(struct pcie_port *pp)
        struct meson_pcie *mp = to_meson_pcie(pci);
        int ret;
 
+       pp->bridge->ops = &meson_pci_ops;
+
        ret = meson_pcie_establish_link(mp);
        if (ret)
                return ret;
 
-       meson_pcie_enable_interrupts(mp);
+       dw_pcie_msi_init(pp);
 
        return 0;
 }
 
 static const struct dw_pcie_host_ops meson_pcie_host_ops = {
-       .rd_own_conf = meson_pcie_rd_own_conf,
-       .wr_own_conf = meson_pcie_wr_own_conf,
        .host_init = meson_pcie_host_init,
 };
 
@@ -493,7 +412,6 @@ static int meson_add_pcie_port(struct meson_pcie *mp,
        }
 
        pp->ops = &meson_pcie_host_ops;
-       pci->dbi_base = mp->mem_res.elbi_base;
 
        ret = dw_pcie_host_init(pp);
        if (ret) {
@@ -522,6 +440,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
        pci = &mp->pci;
        pci->dev = dev;
        pci->ops = &dw_pcie_ops;
+       pci->num_lanes = 1;
 
        mp->phy = devm_phy_get(dev, "pcie");
        if (IS_ERR(mp->phy)) {
@@ -589,6 +508,7 @@ static const struct of_device_id meson_pcie_of_match[] = {
        },
        {},
 };
+MODULE_DEVICE_TABLE(of, meson_pcie_of_match);
 
 static struct platform_driver meson_pcie_driver = {
        .probe = meson_pcie_probe,
@@ -598,4 +518,8 @@ static struct platform_driver meson_pcie_driver = {
        },
 };
 
-builtin_platform_driver(meson_pcie_driver);
+module_platform_driver(meson_pcie_driver);
+
+MODULE_AUTHOR("Yue Wang <yue.wang@amlogic.com>");
+MODULE_DESCRIPTION("Amlogic PCIe Controller driver");
+MODULE_LICENSE("GPL v2");
index d57d4ee1584806d286807ba2291d35e926357a88..f973fbca90cf7ce4e00d84b02ebd66f3da047dbf 100644 (file)
@@ -217,14 +217,15 @@ static inline void al_pcie_target_bus_set(struct al_pcie *pcie,
                                  reg);
 }
 
-static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie,
-                                          unsigned int busnr,
-                                          unsigned int devfn)
+static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
+                                              unsigned int devfn, int where)
 {
+       struct pcie_port *pp = bus->sysdata;
+       struct al_pcie *pcie = to_al_pcie(to_dw_pcie_from_pp(pp));
+       unsigned int busnr = bus->number;
        struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg;
        unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask;
        unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask;
-       struct pcie_port *pp = &pcie->pci->pp;
        void __iomem *pci_base_addr;
 
        pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base +
@@ -240,52 +241,14 @@ static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie,
                                       target_bus_cfg->reg_mask);
        }
 
-       return pci_base_addr;
-}
-
-static int al_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-                                unsigned int devfn, int where, int size,
-                                u32 *val)
-{
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct al_pcie *pcie = to_al_pcie(pci);
-       unsigned int busnr = bus->number;
-       void __iomem *pci_addr;
-       int rc;
-
-       pci_addr = al_pcie_conf_addr_map(pcie, busnr, devfn);
-
-       rc = dw_pcie_read(pci_addr + where, size, val);
-
-       dev_dbg(pci->dev, "%d-byte config read from %04x:%02x:%02x.%d offset 0x%x (pci_addr: 0x%px) - val:0x%x\n",
-               size, pci_domain_nr(bus), bus->number,
-               PCI_SLOT(devfn), PCI_FUNC(devfn), where,
-               (pci_addr + where), *val);
-
-       return rc;
+       return pci_base_addr + where;
 }
 
-static int al_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-                                unsigned int devfn, int where, int size,
-                                u32 val)
-{
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct al_pcie *pcie = to_al_pcie(pci);
-       unsigned int busnr = bus->number;
-       void __iomem *pci_addr;
-       int rc;
-
-       pci_addr = al_pcie_conf_addr_map(pcie, busnr, devfn);
-
-       rc = dw_pcie_write(pci_addr + where, size, val);
-
-       dev_dbg(pci->dev, "%d-byte config write to %04x:%02x:%02x.%d offset 0x%x (pci_addr: 0x%px) - val:0x%x\n",
-               size, pci_domain_nr(bus), bus->number,
-               PCI_SLOT(devfn), PCI_FUNC(devfn), where,
-               (pci_addr + where), val);
-
-       return rc;
-}
+static struct pci_ops al_child_pci_ops = {
+       .map_bus = al_pcie_conf_addr_map_bus,
+       .read = pci_generic_config_read,
+       .write = pci_generic_config_write,
+};
 
 static void al_pcie_config_prepare(struct al_pcie *pcie)
 {
@@ -297,6 +260,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
        u8 secondary_bus;
        u32 cfg_control;
        u32 reg;
+       struct resource *bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS)->res;
 
        target_bus_cfg = &pcie->target_bus_cfg;
 
@@ -310,13 +274,13 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
        target_bus_cfg->ecam_mask = ecam_bus_mask;
        /* This portion is taken from the cfg_target_bus reg */
        target_bus_cfg->reg_mask = ~target_bus_cfg->ecam_mask;
-       target_bus_cfg->reg_val = pp->busn->start & target_bus_cfg->reg_mask;
+       target_bus_cfg->reg_val = bus->start & target_bus_cfg->reg_mask;
 
        al_pcie_target_bus_set(pcie, target_bus_cfg->reg_val,
                               target_bus_cfg->reg_mask);
 
-       secondary_bus = pp->busn->start + 1;
-       subordinate_bus = pp->busn->end;
+       secondary_bus = bus->start + 1;
+       subordinate_bus = bus->end;
 
        /* Set the valid values of secondary and subordinate buses */
        cfg_control_offset = AXI_BASE_OFFSET + pcie->reg_offsets.ob_ctrl +
@@ -339,6 +303,8 @@ static int al_pcie_host_init(struct pcie_port *pp)
        struct al_pcie *pcie = to_al_pcie(pci);
        int rc;
 
+       pp->bridge->child_ops = &al_child_pci_ops;
+
        rc = al_pcie_rev_id_get(pcie, &pcie->controller_rev_id);
        if (rc)
                return rc;
@@ -353,8 +319,6 @@ static int al_pcie_host_init(struct pcie_port *pp)
 }
 
 static const struct dw_pcie_host_ops al_pcie_host_ops = {
-       .rd_other_conf = al_pcie_rd_other_conf,
-       .wr_other_conf = al_pcie_wr_other_conf,
        .host_init = al_pcie_host_init,
 };
 
index 97d50bb50f06b3244414ef10768e01494d57275e..929448e9e0bc62d1c6331cf3657777f84728db73 100644 (file)
@@ -44,13 +44,6 @@ struct artpec_pcie_of_data {
 
 static const struct of_device_id artpec6_pcie_of_match[];
 
-/* PCIe Port Logic registers (memory-mapped) */
-#define PL_OFFSET                      0x700
-
-#define ACK_F_ASPM_CTRL_OFF            (PL_OFFSET + 0xc)
-#define ACK_N_FTS_MASK                 GENMASK(15, 8)
-#define ACK_N_FTS(x)                   (((x) << 8) & ACK_N_FTS_MASK)
-
 /* ARTPEC-6 specific registers */
 #define PCIECFG                                0x18
 #define  PCIECFG_DBG_OEN               BIT(24)
@@ -289,30 +282,6 @@ static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie)
        }
 }
 
-static void artpec6_pcie_set_nfts(struct artpec6_pcie *artpec6_pcie)
-{
-       struct dw_pcie *pci = artpec6_pcie->pci;
-       u32 val;
-
-       if (artpec6_pcie->variant != ARTPEC7)
-               return;
-
-       /*
-        * Increase the N_FTS (Number of Fast Training Sequences)
-        * to be transmitted when transitioning from L0s to L0.
-        */
-       val = dw_pcie_readl_dbi(pci, ACK_F_ASPM_CTRL_OFF);
-       val &= ~ACK_N_FTS_MASK;
-       val |= ACK_N_FTS(180);
-       dw_pcie_writel_dbi(pci, ACK_F_ASPM_CTRL_OFF, val);
-
-       /*
-        * Set the Number of Fast Training Sequences that the core
-        * advertises as its N_FTS during Gen2 or Gen3 link training.
-        */
-       dw_pcie_link_set_n_fts(pci, 180);
-}
-
 static void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie)
 {
        u32 val;
@@ -346,29 +315,23 @@ static void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie)
        usleep_range(100, 200);
 }
 
-static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie)
-{
-       struct dw_pcie *pci = artpec6_pcie->pci;
-       struct pcie_port *pp = &pci->pp;
-
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(pp);
-}
-
 static int artpec6_pcie_host_init(struct pcie_port *pp)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
 
+       if (artpec6_pcie->variant == ARTPEC7) {
+               pci->n_fts[0] = 180;
+               pci->n_fts[1] = 180;
+       }
        artpec6_pcie_assert_core_reset(artpec6_pcie);
        artpec6_pcie_init_phy(artpec6_pcie);
        artpec6_pcie_deassert_core_reset(artpec6_pcie);
        artpec6_pcie_wait_for_phy(artpec6_pcie);
-       artpec6_pcie_set_nfts(artpec6_pcie);
        dw_pcie_setup_rc(pp);
        artpec6_pcie_establish_link(pci);
        dw_pcie_wait_for_link(pci);
-       artpec6_pcie_enable_interrupts(artpec6_pcie);
+       dw_pcie_msi_init(pp);
 
        return 0;
 }
@@ -412,7 +375,6 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
        artpec6_pcie_init_phy(artpec6_pcie);
        artpec6_pcie_deassert_core_reset(artpec6_pcie);
        artpec6_pcie_wait_for_phy(artpec6_pcie);
-       artpec6_pcie_set_nfts(artpec6_pcie);
 
        for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
                dw_pcie_ep_reset_bar(pci, bar);
index 305bfec2424d87d122017593ea6ad60c9b721365..ad7da4ea43a5e963dfc384dcfd9584d884c70148 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/pci-epc.h>
 #include <linux/pci-epf.h>
 
+#include "../../pci.h"
+
 void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
 {
        struct pci_epc *epc = ep->epc;
@@ -28,12 +30,39 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep)
 }
 EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify);
 
-static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar,
-                                  int flags)
+struct dw_pcie_ep_func *
+dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
+{
+       struct dw_pcie_ep_func *ep_func;
+
+       list_for_each_entry(ep_func, &ep->func_list, list) {
+               if (ep_func->func_no == func_no)
+                       return ep_func;
+       }
+
+       return NULL;
+}
+
+static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no)
+{
+       unsigned int func_offset = 0;
+
+       if (ep->ops->func_conf_select)
+               func_offset = ep->ops->func_conf_select(ep, func_no);
+
+       return func_offset;
+}
+
+static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no,
+                                  enum pci_barno bar, int flags)
 {
        u32 reg;
+       unsigned int func_offset = 0;
+       struct dw_pcie_ep *ep = &pci->ep;
 
-       reg = PCI_BASE_ADDRESS_0 + (4 * bar);
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
        dw_pcie_dbi_ro_wr_en(pci);
        dw_pcie_writel_dbi2(pci, reg, 0x0);
        dw_pcie_writel_dbi(pci, reg, 0x0);
@@ -46,7 +75,53 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar,
 
 void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
 {
-       __dw_pcie_ep_reset_bar(pci, bar, 0);
+       u8 func_no, funcs;
+
+       funcs = pci->ep.epc->max_functions;
+
+       for (func_no = 0; func_no < funcs; func_no++)
+               __dw_pcie_ep_reset_bar(pci, func_no, bar, 0);
+}
+
+static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no,
+               u8 cap_ptr, u8 cap)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       unsigned int func_offset = 0;
+       u8 cap_id, next_cap_ptr;
+       u16 reg;
+
+       if (!cap_ptr)
+               return 0;
+
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr);
+       cap_id = (reg & 0x00ff);
+
+       if (cap_id > PCI_CAP_ID_MAX)
+               return 0;
+
+       if (cap_id == cap)
+               return cap_ptr;
+
+       next_cap_ptr = (reg & 0xff00) >> 8;
+       return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
+}
+
+static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       unsigned int func_offset = 0;
+       u8 next_cap_ptr;
+       u16 reg;
+
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST);
+       next_cap_ptr = (reg & 0x00ff);
+
+       return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
 }
 
 static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
@@ -54,28 +129,31 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
 {
        struct dw_pcie_ep *ep = epc_get_drvdata(epc);
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       unsigned int func_offset = 0;
+
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
 
        dw_pcie_dbi_ro_wr_en(pci);
-       dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid);
-       dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid);
-       dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid);
-       dw_pcie_writeb_dbi(pci, PCI_CLASS_PROG, hdr->progif_code);
-       dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE,
+       dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid);
+       dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid);
+       dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid);
+       dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code);
+       dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE,
                           hdr->subclass_code | hdr->baseclass_code << 8);
-       dw_pcie_writeb_dbi(pci, PCI_CACHE_LINE_SIZE,
+       dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE,
                           hdr->cache_line_size);
-       dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_VENDOR_ID,
+       dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID,
                           hdr->subsys_vendor_id);
-       dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id);
-       dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN,
+       dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_ID, hdr->subsys_id);
+       dw_pcie_writeb_dbi(pci, func_offset + PCI_INTERRUPT_PIN,
                           hdr->interrupt_pin);
        dw_pcie_dbi_ro_wr_dis(pci);
 
        return 0;
 }
 
-static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
-                                 dma_addr_t cpu_addr,
+static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no,
+                                 enum pci_barno bar, dma_addr_t cpu_addr,
                                  enum dw_pcie_as_type as_type)
 {
        int ret;
@@ -88,7 +166,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
                return -EINVAL;
        }
 
-       ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr,
+       ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar, cpu_addr,
                                       as_type);
        if (ret < 0) {
                dev_err(pci->dev, "Failed to program IB window\n");
@@ -101,7 +179,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
        return 0;
 }
 
-static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
+static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no,
+                                  phys_addr_t phys_addr,
                                   u64 pci_addr, size_t size)
 {
        u32 free_win;
@@ -113,8 +192,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
                return -EINVAL;
        }
 
-       dw_pcie_prog_outbound_atu(pci, free_win, PCIE_ATU_TYPE_MEM,
-                                 phys_addr, pci_addr, size);
+       dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM,
+                                    phys_addr, pci_addr, size);
 
        set_bit(free_win, ep->ob_window_map);
        ep->outbound_addr[free_win] = phys_addr;
@@ -130,7 +209,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
        enum pci_barno bar = epf_bar->barno;
        u32 atu_index = ep->bar_to_atu[bar];
 
-       __dw_pcie_ep_reset_bar(pci, bar, epf_bar->flags);
+       __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags);
 
        dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
        clear_bit(atu_index, ep->ib_window_map);
@@ -147,14 +226,20 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
        size_t size = epf_bar->size;
        int flags = epf_bar->flags;
        enum dw_pcie_as_type as_type;
-       u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
+       u32 reg;
+       unsigned int func_offset = 0;
+
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset;
 
        if (!(flags & PCI_BASE_ADDRESS_SPACE))
                as_type = DW_PCIE_AS_MEM;
        else
                as_type = DW_PCIE_AS_IO;
 
-       ret = dw_pcie_ep_inbound_atu(ep, bar, epf_bar->phys_addr, as_type);
+       ret = dw_pcie_ep_inbound_atu(ep, func_no, bar,
+                                    epf_bar->phys_addr, as_type);
        if (ret)
                return ret;
 
@@ -213,7 +298,7 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no,
        struct dw_pcie_ep *ep = epc_get_drvdata(epc);
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 
-       ret = dw_pcie_ep_outbound_atu(ep, addr, pci_addr, size);
+       ret = dw_pcie_ep_outbound_atu(ep, func_no, addr, pci_addr, size);
        if (ret) {
                dev_err(pci->dev, "Failed to enable address\n");
                return ret;
@@ -227,11 +312,16 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
        struct dw_pcie_ep *ep = epc_get_drvdata(epc);
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        u32 val, reg;
+       unsigned int func_offset = 0;
+       struct dw_pcie_ep_func *ep_func;
 
-       if (!ep->msi_cap)
+       ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
+       if (!ep_func || !ep_func->msi_cap)
                return -EINVAL;
 
-       reg = ep->msi_cap + PCI_MSI_FLAGS;
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
        val = dw_pcie_readw_dbi(pci, reg);
        if (!(val & PCI_MSI_FLAGS_ENABLE))
                return -EINVAL;
@@ -246,11 +336,16 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
        struct dw_pcie_ep *ep = epc_get_drvdata(epc);
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        u32 val, reg;
+       unsigned int func_offset = 0;
+       struct dw_pcie_ep_func *ep_func;
 
-       if (!ep->msi_cap)
+       ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
+       if (!ep_func || !ep_func->msi_cap)
                return -EINVAL;
 
-       reg = ep->msi_cap + PCI_MSI_FLAGS;
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
        val = dw_pcie_readw_dbi(pci, reg);
        val &= ~PCI_MSI_FLAGS_QMASK;
        val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
@@ -266,11 +361,16 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
        struct dw_pcie_ep *ep = epc_get_drvdata(epc);
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        u32 val, reg;
+       unsigned int func_offset = 0;
+       struct dw_pcie_ep_func *ep_func;
 
-       if (!ep->msix_cap)
+       ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
+       if (!ep_func || !ep_func->msix_cap)
                return -EINVAL;
 
-       reg = ep->msix_cap + PCI_MSIX_FLAGS;
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
        val = dw_pcie_readw_dbi(pci, reg);
        if (!(val & PCI_MSIX_FLAGS_ENABLE))
                return -EINVAL;
@@ -286,23 +386,28 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
        struct dw_pcie_ep *ep = epc_get_drvdata(epc);
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        u32 val, reg;
+       unsigned int func_offset = 0;
+       struct dw_pcie_ep_func *ep_func;
 
-       if (!ep->msix_cap)
+       ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
+       if (!ep_func || !ep_func->msix_cap)
                return -EINVAL;
 
        dw_pcie_dbi_ro_wr_en(pci);
 
-       reg = ep->msix_cap + PCI_MSIX_FLAGS;
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
        val = dw_pcie_readw_dbi(pci, reg);
        val &= ~PCI_MSIX_FLAGS_QSIZE;
        val |= interrupts;
        dw_pcie_writew_dbi(pci, reg, val);
 
-       reg = ep->msix_cap + PCI_MSIX_TABLE;
+       reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
        val = offset | bir;
        dw_pcie_writel_dbi(pci, reg, val);
 
-       reg = ep->msix_cap + PCI_MSIX_PBA;
+       reg = ep_func->msix_cap + func_offset + PCI_MSIX_PBA;
        val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
        dw_pcie_writel_dbi(pci, reg, val);
 
@@ -385,31 +490,36 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
                             u8 interrupt_num)
 {
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       struct dw_pcie_ep_func *ep_func;
        struct pci_epc *epc = ep->epc;
        unsigned int aligned_offset;
+       unsigned int func_offset = 0;
        u16 msg_ctrl, msg_data;
        u32 msg_addr_lower, msg_addr_upper, reg;
        u64 msg_addr;
        bool has_upper;
        int ret;
 
-       if (!ep->msi_cap)
+       ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
+       if (!ep_func || !ep_func->msi_cap)
                return -EINVAL;
 
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
        /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */
-       reg = ep->msi_cap + PCI_MSI_FLAGS;
+       reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
        msg_ctrl = dw_pcie_readw_dbi(pci, reg);
        has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
-       reg = ep->msi_cap + PCI_MSI_ADDRESS_LO;
+       reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_LO;
        msg_addr_lower = dw_pcie_readl_dbi(pci, reg);
        if (has_upper) {
-               reg = ep->msi_cap + PCI_MSI_ADDRESS_HI;
+               reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_HI;
                msg_addr_upper = dw_pcie_readl_dbi(pci, reg);
-               reg = ep->msi_cap + PCI_MSI_DATA_64;
+               reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_64;
                msg_data = dw_pcie_readw_dbi(pci, reg);
        } else {
                msg_addr_upper = 0;
-               reg = ep->msi_cap + PCI_MSI_DATA_32;
+               reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_32;
                msg_data = dw_pcie_readw_dbi(pci, reg);
        }
        aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1);
@@ -427,12 +537,33 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
        return 0;
 }
 
+int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
+                                      u16 interrupt_num)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       struct dw_pcie_ep_func *ep_func;
+       u32 msg_data;
+
+       ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
+       if (!ep_func || !ep_func->msix_cap)
+               return -EINVAL;
+
+       msg_data = (func_no << PCIE_MSIX_DOORBELL_PF_SHIFT) |
+                  (interrupt_num - 1);
+
+       dw_pcie_writel_dbi(pci, PCIE_MSIX_DOORBELL, msg_data);
+
+       return 0;
+}
+
 int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
-                            u16 interrupt_num)
+                             u16 interrupt_num)
 {
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       struct dw_pcie_ep_func *ep_func;
        struct pci_epf_msix_tbl *msix_tbl;
        struct pci_epc *epc = ep->epc;
+       unsigned int func_offset = 0;
        u32 reg, msg_data, vec_ctrl;
        unsigned int aligned_offset;
        u32 tbl_offset;
@@ -440,7 +571,13 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
        int ret;
        u8 bir;
 
-       reg = ep->msix_cap + PCI_MSIX_TABLE;
+       ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
+       if (!ep_func || !ep_func->msix_cap)
+               return -EINVAL;
+
+       func_offset = dw_pcie_ep_func_select(ep, func_no);
+
+       reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
        tbl_offset = dw_pcie_readl_dbi(pci, reg);
        bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
        tbl_offset &= PCI_MSIX_TABLE_OFFSET;
@@ -505,7 +642,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
        u32 reg;
        int i;
 
-       hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE);
+       hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) &
+                  PCI_HEADER_TYPE_MASK;
        if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
                dev_err(pci->dev,
                        "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n",
@@ -513,23 +651,21 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
                return -EIO;
        }
 
-       ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
+       offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
 
-       ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX);
+       dw_pcie_dbi_ro_wr_en(pci);
 
-       offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
        if (offset) {
                reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
                nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >>
                        PCI_REBAR_CTRL_NBAR_SHIFT;
 
-               dw_pcie_dbi_ro_wr_en(pci);
                for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
                        dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0);
-               dw_pcie_dbi_ro_wr_dis(pci);
        }
 
        dw_pcie_setup(pci);
+       dw_pcie_dbi_ro_wr_dis(pci);
 
        return 0;
 }
@@ -539,11 +675,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
 {
        int ret;
        void *addr;
+       u8 func_no;
        struct pci_epc *epc;
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        struct device *dev = pci->dev;
        struct device_node *np = dev->of_node;
        const struct pci_epc_features *epc_features;
+       struct dw_pcie_ep_func *ep_func;
+
+       INIT_LIST_HEAD(&ep->func_list);
 
        if (!pci->dbi_base || !pci->dbi_base2) {
                dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
@@ -590,6 +730,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
                return -ENOMEM;
        ep->outbound_addr = addr;
 
+       if (pci->link_gen < 1)
+               pci->link_gen = of_pci_get_max_link_speed(np);
+
        epc = devm_pci_epc_create(dev, &epc_ops);
        if (IS_ERR(epc)) {
                dev_err(dev, "Failed to create epc device\n");
@@ -599,13 +742,27 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
        ep->epc = epc;
        epc_set_drvdata(epc, ep);
 
-       if (ep->ops->ep_init)
-               ep->ops->ep_init(ep);
-
        ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
        if (ret < 0)
                epc->max_functions = 1;
 
+       for (func_no = 0; func_no < epc->max_functions; func_no++) {
+               ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL);
+               if (!ep_func)
+                       return -ENOMEM;
+
+               ep_func->func_no = func_no;
+               ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no,
+                                                             PCI_CAP_ID_MSI);
+               ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no,
+                                                              PCI_CAP_ID_MSIX);
+
+               list_add_tail(&ep_func->list, &ep->func_list);
+       }
+
+       if (ep->ops->ep_init)
+               ep->ops->ep_init(ep);
+
        ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
                               ep->page_size);
        if (ret < 0) {
index 9dafecba347f07383fc718941c53e26f9bef3434..674f32db85ca4ccf5935eb4b3ba59ecdbd7401a7 100644 (file)
 #include "pcie-designware.h"
 
 static struct pci_ops dw_pcie_ops;
-
-static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
-                              u32 *val)
-{
-       struct dw_pcie *pci;
-
-       if (pp->ops->rd_own_conf)
-               return pp->ops->rd_own_conf(pp, where, size, val);
-
-       pci = to_dw_pcie_from_pp(pp);
-       return dw_pcie_read(pci->dbi_base + where, size, val);
-}
-
-static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
-                              u32 val)
-{
-       struct dw_pcie *pci;
-
-       if (pp->ops->wr_own_conf)
-               return pp->ops->wr_own_conf(pp, where, size, val);
-
-       pci = to_dw_pcie_from_pp(pp);
-       return dw_pcie_write(pci->dbi_base + where, size, val);
-}
+static struct pci_ops dw_child_pcie_ops;
 
 static void dw_msi_ack_irq(struct irq_data *d)
 {
@@ -82,13 +59,13 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
        unsigned long val;
        u32 status, num_ctrls;
        irqreturn_t ret = IRQ_NONE;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
        num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
 
        for (i = 0; i < num_ctrls; i++) {
-               dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS +
-                                       (i * MSI_REG_CTRL_BLOCK_SIZE),
-                                   4, &status);
+               status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS +
+                                          (i * MSI_REG_CTRL_BLOCK_SIZE));
                if (!status)
                        continue;
 
@@ -148,6 +125,7 @@ static int dw_pci_msi_set_affinity(struct irq_data *d,
 static void dw_pci_bottom_mask(struct irq_data *d)
 {
        struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        unsigned int res, bit, ctrl;
        unsigned long flags;
 
@@ -158,8 +136,7 @@ static void dw_pci_bottom_mask(struct irq_data *d)
        bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
        pp->irq_mask[ctrl] |= BIT(bit);
-       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
-                           pp->irq_mask[ctrl]);
+       dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, pp->irq_mask[ctrl]);
 
        raw_spin_unlock_irqrestore(&pp->lock, flags);
 }
@@ -167,6 +144,7 @@ static void dw_pci_bottom_mask(struct irq_data *d)
 static void dw_pci_bottom_unmask(struct irq_data *d)
 {
        struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        unsigned int res, bit, ctrl;
        unsigned long flags;
 
@@ -177,8 +155,7 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
        bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
        pp->irq_mask[ctrl] &= ~BIT(bit);
-       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
-                           pp->irq_mask[ctrl]);
+       dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, pp->irq_mask[ctrl]);
 
        raw_spin_unlock_irqrestore(&pp->lock, flags);
 }
@@ -186,13 +163,14 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
 static void dw_pci_bottom_ack(struct irq_data *d)
 {
        struct pcie_port *pp  = irq_data_get_irq_chip_data(d);
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        unsigned int res, bit, ctrl;
 
        ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
        res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
        bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
-       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit));
+       dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit));
 }
 
 static struct irq_chip dw_pci_msi_bottom_irq_chip = {
@@ -288,32 +266,26 @@ void dw_pcie_free_msi(struct pcie_port *pp)
        irq_domain_remove(pp->msi_domain);
        irq_domain_remove(pp->irq_domain);
 
-       if (pp->msi_page)
-               __free_page(pp->msi_page);
+       if (pp->msi_data) {
+               struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+               struct device *dev = pci->dev;
+
+               dma_unmap_single_attrs(dev, pp->msi_data, sizeof(pp->msi_msg),
+                                      DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+       }
 }
 
 void dw_pcie_msi_init(struct pcie_port *pp)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct device *dev = pci->dev;
-       u64 msi_target;
+       u64 msi_target = (u64)pp->msi_data;
 
-       pp->msi_page = alloc_page(GFP_KERNEL);
-       pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE,
-                                   DMA_FROM_DEVICE);
-       if (dma_mapping_error(dev, pp->msi_data)) {
-               dev_err(dev, "Failed to map MSI data\n");
-               __free_page(pp->msi_page);
-               pp->msi_page = NULL;
+       if (!IS_ENABLED(CONFIG_PCI_MSI))
                return;
-       }
-       msi_target = (u64)pp->msi_data;
 
        /* Program the msi_data */
-       dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
-                           lower_32_bits(msi_target));
-       dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
-                           upper_32_bits(msi_target));
+       dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
+       dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
 }
 EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
 
@@ -324,20 +296,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
        struct device_node *np = dev->of_node;
        struct platform_device *pdev = to_platform_device(dev);
        struct resource_entry *win;
-       struct pci_bus *child;
        struct pci_host_bridge *bridge;
        struct resource *cfg_res;
-       u32 hdr_type;
        int ret;
 
        raw_spin_lock_init(&pci->pp.lock);
 
        cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
        if (cfg_res) {
-               pp->cfg0_size = resource_size(cfg_res) >> 1;
-               pp->cfg1_size = resource_size(cfg_res) >> 1;
+               pp->cfg0_size = resource_size(cfg_res);
                pp->cfg0_base = cfg_res->start;
-               pp->cfg1_base = cfg_res->start + pp->cfg0_size;
        } else if (!pp->va_cfg0_base) {
                dev_err(dev, "Missing *config* reg space\n");
        }
@@ -346,47 +314,33 @@ int dw_pcie_host_init(struct pcie_port *pp)
        if (!bridge)
                return -ENOMEM;
 
+       pp->bridge = bridge;
+
        /* Get the I/O and memory ranges from DT */
        resource_list_for_each_entry(win, &bridge->windows) {
                switch (resource_type(win->res)) {
                case IORESOURCE_IO:
-                       pp->io = win->res;
-                       pp->io->name = "I/O";
-                       pp->io_size = resource_size(pp->io);
-                       pp->io_bus_addr = pp->io->start - win->offset;
-                       pp->io_base = pci_pio_to_address(pp->io->start);
-                       break;
-               case IORESOURCE_MEM:
-                       pp->mem = win->res;
-                       pp->mem->name = "MEM";
-                       pp->mem_size = resource_size(pp->mem);
-                       pp->mem_bus_addr = pp->mem->start - win->offset;
+                       pp->io_size = resource_size(win->res);
+                       pp->io_bus_addr = win->res->start - win->offset;
+                       pp->io_base = pci_pio_to_address(win->res->start);
                        break;
                case 0:
-                       pp->cfg = win->res;
-                       pp->cfg0_size = resource_size(pp->cfg) >> 1;
-                       pp->cfg1_size = resource_size(pp->cfg) >> 1;
-                       pp->cfg0_base = pp->cfg->start;
-                       pp->cfg1_base = pp->cfg->start + pp->cfg0_size;
-                       break;
-               case IORESOURCE_BUS:
-                       pp->busn = win->res;
+                       dev_err(dev, "Missing *config* reg space\n");
+                       pp->cfg0_size = resource_size(win->res);
+                       pp->cfg0_base = win->res->start;
+                       if (!pci->dbi_base) {
+                               pci->dbi_base = devm_pci_remap_cfgspace(dev,
+                                                               pp->cfg0_base,
+                                                               pp->cfg0_size);
+                               if (!pci->dbi_base) {
+                                       dev_err(dev, "Error with ioremap\n");
+                                       return -ENOMEM;
+                               }
+                       }
                        break;
                }
        }
 
-       if (!pci->dbi_base) {
-               pci->dbi_base = devm_pci_remap_cfgspace(dev,
-                                               pp->cfg->start,
-                                               resource_size(pp->cfg));
-               if (!pci->dbi_base) {
-                       dev_err(dev, "Error with ioremap\n");
-                       return -ENOMEM;
-               }
-       }
-
-       pp->mem_base = pp->mem->start;
-
        if (!pp->va_cfg0_base) {
                pp->va_cfg0_base = devm_pci_remap_cfgspace(dev,
                                        pp->cfg0_base, pp->cfg0_size);
@@ -396,20 +350,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
                }
        }
 
-       if (!pp->va_cfg1_base) {
-               pp->va_cfg1_base = devm_pci_remap_cfgspace(dev,
-                                               pp->cfg1_base,
-                                               pp->cfg1_size);
-               if (!pp->va_cfg1_base) {
-                       dev_err(dev, "Error with ioremap\n");
-                       return -ENOMEM;
-               }
-       }
-
        ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
        if (ret)
                pci->num_viewport = 2;
 
+       if (pci->link_gen < 1)
+               pci->link_gen = of_pci_get_max_link_speed(np);
+
        if (pci_msi_enabled()) {
                /*
                 * If a specific SoC driver needs to change the
@@ -440,6 +387,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                irq_set_chained_handler_and_data(pp->msi_irq,
                                                            dw_chained_msi_isr,
                                                            pp);
+
+                       pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg,
+                                                     sizeof(pp->msi_msg),
+                                                     DMA_FROM_DEVICE,
+                                                     DMA_ATTR_SKIP_CPU_SYNC);
+                       if (dma_mapping_error(pci->dev, pp->msi_data)) {
+                               dev_err(pci->dev, "Failed to map MSI data\n");
+                               pp->msi_data = 0;
+                               goto err_free_msi;
+                       }
                } else {
                        ret = pp->ops->msi_host_init(pp);
                        if (ret < 0)
@@ -447,47 +404,21 @@ int dw_pcie_host_init(struct pcie_port *pp)
                }
        }
 
+       /* Set default bus ops */
+       bridge->ops = &dw_pcie_ops;
+       bridge->child_ops = &dw_child_pcie_ops;
+
        if (pp->ops->host_init) {
                ret = pp->ops->host_init(pp);
                if (ret)
                        goto err_free_msi;
        }
 
-       ret = dw_pcie_rd_own_conf(pp, PCI_HEADER_TYPE, 1, &hdr_type);
-       if (ret != PCIBIOS_SUCCESSFUL) {
-               dev_err(pci->dev, "Failed reading PCI_HEADER_TYPE cfg space reg (ret: 0x%x)\n",
-                       ret);
-               ret = pcibios_err_to_errno(ret);
-               goto err_free_msi;
-       }
-       if (hdr_type != PCI_HEADER_TYPE_BRIDGE) {
-               dev_err(pci->dev,
-                       "PCIe controller is not set to bridge type (hdr_type: 0x%x)!\n",
-                       hdr_type);
-               ret = -EIO;
-               goto err_free_msi;
-       }
-
        bridge->sysdata = pp;
-       bridge->ops = &dw_pcie_ops;
-
-       ret = pci_scan_root_bus_bridge(bridge);
-       if (ret)
-               goto err_free_msi;
-
-       pp->root_bus = bridge->bus;
-
-       if (pp->ops->scan_bus)
-               pp->ops->scan_bus(pp);
 
-       pci_bus_size_bridges(pp->root_bus);
-       pci_bus_assign_resources(pp->root_bus);
-
-       list_for_each_entry(child, &pp->root_bus->children, node)
-               pcie_bus_configure_settings(child);
-
-       pci_bus_add_devices(pp->root_bus);
-       return 0;
+       ret = pci_host_probe(bridge);
+       if (!ret)
+               return 0;
 
 err_free_msi:
        if (pci_msi_enabled() && !pp->ops->msi_host_init)
@@ -498,125 +429,104 @@ EXPORT_SYMBOL_GPL(dw_pcie_host_init);
 
 void dw_pcie_host_deinit(struct pcie_port *pp)
 {
-       pci_stop_root_bus(pp->root_bus);
-       pci_remove_root_bus(pp->root_bus);
+       pci_stop_root_bus(pp->bridge->bus);
+       pci_remove_root_bus(pp->bridge->bus);
        if (pci_msi_enabled() && !pp->ops->msi_host_init)
                dw_pcie_free_msi(pp);
 }
 EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
 
-static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-                                    u32 devfn, int where, int size, u32 *val,
-                                    bool write)
+static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
+                                               unsigned int devfn, int where)
 {
-       int ret, type;
-       u32 busdev, cfg_size;
-       u64 cpu_addr;
-       void __iomem *va_cfg_base;
+       int type;
+       u32 busdev;
+       struct pcie_port *pp = bus->sysdata;
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
+       /*
+        * Checking whether the link is up here is a last line of defense
+        * against platforms that forward errors on the system bus as
+        * SError upon PCI configuration transactions issued when the link
+        * is down. This check is racy by definition and does not stop
+        * the system from triggering an SError if the link goes down
+        * after this check is performed.
+        */
+       if (!dw_pcie_link_up(pci))
+               return NULL;
+
        busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
                 PCIE_ATU_FUNC(PCI_FUNC(devfn));
 
-       if (pci_is_root_bus(bus->parent)) {
+       if (pci_is_root_bus(bus->parent))
                type = PCIE_ATU_TYPE_CFG0;
-               cpu_addr = pp->cfg0_base;
-               cfg_size = pp->cfg0_size;
-               va_cfg_base = pp->va_cfg0_base;
-       } else {
-               type = PCIE_ATU_TYPE_CFG1;
-               cpu_addr = pp->cfg1_base;
-               cfg_size = pp->cfg1_size;
-               va_cfg_base = pp->va_cfg1_base;
-       }
-
-       dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
-                                 type, cpu_addr,
-                                 busdev, cfg_size);
-       if (write)
-               ret = dw_pcie_write(va_cfg_base + where, size, *val);
        else
-               ret = dw_pcie_read(va_cfg_base + where, size, val);
-
-       if (pci->num_viewport <= 2)
-               dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
-                                         PCIE_ATU_TYPE_IO, pp->io_base,
-                                         pp->io_bus_addr, pp->io_size);
-
-       return ret;
-}
-
-static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-                                u32 devfn, int where, int size, u32 *val)
-{
-       if (pp->ops->rd_other_conf)
-               return pp->ops->rd_other_conf(pp, bus, devfn, where,
-                                             size, val);
+               type = PCIE_ATU_TYPE_CFG1;
 
-       return dw_pcie_access_other_conf(pp, bus, devfn, where, size, val,
-                                        false);
-}
 
-static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-                                u32 devfn, int where, int size, u32 val)
-{
-       if (pp->ops->wr_other_conf)
-               return pp->ops->wr_other_conf(pp, bus, devfn, where,
-                                             size, val);
+       dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
+                                 type, pp->cfg0_base,
+                                 busdev, pp->cfg0_size);
 
-       return dw_pcie_access_other_conf(pp, bus, devfn, where, size, &val,
-                                        true);
+       return pp->va_cfg0_base + where;
 }
 
-static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus,
-                               int dev)
+static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
+                                int where, int size, u32 *val)
 {
+       int ret;
+       struct pcie_port *pp = bus->sysdata;
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
-       /* If there is no link, then there is no device */
-       if (!pci_is_root_bus(bus)) {
-               if (!dw_pcie_link_up(pci))
-                       return 0;
-       } else if (dev > 0)
-               /* Access only one slot on each root port */
-               return 0;
+       ret = pci_generic_config_read(bus, devfn, where, size, val);
 
-       return 1;
+       if (!ret && pci->num_viewport <= 2)
+               dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
+                                         PCIE_ATU_TYPE_IO, pp->io_base,
+                                         pp->io_bus_addr, pp->io_size);
+
+       return ret;
 }
 
-static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
-                          int size, u32 *val)
+static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
+                                int where, int size, u32 val)
 {
+       int ret;
        struct pcie_port *pp = bus->sysdata;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
-       if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn))) {
-               *val = 0xffffffff;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       }
+       ret = pci_generic_config_write(bus, devfn, where, size, val);
 
-       if (pci_is_root_bus(bus))
-               return dw_pcie_rd_own_conf(pp, where, size, val);
+       if (!ret && pci->num_viewport <= 2)
+               dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
+                                         PCIE_ATU_TYPE_IO, pp->io_base,
+                                         pp->io_bus_addr, pp->io_size);
 
-       return dw_pcie_rd_other_conf(pp, bus, devfn, where, size, val);
+       return ret;
 }
 
-static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
-                          int where, int size, u32 val)
+static struct pci_ops dw_child_pcie_ops = {
+       .map_bus = dw_pcie_other_conf_map_bus,
+       .read = dw_pcie_rd_other_conf,
+       .write = dw_pcie_wr_other_conf,
+};
+
+void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn, int where)
 {
        struct pcie_port *pp = bus->sysdata;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
-       if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn)))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       if (pci_is_root_bus(bus))
-               return dw_pcie_wr_own_conf(pp, where, size, val);
+       if (PCI_SLOT(devfn) > 0)
+               return NULL;
 
-       return dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val);
+       return pci->dbi_base + where;
 }
+EXPORT_SYMBOL_GPL(dw_pcie_own_conf_map_bus);
 
 static struct pci_ops dw_pcie_ops = {
-       .read = dw_pcie_rd_conf,
-       .write = dw_pcie_wr_conf,
+       .map_bus = dw_pcie_own_conf_map_bus,
+       .read = pci_generic_config_read,
+       .write = pci_generic_config_write,
 };
 
 void dw_pcie_setup_rc(struct pcie_port *pp)
@@ -632,18 +542,18 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 
        dw_pcie_setup(pci);
 
-       if (!pp->ops->msi_host_init) {
+       if (pci_msi_enabled() && !pp->ops->msi_host_init) {
                num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
 
                /* Initialize IRQ Status array */
                for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
                        pp->irq_mask[ctrl] = ~0;
-                       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
+                       dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
                                            (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
-                                           4, pp->irq_mask[ctrl]);
-                       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
+                                           pp->irq_mask[ctrl]);
+                       dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
                                            (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
-                                           4, ~0);
+                                           ~0);
                }
        }
 
@@ -671,28 +581,32 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
        dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
 
        /*
-        * If the platform provides ->rd_other_conf, it means the platform
-        * uses its own address translation component rather than ATU, so
-        * we should not program the ATU here.
+        * If the platform provides its own child bus config accesses, it means
+        * the platform uses its own address translation component rather than
+        * ATU, so we should not program the ATU here.
         */
-       if (!pp->ops->rd_other_conf) {
+       if (pp->bridge->child_ops == &dw_child_pcie_ops) {
+               struct resource_entry *entry =
+                       resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM);
+
                dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
-                                         PCIE_ATU_TYPE_MEM, pp->mem_base,
-                                         pp->mem_bus_addr, pp->mem_size);
+                                         PCIE_ATU_TYPE_MEM, entry->res->start,
+                                         entry->res->start - entry->offset,
+                                         resource_size(entry->res));
                if (pci->num_viewport > 2)
                        dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
                                                  PCIE_ATU_TYPE_IO, pp->io_base,
                                                  pp->io_bus_addr, pp->io_size);
        }
 
-       dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
+       dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
 
        /* Program correct class for RC */
-       dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
+       dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
 
-       dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
+       val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
        val |= PORT_LOGIC_SPEED_CHANGE;
-       dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
+       dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
 
        dw_pcie_dbi_ro_wr_dis(pci);
 }
index 712456f6ce36c9baa02871bfa312fecd6a8ae1e1..e3e300669ed56f79db48807c331f75d513ace409 100644 (file)
@@ -39,9 +39,7 @@ static int dw_plat_pcie_host_init(struct pcie_port *pp)
 
        dw_pcie_setup_rc(pp);
        dw_pcie_wait_for_link(pci);
-
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(pp);
+       dw_pcie_msi_init(pp);
 
        return 0;
 }
index b723e0cc41fb4d0579df9ace2363e67a057efb65..c2dea8fc97c8fba7d0a1e933674ec3d819068f1c 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/delay.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/types.h>
 
 #include "../../pci.h"
@@ -166,21 +167,6 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
 }
 EXPORT_SYMBOL_GPL(dw_pcie_write_dbi);
 
-u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size)
-{
-       int ret;
-       u32 val;
-
-       if (pci->ops->read_dbi2)
-               return pci->ops->read_dbi2(pci, pci->dbi_base2, reg, size);
-
-       ret = dw_pcie_read(pci->dbi_base2 + reg, size, &val);
-       if (ret)
-               dev_err(pci->dev, "read DBI address failed\n");
-
-       return val;
-}
-
 void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
 {
        int ret;
@@ -195,31 +181,31 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
                dev_err(pci->dev, "write DBI address failed\n");
 }
 
-u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size)
+static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
 {
        int ret;
        u32 val;
 
        if (pci->ops->read_dbi)
-               return pci->ops->read_dbi(pci, pci->atu_base, reg, size);
+               return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
 
-       ret = dw_pcie_read(pci->atu_base + reg, size, &val);
+       ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
        if (ret)
                dev_err(pci->dev, "Read ATU address failed\n");
 
        return val;
 }
 
-void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
+static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
 {
        int ret;
 
        if (pci->ops->write_dbi) {
-               pci->ops->write_dbi(pci, pci->atu_base, reg, size, val);
+               pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
                return;
        }
 
-       ret = dw_pcie_write(pci->atu_base + reg, size, val);
+       ret = dw_pcie_write(pci->atu_base + reg, 4, val);
        if (ret)
                dev_err(pci->dev, "Write ATU address failed\n");
 }
@@ -239,9 +225,10 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
        dw_pcie_writel_atu(pci, offset + reg, val);
 }
 
-static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
-                                            int type, u64 cpu_addr,
-                                            u64 pci_addr, u32 size)
+static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
+                                            int index, int type,
+                                            u64 cpu_addr, u64 pci_addr,
+                                            u32 size)
 {
        u32 retries, val;
        u64 limit_addr = cpu_addr + size - 1;
@@ -259,7 +246,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
        dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
                                 upper_32_bits(pci_addr));
        dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-                                type);
+                                type | PCIE_ATU_FUNC_NUM(func_no));
        dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
                                 PCIE_ATU_ENABLE);
 
@@ -278,8 +265,9 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
        dev_err(pci->dev, "Outbound iATU is not being enabled\n");
 }
 
-void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
-                              u64 cpu_addr, u64 pci_addr, u32 size)
+static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
+                                       int index, int type, u64 cpu_addr,
+                                       u64 pci_addr, u32 size)
 {
        u32 retries, val;
 
@@ -287,8 +275,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
                cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
 
        if (pci->iatu_unroll_enabled) {
-               dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr,
-                                                pci_addr, size);
+               dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type,
+                                                cpu_addr, pci_addr, size);
                return;
        }
 
@@ -304,7 +292,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
                           lower_32_bits(pci_addr));
        dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
                           upper_32_bits(pci_addr));
-       dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type);
+       dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
+                          PCIE_ATU_FUNC_NUM(func_no));
        dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
 
        /*
@@ -321,6 +310,21 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
        dev_err(pci->dev, "Outbound iATU is not being enabled\n");
 }
 
+void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
+                              u64 cpu_addr, u64 pci_addr, u32 size)
+{
+       __dw_pcie_prog_outbound_atu(pci, 0, index, type,
+                                   cpu_addr, pci_addr, size);
+}
+
+void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+                                 int type, u64 cpu_addr, u64 pci_addr,
+                                 u32 size)
+{
+       __dw_pcie_prog_outbound_atu(pci, func_no, index, type,
+                                   cpu_addr, pci_addr, size);
+}
+
 static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
 {
        u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
@@ -336,8 +340,8 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
        dw_pcie_writel_atu(pci, offset + reg, val);
 }
 
-static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
-                                          int bar, u64 cpu_addr,
+static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
+                                          int index, int bar, u64 cpu_addr,
                                           enum dw_pcie_as_type as_type)
 {
        int type;
@@ -359,8 +363,10 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
                return -EINVAL;
        }
 
-       dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type);
+       dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
+                                PCIE_ATU_FUNC_NUM(func_no));
        dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
+                                PCIE_ATU_FUNC_NUM_MATCH_EN |
                                 PCIE_ATU_ENABLE |
                                 PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
 
@@ -381,14 +387,15 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
        return -EBUSY;
 }
 
-int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
-                            u64 cpu_addr, enum dw_pcie_as_type as_type)
+int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+                            int bar, u64 cpu_addr,
+                            enum dw_pcie_as_type as_type)
 {
        int type;
        u32 retries, val;
 
        if (pci->iatu_unroll_enabled)
-               return dw_pcie_prog_inbound_atu_unroll(pci, index, bar,
+               return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar,
                                                       cpu_addr, as_type);
 
        dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
@@ -407,9 +414,11 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
                return -EINVAL;
        }
 
-       dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type);
-       dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE
-                          | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
+       dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
+                          PCIE_ATU_FUNC_NUM(func_no));
+       dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
+                          PCIE_ATU_FUNC_NUM_MATCH_EN |
+                          PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
 
        /*
         * Make sure ATU enable takes effect before any subsequent config
@@ -444,7 +453,7 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
        }
 
        dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index);
-       dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, (u32)~PCIE_ATU_ENABLE);
+       dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE);
 }
 
 int dw_pcie_wait_for_link(struct dw_pcie *pci)
@@ -488,50 +497,41 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci)
 }
 EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
 
-void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
+static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
 {
-       u32 reg, val;
+       u32 cap, ctrl2, link_speed;
        u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
 
-       reg = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
-       reg &= ~PCI_EXP_LNKCTL2_TLS;
+       cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
+       ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
+       ctrl2 &= ~PCI_EXP_LNKCTL2_TLS;
 
        switch (pcie_link_speed[link_gen]) {
        case PCIE_SPEED_2_5GT:
-               reg |= PCI_EXP_LNKCTL2_TLS_2_5GT;
+               link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT;
                break;
        case PCIE_SPEED_5_0GT:
-               reg |= PCI_EXP_LNKCTL2_TLS_5_0GT;
+               link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;
                break;
        case PCIE_SPEED_8_0GT:
-               reg |= PCI_EXP_LNKCTL2_TLS_8_0GT;
+               link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT;
                break;
        case PCIE_SPEED_16_0GT:
-               reg |= PCI_EXP_LNKCTL2_TLS_16_0GT;
+               link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT;
                break;
        default:
                /* Use hardware capability */
-               val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
-               val = FIELD_GET(PCI_EXP_LNKCAP_SLS, val);
-               reg &= ~PCI_EXP_LNKCTL2_HASD;
-               reg |= FIELD_PREP(PCI_EXP_LNKCTL2_TLS, val);
+               link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap);
+               ctrl2 &= ~PCI_EXP_LNKCTL2_HASD;
                break;
        }
 
-       dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, reg);
-}
-EXPORT_SYMBOL_GPL(dw_pcie_link_set_max_speed);
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed);
 
-void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts)
-{
-       u32 val;
+       cap &= ~((u32)PCI_EXP_LNKCAP_SLS);
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed);
 
-       val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-       val &= ~PORT_LOGIC_N_FTS_MASK;
-       val |= n_fts & PORT_LOGIC_N_FTS_MASK;
-       dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
 }
-EXPORT_SYMBOL_GPL(dw_pcie_link_set_n_fts);
 
 static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
 {
@@ -546,32 +546,58 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
 
 void dw_pcie_setup(struct dw_pcie *pci)
 {
-       int ret;
        u32 val;
-       u32 lanes;
        struct device *dev = pci->dev;
        struct device_node *np = dev->of_node;
+       struct platform_device *pdev = to_platform_device(dev);
 
        if (pci->version >= 0x480A || (!pci->version &&
                                       dw_pcie_iatu_unroll_enabled(pci))) {
                pci->iatu_unroll_enabled = true;
                if (!pci->atu_base)
+                       pci->atu_base =
+                           devm_platform_ioremap_resource_byname(pdev, "atu");
+               if (IS_ERR(pci->atu_base))
                        pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
        }
        dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
                "enabled" : "disabled");
 
+       if (pci->link_gen > 0)
+               dw_pcie_link_set_max_speed(pci, pci->link_gen);
 
-       ret = of_property_read_u32(np, "num-lanes", &lanes);
-       if (ret) {
-               dev_dbg(pci->dev, "property num-lanes isn't found\n");
+       /* Configure Gen1 N_FTS */
+       if (pci->n_fts[0]) {
+               val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
+               val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);
+               val |= PORT_AFR_N_FTS(pci->n_fts[0]);
+               val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);
+               dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
+       }
+
+       /* Configure Gen2+ N_FTS */
+       if (pci->n_fts[1]) {
+               val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
+               val &= ~PORT_LOGIC_N_FTS_MASK;
+               val |= pci->n_fts[pci->link_gen - 1];
+               dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+       }
+
+       val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
+       val &= ~PORT_LINK_FAST_LINK_MODE;
+       val |= PORT_LINK_DLL_LINK_EN;
+       dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
+
+       of_property_read_u32(np, "num-lanes", &pci->num_lanes);
+       if (!pci->num_lanes) {
+               dev_dbg(pci->dev, "Using h/w default number of lanes\n");
                return;
        }
 
        /* Set the number of lanes */
-       val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
+       val &= ~PORT_LINK_FAST_LINK_MODE;
        val &= ~PORT_LINK_MODE_MASK;
-       switch (lanes) {
+       switch (pci->num_lanes) {
        case 1:
                val |= PORT_LINK_MODE_1_LANES;
                break;
@@ -585,7 +611,7 @@ void dw_pcie_setup(struct dw_pcie *pci)
                val |= PORT_LINK_MODE_8_LANES;
                break;
        default:
-               dev_err(pci->dev, "num-lanes %u: invalid value\n", lanes);
+               dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->num_lanes);
                return;
        }
        dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
@@ -593,7 +619,7 @@ void dw_pcie_setup(struct dw_pcie *pci)
        /* Set link width speed control register */
        val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
        val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
-       switch (lanes) {
+       switch (pci->num_lanes) {
        case 1:
                val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
                break;
index f911760dcc69e635be8018634239898517c6af09..9d2f511f13fafad6f4c852f7866176c4da392f71 100644 (file)
 /* Synopsys-specific PCIe configuration registers */
 #define PCIE_PORT_AFR                  0x70C
 #define PORT_AFR_N_FTS_MASK            GENMASK(15, 8)
+#define PORT_AFR_N_FTS(n)              FIELD_PREP(PORT_AFR_N_FTS_MASK, n)
 #define PORT_AFR_CC_N_FTS_MASK         GENMASK(23, 16)
+#define PORT_AFR_CC_N_FTS(n)           FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, n)
+#define PORT_AFR_ENTER_ASPM            BIT(30)
+#define PORT_AFR_L0S_ENTRANCE_LAT_SHIFT        24
+#define PORT_AFR_L0S_ENTRANCE_LAT_MASK GENMASK(26, 24)
+#define PORT_AFR_L1_ENTRANCE_LAT_SHIFT 27
+#define PORT_AFR_L1_ENTRANCE_LAT_MASK  GENMASK(29, 27)
 
 #define PCIE_PORT_LINK_CONTROL         0x710
 #define PORT_LINK_DLL_LINK_EN          BIT(5)
+#define PORT_LINK_FAST_LINK_MODE       BIT(7)
 #define PORT_LINK_MODE_MASK            GENMASK(21, 16)
 #define PORT_LINK_MODE(n)              FIELD_PREP(PORT_LINK_MODE_MASK, n)
 #define PORT_LINK_MODE_1_LANES         PORT_LINK_MODE(0x1)
 #define PCIE_ATU_TYPE_IO               0x2
 #define PCIE_ATU_TYPE_CFG0             0x4
 #define PCIE_ATU_TYPE_CFG1             0x5
+#define PCIE_ATU_FUNC_NUM(pf)           ((pf) << 20)
 #define PCIE_ATU_CR2                   0x908
 #define PCIE_ATU_ENABLE                        BIT(31)
 #define PCIE_ATU_BAR_MODE_ENABLE       BIT(30)
+#define PCIE_ATU_FUNC_NUM_MATCH_EN      BIT(19)
 #define PCIE_ATU_LOWER_BASE            0x90C
 #define PCIE_ATU_UPPER_BASE            0x910
 #define PCIE_ATU_LIMIT                 0x914
 #define PCIE_MISC_CONTROL_1_OFF                0x8BC
 #define PCIE_DBI_RO_WR_EN              BIT(0)
 
+#define PCIE_MSIX_DOORBELL             0x948
+#define PCIE_MSIX_DOORBELL_PF_SHIFT    24
+
 #define PCIE_PL_CHK_REG_CONTROL_STATUS                 0xB20
 #define PCIE_PL_CHK_REG_CHK_REG_START                  BIT(0)
 #define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS             BIT(1)
@@ -160,14 +173,7 @@ enum dw_pcie_device_mode {
 };
 
 struct dw_pcie_host_ops {
-       int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
-       int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
-       int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
-                            unsigned int devfn, int where, int size, u32 *val);
-       int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
-                            unsigned int devfn, int where, int size, u32 val);
        int (*host_init)(struct pcie_port *pp);
-       void (*scan_bus)(struct pcie_port *pp);
        void (*set_num_vectors)(struct pcie_port *pp);
        int (*msi_host_init)(struct pcie_port *pp);
 };
@@ -176,30 +182,20 @@ struct pcie_port {
        u64                     cfg0_base;
        void __iomem            *va_cfg0_base;
        u32                     cfg0_size;
-       u64                     cfg1_base;
-       void __iomem            *va_cfg1_base;
-       u32                     cfg1_size;
        resource_size_t         io_base;
        phys_addr_t             io_bus_addr;
        u32                     io_size;
-       u64                     mem_base;
-       phys_addr_t             mem_bus_addr;
-       u32                     mem_size;
-       struct resource         *cfg;
-       struct resource         *io;
-       struct resource         *mem;
-       struct resource         *busn;
        int                     irq;
        const struct dw_pcie_host_ops *ops;
        int                     msi_irq;
        struct irq_domain       *irq_domain;
        struct irq_domain       *msi_domain;
+       u16                     msi_msg;
        dma_addr_t              msi_data;
-       struct page             *msi_page;
        struct irq_chip         *msi_irq_chip;
        u32                     num_vectors;
        u32                     irq_mask[MAX_MSI_CTRLS];
-       struct pci_bus          *root_bus;
+       struct pci_host_bridge  *bridge;
        raw_spinlock_t          lock;
        DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
@@ -215,10 +211,26 @@ struct dw_pcie_ep_ops {
        int     (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
                             enum pci_epc_irq_type type, u16 interrupt_num);
        const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep);
+       /*
+        * Provide a method to implement the different func config space
+        * access for different platform, if different func have different
+        * offset, return the offset of func. if use write a register way
+        * return a 0, and implement code in callback function of platform
+        * driver.
+        */
+       unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no);
+};
+
+struct dw_pcie_ep_func {
+       struct list_head        list;
+       u8                      func_no;
+       u8                      msi_cap;        /* MSI capability offset */
+       u8                      msix_cap;       /* MSI-X capability offset */
 };
 
 struct dw_pcie_ep {
        struct pci_epc          *epc;
+       struct list_head        func_list;
        const struct dw_pcie_ep_ops *ops;
        phys_addr_t             phys_base;
        size_t                  addr_size;
@@ -231,8 +243,6 @@ struct dw_pcie_ep {
        u32                     num_ob_windows;
        void __iomem            *msi_mem;
        phys_addr_t             msi_mem_phys;
-       u8                      msi_cap;        /* MSI capability offset */
-       u8                      msix_cap;       /* MSI-X capability offset */
        struct pci_epf_bar      *epf_bar[PCI_STD_NUM_BARS];
 };
 
@@ -242,8 +252,6 @@ struct dw_pcie_ops {
                            size_t size);
        void    (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
                             size_t size, u32 val);
-       u32     (*read_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
-                            size_t size);
        void    (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
                              size_t size, u32 val);
        int     (*link_up)(struct dw_pcie *pcie);
@@ -263,6 +271,9 @@ struct dw_pcie {
        struct dw_pcie_ep       ep;
        const struct dw_pcie_ops *ops;
        unsigned int            version;
+       int                     num_lanes;
+       int                     link_gen;
+       u8                      n_fts[2];
 };
 
 #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
@@ -278,20 +289,19 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val);
 
 u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size);
 void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
-u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size);
 void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
-u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size);
-void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
 int dw_pcie_link_up(struct dw_pcie *pci);
 void dw_pcie_upconfig_setup(struct dw_pcie *pci);
-void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen);
-void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts);
 int dw_pcie_wait_for_link(struct dw_pcie *pci);
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
                               int type, u64 cpu_addr, u64 pci_addr,
                               u32 size);
-int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
-                            u64 cpu_addr, enum dw_pcie_as_type as_type);
+void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+                                 int type, u64 cpu_addr, u64 pci_addr,
+                                 u32 size);
+int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+                            int bar, u64 cpu_addr,
+                            enum dw_pcie_as_type as_type);
 void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
                         enum dw_pcie_region_type type);
 void dw_pcie_setup(struct dw_pcie *pci);
@@ -331,21 +341,6 @@ static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val)
        dw_pcie_write_dbi2(pci, reg, 0x4, val);
 }
 
-static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
-{
-       return dw_pcie_read_dbi2(pci, reg, 0x4);
-}
-
-static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
-{
-       dw_pcie_write_atu(pci, reg, 0x4, val);
-}
-
-static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
-{
-       return dw_pcie_read_atu(pci, reg, 0x4);
-}
-
 static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
 {
        u32 reg;
@@ -376,6 +371,8 @@ void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
 void dw_pcie_host_deinit(struct pcie_port *pp);
 int dw_pcie_allocate_domains(struct pcie_port *pp);
+void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn,
+                                      int where);
 #else
 static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 {
@@ -407,6 +404,12 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp)
 {
        return 0;
 }
+static inline void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus,
+                                                    unsigned int devfn,
+                                                    int where)
+{
+       return NULL;
+}
 #endif
 
 #ifdef CONFIG_PCIE_DW_EP
@@ -420,7 +423,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
                             u8 interrupt_num);
 int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
                             u16 interrupt_num);
+int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
+                                      u16 interrupt_num);
 void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
+struct dw_pcie_ep_func *
+dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no);
 #else
 static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
 {
@@ -461,8 +468,21 @@ static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
        return 0;
 }
 
+static inline int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep,
+                                                    u8 func_no,
+                                                    u16 interrupt_num)
+{
+       return 0;
+}
+
 static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
 {
 }
+
+static inline struct dw_pcie_ep_func *
+dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
+{
+       return NULL;
+}
 #endif
 #endif /* _PCIE_DESIGNWARE_H */
index 2a28357460775fc7171569fa999c8615fed72836..afc1abbe49aa9e9526cfec6bddf10c4e6021458e 100644 (file)
@@ -122,32 +122,37 @@ static void histb_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
        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)
+static int histb_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 *val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       int ret;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
 
-       histb_pcie_dbi_r_mode(pp, true);
-       ret = dw_pcie_read(pci->dbi_base + where, size, val);
-       histb_pcie_dbi_r_mode(pp, false);
+       if (PCI_SLOT(devfn)) {
+               *val = ~0;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
 
-       return ret;
+       *val = dw_pcie_read_dbi(pci, where, size);
+       return PCIBIOS_SUCCESSFUL;
 }
 
-static int histb_pcie_wr_own_conf(struct pcie_port *pp, int where,
-                                 int size, u32 val)
+static int histb_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       int ret;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
 
-       histb_pcie_dbi_w_mode(pp, true);
-       ret = dw_pcie_write(pci->dbi_base + where, size, val);
-       histb_pcie_dbi_w_mode(pp, false);
+       if (PCI_SLOT(devfn))
+               return PCIBIOS_DEVICE_NOT_FOUND;
 
-       return ret;
+       dw_pcie_write_dbi(pci, where, size, val);
+       return PCIBIOS_SUCCESSFUL;
 }
 
+static struct pci_ops histb_pci_ops = {
+       .read = histb_pcie_rd_own_conf,
+       .write = histb_pcie_wr_own_conf,
+};
+
 static int histb_pcie_link_up(struct dw_pcie *pci)
 {
        struct histb_pcie *hipcie = to_histb_pcie(pci);
@@ -194,17 +199,15 @@ static int histb_pcie_establish_link(struct pcie_port *pp)
 
 static int histb_pcie_host_init(struct pcie_port *pp)
 {
-       histb_pcie_establish_link(pp);
+       pp->bridge->ops = &histb_pci_ops;
 
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(pp);
+       histb_pcie_establish_link(pp);
+       dw_pcie_msi_init(pp);
 
        return 0;
 }
 
 static const 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,
 };
 
index c3b3a1d162b5361521d0df7a11a47f83889b1d7b..5650cb78acbad31ceb492279302567b11f6e5087 100644 (file)
@@ -67,14 +67,9 @@ struct intel_pcie_port {
        void __iomem            *app_base;
        struct gpio_desc        *reset_gpio;
        u32                     rst_intrvl;
-       u32                     max_speed;
-       u32                     link_gen;
-       u32                     max_width;
-       u32                     n_fts;
        struct clk              *core_clk;
        struct reset_control    *core_rst;
        struct phy              *phy;
-       u8                      pcie_cap_ofst;
 };
 
 static void pcie_update_bits(void __iomem *base, u32 ofs, u32 mask, u32 val)
@@ -134,11 +129,7 @@ static void intel_pcie_ltssm_disable(struct intel_pcie_port *lpp)
 static void intel_pcie_link_setup(struct intel_pcie_port *lpp)
 {
        u32 val;
-       u8 offset = lpp->pcie_cap_ofst;
-
-       val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCAP);
-       lpp->max_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, val);
-       lpp->max_width = FIELD_GET(PCI_EXP_LNKCAP_MLW, val);
+       u8 offset = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP);
 
        val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCTL);
 
@@ -146,41 +137,29 @@ static void intel_pcie_link_setup(struct intel_pcie_port *lpp)
        pcie_rc_cfg_wr(lpp, offset + PCI_EXP_LNKCTL, val);
 }
 
-static void intel_pcie_port_logic_setup(struct intel_pcie_port *lpp)
+static void intel_pcie_init_n_fts(struct dw_pcie *pci)
 {
-       u32 val, mask;
-
-       switch (pcie_link_speed[lpp->max_speed]) {
-       case PCIE_SPEED_8_0GT:
-               lpp->n_fts = PORT_AFR_N_FTS_GEN3;
+       switch (pci->link_gen) {
+       case 3:
+               pci->n_fts[1] = PORT_AFR_N_FTS_GEN3;
                break;
-       case PCIE_SPEED_16_0GT:
-               lpp->n_fts = PORT_AFR_N_FTS_GEN4;
+       case 4:
+               pci->n_fts[1] = PORT_AFR_N_FTS_GEN4;
                break;
        default:
-               lpp->n_fts = PORT_AFR_N_FTS_GEN12_DFT;
+               pci->n_fts[1] = PORT_AFR_N_FTS_GEN12_DFT;
                break;
        }
-
-       mask = PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK;
-       val = FIELD_PREP(PORT_AFR_N_FTS_MASK, lpp->n_fts) |
-              FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, lpp->n_fts);
-       pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_AFR, mask, val);
-
-       /* Port Link Control Register */
-       pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_LINK_CONTROL, PORT_LINK_DLL_LINK_EN,
-                           PORT_LINK_DLL_LINK_EN);
+       pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT;
 }
 
 static void intel_pcie_rc_setup(struct intel_pcie_port *lpp)
 {
        intel_pcie_ltssm_disable(lpp);
        intel_pcie_link_setup(lpp);
+       intel_pcie_init_n_fts(&lpp->pci);
        dw_pcie_setup_rc(&lpp->pci.pp);
        dw_pcie_upconfig_setup(&lpp->pci);
-       intel_pcie_port_logic_setup(lpp);
-       dw_pcie_link_set_max_speed(&lpp->pci, lpp->link_gen);
-       dw_pcie_link_set_n_fts(&lpp->pci, lpp->n_fts);
 }
 
 static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp)
@@ -275,20 +254,11 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
                return ret;
        }
 
-       ret = device_property_match_string(dev, "device_type", "pci");
-       if (ret) {
-               dev_err(dev, "Failed to find pci device type: %d\n", ret);
-               return ret;
-       }
-
        ret = device_property_read_u32(dev, "reset-assert-ms",
                                       &lpp->rst_intrvl);
        if (ret)
                lpp->rst_intrvl = RESET_INTERVAL_MS;
 
-       ret = of_pci_get_max_link_speed(dev->of_node);
-       lpp->link_gen = ret < 0 ? 0 : ret;
-
        lpp->app_base = devm_platform_ioremap_resource_byname(pdev, "app");
        if (IS_ERR(lpp->app_base))
                return PTR_ERR(lpp->app_base);
@@ -313,8 +283,9 @@ static int intel_pcie_wait_l2(struct intel_pcie_port *lpp)
 {
        u32 value;
        int ret;
+       struct dw_pcie *pci = &lpp->pci;
 
-       if (pcie_link_speed[lpp->max_speed] < PCIE_SPEED_8_0GT)
+       if (pci->link_gen < 3)
                return 0;
 
        /* Send PME_TURN_OFF message */
@@ -343,7 +314,6 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp)
 
 static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
 {
-       struct device *dev = lpp->pci.dev;
        int ret;
 
        intel_pcie_core_rst_assert(lpp);
@@ -361,17 +331,6 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
                goto clk_err;
        }
 
-       if (!lpp->pcie_cap_ofst) {
-               ret = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP);
-               if (!ret) {
-                       ret = -ENXIO;
-                       dev_err(dev, "Invalid PCIe capability offset\n");
-                       goto app_init_err;
-               }
-
-               lpp->pcie_cap_ofst = ret;
-       }
-
        intel_pcie_rc_setup(lpp);
        ret = intel_pcie_app_logic_setup(lpp);
        if (ret)
index e496f51e015275d654126af8b4f8f8b6e2a7fd5b..d0a6a2dee6f5be7f905bee47900a8cb80d7d0451 100644 (file)
@@ -330,34 +330,37 @@ static void kirin_pcie_sideband_dbi_r_mode(struct kirin_pcie *kirin_pcie,
        kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL1_ADDR);
 }
 
-static int kirin_pcie_rd_own_conf(struct pcie_port *pp,
+static int kirin_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
                                  int where, int size, u32 *val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
-       int ret;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
 
-       kirin_pcie_sideband_dbi_r_mode(kirin_pcie, true);
-       ret = dw_pcie_read(pci->dbi_base + where, size, val);
-       kirin_pcie_sideband_dbi_r_mode(kirin_pcie, false);
+       if (PCI_SLOT(devfn)) {
+               *val = ~0;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
 
-       return ret;
+       *val = dw_pcie_read_dbi(pci, where, size);
+       return PCIBIOS_SUCCESSFUL;
 }
 
-static int kirin_pcie_wr_own_conf(struct pcie_port *pp,
+static int kirin_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
                                  int where, int size, u32 val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
-       int ret;
+       struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
 
-       kirin_pcie_sideband_dbi_w_mode(kirin_pcie, true);
-       ret = dw_pcie_write(pci->dbi_base + where, size, val);
-       kirin_pcie_sideband_dbi_w_mode(kirin_pcie, false);
+       if (PCI_SLOT(devfn))
+               return PCIBIOS_DEVICE_NOT_FOUND;
 
-       return ret;
+       dw_pcie_write_dbi(pci, where, size, val);
+       return PCIBIOS_SUCCESSFUL;
 }
 
+static struct pci_ops kirin_pci_ops = {
+       .read = kirin_pcie_rd_own_conf,
+       .write = kirin_pcie_wr_own_conf,
+};
+
 static u32 kirin_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
                               u32 reg, size_t size)
 {
@@ -423,10 +426,10 @@ static int kirin_pcie_establish_link(struct pcie_port *pp)
 
 static int kirin_pcie_host_init(struct pcie_port *pp)
 {
-       kirin_pcie_establish_link(pp);
+       pp->bridge->ops = &kirin_pci_ops;
 
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(pp);
+       kirin_pcie_establish_link(pp);
+       dw_pcie_msi_init(pp);
 
        return 0;
 }
@@ -438,8 +441,6 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = {
 };
 
 static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
-       .rd_own_conf = kirin_pcie_rd_own_conf,
-       .wr_own_conf = kirin_pcie_wr_own_conf,
        .host_init = kirin_pcie_host_init,
 };
 
@@ -507,8 +508,12 @@ static int kirin_pcie_probe(struct platform_device *pdev)
 
        kirin_pcie->gpio_id_reset = of_get_named_gpio(dev->of_node,
                                                      "reset-gpios", 0);
-       if (kirin_pcie->gpio_id_reset < 0)
+       if (kirin_pcie->gpio_id_reset == -EPROBE_DEFER) {
+               return -EPROBE_DEFER;
+       } else if (!gpio_is_valid(kirin_pcie->gpio_id_reset)) {
+               dev_err(dev, "unable to get a valid gpio pin\n");
                return -ENODEV;
+       }
 
        ret = kirin_pcie_power_on(kirin_pcie);
        if (ret)
index 3aac77a295ba17b7b9a28766cdcd33215db5fae7..b4761640ffd99be522c55f0facd5b4c273ac68dd 100644 (file)
 #define PCIE20_AXI_MSTR_RESP_COMP_CTRL1                0x81c
 #define CFG_BRIDGE_SB_INIT                     BIT(0)
 
-#define PCIE20_CAP                             0x70
-#define PCIE20_DEVICE_CONTROL2_STATUS2         (PCIE20_CAP + PCI_EXP_DEVCTL2)
-#define PCIE20_CAP_LINK_CAPABILITIES           (PCIE20_CAP + PCI_EXP_LNKCAP)
-#define PCIE20_CAP_LINK_1                      (PCIE20_CAP + 0x14)
 #define PCIE_CAP_LINK1_VAL                     0x2FD7F
 
 #define PCIE20_PARF_Q2A_FLUSH                  0x1AC
@@ -193,7 +189,6 @@ struct qcom_pcie {
        struct phy *phy;
        struct gpio_desc *reset;
        const struct qcom_pcie_ops *ops;
-       int gen;
 };
 
 #define to_qcom_pcie(x)                dev_get_drvdata((x)->dev)
@@ -302,6 +297,9 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
        reset_control_assert(res->por_reset);
        reset_control_assert(res->ext_reset);
        reset_control_assert(res->phy_reset);
+
+       writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL);
+
        regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
 }
 
@@ -314,6 +312,16 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
        u32 val;
        int ret;
 
+       /* reset the PCIe interface as uboot can leave it undefined state */
+       reset_control_assert(res->pci_reset);
+       reset_control_assert(res->axi_reset);
+       reset_control_assert(res->ahb_reset);
+       reset_control_assert(res->por_reset);
+       reset_control_assert(res->ext_reset);
+       reset_control_assert(res->phy_reset);
+
+       writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL);
+
        ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
        if (ret < 0) {
                dev_err(dev, "cannot enable regulators\n");
@@ -394,12 +402,6 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
        /* wait for clock acquisition */
        usleep_range(1000, 1500);
 
-       if (pcie->gen == 1) {
-               val = readl(pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
-               val |= PCI_EXP_LNKSTA_CLS_2_5GB;
-               writel(val, pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
-       }
-
        /* Set the Max TLP size to 2K, instead of using default of 4K */
        writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K,
               pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL0);
@@ -1017,6 +1019,7 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
        struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
        struct dw_pcie *pci = pcie->pci;
        struct device *dev = pci->dev;
+       u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        int i, ret;
        u32 val;
 
@@ -1092,14 +1095,14 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
 
        writel(PCI_COMMAND_MASTER, pci->dbi_base + PCI_COMMAND);
        writel(DBI_RO_WR_EN, pci->dbi_base + PCIE20_MISC_CONTROL_1_REG);
-       writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + PCIE20_CAP_LINK_1);
+       writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP);
 
-       val = readl(pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
+       val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
        val &= ~PCI_EXP_LNKCAP_ASPMS;
-       writel(val, pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
+       writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
 
-       writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base +
-               PCIE20_DEVICE_CONTROL2_STATUS2);
+       writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset +
+               PCI_EXP_DEVCTL2);
 
        return 0;
 
@@ -1252,7 +1255,8 @@ static void qcom_pcie_post_deinit_2_7_0(struct qcom_pcie *pcie)
 
 static int qcom_pcie_link_up(struct dw_pcie *pci)
 {
-       u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA);
+       u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+       u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
 
        return !!(val & PCI_EXP_LNKSTA_DLLLA);
 }
@@ -1280,9 +1284,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
        }
 
        dw_pcie_setup_rc(pp);
-
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(pp);
+       dw_pcie_msi_init(pp);
 
        qcom_ep_reset_deassert(pcie);
 
@@ -1399,10 +1401,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
                goto err_pm_runtime_put;
        }
 
-       pcie->gen = of_pci_get_max_link_speed(pdev->dev.of_node);
-       if (pcie->gen < 0)
-               pcie->gen = 2;
-
        pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
        if (IS_ERR(pcie->parf)) {
                ret = PTR_ERR(pcie->parf);
index 62846562da0b122174d5f0813da189e9726c7042..e348225f651fb01e5ac32001f5bedf3bb02afc51 100644 (file)
@@ -26,7 +26,6 @@ struct spear13xx_pcie {
        void __iomem            *app_base;
        struct phy              *phy;
        struct clk              *clk;
-       bool                    is_gen1;
 };
 
 struct pcie_app_reg {
@@ -65,8 +64,6 @@ struct pcie_app_reg {
 /* CR6 */
 #define MSI_CTRL_INT                           (1 << 26)
 
-#define EXP_CAP_ID_OFFSET                      0x70
-
 #define to_spear13xx_pcie(x)   dev_get_drvdata((x)->dev)
 
 static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
@@ -75,7 +72,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
        struct pcie_port *pp = &pci->pp;
        struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
        u32 val;
-       u32 exp_cap_off = EXP_CAP_ID_OFFSET;
+       u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
 
        if (dw_pcie_link_up(pci)) {
                dev_err(pci->dev, "link already up\n");
@@ -89,36 +86,12 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
         * default value in capability register is 512 bytes. So force
         * it to 128 here.
         */
-       dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
+       val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
        val &= ~PCI_EXP_DEVCTL_READRQ;
-       dw_pcie_write(pci->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
-
-       dw_pcie_write(pci->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
-       dw_pcie_write(pci->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
+       dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
 
-       /*
-        * if is_gen1 is set then handle it, so that some buggy card
-        * also works
-        */
-       if (spear13xx_pcie->is_gen1) {
-               dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
-                            4, &val);
-               if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
-                       val &= ~((u32)PCI_EXP_LNKCAP_SLS);
-                       val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-                       dw_pcie_write(pci->dbi_base + exp_cap_off +
-                                     PCI_EXP_LNKCAP, 4, val);
-               }
-
-               dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
-                            2, &val);
-               if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
-                       val &= ~((u32)PCI_EXP_LNKCAP_SLS);
-                       val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-                       dw_pcie_write(pci->dbi_base + exp_cap_off +
-                                     PCI_EXP_LNKCTL2, 2, val);
-               }
-       }
+       dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
+       dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
 
        /* enable ltssm */
        writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID)
@@ -278,7 +251,7 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
        spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
 
        if (of_property_read_bool(np, "st,pcie-is-gen1"))
-               spear13xx_pcie->is_gen1 = true;
+               pci->link_gen = 1;
 
        platform_set_drvdata(pdev, spear13xx_pcie);
 
index 70498689d0c0a162d78b68b0ace8478e0b30e26e..f920e7efe118f40fd4abbc6e2d5eecd0358b881a 100644 (file)
 #define EVENT_COUNTER_GROUP_SEL_SHIFT  24
 #define EVENT_COUNTER_GROUP_5          0x5
 
-#define PORT_LOGIC_ACK_F_ASPM_CTRL                     0x70C
-#define ENTER_ASPM                                     BIT(30)
-#define L0S_ENTRANCE_LAT_SHIFT                         24
-#define L0S_ENTRANCE_LAT_MASK                          GENMASK(26, 24)
-#define L1_ENTRANCE_LAT_SHIFT                          27
-#define L1_ENTRANCE_LAT_MASK                           GENMASK(29, 27)
-#define N_FTS_SHIFT                                    8
-#define N_FTS_MASK                                     GENMASK(7, 0)
 #define N_FTS_VAL                                      52
-
-#define PORT_LOGIC_GEN2_CTRL                           0x80C
-#define PORT_LOGIC_GEN2_CTRL_DIRECT_SPEED_CHANGE       BIT(17)
-#define FTS_MASK                                       GENMASK(7, 0)
 #define FTS_VAL                                                52
 
 #define PORT_LOGIC_MSI_CTRL_INT_0_EN           0x828
@@ -296,7 +284,6 @@ struct tegra_pcie_dw {
        u8 init_link_width;
        u32 msi_ctrl_int;
        u32 num_lanes;
-       u32 max_speed;
        u32 cid;
        u32 cfg_link_cap_l1sub;
        u32 pcie_cap_base;
@@ -401,9 +388,9 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
                        val |= APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N;
                        appl_writel(pcie, val, APPL_CAR_RESET_OVRD);
 
-                       val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
-                       val |= PORT_LOGIC_GEN2_CTRL_DIRECT_SPEED_CHANGE;
-                       dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
+                       val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
+                       val |= PORT_LOGIC_SPEED_CHANGE;
+                       dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
                }
        }
 
@@ -568,42 +555,44 @@ static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static int tegra_pcie_dw_rd_own_conf(struct pcie_port *pp, int where, int size,
-                                    u32 *val)
+static int tegra_pcie_dw_rd_own_conf(struct pci_bus *bus, u32 devfn, int where,
+                                    int size, u32 *val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-
        /*
         * This is an endpoint mode specific register happen to appear even
         * when controller is operating in root port mode and system hangs
         * when it is accessed with link being in ASPM-L1 state.
         * So skip accessing it altogether
         */
-       if (where == PORT_LOGIC_MSIX_DOORBELL) {
+       if (!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) {
                *val = 0x00000000;
                return PCIBIOS_SUCCESSFUL;
        }
 
-       return dw_pcie_read(pci->dbi_base + where, size, val);
+       return pci_generic_config_read(bus, devfn, where, size, val);
 }
 
-static int tegra_pcie_dw_wr_own_conf(struct pcie_port *pp, int where, int size,
-                                    u32 val)
+static int tegra_pcie_dw_wr_own_conf(struct pci_bus *bus, u32 devfn, int where,
+                                    int size, u32 val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-
        /*
         * This is an endpoint mode specific register happen to appear even
         * when controller is operating in root port mode and system hangs
         * when it is accessed with link being in ASPM-L1 state.
         * So skip accessing it altogether
         */
-       if (where == PORT_LOGIC_MSIX_DOORBELL)
+       if (!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL)
                return PCIBIOS_SUCCESSFUL;
 
-       return dw_pcie_write(pci->dbi_base + where, size, val);
+       return pci_generic_config_write(bus, devfn, where, size, val);
 }
 
+static struct pci_ops tegra_pci_ops = {
+       .map_bus = dw_pcie_own_conf_map_bus,
+       .read = tegra_pcie_dw_rd_own_conf,
+       .write = tegra_pcie_dw_wr_own_conf,
+};
+
 #if defined(CONFIG_PCIEASPM)
 static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
 {
@@ -692,30 +681,23 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
        dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
 
        /* Program L0s and L1 entrance latencies */
-       val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
-       val &= ~L0S_ENTRANCE_LAT_MASK;
-       val |= (pcie->aspm_l0s_enter_lat << L0S_ENTRANCE_LAT_SHIFT);
-       val |= ENTER_ASPM;
-       dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
+       val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
+       val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
+       val |= (pcie->aspm_l0s_enter_lat << PORT_AFR_L0S_ENTRANCE_LAT_SHIFT);
+       val |= PORT_AFR_ENTER_ASPM;
+       dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
 }
 
-static int init_debugfs(struct tegra_pcie_dw *pcie)
+static void init_debugfs(struct tegra_pcie_dw *pcie)
 {
-       struct dentry *d;
-
-       d = debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt",
-                                       pcie->debugfs, aspm_state_cnt);
-       if (IS_ERR_OR_NULL(d))
-               dev_err(pcie->dev,
-                       "Failed to create debugfs file \"aspm_state_cnt\"\n");
-
-       return 0;
+       debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt", pcie->debugfs,
+                                   aspm_state_cnt);
 }
 #else
 static inline void disable_aspm_l12(struct tegra_pcie_dw *pcie) { return; }
 static inline void disable_aspm_l11(struct tegra_pcie_dw *pcie) { return; }
 static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; }
-static inline int init_debugfs(struct tegra_pcie_dw *pcie) { return 0; }
+static inline void init_debugfs(struct tegra_pcie_dw *pcie) { return; }
 #endif
 
 static void tegra_pcie_enable_system_interrupts(struct pcie_port *pp)
@@ -827,26 +809,24 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
 
        /* Program init preset */
        for (i = 0; i < pcie->num_lanes; i++) {
-               dw_pcie_read(pci->dbi_base + CAP_SPCIE_CAP_OFF
-                                + (i * 2), 2, &val);
+               val = dw_pcie_readw_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2));
                val &= ~CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK;
                val |= GEN3_GEN4_EQ_PRESET_INIT;
                val &= ~CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK;
                val |= (GEN3_GEN4_EQ_PRESET_INIT <<
                           CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT);
-               dw_pcie_write(pci->dbi_base + CAP_SPCIE_CAP_OFF
-                                + (i * 2), 2, val);
+               dw_pcie_writew_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2), val);
 
                offset = dw_pcie_find_ext_capability(pci,
                                                     PCI_EXT_CAP_ID_PL_16GT) +
                                PCI_PL_16GT_LE_CTRL;
-               dw_pcie_read(pci->dbi_base + offset + i, 1, &val);
+               val = dw_pcie_readb_dbi(pci, offset + i);
                val &= ~PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK;
                val |= GEN3_GEN4_EQ_PRESET_INIT;
                val &= ~PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK;
                val |= (GEN3_GEN4_EQ_PRESET_INIT <<
                        PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT);
-               dw_pcie_write(pci->dbi_base + offset + i, 1, val);
+               dw_pcie_writeb_dbi(pci, offset + i, val);
        }
 
        val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
@@ -892,17 +872,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
 
        dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
 
-       /* Configure FTS */
-       val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
-       val &= ~(N_FTS_MASK << N_FTS_SHIFT);
-       val |= N_FTS_VAL << N_FTS_SHIFT;
-       dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
-
-       val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
-       val &= ~FTS_MASK;
-       val |= FTS_VAL;
-       dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
-
        /* Enable as 0xFFFF0001 response for CRS */
        val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT);
        val &= ~(AMBA_ERROR_RESPONSE_CRS_MASK << AMBA_ERROR_RESPONSE_CRS_SHIFT);
@@ -910,16 +879,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
                AMBA_ERROR_RESPONSE_CRS_SHIFT);
        dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
 
-       /* Configure Max Speed from DT */
-       if (pcie->max_speed && pcie->max_speed != -EINVAL) {
-               val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
-                                       PCI_EXP_LNKCAP);
-               val &= ~PCI_EXP_LNKCAP_SLS;
-               val |= pcie->max_speed;
-               dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
-                                  val);
-       }
-
        /* Configure Max lane width from DT */
        val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP);
        val &= ~PCI_EXP_LNKCAP_MLW;
@@ -970,6 +929,8 @@ static int tegra_pcie_dw_host_init(struct pcie_port *pp)
        struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
        u32 val, tmp, offset, speed;
 
+       pp->bridge->ops = &tegra_pci_ops;
+
        tegra_pcie_prepare_host(pp);
 
        if (dw_pcie_wait_for_link(pci)) {
@@ -1057,8 +1018,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
 };
 
 static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
-       .rd_own_conf = tegra_pcie_dw_rd_own_conf,
-       .wr_own_conf = tegra_pcie_dw_wr_own_conf,
        .host_init = tegra_pcie_dw_host_init,
        .set_num_vectors = tegra_pcie_set_msi_vec_num,
 };
@@ -1129,8 +1088,6 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
                return ret;
        }
 
-       pcie->max_speed = of_pci_get_max_link_speed(np);
-
        ret = of_property_read_u32_index(np, "nvidia,bpmp", 1, &pcie->cid);
        if (ret) {
                dev_err(pcie->dev, "Failed to read Controller-ID: %d\n", ret);
@@ -1262,9 +1219,9 @@ static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
         * 5.2 Link State Power Management (Page #428).
         */
 
-       list_for_each_entry(child, &pp->root_bus->children, node) {
+       list_for_each_entry(child, &pp->bridge->bus->children, node) {
                /* Bring downstream devices to D0 if they are not already in */
-               if (child->parent == pp->root_bus) {
+               if (child->parent == pp->bridge->bus) {
                        root_bus = child;
                        break;
                }
@@ -1641,10 +1598,7 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
        }
 
        pcie->debugfs = debugfs_create_dir(name, NULL);
-       if (!pcie->debugfs)
-               dev_err(dev, "Failed to create debugfs\n");
-       else
-               init_debugfs(pcie);
+       init_debugfs(pcie);
 
        return ret;
 
@@ -1817,27 +1771,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
        val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
        dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
 
-       /* Configure N_FTS & FTS */
-       val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
-       val &= ~(N_FTS_MASK << N_FTS_SHIFT);
-       val |= N_FTS_VAL << N_FTS_SHIFT;
-       dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
-
-       val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
-       val &= ~FTS_MASK;
-       val |= FTS_VAL;
-       dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
-
-       /* Configure Max Speed from DT */
-       if (pcie->max_speed && pcie->max_speed != -EINVAL) {
-               val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
-                                       PCI_EXP_LNKCAP);
-               val &= ~PCI_EXP_LNKCAP_SLS;
-               val |= pcie->max_speed;
-               dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
-                                  val);
-       }
-
        pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
                                                      PCI_CAP_ID_EXP);
        clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
@@ -2066,6 +1999,9 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
        pci = &pcie->pci;
        pci->dev = &pdev->dev;
        pci->ops = &tegra_dw_pcie_ops;
+       pci->n_fts[0] = N_FTS_VAL;
+       pci->n_fts[1] = FTS_VAL;
+
        pp = &pci->pp;
        pcie->dev = &pdev->dev;
        pcie->mode = (enum dw_pcie_device_mode)data->mode;
index 3a7f403b57b8d94837b6a39a041adaeb33588a30..48176265c867e417e8bb0a3ab8e9d8ca514625ea 100644 (file)
@@ -322,8 +322,7 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
        if (ret)
                return ret;
 
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(pp);
+       dw_pcie_msi_init(pp);
 
        return 0;
 }
index 3adec419a45b1e18cafa7c2517d4728d36d595c4..a2632d02ce8f8c4b51f8f8b1420a1f5dee8438fe 100644 (file)
@@ -480,7 +480,6 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
        struct device *dev = &pcie->pdev->dev;
        struct device_node *node = dev->of_node;
        struct mobiveil_root_port *rp = &pcie->rp;
-       int ret;
 
        /* setup INTx */
        rp->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
@@ -494,11 +493,7 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
        raw_spin_lock_init(&rp->intx_mask_lock);
 
        /* setup MSI */
-       ret = mobiveil_allocate_msi_domains(pcie);
-       if (ret)
-               return ret;
-
-       return 0;
+       return mobiveil_allocate_msi_domains(pcie);
 }
 
 static int mobiveil_pcie_integrated_interrupt_init(struct mobiveil_pcie *pcie)
index 1559f79e63b6fa9be0446ac4b3f71244ffcb8f79..0be485a253273a6c089550f01bc6345634eda4d8 100644 (file)
@@ -9,11 +9,12 @@
  */
 
 #include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/phy/phy.h>
@@ -251,6 +252,25 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
        }
 }
 
+static void advk_pcie_issue_perst(struct advk_pcie *pcie)
+{
+       u32 reg;
+
+       if (!pcie->reset_gpio)
+               return;
+
+       /* PERST does not work for some cards when link training is enabled */
+       reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+       reg &= ~LINK_TRAINING_EN;
+       advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+       /* 10ms delay is needed for some cards */
+       dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n");
+       gpiod_set_value_cansleep(pcie->reset_gpio, 1);
+       usleep_range(10000, 11000);
+       gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+}
+
 static int advk_pcie_train_at_gen(struct advk_pcie *pcie, int gen)
 {
        int ret, neg_gen;
@@ -298,6 +318,21 @@ static void advk_pcie_train_link(struct advk_pcie *pcie)
        struct device *dev = &pcie->pdev->dev;
        int neg_gen = -1, gen;
 
+       /*
+        * Reset PCIe card via PERST# signal. Some cards are not detected
+        * during link training when they are in some non-initial state.
+        */
+       advk_pcie_issue_perst(pcie);
+
+       /*
+        * PERST# signal could have been asserted by pinctrl subsystem before
+        * probe() callback has been called or issued explicitly by reset gpio
+        * function advk_pcie_issue_perst(), making the endpoint going into
+        * fundamental reset. As required by PCI Express spec a delay for at
+        * least 100ms after such a reset before link training is needed.
+        */
+       msleep(PCI_PM_D3COLD_WAIT);
+
        /*
         * Try link training at link gen specified by device tree property
         * 'max-link-speed'. If this fails, iteratively train at lower gen.
@@ -330,31 +365,10 @@ err:
        dev_err(dev, "link never came up\n");
 }
 
-static void advk_pcie_issue_perst(struct advk_pcie *pcie)
-{
-       u32 reg;
-
-       if (!pcie->reset_gpio)
-               return;
-
-       /* PERST does not work for some cards when link training is enabled */
-       reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
-       reg &= ~LINK_TRAINING_EN;
-       advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
-
-       /* 10ms delay is needed for some cards */
-       dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n");
-       gpiod_set_value_cansleep(pcie->reset_gpio, 1);
-       usleep_range(10000, 11000);
-       gpiod_set_value_cansleep(pcie->reset_gpio, 0);
-}
-
 static void advk_pcie_setup_hw(struct advk_pcie *pcie)
 {
        u32 reg;
 
-       advk_pcie_issue_perst(pcie);
-
        /* Enable TX */
        reg = advk_readl(pcie, PCIE_CORE_REF_CLK_REG);
        reg |= PCIE_CORE_REF_CLK_TX_ENABLE;
@@ -431,15 +445,6 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
        reg |= PIO_CTRL_ADDR_WIN_DISABLE;
        advk_writel(pcie, reg, PIO_CTRL);
 
-       /*
-        * PERST# signal could have been asserted by pinctrl subsystem before
-        * probe() callback has been called or issued explicitly by reset gpio
-        * function advk_pcie_issue_perst(), making the endpoint going into
-        * fundamental reset. As required by PCI Express spec a delay for at
-        * least 100ms after such a reset before link training is needed.
-        */
-       msleep(PCI_PM_D3COLD_WAIT);
-
        advk_pcie_train_link(pcie);
 
        /*
@@ -607,7 +612,7 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {
  * Initialize the configuration space of the PCI-to-PCI bridge
  * associated with the given PCIe interface.
  */
-static void advk_sw_pci_bridge_init(struct advk_pcie *pcie)
+static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
 {
        struct pci_bridge_emul *bridge = &pcie->bridge;
 
@@ -633,8 +638,7 @@ static void advk_sw_pci_bridge_init(struct advk_pcie *pcie)
        bridge->data = pcie;
        bridge->ops = &advk_pci_bridge_emul_ops;
 
-       pci_bridge_emul_init(bridge, 0);
-
+       return pci_bridge_emul_init(bridge, 0);
 }
 
 static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
@@ -1077,7 +1081,9 @@ static int advk_pcie_enable_phy(struct advk_pcie *pcie)
        }
 
        ret = phy_power_on(pcie->phy);
-       if (ret) {
+       if (ret == -EOPNOTSUPP) {
+               dev_warn(&pcie->pdev->dev, "PHY unsupported by firmware\n");
+       } else if (ret) {
                phy_exit(pcie->phy);
                return ret;
        }
@@ -1122,6 +1128,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
 
        pcie = pci_host_bridge_priv(bridge);
        pcie->pdev = pdev;
+       platform_set_drvdata(pdev, pcie);
 
        pcie->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pcie->base))
@@ -1167,7 +1174,11 @@ static int advk_pcie_probe(struct platform_device *pdev)
 
        advk_pcie_setup_hw(pcie);
 
-       advk_sw_pci_bridge_init(pcie);
+       ret = advk_sw_pci_bridge_init(pcie);
+       if (ret) {
+               dev_err(dev, "Failed to register emulated root PCI bridge\n");
+               return ret;
+       }
 
        ret = advk_pcie_init_irq_domain(pcie);
        if (ret) {
@@ -1195,18 +1206,37 @@ static int advk_pcie_probe(struct platform_device *pdev)
        return 0;
 }
 
+static int advk_pcie_remove(struct platform_device *pdev)
+{
+       struct advk_pcie *pcie = platform_get_drvdata(pdev);
+       struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
+
+       pci_lock_rescan_remove();
+       pci_stop_root_bus(bridge->bus);
+       pci_remove_root_bus(bridge->bus);
+       pci_unlock_rescan_remove();
+
+       advk_pcie_remove_msi_irq_domain(pcie);
+       advk_pcie_remove_irq_domain(pcie);
+
+       return 0;
+}
+
 static const struct of_device_id advk_pcie_of_match_table[] = {
        { .compatible = "marvell,armada-3700-pcie", },
        {},
 };
+MODULE_DEVICE_TABLE(of, advk_pcie_of_match_table);
 
 static struct platform_driver advk_pcie_driver = {
        .driver = {
                .name = "advk-pcie",
                .of_match_table = advk_pcie_of_match_table,
-               /* Driver unloading/unbinding currently not supported */
-               .suppress_bind_attrs = true,
        },
        .probe = advk_pcie_probe,
+       .remove = advk_pcie_remove,
 };
-builtin_platform_driver(advk_pcie_driver);
+module_platform_driver(advk_pcie_driver);
+
+MODULE_DESCRIPTION("Aardvark PCIe controller");
+MODULE_LICENSE("GPL v2");
index 4e992403fffedf2e39d88b9b99ae28a6c9de2b54..03ed5cb1c4b25224b7175fe7fca4dbe1745e1527 100644 (file)
@@ -1276,11 +1276,25 @@ static void hv_irq_unmask(struct irq_data *data)
 exit_unlock:
        spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags);
 
-       if (res) {
+       /*
+        * During hibernation, when a CPU is offlined, the kernel tries
+        * to move the interrupt to the remaining CPUs that haven't
+        * been offlined yet. In this case, the below hv_do_hypercall()
+        * always fails since the vmbus channel has been closed:
+        * refer to cpu_disable_common() -> fixup_irqs() ->
+        * irq_migrate_all_off_this_cpu() -> migrate_one_irq().
+        *
+        * Suppress the error message for hibernation because the failure
+        * during hibernation does not matter (at this time all the devices
+        * have been frozen). Note: the correct affinity info is still updated
+        * into the irqdata data structure in migrate_one_irq() ->
+        * irq_do_set_affinity() -> hv_set_affinity(), so later when the VM
+        * resumes, hv_pci_restore_msi_state() is able to correctly restore
+        * the interrupt with the correct affinity.
+        */
+       if (res && hbus->state != hv_pcibus_removing)
                dev_err(&hbus->hdev->device,
                        "%s() failed: %#llx", __func__, res);
-               return;
-       }
 
        pci_msi_unmask_irq(data);
 }
@@ -3367,6 +3381,34 @@ static int hv_pci_suspend(struct hv_device *hdev)
        return 0;
 }
 
+static int hv_pci_restore_msi_msg(struct pci_dev *pdev, void *arg)
+{
+       struct msi_desc *entry;
+       struct irq_data *irq_data;
+
+       for_each_pci_msi_entry(entry, pdev) {
+               irq_data = irq_get_irq_data(entry->irq);
+               if (WARN_ON_ONCE(!irq_data))
+                       return -EINVAL;
+
+               hv_compose_msi_msg(irq_data, &entry->msg);
+       }
+
+       return 0;
+}
+
+/*
+ * Upon resume, pci_restore_msi_state() -> ... ->  __pci_write_msi_msg()
+ * directly writes the MSI/MSI-X registers via MMIO, but since Hyper-V
+ * doesn't trap and emulate the MMIO accesses, here hv_compose_msi_msg()
+ * must be used to ask Hyper-V to re-create the IOMMU Interrupt Remapping
+ * Table entries.
+ */
+static void hv_pci_restore_msi_state(struct hv_pcibus_device *hbus)
+{
+       pci_walk_bus(hbus->pci_bus, hv_pci_restore_msi_msg, NULL);
+}
+
 static int hv_pci_resume(struct hv_device *hdev)
 {
        struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
@@ -3400,6 +3442,8 @@ static int hv_pci_resume(struct hv_device *hdev)
 
        prepopulate_bars(hbus);
 
+       hv_pci_restore_msi_state(hbus);
+
        hbus->state = hv_pcibus_installed;
        return 0;
 out:
index 719c19fe2bfb0c1b370a169fe1378bc61102ba54..48169b1e38171d307897db0d355a097c9a0980a2 100644 (file)
@@ -183,7 +183,6 @@ static int loongson_pci_probe(struct platform_device *pdev)
        struct device_node *node = dev->of_node;
        struct pci_host_bridge *bridge;
        struct resource *regs;
-       int err;
 
        if (!node)
                return -ENODEV;
@@ -222,11 +221,7 @@ static int loongson_pci_probe(struct platform_device *pdev)
        bridge->ops = &loongson_pci_ops;
        bridge->map_irq = loongson_map_irq;
 
-       err = pci_host_probe(bridge);
-       if (err)
-               return err;
-
-       return 0;
+       return pci_host_probe(bridge);
 }
 
 static struct platform_driver loongson_pci_driver = {
index c39978b750ec67278f45d3fbf702a9fc6ba49a49..eee82838f4bace3309541ae14d1b516b9000bf70 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/mbus.h>
-#include <linux/msi.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/of_address.h>
@@ -70,7 +69,6 @@ struct mvebu_pcie_port;
 struct mvebu_pcie {
        struct platform_device *pdev;
        struct mvebu_pcie_port *ports;
-       struct msi_controller *msi;
        struct resource io;
        struct resource realio;
        struct resource mem;
@@ -1127,7 +1125,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
        bridge->sysdata = pcie;
        bridge->ops = &mvebu_pcie_ops;
        bridge->align_resource = mvebu_pcie_align_resource;
-       bridge->msi = pcie->msi;
 
        return mvebu_pci_host_probe(bridge);
 }
index c1d34353c29b9ac1217013215a2d142adc362631..8fcabed7c6a676c71118a0e8d58dbcb8183b6bd9 100644 (file)
@@ -2564,36 +2564,14 @@ static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static const struct seq_operations tegra_pcie_ports_seq_ops = {
+static const struct seq_operations tegra_pcie_ports_sops = {
        .start = tegra_pcie_ports_seq_start,
        .next = tegra_pcie_ports_seq_next,
        .stop = tegra_pcie_ports_seq_stop,
        .show = tegra_pcie_ports_seq_show,
 };
 
-static int tegra_pcie_ports_open(struct inode *inode, struct file *file)
-{
-       struct tegra_pcie *pcie = inode->i_private;
-       struct seq_file *s;
-       int err;
-
-       err = seq_open(file, &tegra_pcie_ports_seq_ops);
-       if (err)
-               return err;
-
-       s = file->private_data;
-       s->private = pcie;
-
-       return 0;
-}
-
-static const struct file_operations tegra_pcie_ports_ops = {
-       .owner = THIS_MODULE,
-       .open = tegra_pcie_ports_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = seq_release,
-};
+DEFINE_SEQ_ATTRIBUTE(tegra_pcie_ports);
 
 static void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie)
 {
@@ -2601,24 +2579,12 @@ static void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie)
        pcie->debugfs = NULL;
 }
 
-static int tegra_pcie_debugfs_init(struct tegra_pcie *pcie)
+static void tegra_pcie_debugfs_init(struct tegra_pcie *pcie)
 {
-       struct dentry *file;
-
        pcie->debugfs = debugfs_create_dir("pcie", NULL);
-       if (!pcie->debugfs)
-               return -ENOMEM;
 
-       file = debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs,
-                                  pcie, &tegra_pcie_ports_ops);
-       if (!file)
-               goto remove;
-
-       return 0;
-
-remove:
-       tegra_pcie_debugfs_exit(pcie);
-       return -ENOMEM;
+       debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, pcie,
+                           &tegra_pcie_ports_fops);
 }
 
 static int tegra_pcie_probe(struct platform_device *pdev)
@@ -2672,11 +2638,8 @@ static int tegra_pcie_probe(struct platform_device *pdev)
                goto pm_runtime_put;
        }
 
-       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
-               err = tegra_pcie_debugfs_init(pcie);
-               if (err < 0)
-                       dev_err(dev, "failed to setup debugfs: %d\n", err);
-       }
+       if (IS_ENABLED(CONFIG_DEBUG_FS))
+               tegra_pcie_debugfs_init(pcie);
 
        return 0;
 
index 1f54334f09f7a83a17a51dd5ef6f21081b4be3e7..154a5398633ccb3a539a377583e02c2c0c2a4684 100644 (file)
@@ -658,7 +658,6 @@ static int v3_get_dma_range_config(struct v3_pci *v3,
        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;
index 02271c6d17a1126c358dccc169b65f6cfcb83828..2470782cb01afae6690d6101718672778f500d9a 100644 (file)
@@ -493,8 +493,8 @@ static int xgene_msi_probe(struct platform_device *pdev)
         */
        for (irq_index = 0; irq_index < NR_HW_IRQS; irq_index++) {
                for (msi_idx = 0; msi_idx < IDX_PER_GROUP; msi_idx++)
-                       msi_val = xgene_msi_ir_read(xgene_msi, irq_index,
-                                                   msi_idx);
+                       xgene_msi_ir_read(xgene_msi, irq_index, msi_idx);
+
                /* Read MSIINTn to confirm */
                msi_val = xgene_msi_int_read(xgene_msi, irq_index);
                if (msi_val) {
index bac63d04297f0740ae4a1ab6889bed1da0d148ef..bea86899bd5df1c4371eb6c7c3834d9d3654ba9a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/of_platform.h>
 #include <linux/pci.h>
 #include <linux/printk.h>
+#include <linux/reset.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #define  PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK                0x1000
 #define  PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK     0x2000
 #define  PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK       0x300000
-#define  PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128                0x0
+
 #define  PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK            0xf8000000
+#define  PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK            0x07c00000
+#define  PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK            0x0000001f
+#define  SCB_SIZE_MASK(x) PCIE_MISC_MISC_CTRL_SCB ## x ## _SIZE_MASK
 
 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO               0x400c
 #define PCIE_MEM_WIN0_LO(win)  \
 #define PCIE_MISC_MSI_BAR_CONFIG_HI                    0x4048
 
 #define PCIE_MISC_MSI_DATA_CONFIG                      0x404c
-#define  PCIE_MISC_MSI_DATA_CONFIG_VAL                 0xffe06540
+#define  PCIE_MISC_MSI_DATA_CONFIG_VAL_32              0xffe06540
+#define  PCIE_MISC_MSI_DATA_CONFIG_VAL_8               0xfff86540
 
 #define PCIE_MISC_PCIE_CTRL                            0x4064
 #define  PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK     0x1
+#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK           0x4
 
 #define PCIE_MISC_PCIE_STATUS                          0x4068
 #define  PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK          0x80
@@ -88,6 +94,9 @@
 #define  PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK     0x10
 #define  PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK   0x40
 
+#define PCIE_MISC_REVISION                             0x406c
+#define  BRCM_PCIE_HW_REV_33                           0x0303
+
 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT               0x4070
 #define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK   0xfff00000
 #define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK    0xfff0
 #define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK       0x2
 #define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK               0x08000000
 
-#define PCIE_MSI_INTR2_STATUS                          0x4500
-#define PCIE_MSI_INTR2_CLR                             0x4508
-#define PCIE_MSI_INTR2_MASK_SET                                0x4510
-#define PCIE_MSI_INTR2_MASK_CLR                                0x4514
+
+#define PCIE_INTR2_CPU_BASE            0x4300
+#define PCIE_MSI_INTR2_BASE            0x4500
+/* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */
+#define  MSI_INT_STATUS                        0x0
+#define  MSI_INT_CLR                   0x8
+#define  MSI_INT_MASK_SET              0x10
+#define  MSI_INT_MASK_CLR              0x14
 
 #define PCIE_EXT_CFG_DATA                              0x8000
 
 #define  PCIE_EXT_SLOT_SHIFT                           15
 #define  PCIE_EXT_FUNC_SHIFT                           12
 
-#define PCIE_RGR1_SW_INIT_1                            0x9210
 #define  PCIE_RGR1_SW_INIT_1_PERST_MASK                        0x1
-#define  PCIE_RGR1_SW_INIT_1_INIT_MASK                 0x2
+#define  PCIE_RGR1_SW_INIT_1_PERST_SHIFT               0x0
+
+#define RGR1_SW_INIT_1_INIT_GENERIC_MASK               0x2
+#define RGR1_SW_INIT_1_INIT_GENERIC_SHIFT              0x1
+#define RGR1_SW_INIT_1_INIT_7278_MASK                  0x1
+#define RGR1_SW_INIT_1_INIT_7278_SHIFT                 0x0
 
 /* PCIe parameters */
 #define BRCM_NUM_PCIE_OUT_WINS         0x4
 #define BRCM_INT_PCI_MSI_NR            32
+#define BRCM_INT_PCI_MSI_LEGACY_NR     8
+#define BRCM_INT_PCI_MSI_SHIFT         0
 
 /* MSI target adresses */
 #define BRCM_MSI_TARGET_ADDR_LT_4GB    0x0fffffffcULL
 #define SSC_STATUS_OFFSET              0x1
 #define SSC_STATUS_SSC_MASK            0x400
 #define SSC_STATUS_PLL_LOCK_MASK       0x800
+#define PCIE_BRCM_MAX_MEMC             3
+
+#define IDX_ADDR(pcie)                 (pcie->reg_offsets[EXT_CFG_INDEX])
+#define DATA_ADDR(pcie)                        (pcie->reg_offsets[EXT_CFG_DATA])
+#define PCIE_RGR1_SW_INIT_1(pcie)      (pcie->reg_offsets[RGR1_SW_INIT_1])
+
+/* Rescal registers */
+#define PCIE_DVT_PMU_PCIE_PHY_CTRL                             0xc700
+#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS                 0x3
+#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_MASK                0x4
+#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_SHIFT       0x2
+#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_MASK            0x2
+#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT           0x1
+#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_MASK            0x1
+#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT           0x0
+
+/* Forward declarations */
+struct brcm_pcie;
+static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val);
+static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val);
+static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val);
+static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val);
+
+enum {
+       RGR1_SW_INIT_1,
+       EXT_CFG_INDEX,
+       EXT_CFG_DATA,
+};
+
+enum {
+       RGR1_SW_INIT_1_INIT_MASK,
+       RGR1_SW_INIT_1_INIT_SHIFT,
+};
+
+enum pcie_type {
+       GENERIC,
+       BCM7278,
+       BCM2711,
+};
+
+struct pcie_cfg_data {
+       const int *offsets;
+       const enum pcie_type type;
+       void (*perst_set)(struct brcm_pcie *pcie, u32 val);
+       void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
+};
+
+static const int pcie_offsets[] = {
+       [RGR1_SW_INIT_1] = 0x9210,
+       [EXT_CFG_INDEX]  = 0x9000,
+       [EXT_CFG_DATA]   = 0x9004,
+};
+
+static const struct pcie_cfg_data generic_cfg = {
+       .offsets        = pcie_offsets,
+       .type           = GENERIC,
+       .perst_set      = brcm_pcie_perst_set_generic,
+       .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
+};
+
+static const int pcie_offset_bcm7278[] = {
+       [RGR1_SW_INIT_1] = 0xc010,
+       [EXT_CFG_INDEX] = 0x9000,
+       [EXT_CFG_DATA] = 0x9004,
+};
+
+static const struct pcie_cfg_data bcm7278_cfg = {
+       .offsets        = pcie_offset_bcm7278,
+       .type           = BCM7278,
+       .perst_set      = brcm_pcie_perst_set_7278,
+       .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278,
+};
+
+static const struct pcie_cfg_data bcm2711_cfg = {
+       .offsets        = pcie_offsets,
+       .type           = BCM2711,
+       .perst_set      = brcm_pcie_perst_set_generic,
+       .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
+};
 
 struct brcm_msi {
        struct device           *dev;
@@ -163,6 +261,12 @@ struct brcm_msi {
        int                     irq;
        /* used indicates which MSI interrupts have been alloc'd */
        unsigned long           used;
+       bool                    legacy;
+       /* Some chips have MSIs in bits [31..24] of a shared register. */
+       int                     legacy_shift;
+       int                     nr; /* No. of MSI available, depends on chip */
+       /* This is the base pointer for interrupt status/set/clr regs */
+       void __iomem            *intr_base;
 };
 
 /* Internal PCIe Host Controller Information.*/
@@ -175,6 +279,14 @@ struct brcm_pcie {
        int                     gen;
        u64                     msi_target_addr;
        struct brcm_msi         *msi;
+       const int               *reg_offsets;
+       enum pcie_type          type;
+       struct reset_control    *rescal;
+       int                     num_memc;
+       u64                     memc_size[PCIE_BRCM_MAX_MEMC];
+       u32                     hw_rev;
+       void                    (*perst_set)(struct brcm_pcie *pcie, u32 val);
+       void                    (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
 };
 
 /*
@@ -365,8 +477,10 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc)
        msi = irq_desc_get_handler_data(desc);
        dev = msi->dev;
 
-       status = readl(msi->base + PCIE_MSI_INTR2_STATUS);
-       for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
+       status = readl(msi->intr_base + MSI_INT_STATUS);
+       status >>= msi->legacy_shift;
+
+       for_each_set_bit(bit, &status, msi->nr) {
                virq = irq_find_mapping(msi->inner_domain, bit);
                if (virq)
                        generic_handle_irq(virq);
@@ -383,7 +497,7 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 
        msg->address_lo = lower_32_bits(msi->target_addr);
        msg->address_hi = upper_32_bits(msi->target_addr);
-       msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq;
+       msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq;
 }
 
 static int brcm_msi_set_affinity(struct irq_data *irq_data,
@@ -395,8 +509,9 @@ static int brcm_msi_set_affinity(struct irq_data *irq_data,
 static void brcm_msi_ack_irq(struct irq_data *data)
 {
        struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
+       const int shift_amt = data->hwirq + msi->legacy_shift;
 
-       writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR);
+       writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR);
 }
 
 
@@ -412,7 +527,7 @@ static int brcm_msi_alloc(struct brcm_msi *msi)
        int hwirq;
 
        mutex_lock(&msi->lock);
-       hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0);
+       hwirq = bitmap_find_free_region(&msi->used, msi->nr, 0);
        mutex_unlock(&msi->lock);
 
        return hwirq;
@@ -461,8 +576,7 @@ static int brcm_allocate_domains(struct brcm_msi *msi)
        struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np);
        struct device *dev = msi->dev;
 
-       msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
-                                                 &msi_domain_ops, msi);
+       msi->inner_domain = irq_domain_add_linear(NULL, msi->nr, &msi_domain_ops, msi);
        if (!msi->inner_domain) {
                dev_err(dev, "failed to create IRQ domain\n");
                return -ENOMEM;
@@ -499,7 +613,10 @@ static void brcm_msi_remove(struct brcm_pcie *pcie)
 
 static void brcm_msi_set_regs(struct brcm_msi *msi)
 {
-       writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR);
+       u32 val = __GENMASK(31, msi->legacy_shift);
+
+       writel(val, msi->intr_base + MSI_INT_MASK_CLR);
+       writel(val, msi->intr_base + MSI_INT_CLR);
 
        /*
         * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
@@ -510,8 +627,8 @@ static void brcm_msi_set_regs(struct brcm_msi *msi)
        writel(upper_32_bits(msi->target_addr),
               msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
 
-       writel(PCIE_MISC_MSI_DATA_CONFIG_VAL,
-              msi->base + PCIE_MISC_MSI_DATA_CONFIG);
+       val = msi->legacy ? PCIE_MISC_MSI_DATA_CONFIG_VAL_8 : PCIE_MISC_MSI_DATA_CONFIG_VAL_32;
+       writel(val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);
 }
 
 static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
@@ -536,6 +653,17 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
        msi->np = pcie->np;
        msi->target_addr = pcie->msi_target_addr;
        msi->irq = irq;
+       msi->legacy = pcie->hw_rev < BRCM_PCIE_HW_REV_33;
+
+       if (msi->legacy) {
+               msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE;
+               msi->nr = BRCM_INT_PCI_MSI_LEGACY_NR;
+               msi->legacy_shift = 24;
+       } else {
+               msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
+               msi->nr = BRCM_INT_PCI_MSI_NR;
+               msi->legacy_shift = 0;
+       }
 
        ret = brcm_allocate_domains(msi);
        if (ret)
@@ -599,22 +727,43 @@ static struct pci_ops brcm_pcie_ops = {
        .write = pci_generic_config_write,
 };
 
-static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val)
+static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val)
+{
+       u32 tmp, mask =  RGR1_SW_INIT_1_INIT_GENERIC_MASK;
+       u32 shift = RGR1_SW_INIT_1_INIT_GENERIC_SHIFT;
+
+       tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
+       tmp = (tmp & ~mask) | ((val << shift) & mask);
+       writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
+}
+
+static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val)
+{
+       u32 tmp, mask =  RGR1_SW_INIT_1_INIT_7278_MASK;
+       u32 shift = RGR1_SW_INIT_1_INIT_7278_SHIFT;
+
+       tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
+       tmp = (tmp & ~mask) | ((val << shift) & mask);
+       writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
+}
+
+static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val)
 {
        u32 tmp;
 
-       tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1);
-       u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK);
-       writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1);
+       /* Perst bit has moved and assert value is 0 */
+       tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL);
+       u32p_replace_bits(&tmp, !val, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK);
+       writel(tmp, pcie->base +  PCIE_MISC_PCIE_CTRL);
 }
 
-static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val)
+static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
 {
        u32 tmp;
 
-       tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1);
+       tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
        u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK);
-       writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1);
+       writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
 }
 
 static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
@@ -622,22 +771,44 @@ static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
                                                        u64 *rc_bar2_offset)
 {
        struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
-       struct device *dev = pcie->dev;
        struct resource_entry *entry;
+       struct device *dev = pcie->dev;
+       u64 lowest_pcie_addr = ~(u64)0;
+       int ret, i = 0;
+       u64 size = 0;
 
-       entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
-       if (!entry)
-               return -ENODEV;
+       resource_list_for_each_entry(entry, &bridge->dma_ranges) {
+               u64 pcie_beg = entry->res->start - entry->offset;
 
+               size += entry->res->end - entry->res->start + 1;
+               if (pcie_beg < lowest_pcie_addr)
+                       lowest_pcie_addr = pcie_beg;
+       }
 
-       /*
-        * The controller expects the inbound window offset to be calculated as
-        * the difference between PCIe's address space and CPU's. The offset
-        * provided by the firmware is calculated the opposite way, so we
-        * negate it.
-        */
-       *rc_bar2_offset = -entry->offset;
-       *rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start);
+       if (lowest_pcie_addr == ~(u64)0) {
+               dev_err(dev, "DT node has no dma-ranges\n");
+               return -EINVAL;
+       }
+
+       ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1,
+                                                 PCIE_BRCM_MAX_MEMC);
+
+       if (ret <= 0) {
+               /* Make an educated guess */
+               pcie->num_memc = 1;
+               pcie->memc_size[0] = 1ULL << fls64(size - 1);
+       } else {
+               pcie->num_memc = ret;
+       }
+
+       /* Each memc is viewed through a "port" that is a power of 2 */
+       for (i = 0, size = 0; i < pcie->num_memc; i++)
+               size += pcie->memc_size[i];
+
+       /* System memory starts at this address in PCIe-space */
+       *rc_bar2_offset = lowest_pcie_addr;
+       /* The sum of all memc views must also be a power of 2 */
+       *rc_bar2_size = 1ULL << fls64(size - 1);
 
        /*
         * We validate the inbound memory view even though we should trust
@@ -689,22 +860,19 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
        void __iomem *base = pcie->base;
        struct device *dev = pcie->dev;
        struct resource_entry *entry;
-       unsigned int scb_size_val;
        bool ssc_good = false;
        struct resource *res;
        int num_out_wins = 0;
        u16 nlw, cls, lnksta;
-       int i, ret;
-       u32 tmp, aspm_support;
+       int i, ret, memc;
+       u32 tmp, burst, aspm_support;
 
        /* Reset the bridge */
-       brcm_pcie_bridge_sw_init_set(pcie, 1);
-       brcm_pcie_perst_set(pcie, 1);
-
+       pcie->bridge_sw_init_set(pcie, 1);
        usleep_range(100, 200);
 
        /* Take the bridge out of reset */
-       brcm_pcie_bridge_sw_init_set(pcie, 0);
+       pcie->bridge_sw_init_set(pcie, 0);
 
        tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
        tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK;
@@ -712,11 +880,22 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
        /* Wait for SerDes to be stable */
        usleep_range(100, 200);
 
+       /*
+        * SCB_MAX_BURST_SIZE is a two bit field.  For GENERIC chips it
+        * is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it
+        * is encoded as 0=Rsvd, 1=128, 2=256, 3=512.
+        */
+       if (pcie->type == BCM2711)
+               burst = 0x0; /* 128B */
+       else if (pcie->type == BCM7278)
+               burst = 0x3; /* 512 bytes */
+       else
+               burst = 0x2; /* 512 bytes */
+
        /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
        u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
        u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
-       u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128,
-                         PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
+       u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
        writel(tmp, base + PCIE_MISC_MISC_CTRL);
 
        ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size,
@@ -731,11 +910,17 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
        writel(upper_32_bits(rc_bar2_offset),
               base + PCIE_MISC_RC_BAR2_CONFIG_HI);
 
-       scb_size_val = rc_bar2_size ?
-                      ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */
        tmp = readl(base + PCIE_MISC_MISC_CTRL);
-       u32p_replace_bits(&tmp, scb_size_val,
-                         PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK);
+       for (memc = 0; memc < pcie->num_memc; memc++) {
+               u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15;
+
+               if (memc == 0)
+                       u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(0));
+               else if (memc == 1)
+                       u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(1));
+               else if (memc == 2)
+                       u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2));
+       }
        writel(tmp, base + PCIE_MISC_MISC_CTRL);
 
        /*
@@ -760,17 +945,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
        tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK;
        writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO);
 
-       /* Mask all interrupts since we are not handling any yet */
-       writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET);
-
-       /* clear any interrupts we find on boot */
-       writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR);
-
        if (pcie->gen)
                brcm_pcie_set_gen(pcie, pcie->gen);
 
        /* Unassert the fundamental reset */
-       brcm_pcie_perst_set(pcie, 0);
+       pcie->perst_set(pcie, 0);
 
        /*
         * Give the RC/EP time to wake up, before trying to configure RC.
@@ -882,6 +1061,52 @@ static void brcm_pcie_enter_l23(struct brcm_pcie *pcie)
                dev_err(pcie->dev, "failed to enter low-power link state\n");
 }
 
+static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start)
+{
+       static const u32 shifts[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = {
+               PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT,
+               PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT,
+               PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_SHIFT,};
+       static const u32 masks[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = {
+               PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_MASK,
+               PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_MASK,
+               PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_MASK,};
+       const int beg = start ? 0 : PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS - 1;
+       const int end = start ? PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS : -1;
+       u32 tmp, combined_mask = 0;
+       u32 val;
+       void __iomem *base = pcie->base;
+       int i, ret;
+
+       for (i = beg; i != end; start ? i++ : i--) {
+               val = start ? BIT_MASK(shifts[i]) : 0;
+               tmp = readl(base + PCIE_DVT_PMU_PCIE_PHY_CTRL);
+               tmp = (tmp & ~masks[i]) | (val & masks[i]);
+               writel(tmp, base + PCIE_DVT_PMU_PCIE_PHY_CTRL);
+               usleep_range(50, 200);
+               combined_mask |= masks[i];
+       }
+
+       tmp = readl(base + PCIE_DVT_PMU_PCIE_PHY_CTRL);
+       val = start ? combined_mask : 0;
+
+       ret = (tmp & combined_mask) == val ? 0 : -EIO;
+       if (ret)
+               dev_err(pcie->dev, "failed to %s phy\n", (start ? "start" : "stop"));
+
+       return ret;
+}
+
+static inline int brcm_phy_start(struct brcm_pcie *pcie)
+{
+       return pcie->rescal ? brcm_phy_cntl(pcie, 1) : 0;
+}
+
+static inline int brcm_phy_stop(struct brcm_pcie *pcie)
+{
+       return pcie->rescal ? brcm_phy_cntl(pcie, 0) : 0;
+}
+
 static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
 {
        void __iomem *base = pcie->base;
@@ -890,7 +1115,7 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
        if (brcm_pcie_link_up(pcie))
                brcm_pcie_enter_l23(pcie);
        /* Assert fundamental reset */
-       brcm_pcie_perst_set(pcie, 1);
+       pcie->perst_set(pcie, 1);
 
        /* Deassert request for L23 in case it was asserted */
        tmp = readl(base + PCIE_MISC_PCIE_CTRL);
@@ -903,13 +1128,66 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
        writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
 
        /* Shutdown PCIe bridge */
-       brcm_pcie_bridge_sw_init_set(pcie, 1);
+       pcie->bridge_sw_init_set(pcie, 1);
+}
+
+static int brcm_pcie_suspend(struct device *dev)
+{
+       struct brcm_pcie *pcie = dev_get_drvdata(dev);
+       int ret;
+
+       brcm_pcie_turn_off(pcie);
+       ret = brcm_phy_stop(pcie);
+       clk_disable_unprepare(pcie->clk);
+
+       return ret;
+}
+
+static int brcm_pcie_resume(struct device *dev)
+{
+       struct brcm_pcie *pcie = dev_get_drvdata(dev);
+       void __iomem *base;
+       u32 tmp;
+       int ret;
+
+       base = pcie->base;
+       clk_prepare_enable(pcie->clk);
+
+       ret = brcm_phy_start(pcie);
+       if (ret)
+               goto err;
+
+       /* Take bridge out of reset so we can access the SERDES reg */
+       pcie->bridge_sw_init_set(pcie, 0);
+
+       /* SERDES_IDDQ = 0 */
+       tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+       u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
+       writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+
+       /* wait for serdes to be stable */
+       udelay(100);
+
+       ret = brcm_pcie_setup(pcie);
+       if (ret)
+               goto err;
+
+       if (pcie->msi)
+               brcm_msi_set_regs(pcie->msi);
+
+       return 0;
+
+err:
+       clk_disable_unprepare(pcie->clk);
+       return ret;
 }
 
 static void __brcm_pcie_remove(struct brcm_pcie *pcie)
 {
        brcm_msi_remove(pcie);
        brcm_pcie_turn_off(pcie);
+       brcm_phy_stop(pcie);
+       reset_control_assert(pcie->rescal);
        clk_disable_unprepare(pcie->clk);
 }
 
@@ -925,10 +1203,20 @@ static int brcm_pcie_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id brcm_pcie_match[] = {
+       { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
+       { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg },
+       { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
+       { .compatible = "brcm,bcm7216-pcie", .data = &bcm7278_cfg },
+       { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg },
+       {},
+};
+
 static int brcm_pcie_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node, *msi_np;
        struct pci_host_bridge *bridge;
+       const struct pcie_cfg_data *data;
        struct brcm_pcie *pcie;
        int ret;
 
@@ -936,9 +1224,19 @@ static int brcm_pcie_probe(struct platform_device *pdev)
        if (!bridge)
                return -ENOMEM;
 
+       data = of_device_get_match_data(&pdev->dev);
+       if (!data) {
+               pr_err("failed to look up compatible string\n");
+               return -EINVAL;
+       }
+
        pcie = pci_host_bridge_priv(bridge);
        pcie->dev = &pdev->dev;
        pcie->np = np;
+       pcie->reg_offsets = data->offsets;
+       pcie->type = data->type;
+       pcie->perst_set = data->perst_set;
+       pcie->bridge_sw_init_set = data->bridge_sw_init_set;
 
        pcie->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pcie->base))
@@ -958,11 +1256,29 @@ static int brcm_pcie_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "could not enable clock\n");
                return ret;
        }
+       pcie->rescal = devm_reset_control_get_optional_shared(&pdev->dev, "rescal");
+       if (IS_ERR(pcie->rescal)) {
+               clk_disable_unprepare(pcie->clk);
+               return PTR_ERR(pcie->rescal);
+       }
+
+       ret = reset_control_deassert(pcie->rescal);
+       if (ret)
+               dev_err(&pdev->dev, "failed to deassert 'rescal'\n");
+
+       ret = brcm_phy_start(pcie);
+       if (ret) {
+               reset_control_assert(pcie->rescal);
+               clk_disable_unprepare(pcie->clk);
+               return ret;
+       }
 
        ret = brcm_pcie_setup(pcie);
        if (ret)
                goto fail;
 
+       pcie->hw_rev = readl(pcie->base + PCIE_MISC_REVISION);
+
        msi_np = of_parse_phandle(pcie->np, "msi-parent", 0);
        if (pci_msi_enabled() && msi_np == pcie->np) {
                ret = brcm_pcie_enable_msi(pcie);
@@ -983,18 +1299,20 @@ fail:
        return ret;
 }
 
-static const struct of_device_id brcm_pcie_match[] = {
-       { .compatible = "brcm,bcm2711-pcie" },
-       {},
-};
 MODULE_DEVICE_TABLE(of, brcm_pcie_match);
 
+static const struct dev_pm_ops brcm_pcie_pm_ops = {
+       .suspend = brcm_pcie_suspend,
+       .resume = brcm_pcie_resume,
+};
+
 static struct platform_driver brcm_pcie_driver = {
        .probe = brcm_pcie_probe,
        .remove = brcm_pcie_remove,
        .driver = {
                .name = "brcm-pcie",
                .of_match_table = brcm_pcie_match,
+               .pm = &brcm_pcie_pm_ops,
        },
 };
 module_platform_driver(brcm_pcie_driver);
diff --git a/drivers/pci/controller/pcie-hisi-error.c b/drivers/pci/controller/pcie-hisi-error.c
new file mode 100644 (file)
index 0000000..7959c9c
--- /dev/null
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for handling the PCIe controller errors on
+ * HiSilicon HIP SoCs.
+ *
+ * Copyright (c) 2020 HiSilicon Limited.
+ */
+
+#include <linux/acpi.h>
+#include <acpi/ghes.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+
+/* HISI PCIe controller error definitions */
+#define HISI_PCIE_ERR_MISC_REGS        33
+
+#define HISI_PCIE_LOCAL_VALID_VERSION          BIT(0)
+#define HISI_PCIE_LOCAL_VALID_SOC_ID           BIT(1)
+#define HISI_PCIE_LOCAL_VALID_SOCKET_ID                BIT(2)
+#define HISI_PCIE_LOCAL_VALID_NIMBUS_ID                BIT(3)
+#define HISI_PCIE_LOCAL_VALID_SUB_MODULE_ID    BIT(4)
+#define HISI_PCIE_LOCAL_VALID_CORE_ID          BIT(5)
+#define HISI_PCIE_LOCAL_VALID_PORT_ID          BIT(6)
+#define HISI_PCIE_LOCAL_VALID_ERR_TYPE         BIT(7)
+#define HISI_PCIE_LOCAL_VALID_ERR_SEVERITY     BIT(8)
+#define HISI_PCIE_LOCAL_VALID_ERR_MISC         9
+
+static guid_t hisi_pcie_sec_guid =
+       GUID_INIT(0xB2889FC9, 0xE7D7, 0x4F9D,
+                 0xA8, 0x67, 0xAF, 0x42, 0xE9, 0x8B, 0xE7, 0x72);
+
+/*
+ * Firmware reports the socket port ID where the error occurred.  These
+ * macros convert that to the core ID and core port ID required by the
+ * ACPI reset method.
+ */
+#define HISI_PCIE_PORT_ID(core, v)       (((v) >> 1) + ((core) << 3))
+#define HISI_PCIE_CORE_ID(v)             ((v) >> 3)
+#define HISI_PCIE_CORE_PORT_ID(v)        (((v) & 7) << 1)
+
+struct hisi_pcie_error_data {
+       u64     val_bits;
+       u8      version;
+       u8      soc_id;
+       u8      socket_id;
+       u8      nimbus_id;
+       u8      sub_module_id;
+       u8      core_id;
+       u8      port_id;
+       u8      err_severity;
+       u16     err_type;
+       u8      reserv[2];
+       u32     err_misc[HISI_PCIE_ERR_MISC_REGS];
+};
+
+struct hisi_pcie_error_private {
+       struct notifier_block   nb;
+       struct device *dev;
+};
+
+enum hisi_pcie_submodule_id {
+       HISI_PCIE_SUB_MODULE_ID_AP,
+       HISI_PCIE_SUB_MODULE_ID_TL,
+       HISI_PCIE_SUB_MODULE_ID_MAC,
+       HISI_PCIE_SUB_MODULE_ID_DL,
+       HISI_PCIE_SUB_MODULE_ID_SDI,
+};
+
+static const char * const hisi_pcie_sub_module[] = {
+       [HISI_PCIE_SUB_MODULE_ID_AP]    = "AP Layer",
+       [HISI_PCIE_SUB_MODULE_ID_TL]    = "TL Layer",
+       [HISI_PCIE_SUB_MODULE_ID_MAC]   = "MAC Layer",
+       [HISI_PCIE_SUB_MODULE_ID_DL]    = "DL Layer",
+       [HISI_PCIE_SUB_MODULE_ID_SDI]   = "SDI Layer",
+};
+
+enum hisi_pcie_err_severity {
+       HISI_PCIE_ERR_SEV_RECOVERABLE,
+       HISI_PCIE_ERR_SEV_FATAL,
+       HISI_PCIE_ERR_SEV_CORRECTED,
+       HISI_PCIE_ERR_SEV_NONE,
+};
+
+static const char * const hisi_pcie_error_sev[] = {
+       [HISI_PCIE_ERR_SEV_RECOVERABLE] = "recoverable",
+       [HISI_PCIE_ERR_SEV_FATAL]       = "fatal",
+       [HISI_PCIE_ERR_SEV_CORRECTED]   = "corrected",
+       [HISI_PCIE_ERR_SEV_NONE]        = "none",
+};
+
+static const char *hisi_pcie_get_string(const char * const *array,
+                                       size_t n, u32 id)
+{
+       u32 index;
+
+       for (index = 0; index < n; index++) {
+               if (index == id && array[index])
+                       return array[index];
+       }
+
+       return "unknown";
+}
+
+static int hisi_pcie_port_reset(struct platform_device *pdev,
+                               u32 chip_id, u32 port_id)
+{
+       struct device *dev = &pdev->dev;
+       acpi_handle handle = ACPI_HANDLE(dev);
+       union acpi_object arg[3];
+       struct acpi_object_list arg_list;
+       acpi_status s;
+       unsigned long long data = 0;
+
+       arg[0].type = ACPI_TYPE_INTEGER;
+       arg[0].integer.value = chip_id;
+       arg[1].type = ACPI_TYPE_INTEGER;
+       arg[1].integer.value = HISI_PCIE_CORE_ID(port_id);
+       arg[2].type = ACPI_TYPE_INTEGER;
+       arg[2].integer.value = HISI_PCIE_CORE_PORT_ID(port_id);
+
+       arg_list.count = 3;
+       arg_list.pointer = arg;
+
+       s = acpi_evaluate_integer(handle, "RST", &arg_list, &data);
+       if (ACPI_FAILURE(s)) {
+               dev_err(dev, "No RST method\n");
+               return -EIO;
+       }
+
+       if (data) {
+               dev_err(dev, "Failed to Reset\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int hisi_pcie_port_do_recovery(struct platform_device *dev,
+                                     u32 chip_id, u32 port_id)
+{
+       acpi_status s;
+       struct device *device = &dev->dev;
+       acpi_handle root_handle = ACPI_HANDLE(device);
+       struct acpi_pci_root *pci_root;
+       struct pci_bus *root_bus;
+       struct pci_dev *pdev;
+       u32 domain, busnr, devfn;
+
+       s = acpi_get_parent(root_handle, &root_handle);
+       if (ACPI_FAILURE(s))
+               return -ENODEV;
+       pci_root = acpi_pci_find_root(root_handle);
+       if (!pci_root)
+               return -ENODEV;
+       root_bus = pci_root->bus;
+       domain = pci_root->segment;
+
+       busnr = root_bus->number;
+       devfn = PCI_DEVFN(port_id, 0);
+       pdev = pci_get_domain_bus_and_slot(domain, busnr, devfn);
+       if (!pdev) {
+               dev_info(device, "Fail to get root port %04x:%02x:%02x.%d device\n",
+                        domain, busnr, PCI_SLOT(devfn), PCI_FUNC(devfn));
+               return -ENODEV;
+       }
+
+       pci_stop_and_remove_bus_device_locked(pdev);
+       pci_dev_put(pdev);
+
+       if (hisi_pcie_port_reset(dev, chip_id, port_id))
+               return -EIO;
+
+       /*
+        * The initialization time of subordinate devices after
+        * hot reset is no more than 1s, which is required by
+        * the PCI spec v5.0 sec 6.6.1. The time will shorten
+        * if Readiness Notifications mechanisms are used. But
+        * wait 1s here to adapt any conditions.
+        */
+       ssleep(1UL);
+
+       /* add root port and downstream devices */
+       pci_lock_rescan_remove();
+       pci_rescan_bus(root_bus);
+       pci_unlock_rescan_remove();
+
+       return 0;
+}
+
+static void hisi_pcie_handle_error(struct platform_device *pdev,
+                                  const struct hisi_pcie_error_data *edata)
+{
+       struct device *dev = &pdev->dev;
+       int idx, rc;
+       const unsigned long valid_bits[] = {BITMAP_FROM_U64(edata->val_bits)};
+
+       if (edata->val_bits == 0) {
+               dev_warn(dev, "%s: no valid error information\n", __func__);
+               return;
+       }
+
+       dev_info(dev, "\nHISI : HIP : PCIe controller error\n");
+       if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SOC_ID)
+               dev_info(dev, "Table version = %d\n", edata->version);
+       if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SOCKET_ID)
+               dev_info(dev, "Socket ID = %d\n", edata->socket_id);
+       if (edata->val_bits & HISI_PCIE_LOCAL_VALID_NIMBUS_ID)
+               dev_info(dev, "Nimbus ID = %d\n", edata->nimbus_id);
+       if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SUB_MODULE_ID)
+               dev_info(dev, "Sub Module = %s\n",
+                        hisi_pcie_get_string(hisi_pcie_sub_module,
+                                             ARRAY_SIZE(hisi_pcie_sub_module),
+                                             edata->sub_module_id));
+       if (edata->val_bits & HISI_PCIE_LOCAL_VALID_CORE_ID)
+               dev_info(dev, "Core ID = core%d\n", edata->core_id);
+       if (edata->val_bits & HISI_PCIE_LOCAL_VALID_PORT_ID)
+               dev_info(dev, "Port ID = port%d\n", edata->port_id);
+       if (edata->val_bits & HISI_PCIE_LOCAL_VALID_ERR_SEVERITY)
+               dev_info(dev, "Error severity = %s\n",
+                        hisi_pcie_get_string(hisi_pcie_error_sev,
+                                             ARRAY_SIZE(hisi_pcie_error_sev),
+                                             edata->err_severity));
+       if (edata->val_bits & HISI_PCIE_LOCAL_VALID_ERR_TYPE)
+               dev_info(dev, "Error type = 0x%x\n", edata->err_type);
+
+       dev_info(dev, "Reg Dump:\n");
+       idx = HISI_PCIE_LOCAL_VALID_ERR_MISC;
+       for_each_set_bit_from(idx, valid_bits,
+                             HISI_PCIE_LOCAL_VALID_ERR_MISC + HISI_PCIE_ERR_MISC_REGS)
+               dev_info(dev, "ERR_MISC_%d = 0x%x\n", idx - HISI_PCIE_LOCAL_VALID_ERR_MISC,
+                        edata->err_misc[idx - HISI_PCIE_LOCAL_VALID_ERR_MISC]);
+
+       if (edata->err_severity != HISI_PCIE_ERR_SEV_RECOVERABLE)
+               return;
+
+       /* Recovery for the PCIe controller errors, try reset
+        * PCI port for the error recovery
+        */
+       rc = hisi_pcie_port_do_recovery(pdev, edata->socket_id,
+                       HISI_PCIE_PORT_ID(edata->core_id, edata->port_id));
+       if (rc)
+               dev_info(dev, "fail to do hisi pcie port reset\n");
+}
+
+static int hisi_pcie_notify_error(struct notifier_block *nb,
+                                 unsigned long event, void *data)
+{
+       struct acpi_hest_generic_data *gdata = data;
+       const struct hisi_pcie_error_data *error_data = acpi_hest_get_payload(gdata);
+       struct hisi_pcie_error_private *priv;
+       struct device *dev;
+       struct platform_device *pdev;
+       guid_t err_sec_guid;
+       u8 socket;
+
+       import_guid(&err_sec_guid, gdata->section_type);
+       if (!guid_equal(&err_sec_guid, &hisi_pcie_sec_guid))
+               return NOTIFY_DONE;
+
+       priv = container_of(nb, struct hisi_pcie_error_private, nb);
+       dev = priv->dev;
+
+       if (device_property_read_u8(dev, "socket", &socket))
+               return NOTIFY_DONE;
+
+       if (error_data->socket_id != socket)
+               return NOTIFY_DONE;
+
+       pdev = container_of(dev, struct platform_device, dev);
+       hisi_pcie_handle_error(pdev, error_data);
+
+       return NOTIFY_OK;
+}
+
+static int hisi_pcie_error_handler_probe(struct platform_device *pdev)
+{
+       struct hisi_pcie_error_private *priv;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->nb.notifier_call = hisi_pcie_notify_error;
+       priv->dev = &pdev->dev;
+       ret = ghes_register_vendor_record_notifier(&priv->nb);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Failed to register hisi pcie controller error handler with apei\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, priv);
+
+       return 0;
+}
+
+static int hisi_pcie_error_handler_remove(struct platform_device *pdev)
+{
+       struct hisi_pcie_error_private *priv = platform_get_drvdata(pdev);
+
+       ghes_unregister_vendor_record_notifier(&priv->nb);
+
+       return 0;
+}
+
+static const struct acpi_device_id hisi_pcie_acpi_match[] = {
+       { "HISI0361", 0 },
+       { }
+};
+
+static struct platform_driver hisi_pcie_error_handler_driver = {
+       .driver = {
+               .name   = "hisi-pcie-error-handler",
+               .acpi_match_table = hisi_pcie_acpi_match,
+       },
+       .probe          = hisi_pcie_error_handler_probe,
+       .remove         = hisi_pcie_error_handler_remove,
+};
+module_platform_driver(hisi_pcie_error_handler_driver);
+
+MODULE_DESCRIPTION("HiSilicon HIP PCIe controller error handling driver");
+MODULE_LICENSE("GPL v2");
index aa55b064f64db5ce0691e79120b22de2c536b82d..56b8ee7bf33072f01c64a53a9a936b8a8effb782 100644 (file)
@@ -94,18 +94,7 @@ static struct bcma_driver iproc_pcie_bcma_driver = {
        .probe          = iproc_pcie_bcma_probe,
        .remove         = iproc_pcie_bcma_remove,
 };
-
-static int __init iproc_pcie_bcma_init(void)
-{
-       return bcma_driver_register(&iproc_pcie_bcma_driver);
-}
-module_init(iproc_pcie_bcma_init);
-
-static void __exit iproc_pcie_bcma_exit(void)
-{
-       bcma_driver_unregister(&iproc_pcie_bcma_driver);
-}
-module_exit(iproc_pcie_bcma_exit);
+module_bcma_driver(iproc_pcie_bcma_driver);
 
 MODULE_AUTHOR("Hauke Mehrtens");
 MODULE_DESCRIPTION("Broadcom iProc PCIe BCMA driver");
index 3176ad3ab0e5268c9a632ab758a712214da8ba0b..908475d27e0e72214c55031e0cc3dc25b39d007b 100644 (file)
@@ -209,15 +209,20 @@ static int iproc_msi_irq_set_affinity(struct irq_data *data,
        struct iproc_msi *msi = irq_data_get_irq_chip_data(data);
        int target_cpu = cpumask_first(mask);
        int curr_cpu;
+       int ret;
 
        curr_cpu = hwirq_to_cpu(msi, data->hwirq);
        if (curr_cpu == target_cpu)
-               return IRQ_SET_MASK_OK_DONE;
+               ret = IRQ_SET_MASK_OK_DONE;
+       else {
+               /* steer MSI to the target CPU */
+               data->hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq) + target_cpu;
+               ret = IRQ_SET_MASK_OK;
+       }
 
-       /* steer MSI to the target CPU */
-       data->hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq) + target_cpu;
+       irq_data_update_effective_affinity(data, cpumask_of(target_cpu));
 
-       return IRQ_SET_MASK_OK;
+       return ret;
 }
 
 static void iproc_msi_irq_compose_msi_msg(struct irq_data *data,
index a956b0c18bd1b2a8640179506e41505fbba7119d..b93e7bda101bc106a80ea988ff554d68012bd81a 100644 (file)
@@ -99,7 +99,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
        switch (pcie->type) {
        case IPROC_PCIE_PAXC:
        case IPROC_PCIE_PAXC_V2:
-               pcie->map_irq = 0;
+               pcie->map_irq = NULL;
                break;
        default:
                break;
index f3082de44e8a8f2e6bdf6190b04e4d612f8244ac..f92e0152e65e30f229e33607dce8468c438b29eb 100644 (file)
@@ -572,12 +572,8 @@ static int xilinx_cpm_pcie_probe(struct platform_device *pdev)
                goto err_setup_irq;
        }
 
-       bridge->dev.parent = dev;
        bridge->sysdata = port->cfg;
-       bridge->busnr = port->cfg->busr.start;
        bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
-       bridge->map_irq = of_irq_parse_and_map_pci;
-       bridge->swizzle_irq = pci_common_swizzle;
 
        err = pci_host_probe(bridge);
        if (err < 0)
index aa1b12bac9a1567a8ccc48d7cf273c46788e0542..f375c21ceeb16308285df97788ec5a8b6c085f8b 100644 (file)
@@ -298,6 +298,33 @@ static struct msi_domain_info vmd_msi_domain_info = {
        .chip           = &vmd_msi_controller,
 };
 
+static int vmd_create_irq_domain(struct vmd_dev *vmd)
+{
+       struct fwnode_handle *fn;
+
+       fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);
+       if (!fn)
+               return -ENODEV;
+
+       vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, NULL);
+       if (!vmd->irq_domain) {
+               irq_domain_free_fwnode(fn);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void vmd_remove_irq_domain(struct vmd_dev *vmd)
+{
+       if (vmd->irq_domain) {
+               struct fwnode_handle *fn = vmd->irq_domain->fwnode;
+
+               irq_domain_remove(vmd->irq_domain);
+               irq_domain_free_fwnode(fn);
+       }
+}
+
 static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
                                  unsigned int devfn, int reg, int len)
 {
@@ -417,97 +444,175 @@ static int vmd_find_free_domain(void)
        return domain + 1;
 }
 
-static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
+static int vmd_get_phys_offsets(struct vmd_dev *vmd, bool native_hint,
+                               resource_size_t *offset1,
+                               resource_size_t *offset2)
 {
-       struct pci_sysdata *sd = &vmd->sysdata;
-       struct fwnode_handle *fn;
-       struct resource *res;
-       u32 upper_bits;
-       unsigned long flags;
-       LIST_HEAD(resources);
-       resource_size_t offset[2] = {0};
-       resource_size_t membar2_offset = 0x2000;
-       struct pci_bus *child;
+       struct pci_dev *dev = vmd->dev;
+       u64 phys1, phys2;
 
-       /*
-        * Shadow registers may exist in certain VMD device ids which allow
-        * guests to correctly assign host physical addresses to the root ports
-        * and child devices. These registers will either return the host value
-        * or 0, depending on an enable bit in the VMD device.
-        */
-       if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) {
+       if (native_hint) {
                u32 vmlock;
                int ret;
 
-               membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE;
-               ret = pci_read_config_dword(vmd->dev, PCI_REG_VMLOCK, &vmlock);
+               ret = pci_read_config_dword(dev, PCI_REG_VMLOCK, &vmlock);
                if (ret || vmlock == ~0)
                        return -ENODEV;
 
                if (MB2_SHADOW_EN(vmlock)) {
                        void __iomem *membar2;
 
-                       membar2 = pci_iomap(vmd->dev, VMD_MEMBAR2, 0);
+                       membar2 = pci_iomap(dev, VMD_MEMBAR2, 0);
                        if (!membar2)
                                return -ENOMEM;
-                       offset[0] = vmd->dev->resource[VMD_MEMBAR1].start -
-                                       (readq(membar2 + MB2_SHADOW_OFFSET) &
-                                        PCI_BASE_ADDRESS_MEM_MASK);
-                       offset[1] = vmd->dev->resource[VMD_MEMBAR2].start -
-                                       (readq(membar2 + MB2_SHADOW_OFFSET + 8) &
-                                        PCI_BASE_ADDRESS_MEM_MASK);
-                       pci_iounmap(vmd->dev, membar2);
-               }
-       }
-
-       if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) {
-               int pos = pci_find_capability(vmd->dev, PCI_CAP_ID_VNDR);
+                       phys1 = readq(membar2 + MB2_SHADOW_OFFSET);
+                       phys2 = readq(membar2 + MB2_SHADOW_OFFSET + 8);
+                       pci_iounmap(dev, membar2);
+               } else
+                       return 0;
+       } else {
+               /* Hypervisor-Emulated Vendor-Specific Capability */
+               int pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);
                u32 reg, regu;
 
-               pci_read_config_dword(vmd->dev, pos + 4, &reg);
+               pci_read_config_dword(dev, pos + 4, &reg);
 
                /* "SHDW" */
                if (pos && reg == 0x53484457) {
-                       pci_read_config_dword(vmd->dev, pos + 8, &reg);
-                       pci_read_config_dword(vmd->dev, pos + 12, &regu);
-                       offset[0] = vmd->dev->resource[VMD_MEMBAR1].start -
-                                       (((u64) regu << 32 | reg) &
-                                        PCI_BASE_ADDRESS_MEM_MASK);
-
-                       pci_read_config_dword(vmd->dev, pos + 16, &reg);
-                       pci_read_config_dword(vmd->dev, pos + 20, &regu);
-                       offset[1] = vmd->dev->resource[VMD_MEMBAR2].start -
-                                       (((u64) regu << 32 | reg) &
-                                        PCI_BASE_ADDRESS_MEM_MASK);
+                       pci_read_config_dword(dev, pos + 8, &reg);
+                       pci_read_config_dword(dev, pos + 12, &regu);
+                       phys1 = (u64) regu << 32 | reg;
+
+                       pci_read_config_dword(dev, pos + 16, &reg);
+                       pci_read_config_dword(dev, pos + 20, &regu);
+                       phys2 = (u64) regu << 32 | reg;
+               } else
+                       return 0;
+       }
+
+       *offset1 = dev->resource[VMD_MEMBAR1].start -
+                       (phys1 & PCI_BASE_ADDRESS_MEM_MASK);
+       *offset2 = dev->resource[VMD_MEMBAR2].start -
+                       (phys2 & PCI_BASE_ADDRESS_MEM_MASK);
+
+       return 0;
+}
+
+static int vmd_get_bus_number_start(struct vmd_dev *vmd)
+{
+       struct pci_dev *dev = vmd->dev;
+       u16 reg;
+
+       pci_read_config_word(dev, PCI_REG_VMCAP, &reg);
+       if (BUS_RESTRICT_CAP(reg)) {
+               pci_read_config_word(dev, PCI_REG_VMCONFIG, &reg);
+
+               switch (BUS_RESTRICT_CFG(reg)) {
+               case 0:
+                       vmd->busn_start = 0;
+                       break;
+               case 1:
+                       vmd->busn_start = 128;
+                       break;
+               case 2:
+                       vmd->busn_start = 224;
+                       break;
+               default:
+                       pci_err(dev, "Unknown Bus Offset Setting (%d)\n",
+                               BUS_RESTRICT_CFG(reg));
+                       return -ENODEV;
                }
        }
 
+       return 0;
+}
+
+static irqreturn_t vmd_irq(int irq, void *data)
+{
+       struct vmd_irq_list *irqs = data;
+       struct vmd_irq *vmdirq;
+       int idx;
+
+       idx = srcu_read_lock(&irqs->srcu);
+       list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)
+               generic_handle_irq(vmdirq->virq);
+       srcu_read_unlock(&irqs->srcu, idx);
+
+       return IRQ_HANDLED;
+}
+
+static int vmd_alloc_irqs(struct vmd_dev *vmd)
+{
+       struct pci_dev *dev = vmd->dev;
+       int i, err;
+
+       vmd->msix_count = pci_msix_vec_count(dev);
+       if (vmd->msix_count < 0)
+               return -ENODEV;
+
+       vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,
+                                               PCI_IRQ_MSIX);
+       if (vmd->msix_count < 0)
+               return vmd->msix_count;
+
+       vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs),
+                                GFP_KERNEL);
+       if (!vmd->irqs)
+               return -ENOMEM;
+
+       for (i = 0; i < vmd->msix_count; i++) {
+               err = init_srcu_struct(&vmd->irqs[i].srcu);
+               if (err)
+                       return err;
+
+               INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
+               err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
+                                      vmd_irq, IRQF_NO_THREAD,
+                                      "vmd", &vmd->irqs[i]);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
+{
+       struct pci_sysdata *sd = &vmd->sysdata;
+       struct resource *res;
+       u32 upper_bits;
+       unsigned long flags;
+       LIST_HEAD(resources);
+       resource_size_t offset[2] = {0};
+       resource_size_t membar2_offset = 0x2000;
+       struct pci_bus *child;
+       int ret;
+
+       /*
+        * Shadow registers may exist in certain VMD device ids which allow
+        * guests to correctly assign host physical addresses to the root ports
+        * and child devices. These registers will either return the host value
+        * or 0, depending on an enable bit in the VMD device.
+        */
+       if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) {
+               membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE;
+               ret = vmd_get_phys_offsets(vmd, true, &offset[0], &offset[1]);
+               if (ret)
+                       return ret;
+       } else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) {
+               ret = vmd_get_phys_offsets(vmd, false, &offset[0], &offset[1]);
+               if (ret)
+                       return ret;
+       }
+
        /*
         * Certain VMD devices may have a root port configuration option which
         * limits the bus range to between 0-127, 128-255, or 224-255
         */
        if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) {
-               u16 reg16;
-
-               pci_read_config_word(vmd->dev, PCI_REG_VMCAP, &reg16);
-               if (BUS_RESTRICT_CAP(reg16)) {
-                       pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG,
-                                            &reg16);
-
-                       switch (BUS_RESTRICT_CFG(reg16)) {
-                       case 1:
-                               vmd->busn_start = 128;
-                               break;
-                       case 2:
-                               vmd->busn_start = 224;
-                               break;
-                       case 3:
-                               pci_err(vmd->dev, "Unknown Bus Offset Setting\n");
-                               return -ENODEV;
-                       default:
-                               break;
-                       }
-               }
+               ret = vmd_get_bus_number_start(vmd);
+               if (ret)
+                       return ret;
        }
 
        res = &vmd->dev->resource[VMD_CFGBAR];
@@ -568,17 +673,9 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
 
        sd->node = pcibus_to_node(vmd->dev->bus);
 
-       fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);
-       if (!fn)
-               return -ENODEV;
-
-       vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info,
-                                                   NULL);
-
-       if (!vmd->irq_domain) {
-               irq_domain_free_fwnode(fn);
-               return -ENODEV;
-       }
+       ret = vmd_create_irq_domain(vmd);
+       if (ret)
+               return ret;
 
        /*
         * Override the irq domain bus token so the domain can be distinguished
@@ -594,13 +691,13 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
                                       &vmd_ops, sd, &resources);
        if (!vmd->bus) {
                pci_free_resource_list(&resources);
-               irq_domain_remove(vmd->irq_domain);
-               irq_domain_free_fwnode(fn);
+               vmd_remove_irq_domain(vmd);
                return -ENODEV;
        }
 
        vmd_attach_resources(vmd);
-       dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
+       if (vmd->irq_domain)
+               dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
 
        pci_scan_child_bus(vmd->bus);
        pci_assign_unassigned_bus_resources(vmd->bus);
@@ -620,24 +717,10 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
        return 0;
 }
 
-static irqreturn_t vmd_irq(int irq, void *data)
-{
-       struct vmd_irq_list *irqs = data;
-       struct vmd_irq *vmdirq;
-       int idx;
-
-       idx = srcu_read_lock(&irqs->srcu);
-       list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)
-               generic_handle_irq(vmdirq->virq);
-       srcu_read_unlock(&irqs->srcu, idx);
-
-       return IRQ_HANDLED;
-}
-
 static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct vmd_dev *vmd;
-       int i, err;
+       int err;
 
        if (resource_size(&dev->resource[VMD_CFGBAR]) < (1 << 20))
                return -ENOMEM;
@@ -660,32 +743,9 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
            dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)))
                return -ENODEV;
 
-       vmd->msix_count = pci_msix_vec_count(dev);
-       if (vmd->msix_count < 0)
-               return -ENODEV;
-
-       vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,
-                                       PCI_IRQ_MSIX);
-       if (vmd->msix_count < 0)
-               return vmd->msix_count;
-
-       vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs),
-                                GFP_KERNEL);
-       if (!vmd->irqs)
-               return -ENOMEM;
-
-       for (i = 0; i < vmd->msix_count; i++) {
-               err = init_srcu_struct(&vmd->irqs[i].srcu);
-               if (err)
-                       return err;
-
-               INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
-               err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
-                                      vmd_irq, IRQF_NO_THREAD,
-                                      "vmd", &vmd->irqs[i]);
-               if (err)
-                       return err;
-       }
+       err = vmd_alloc_irqs(vmd);
+       if (err)
+               return err;
 
        spin_lock_init(&vmd->cfg_lock);
        pci_set_drvdata(dev, vmd);
@@ -709,15 +769,13 @@ static void vmd_cleanup_srcu(struct vmd_dev *vmd)
 static void vmd_remove(struct pci_dev *dev)
 {
        struct vmd_dev *vmd = pci_get_drvdata(dev);
-       struct fwnode_handle *fn = vmd->irq_domain->fwnode;
 
        sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
        pci_stop_root_bus(vmd->bus);
        pci_remove_root_bus(vmd->bus);
        vmd_cleanup_srcu(vmd);
        vmd_detach_resources(vmd);
-       irq_domain_remove(vmd->irq_domain);
-       irq_domain_free_fwnode(fn);
+       vmd_remove_irq_domain(vmd);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -730,7 +788,6 @@ static int vmd_suspend(struct device *dev)
        for (i = 0; i < vmd->msix_count; i++)
                devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]);
 
-       pci_save_state(pdev);
        return 0;
 }
 
@@ -748,7 +805,6 @@ static int vmd_resume(struct device *dev)
                        return err;
        }
 
-       pci_restore_state(pdev);
        return 0;
 }
 #endif
index 8f065a42fc1a2ec958fa71cb8250369e4d89e556..b54d32a31669360697259f2c5c44a37795f9d897 100644 (file)
@@ -168,4 +168,14 @@ const struct pci_ecam_ops pci_32b_ops = {
                .write          = pci_generic_config_write32,
        }
 };
+
+/* ECAM ops for 32-bit read only (non-compliant) */
+const struct pci_ecam_ops pci_32b_read_ops = {
+       .bus_shift      = 20,
+       .pci_ops        = {
+               .map_bus        = pci_ecam_map_bus,
+               .read           = pci_generic_config_read32,
+               .write          = pci_generic_config_write,
+       }
+};
 #endif
index 9f85815b4f53403dd7f5dd3a0d23384232c25e0c..529c348084401462090b7667394d0ce0cd4bce96 100644 (file)
@@ -73,10 +73,8 @@ static int board_added(struct controller *ctrl)
 
        /* Check link training status */
        retval = pciehp_check_link_status(ctrl);
-       if (retval) {
-               ctrl_err(ctrl, "Failed to check link status\n");
+       if (retval)
                goto err_exit;
-       }
 
        /* Check for a power fault */
        if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) {
index 53433b37e18122f52f0da595b595ff5cf7f9de9d..fb3840e222addf7527469b59513b33bf74861aad 100644 (file)
@@ -283,8 +283,6 @@ static void pcie_wait_for_presence(struct pci_dev *pdev)
                msleep(10);
                timeout -= 10;
        } while (timeout > 0);
-
-       pci_info(pdev, "Timeout waiting for Presence Detect\n");
 }
 
 int pciehp_check_link_status(struct controller *ctrl)
@@ -293,8 +291,10 @@ int pciehp_check_link_status(struct controller *ctrl)
        bool found;
        u16 lnk_status;
 
-       if (!pcie_wait_for_link(pdev, true))
+       if (!pcie_wait_for_link(pdev, true)) {
+               ctrl_info(ctrl, "Slot(%s): No link\n", slot_name(ctrl));
                return -1;
+       }
 
        if (ctrl->inband_presence_disabled)
                pcie_wait_for_presence(pdev);
@@ -311,15 +311,18 @@ int pciehp_check_link_status(struct controller *ctrl)
        ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
        if ((lnk_status & PCI_EXP_LNKSTA_LT) ||
            !(lnk_status & PCI_EXP_LNKSTA_NLW)) {
-               ctrl_err(ctrl, "link training error: status %#06x\n",
-                        lnk_status);
+               ctrl_info(ctrl, "Slot(%s): Cannot train link: status %#06x\n",
+                         slot_name(ctrl), lnk_status);
                return -1;
        }
 
        pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
 
-       if (!found)
+       if (!found) {
+               ctrl_info(ctrl, "Slot(%s): No device found\n",
+                         slot_name(ctrl));
                return -1;
+       }
 
        return 0;
 }
index f979b7098acf3448a638caea7a53ad86d3025612..0a3c80ba66be4c4e48098fa7efa0f0972c504b88 100644 (file)
@@ -40,13 +40,13 @@ static DEFINE_MUTEX(rpadlpar_mutex);
 static struct device_node *find_vio_slot_node(char *drc_name)
 {
        struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
-       struct device_node *dn = NULL;
+       struct device_node *dn;
        int rc;
 
        if (!parent)
                return NULL;
 
-       while ((dn = of_get_next_child(parent, dn))) {
+       for_each_child_of_node(parent, dn) {
                rc = rpaphp_check_drc_props(dn, drc_name, NULL);
                if (rc == 0)
                        break;
@@ -60,10 +60,10 @@ static struct device_node *find_vio_slot_node(char *drc_name)
 static struct device_node *find_php_slot_pci_node(char *drc_name,
                                                  char *drc_type)
 {
-       struct device_node *np = NULL;
+       struct device_node *np;
        int rc;
 
-       while ((np = of_find_node_by_name(np, "pci"))) {
+       for_each_node_by_name(np, "pci") {
                rc = rpaphp_check_drc_props(np, drc_name, drc_type);
                if (rc == 0)
                        break;
index 65502e3f7b4fb68aa43491d4fa94b2bffba61dd7..6a6705e0cf17851cffb68bca54d2dd17b4be3368 100644 (file)
@@ -299,7 +299,6 @@ static int board_added(struct slot *p_slot)
        if (p_slot->status == 0xFF) {
                /* power fault occurred, but it was benign */
                ctrl_dbg(ctrl, "%s: Power fault\n", __func__);
-               rc = POWER_FAILURE;
                p_slot->status = 0;
                goto err_exit;
        }
index 9d53c16b73295e7dd140b71e505dd00479cd8921..de1c331dbed43fdbfb743380a9af9439a2b2638a 100644 (file)
@@ -53,7 +53,7 @@ static ssize_t size_show(struct device *dev, struct device_attribute *attr,
        if (pdev->p2pdma->pool)
                size = gen_pool_size(pdev->p2pdma->pool);
 
-       return snprintf(buf, PAGE_SIZE, "%zd\n", size);
+       return scnprintf(buf, PAGE_SIZE, "%zd\n", size);
 }
 static DEVICE_ATTR_RO(size);
 
@@ -66,7 +66,7 @@ static ssize_t available_show(struct device *dev, struct device_attribute *attr,
        if (pdev->p2pdma->pool)
                avail = gen_pool_avail(pdev->p2pdma->pool);
 
-       return snprintf(buf, PAGE_SIZE, "%zd\n", avail);
+       return scnprintf(buf, PAGE_SIZE, "%zd\n", avail);
 }
 static DEVICE_ATTR_RO(available);
 
@@ -75,8 +75,8 @@ static ssize_t published_show(struct device *dev, struct device_attribute *attr,
 {
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-                       pdev->p2pdma->p2pmem_published);
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        pdev->p2pdma->p2pmem_published);
 }
 static DEVICE_ATTR_RO(published);
 
@@ -762,7 +762,7 @@ struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
        struct scatterlist *sg;
        void *addr;
 
-       sg = kzalloc(sizeof(*sg), GFP_KERNEL);
+       sg = kmalloc(sizeof(*sg), GFP_KERNEL);
        if (!sg)
                return NULL;
 
index d9aa551f8423634ffb803c4b730e87325daf6563..bf03648c2072319d2c2e401d794de263bd38cd75 100644 (file)
@@ -1177,7 +1177,7 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
  * @pdev: the PCI device whose delay is to be updated
  * @handle: ACPI handle of this device
  *
- * Update the d3_delay and d3cold_delay of a PCI device from the ACPI _DSM
+ * Update the d3hot_delay and d3cold_delay of a PCI device from the ACPI _DSM
  * control method of either the device itself or the PCI host bridge.
  *
  * Function 8, "Reset Delay," applies to the entire hierarchy below a PCI
@@ -1216,8 +1216,8 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
                }
                if (elements[3].type == ACPI_TYPE_INTEGER) {
                        value = (int)elements[3].integer.value / 1000;
-                       if (value < PCI_PM_D3_WAIT)
-                               pdev->d3_delay = value;
+                       if (value < PCI_PM_D3HOT_WAIT)
+                               pdev->d3hot_delay = value;
                }
        }
        ACPI_FREE(obj);
index ccf26d12ec61803d960fd6f149ee4df1e06a16f6..139869d50eb2657a37a26e7f78e25c7c82c113a5 100644 (file)
@@ -294,6 +294,7 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(pci_bridge_emul_init);
 
 /*
  * Cleanup a pci_bridge_emul structure that was previously initialized
@@ -305,6 +306,7 @@ void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge)
                kfree(bridge->pcie_cap_regs_behavior);
        kfree(bridge->pci_regs_behavior);
 }
+EXPORT_SYMBOL_GPL(pci_bridge_emul_cleanup);
 
 /*
  * Should be called by the PCI controller driver when reading the PCI
@@ -366,6 +368,7 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
 
        return PCIBIOS_SUCCESSFUL;
 }
+EXPORT_SYMBOL_GPL(pci_bridge_emul_conf_read);
 
 /*
  * Should be called by the PCI controller driver when writing the PCI
@@ -430,3 +433,4 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
 
        return PCIBIOS_SUCCESSFUL;
 }
+EXPORT_SYMBOL_GPL(pci_bridge_emul_conf_write);
index d1b7169c0684036af73e46af2989caed9700dab6..8b587fc97f7bc90787a1e90ff821b001da9cdb48 100644 (file)
@@ -970,12 +970,6 @@ static int pci_pm_resume(struct device *dev)
 
 #ifdef CONFIG_HIBERNATE_CALLBACKS
 
-/*
- * pcibios_pm_ops - provide arch-specific hooks when a PCI device is doing
- * a hibernate transition
- */
-struct dev_pm_ops __weak pcibios_pm_ops;
-
 static int pci_pm_freeze(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -1034,9 +1028,6 @@ static int pci_pm_freeze_noirq(struct device *dev)
 
        pci_pm_set_unknown_state(pci_dev);
 
-       if (pcibios_pm_ops.freeze_noirq)
-               return pcibios_pm_ops.freeze_noirq(dev);
-
        return 0;
 }
 
@@ -1044,13 +1035,6 @@ static int pci_pm_thaw_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int error;
-
-       if (pcibios_pm_ops.thaw_noirq) {
-               error = pcibios_pm_ops.thaw_noirq(dev);
-               if (error)
-                       return error;
-       }
 
        /*
         * The pm->thaw_noirq() callback assumes the device has been
@@ -1175,9 +1159,6 @@ static int pci_pm_poweroff_noirq(struct device *dev)
 
        pci_fixup_device(pci_fixup_suspend_late, pci_dev);
 
-       if (pcibios_pm_ops.poweroff_noirq)
-               return pcibios_pm_ops.poweroff_noirq(dev);
-
        return 0;
 }
 
@@ -1185,13 +1166,6 @@ static int pci_pm_restore_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int error;
-
-       if (pcibios_pm_ops.restore_noirq) {
-               error = pcibios_pm_ops.restore_noirq(dev);
-               if (error)
-                       return error;
-       }
 
        pci_pm_default_resume_early(pci_dev);
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
index a0b2bd6c918a07165c7f0298dd5281c40b94e0c9..45855a5e9fcae7961ea3f2c8d96baeeb0dba7e7d 100644 (file)
@@ -37,18 +37,6 @@ static struct pci_driver pf_stub_driver = {
        .probe                  = pci_pf_stub_probe,
        .sriov_configure        = pci_sriov_configure_simple,
 };
-
-static int __init pci_pf_stub_init(void)
-{
-       return pci_register_driver(&pf_stub_driver);
-}
-
-static void __exit pci_pf_stub_exit(void)
-{
-       pci_unregister_driver(&pf_stub_driver);
-}
-
-module_init(pci_pf_stub_init);
-module_exit(pci_pf_stub_exit);
+module_pci_driver(pf_stub_driver);
 
 MODULE_LICENSE("GPL");
index 6d78df981d41a1bf888b537feefbe44fc100cf8a..d15c881e2e7e70bbc39bb8ec73bba3ba9063a1b7 100644 (file)
@@ -574,7 +574,7 @@ static ssize_t driver_override_show(struct device *dev,
        ssize_t len;
 
        device_lock(dev);
-       len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
+       len = scnprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
        device_unlock(dev);
        return len;
 }
@@ -708,6 +708,7 @@ static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
                data[off - init_off + 3] = (val >> 24) & 0xff;
                off += 4;
                size -= 4;
+               cond_resched();
        }
 
        if (size >= 2) {
@@ -1196,10 +1197,10 @@ static int pci_create_resource_files(struct pci_dev *pdev)
        }
        return 0;
 }
-#else /* !HAVE_PCI_MMAP */
+#else /* !(defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)) */
 int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
 void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
-#endif /* HAVE_PCI_MMAP */
+#endif
 
 /**
  * pci_write_rom - used to enable access to the PCI ROM display
index e39c5499770ff4377766a72ccbb165e2bdbb917e..6d4d5a2f923d9ef291eb7f09d5af3b452fe487df 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 #include <linux/msi.h>
 #include <linux/of.h>
-#include <linux/of_pci.h>
 #include <linux/pci.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
@@ -30,8 +29,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/pci_hotplug.h>
 #include <linux/vmalloc.h>
-#include <linux/pci-ats.h>
-#include <asm/setup.h>
 #include <asm/dma.h>
 #include <linux/aer.h>
 #include "pci.h"
@@ -49,7 +46,7 @@ EXPORT_SYMBOL(isa_dma_bridge_buggy);
 int pci_pci_problems;
 EXPORT_SYMBOL(pci_pci_problems);
 
-unsigned int pci_pm_d3_delay;
+unsigned int pci_pm_d3hot_delay;
 
 static void pci_pme_list_scan(struct work_struct *work);
 
@@ -66,10 +63,10 @@ struct pci_pme_device {
 
 static void pci_dev_d3_sleep(struct pci_dev *dev)
 {
-       unsigned int delay = dev->d3_delay;
+       unsigned int delay = dev->d3hot_delay;
 
-       if (delay < pci_pm_d3_delay)
-               delay = pci_pm_d3_delay;
+       if (delay < pci_pm_d3hot_delay)
+               delay = pci_pm_d3hot_delay;
 
        if (delay)
                msleep(delay);
@@ -101,7 +98,19 @@ unsigned long pci_hotplug_mmio_pref_size = DEFAULT_HOTPLUG_MMIO_PREF_SIZE;
 #define DEFAULT_HOTPLUG_BUS_SIZE       1
 unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
 
+
+/* PCIe MPS/MRRS strategy; can be overridden by kernel command-line param */
+#ifdef CONFIG_PCIE_BUS_TUNE_OFF
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF;
+#elif defined CONFIG_PCIE_BUS_SAFE
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE;
+#elif defined CONFIG_PCIE_BUS_PERFORMANCE
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
+#elif defined CONFIG_PCIE_BUS_PEER2PEER
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PEER2PEER;
+#else
 enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT;
+#endif
 
 /*
  * The default CLS is used if arch didn't set CLS explicitly and not
@@ -876,6 +885,10 @@ static void pci_std_enable_acs(struct pci_dev *dev)
        /* Upstream Forwarding */
        ctrl |= (cap & PCI_ACS_UF);
 
+       /* Enable Translation Blocking for external devices */
+       if (dev->external_facing || dev->untrusted)
+               ctrl |= (cap & PCI_ACS_TB);
+
        pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
 }
 
@@ -1065,7 +1078,7 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
        if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
                pci_dev_d3_sleep(dev);
        else if (state == PCI_D2 || dev->current_state == PCI_D2)
-               msleep(PCI_PM_D2_DELAY);
+               udelay(PCI_PM_D2_DELAY);
 
        pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
        dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
@@ -3013,7 +3026,7 @@ void pci_pm_init(struct pci_dev *dev)
        }
 
        dev->pm_cap = pm;
-       dev->d3_delay = PCI_PM_D3_WAIT;
+       dev->d3hot_delay = PCI_PM_D3HOT_WAIT;
        dev->d3cold_delay = PCI_PM_D3COLD_WAIT;
        dev->bridge_d3 = pci_bridge_d3_possible(dev);
        dev->d3cold_allowed = true;
@@ -3038,7 +3051,7 @@ void pci_pm_init(struct pci_dev *dev)
                         (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
                         (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
                         (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
-                        (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
+                        (pmc & PCI_PM_CAP_PME_D3hot) ? " D3hot" : "",
                         (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
                dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT;
                dev->pme_poll = true;
@@ -4621,7 +4634,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
  *
  * NOTE: This causes the caller to sleep for twice the device power transition
  * cooldown period, which for the D0->D3hot and D3hot->D0 transitions is 10 ms
- * by default (i.e. unless the @dev's d3_delay field has a different value).
+ * by default (i.e. unless the @dev's d3hot_delay field has a different value).
  * Moreover, only devices in D0 can be reset by this function.
  */
 static int pci_pm_reset(struct pci_dev *dev, int probe)
@@ -4701,9 +4714,7 @@ static bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active,
        }
        if (active && ret)
                msleep(delay);
-       else if (ret != active)
-               pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
-                       active ? "set" : "cleared");
+
        return ret == active;
 }
 
@@ -4828,6 +4839,7 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
                        delay);
                if (!pcie_wait_for_link_delay(dev, true, delay)) {
                        /* Did not train, no need to wait any further */
+                       pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n");
                        return;
                }
        }
@@ -4920,16 +4932,10 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
 
 static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
 {
-       struct pci_dev *pdev;
-
-       if (dev->subordinate || !dev->slot ||
+       if (dev->multifunction || dev->subordinate || !dev->slot ||
            dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
                return -ENOTTY;
 
-       list_for_each_entry(pdev, &dev->bus->devices, bus_list)
-               if (pdev != dev && pdev->slot == dev->slot)
-                       return -ENOTTY;
-
        return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
 }
 
@@ -6005,7 +6011,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
 
        if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
                pci_read_config_word(dev, PCI_COMMAND, &cmd);
-               if (decode == true)
+               if (decode)
                        cmd |= command_bits;
                else
                        cmd &= ~command_bits;
@@ -6021,7 +6027,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
                if (bridge) {
                        pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
                                             &cmd);
-                       if (decode == true)
+                       if (decode)
                                cmd |= PCI_BRIDGE_CTL_VGA;
                        else
                                cmd &= ~PCI_BRIDGE_CTL_VGA;
@@ -6350,7 +6356,7 @@ static ssize_t resource_alignment_show(struct bus_type *bus, char *buf)
 
        spin_lock(&resource_alignment_lock);
        if (resource_alignment_param)
-               count = snprintf(buf, PAGE_SIZE, "%s", resource_alignment_param);
+               count = scnprintf(buf, PAGE_SIZE, "%s", resource_alignment_param);
        spin_unlock(&resource_alignment_lock);
 
        /*
index fa12f7cbc1a095ea3e7e2cdca90ad511be4c3c00..f86cae9aa1f4102c8ab684a7c930b82b5c8bdf2a 100644 (file)
@@ -43,10 +43,9 @@ int pci_probe_reset_function(struct pci_dev *dev);
 int pci_bridge_secondary_bus_reset(struct pci_dev *dev);
 int pci_bus_error_reset(struct pci_dev *dev);
 
-#define PCI_PM_D2_DELAY         200
-#define PCI_PM_D3_WAIT          10
-#define PCI_PM_D3COLD_WAIT      100
-#define PCI_PM_BUS_WAIT         50
+#define PCI_PM_D2_DELAY         200    /* usec; see PCIe r4.0, sec 5.9.1 */
+#define PCI_PM_D3HOT_WAIT       10     /* msec */
+#define PCI_PM_D3COLD_WAIT      100    /* msec */
 
 /**
  * struct pci_platform_pm_ops - Firmware PM callbacks
@@ -178,7 +177,7 @@ extern struct mutex pci_slot_mutex;
 
 extern raw_spinlock_t pci_lock;
 
-extern unsigned int pci_pm_d3_delay;
+extern unsigned int pci_pm_d3hot_delay;
 
 #ifdef CONFIG_PCI_MSI
 void pci_no_msi(void);
index 253c30cc19678a99f0280da6db28a08fb0bec0ee..ac0557a305aff383f7a0d9e7ea4112904081f351 100644 (file)
@@ -74,14 +74,6 @@ struct pcie_link_state {
         * has one slot under it, so at most there are 8 functions.
         */
        struct aspm_latency acceptable[8];
-
-       /* L1 PM Substate info */
-       struct {
-               u32 up_cap_ptr;         /* L1SS cap ptr in upstream dev */
-               u32 dw_cap_ptr;         /* L1SS cap ptr in downstream dev */
-               u32 ctl1;               /* value to be programmed in ctl1 */
-               u32 ctl2;               /* value to be programmed in ctl2 */
-       } l1ss;
 };
 
 static int aspm_disabled, aspm_force;
@@ -308,8 +300,10 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
 }
 
 /* Convert L0s latency encoding to ns */
-static u32 calc_l0s_latency(u32 encoding)
+static u32 calc_l0s_latency(u32 lnkcap)
 {
+       u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12;
+
        if (encoding == 0x7)
                return (5 * 1000);      /* > 4us */
        return (64 << encoding);
@@ -324,8 +318,10 @@ static u32 calc_l0s_acceptable(u32 encoding)
 }
 
 /* Convert L1 latency encoding to ns */
-static u32 calc_l1_latency(u32 encoding)
+static u32 calc_l1_latency(u32 lnkcap)
 {
+       u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15;
+
        if (encoding == 0x7)
                return (65 * 1000);     /* > 64us */
        return (1000 << encoding);
@@ -380,58 +376,6 @@ static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
        }
 }
 
-struct aspm_register_info {
-       u32 support:2;
-       u32 enabled:2;
-       u32 latency_encoding_l0s;
-       u32 latency_encoding_l1;
-
-       /* L1 substates */
-       u32 l1ss_cap_ptr;
-       u32 l1ss_cap;
-       u32 l1ss_ctl1;
-       u32 l1ss_ctl2;
-};
-
-static void pcie_get_aspm_reg(struct pci_dev *pdev,
-                             struct aspm_register_info *info)
-{
-       u16 reg16;
-       u32 reg32;
-
-       pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &reg32);
-       info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
-       info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
-       info->latency_encoding_l1  = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
-       pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16);
-       info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
-
-       /* Read L1 PM substate capabilities */
-       info->l1ss_cap = info->l1ss_ctl1 = info->l1ss_ctl2 = 0;
-       info->l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
-       if (!info->l1ss_cap_ptr)
-               return;
-       pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CAP,
-                             &info->l1ss_cap);
-       if (!(info->l1ss_cap & PCI_L1SS_CAP_L1_PM_SS)) {
-               info->l1ss_cap = 0;
-               return;
-       }
-
-       /*
-        * If we don't have LTR for the entire path from the Root Complex
-        * to this device, we can't use ASPM L1.2 because it relies on the
-        * LTR_L1.2_THRESHOLD.  See PCIe r4.0, secs 5.5.4, 6.18.
-        */
-       if (!pdev->ltr_path)
-               info->l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
-
-       pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL1,
-                             &info->l1ss_ctl1);
-       pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL2,
-                             &info->l1ss_ctl2);
-}
-
 static void pcie_aspm_check_latency(struct pci_dev *endpoint)
 {
        u32 latency, l1_switch_latency = 0;
@@ -493,39 +437,49 @@ static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
        return NULL;
 }
 
+static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
+                                   u32 clear, u32 set)
+{
+       u32 val;
+
+       pci_read_config_dword(pdev, pos, &val);
+       val &= ~clear;
+       val |= set;
+       pci_write_config_dword(pdev, pos, val);
+}
+
 /* Calculate L1.2 PM substate timing parameters */
 static void aspm_calc_l1ss_info(struct pcie_link_state *link,
-                               struct aspm_register_info *upreg,
-                               struct aspm_register_info *dwreg)
+                               u32 parent_l1ss_cap, u32 child_l1ss_cap)
 {
+       struct pci_dev *child = link->downstream, *parent = link->pdev;
        u32 val1, val2, scale1, scale2;
        u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
-
-       link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr;
-       link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr;
-       link->l1ss.ctl1 = link->l1ss.ctl2 = 0;
+       u32 ctl1 = 0, ctl2 = 0;
+       u32 pctl1, pctl2, cctl1, cctl2;
+       u32 pl1_2_enables, cl1_2_enables;
 
        if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
                return;
 
        /* 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;
+       val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
+       val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
        t_common_mode = max(val1, val2);
 
        /* 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)) {
-               link->l1ss.ctl2 |= scale1 | (val1 << 3);
-               t_power_on = calc_l1ss_pwron(link->pdev, scale1, val1);
+       val1   = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
+       scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
+       val2   = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
+       scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
+
+       if (calc_l1ss_pwron(parent, scale1, val1) >
+           calc_l1ss_pwron(child, scale2, val2)) {
+               ctl2 |= scale1 | (val1 << 3);
+               t_power_on = calc_l1ss_pwron(parent, scale1, val1);
        } else {
-               link->l1ss.ctl2 |= scale2 | (val2 << 3);
-               t_power_on = calc_l1ss_pwron(link->downstream, scale2, val2);
+               ctl2 |= scale2 | (val2 << 3);
+               t_power_on = calc_l1ss_pwron(child, scale2, val2);
        }
 
        /*
@@ -540,14 +494,60 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
         */
        l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
        encode_l12_threshold(l1_2_threshold, &scale, &value);
-       link->l1ss.ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
+       ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
+
+       pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
+       pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);
+       pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);
+       pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL2, &cctl2);
+
+       if (ctl1 == pctl1 && ctl1 == cctl1 &&
+           ctl2 == pctl2 && ctl2 == cctl2)
+               return;
+
+       /* Disable L1.2 while updating.  See PCIe r5.0, sec 5.5.4, 7.8.3.3 */
+       pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK;
+       cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK;
+
+       if (pl1_2_enables || cl1_2_enables) {
+               pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
+                                       PCI_L1SS_CTL1_L1_2_MASK, 0);
+               pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                                       PCI_L1SS_CTL1_L1_2_MASK, 0);
+       }
+
+       /* Program T_POWER_ON times in both ports */
+       pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2);
+       pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2);
+
+       /* Program Common_Mode_Restore_Time in upstream device */
+       pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                               PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1);
+
+       /* Program LTR_L1.2_THRESHOLD time in both ports */
+       pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                               PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
+                               PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
+       pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
+                               PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
+                               PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
+
+       if (pl1_2_enables || cl1_2_enables) {
+               pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0,
+                                       pl1_2_enables);
+               pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0,
+                                       cl1_2_enables);
+       }
 }
 
 static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
 {
        struct pci_dev *child = link->downstream, *parent = link->pdev;
+       u32 parent_lnkcap, child_lnkcap;
+       u16 parent_lnkctl, child_lnkctl;
+       u32 parent_l1ss_cap, child_l1ss_cap;
+       u32 parent_l1ss_ctl1 = 0, child_l1ss_ctl1 = 0;
        struct pci_bus *linkbus = parent->subordinate;
-       struct aspm_register_info upreg, dwreg;
 
        if (blacklist) {
                /* Set enabled/disable so that we will disable ASPM later */
@@ -556,26 +556,28 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
                return;
        }
 
-       /* Get upstream/downstream components' register state */
-       pcie_get_aspm_reg(parent, &upreg);
-       pcie_get_aspm_reg(child, &dwreg);
-
        /*
         * If ASPM not supported, don't mess with the clocks and link,
         * bail out now.
         */
-       if (!(upreg.support & dwreg.support))
+       pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
+       pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
+       if (!(parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPMS))
                return;
 
        /* Configure common clock before checking latencies */
        pcie_aspm_configure_common_clock(link);
 
        /*
-        * Re-read upstream/downstream components' register state
-        * after clock configuration
+        * Re-read upstream/downstream components' register state after
+        * clock configuration.  L0s & L1 exit latencies in the otherwise
+        * read-only Link Capabilities may change depending on common clock
+        * configuration (PCIe r5.0, sec 7.5.3.6).
         */
-       pcie_get_aspm_reg(parent, &upreg);
-       pcie_get_aspm_reg(child, &dwreg);
+       pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
+       pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
+       pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
+       pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
 
        /*
         * Setup L0s state
@@ -584,44 +586,71 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
         * given link unless components on both sides of the link each
         * support L0s.
         */
-       if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S)
+       if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S)
                link->aspm_support |= ASPM_STATE_L0S;
-       if (dwreg.enabled & PCIE_LINK_STATE_L0S)
+
+       if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
                link->aspm_enabled |= ASPM_STATE_L0S_UP;
-       if (upreg.enabled & PCIE_LINK_STATE_L0S)
+       if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
                link->aspm_enabled |= ASPM_STATE_L0S_DW;
-       link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s);
-       link->latency_dw.l0s = calc_l0s_latency(dwreg.latency_encoding_l0s);
+       link->latency_up.l0s = calc_l0s_latency(parent_lnkcap);
+       link->latency_dw.l0s = calc_l0s_latency(child_lnkcap);
 
        /* Setup L1 state */
-       if (upreg.support & dwreg.support & PCIE_LINK_STATE_L1)
+       if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1)
                link->aspm_support |= ASPM_STATE_L1;
-       if (upreg.enabled & dwreg.enabled & PCIE_LINK_STATE_L1)
+
+       if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1)
                link->aspm_enabled |= ASPM_STATE_L1;
-       link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
-       link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
+       link->latency_up.l1 = calc_l1_latency(parent_lnkcap);
+       link->latency_dw.l1 = calc_l1_latency(child_lnkcap);
 
        /* Setup L1 substate */
-       if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
+       pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
+                             &parent_l1ss_cap);
+       pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
+                             &child_l1ss_cap);
+
+       if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
+               parent_l1ss_cap = 0;
+       if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
+               child_l1ss_cap = 0;
+
+       /*
+        * If we don't have LTR for the entire path from the Root Complex
+        * to this device, we can't use ASPM L1.2 because it relies on the
+        * LTR_L1.2_THRESHOLD.  See PCIe r4.0, secs 5.5.4, 6.18.
+        */
+       if (!child->ltr_path)
+               child_l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
+
+       if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
                link->aspm_support |= ASPM_STATE_L1_1;
-       if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
+       if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
                link->aspm_support |= ASPM_STATE_L1_2;
-       if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
+       if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
                link->aspm_support |= ASPM_STATE_L1_1_PCIPM;
-       if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
+       if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
                link->aspm_support |= ASPM_STATE_L1_2_PCIPM;
 
-       if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
+       if (parent_l1ss_cap)
+               pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                                     &parent_l1ss_ctl1);
+       if (child_l1ss_cap)
+               pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
+                                     &child_l1ss_ctl1);
+
+       if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
                link->aspm_enabled |= ASPM_STATE_L1_1;
-       if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
+       if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
                link->aspm_enabled |= ASPM_STATE_L1_2;
-       if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
+       if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
                link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM;
-       if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
+       if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
                link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM;
 
        if (link->aspm_support & ASPM_STATE_L1SS)
-               aspm_calc_l1ss_info(link, &upreg, &dwreg);
+               aspm_calc_l1ss_info(link, parent_l1ss_cap, child_l1ss_cap);
 
        /* Save default state */
        link->aspm_default = link->aspm_enabled;
@@ -651,24 +680,11 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
        }
 }
 
-static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
-                                   u32 clear, u32 set)
-{
-       u32 val;
-
-       pci_read_config_dword(pdev, pos, &val);
-       val &= ~clear;
-       val |= set;
-       pci_write_config_dword(pdev, pos, val);
-}
-
 /* Configure the ASPM L1 substates */
 static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
 {
        u32 val, enable_req;
        struct pci_dev *child = link->downstream, *parent = link->pdev;
-       u32 up_cap_ptr = link->l1ss.up_cap_ptr;
-       u32 dw_cap_ptr = link->l1ss.dw_cap_ptr;
 
        enable_req = (link->aspm_enabled ^ state) & state;
 
@@ -686,9 +702,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
         */
 
        /* Disable all L1 substates */
-       pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
+       pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
                                PCI_L1SS_CTL1_L1SS_MASK, 0);
-       pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+       pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
                                PCI_L1SS_CTL1_L1SS_MASK, 0);
        /*
         * If needed, disable L1, and it gets enabled later
@@ -701,30 +717,6 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
                                                   PCI_EXP_LNKCTL_ASPM_L1, 0);
        }
 
-       if (enable_req & ASPM_STATE_L1_2_MASK) {
-
-               /* 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 Common_Mode_Restore_Time in upstream device */
-               pci_clear_and_set_dword(parent, up_cap_ptr + PCI_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,
-                                       PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
-                                       PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
-                                       link->l1ss.ctl1);
-       }
-
        val = 0;
        if (state & ASPM_STATE_L1_1)
                val |= PCI_L1SS_CTL1_ASPM_L1_1;
@@ -736,9 +728,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
                val |= PCI_L1SS_CTL1_PCIPM_L1_2;
 
        /* Enable what we need to enable */
-       pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+       pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
                                PCI_L1SS_CTL1_L1SS_MASK, val);
-       pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
+       pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
                                PCI_L1SS_CTL1_L1SS_MASK, val);
 }
 
index 77e685771487411e28af60c2b41e3bc5d4a56e22..565d23cccb8b589863a92abbe33c07fab3d2c6d0 100644 (file)
@@ -14,6 +14,8 @@
  * and warns when links become degraded in operation.
  */
 
+#define dev_fmt(fmt) "bw_notification: " fmt
+
 #include "../pci.h"
 #include "portdrv.h"
 
@@ -97,6 +99,7 @@ static int pcie_bandwidth_notification_probe(struct pcie_device *srv)
                return ret;
 
        pcie_enable_link_bandwidth_notification(srv->port);
+       pci_info(srv->port, "enabled with IRQ %d\n", srv->irq);
 
        return 0;
 }
index daa9a4153776cefeb6e842a454a0c455454bb6e5..e05aba86a317920d1520b2a1773454360266a0e2 100644 (file)
@@ -103,7 +103,8 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
         * Wait until the Link is inactive, then clear DPC Trigger Status
         * to allow the Port to leave DPC.
         */
-       pcie_wait_for_link(pdev, false);
+       if (!pcie_wait_for_link(pdev, false))
+               pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
 
        if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
                return PCI_ERS_RESULT_DISCONNECT;
@@ -111,8 +112,10 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
        pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
                              PCI_EXP_DPC_STATUS_TRIGGER);
 
-       if (!pcie_wait_for_link(pdev, true))
+       if (!pcie_wait_for_link(pdev, true)) {
+               pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n");
                return PCI_ERS_RESULT_DISCONNECT;
+       }
 
        return PCI_ERS_RESULT_RECOVERED;
 }
index 03d37128a24f205602b7f6e9299dde8bb5fea81e..4289030b0fff7543706d0cec7b549f481577ebbe 100644 (file)
@@ -941,6 +941,12 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
 
        pcibios_add_bus(bus);
 
+       if (bus->ops->add_bus) {
+               err = bus->ops->add_bus(bus);
+               if (WARN_ON(err < 0))
+                       dev_err(&bus->dev, "failed to add bus: %d\n", err);
+       }
+
        /* Create legacy_io and legacy_mem files for this bus */
        pci_create_legacy_files(bus);
 
@@ -1036,6 +1042,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
                                           struct pci_dev *bridge, int busnr)
 {
        struct pci_bus *child;
+       struct pci_host_bridge *host;
        int i;
        int ret;
 
@@ -1045,11 +1052,16 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
                return NULL;
 
        child->parent = parent;
-       child->ops = parent->ops;
        child->msi = parent->msi;
        child->sysdata = parent->sysdata;
        child->bus_flags = parent->bus_flags;
 
+       host = pci_find_host_bridge(parent);
+       if (host->child_ops)
+               child->ops = host->child_ops;
+       else
+               child->ops = parent->ops;
+
        /*
         * Initialize some portions of the bus device, but don't register
         * it now as the parent is not properly set up yet.
@@ -2106,6 +2118,9 @@ static void pci_configure_ltr(struct pci_dev *dev)
        if (!pci_is_pcie(dev))
                return;
 
+       /* Read L1 PM substate capabilities */
+       dev->l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
+
        pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
        if (!(cap & PCI_EXP_DEVCAP2_LTR))
                return;
index 01f23e30bd8f4a0c57e9454fbc71c2fc5710d7aa..f70692ac79c565f517209db63b6e614bd4ff3928 100644 (file)
@@ -1846,7 +1846,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,      PCI_DEVICE_ID_INTEL_PXHV,       quirk_pci
  */
 static void quirk_intel_pcie_pm(struct pci_dev *dev)
 {
-       pci_pm_d3_delay = 120;
+       pci_pm_d3hot_delay = 120;
        dev->no_d1d2 = 1;
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   0x25e2, quirk_intel_pcie_pm);
@@ -1873,12 +1873,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    0x260b, quirk_intel_pcie_pm);
 
 static void quirk_d3hot_delay(struct pci_dev *dev, unsigned int delay)
 {
-       if (dev->d3_delay >= delay)
+       if (dev->d3hot_delay >= delay)
                return;
 
-       dev->d3_delay = delay;
+       dev->d3hot_delay = delay;
        pci_info(dev, "extending delay after power-on from D3hot to %d msec\n",
-                dev->d3_delay);
+                dev->d3hot_delay);
 }
 
 static void quirk_radeon_pm(struct pci_dev *dev)
@@ -3387,36 +3387,36 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
  * PCI devices which are on Intel chips can skip the 10ms delay
  * before entering D3 mode.
  */
-static void quirk_remove_d3_delay(struct pci_dev *dev)
-{
-       dev->d3_delay = 0;
-}
-/* C600 Series devices do not need 10ms d3_delay */
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0412, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c00, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c0c, quirk_remove_d3_delay);
-/* Lynxpoint-H PCH devices do not need 10ms d3_delay */
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c02, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c18, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c1c, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c20, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c22, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c26, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c2d, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c31, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3a, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3d, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c4e, quirk_remove_d3_delay);
-/* Intel Cherrytrail devices do not need 10ms d3_delay */
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2280, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2298, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x229c, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b0, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b5, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b7, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b8, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22d8, quirk_remove_d3_delay);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22dc, quirk_remove_d3_delay);
+static void quirk_remove_d3hot_delay(struct pci_dev *dev)
+{
+       dev->d3hot_delay = 0;
+}
+/* C600 Series devices do not need 10ms d3hot_delay */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0412, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c00, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c0c, quirk_remove_d3hot_delay);
+/* Lynxpoint-H PCH devices do not need 10ms d3hot_delay */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c02, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c18, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c1c, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c20, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c22, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c26, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c2d, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c31, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3a, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3d, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c4e, quirk_remove_d3hot_delay);
+/* Intel Cherrytrail devices do not need 10ms d3hot_delay */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2280, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2298, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x229c, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b0, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b5, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b7, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b8, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22d8, quirk_remove_d3hot_delay);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22dc, quirk_remove_d3hot_delay);
 
 /*
  * Some devices may pass our check in pci_intx_mask_supported() if
@@ -4892,6 +4892,13 @@ static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
        }
 }
 
+/*
+ * Currently this quirk does the equivalent of
+ * PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF
+ *
+ * TODO: This quirk also needs to do equivalent of PCI_ACS_TB,
+ * if dev->external_facing || dev->untrusted
+ */
 static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
 {
        if (!pci_quirk_intel_pch_acs_match(dev))
@@ -4931,6 +4938,9 @@ static int pci_quirk_enable_intel_spt_pch_acs(struct pci_dev *dev)
        ctrl |= (cap & PCI_ACS_CR);
        ctrl |= (cap & PCI_ACS_UF);
 
+       if (dev->external_facing || dev->untrusted)
+               ctrl |= (cap & PCI_ACS_TB);
+
        pci_write_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, ctrl);
 
        pci_info(dev, "Intel SPT PCH root port ACS workaround enabled\n");
index 1a138be8bd6a088f89d31d7a4197b9c1acc09fc1..810f25a47632108ebeaf21cd45a5f47c5d4190d7 100644 (file)
@@ -26,7 +26,6 @@
 #define COMPHY_SIP_POWER_ON                    0x82000001
 #define COMPHY_SIP_POWER_OFF                   0x82000002
 #define COMPHY_SIP_PLL_LOCK                    0x82000003
-#define COMPHY_FW_NOT_SUPPORTED                        (-1)
 
 #define COMPHY_FW_MODE_SATA                    0x1
 #define COMPHY_FW_MODE_SGMII                   0x2
@@ -112,10 +111,19 @@ static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane,
                                  unsigned long mode)
 {
        struct arm_smccc_res res;
+       s32 ret;
 
        arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res);
+       ret = res.a0;
 
-       return res.a0;
+       switch (ret) {
+       case SMCCC_RET_SUCCESS:
+               return 0;
+       case SMCCC_RET_NOT_SUPPORTED:
+               return -EOPNOTSUPP;
+       default:
+               return -EINVAL;
+       }
 }
 
 static int mvebu_a3700_comphy_get_fw_mode(int lane, int port,
@@ -220,7 +228,7 @@ static int mvebu_a3700_comphy_power_on(struct phy *phy)
        }
 
        ret = mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param);
-       if (ret == COMPHY_FW_NOT_SUPPORTED)
+       if (ret == -EOPNOTSUPP)
                dev_err(lane->dev,
                        "unsupported SMC call, try updating your firmware\n");
 
index e41367f36ee1c96ecd8059d2d62e330f636a07a4..53ad127b100fe33ef05822ba6ecb8cede28337e6 100644 (file)
 
 #define COMPHY_SIP_POWER_ON    0x82000001
 #define COMPHY_SIP_POWER_OFF   0x82000002
-#define COMPHY_FW_NOT_SUPPORTED        (-1)
 
 /*
  * A lane is described by the following bitfields:
@@ -273,10 +272,19 @@ static int mvebu_comphy_smc(unsigned long function, unsigned long phys,
                            unsigned long lane, unsigned long mode)
 {
        struct arm_smccc_res res;
+       s32 ret;
 
        arm_smccc_smc(function, phys, lane, mode, 0, 0, 0, 0, &res);
+       ret = res.a0;
 
-       return res.a0;
+       switch (ret) {
+       case SMCCC_RET_SUCCESS:
+               return 0;
+       case SMCCC_RET_NOT_SUPPORTED:
+               return -EOPNOTSUPP;
+       default:
+               return -EINVAL;
+       }
 }
 
 static int mvebu_comphy_get_mode(bool fw_mode, int lane, int port,
@@ -819,7 +827,7 @@ static int mvebu_comphy_power_on(struct phy *phy)
        if (!ret)
                return ret;
 
-       if (ret == COMPHY_FW_NOT_SUPPORTED)
+       if (ret == -EOPNOTSUPP)
                dev_err(priv->dev,
                        "unsupported SMC call, try updating your firmware\n");
 
index 376205e97a8911f7858429f4f184808f335e5071..0295e2e32d7973d7750615e482df8fd183096d87 100644 (file)
@@ -1570,7 +1570,7 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
        spin_lock_init(&isp->lock);
 
        /* This is not a true PCI device on SoC, so the delay is not needed. */
-       pdev->d3_delay = 0;
+       pdev->d3hot_delay = 0;
 
        pci_set_drvdata(pdev, isp);
 
index 517a5231cc1ba97aeec54fc6cc5f7dcc0902f049..34fb3431a8f3646c8e45c34183bb43dbfc45540d 100644 (file)
@@ -53,6 +53,24 @@ enum {
        GHES_SEV_PANIC = 0x3,
 };
 
+#ifdef CONFIG_ACPI_APEI_GHES
+/**
+ * ghes_register_vendor_record_notifier - register a notifier for vendor
+ * records that the kernel would otherwise ignore.
+ * @nb: pointer to the notifier_block structure of the event handler.
+ *
+ * return 0 : SUCCESS, non-zero : FAIL
+ */
+int ghes_register_vendor_record_notifier(struct notifier_block *nb);
+
+/**
+ * ghes_unregister_vendor_record_notifier - unregister the previously
+ * registered vendor record notifier.
+ * @nb: pointer to the notifier_block structure of the vendor record handler.
+ */
+void ghes_unregister_vendor_record_notifier(struct notifier_block *nb);
+#endif
+
 int ghes_estatus_pool_init(int num_ghes);
 
 /* From drivers/edac/ghes_edac.c */
index dabf8cb7203b7bf601518a7fd3ae8c8b0f86af9c..9ea83d80eb6f93f62fa98ba9875d03ed58871a69 100644 (file)
@@ -911,18 +911,6 @@ static inline void iowrite64_rep(volatile void __iomem *addr,
 #include <linux/vmalloc.h>
 #define __io_virt(x) ((void __force *)(x))
 
-#ifndef CONFIG_GENERIC_IOMAP
-struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
-
-#ifndef pci_iounmap
-#define pci_iounmap pci_iounmap
-static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
-{
-}
-#endif
-#endif /* CONFIG_GENERIC_IOMAP */
-
 /*
  * Change virtual addresses to physical addresses and vv.
  * These are pretty trivial
@@ -1016,6 +1004,16 @@ static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
        port &= IO_SPACE_LIMIT;
        return (port > MMIO_UPPER_LIMIT) ? NULL : PCI_IOBASE + port;
 }
+#define __pci_ioport_unmap __pci_ioport_unmap
+static inline void __pci_ioport_unmap(void __iomem *p)
+{
+       uintptr_t start = (uintptr_t) PCI_IOBASE;
+       uintptr_t addr = (uintptr_t) p;
+
+       if (addr >= start && addr < start + IO_SPACE_LIMIT)
+               return;
+       iounmap(p);
+}
 #endif
 
 #ifndef ioport_unmap
@@ -1030,6 +1028,23 @@ extern void ioport_unmap(void __iomem *p);
 #endif /* CONFIG_GENERIC_IOMAP */
 #endif /* CONFIG_HAS_IOPORT_MAP */
 
+#ifndef CONFIG_GENERIC_IOMAP
+struct pci_dev;
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+
+#ifndef __pci_ioport_unmap
+static inline void __pci_ioport_unmap(void __iomem *p) {}
+#endif
+
+#ifndef pci_iounmap
+#define pci_iounmap pci_iounmap
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
+{
+       __pci_ioport_unmap(p);
+}
+#endif
+#endif /* CONFIG_GENERIC_IOMAP */
+
 /*
  * Convert a virtual cached pointer to an uncached pointer
  */
index 1af5cb02ef7f90f4769047d8b60ad33b66677f99..033ce74f02e812b9707138209dd7c112d6482b1f 100644 (file)
@@ -51,6 +51,7 @@ extern const struct pci_ecam_ops pci_generic_ecam_ops;
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
 extern const struct pci_ecam_ops pci_32b_ops;  /* 32-bit accesses only */
+extern const struct pci_ecam_ops pci_32b_read_ops; /* 32-bit read only */
 extern const struct pci_ecam_ops hisi_pcie_ops;        /* HiSilicon */
 extern const struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */
 extern const struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */
index f42b0fd4b4bc5793e10d0181ba64a5b21f317a46..662881335c7ec71b48cc2020e39b09e6f0abf565 100644 (file)
@@ -19,7 +19,7 @@ void pci_ep_cfs_remove_epf_group(struct config_group *group);
 #else
 static inline struct config_group *pci_ep_cfs_add_epc_group(const char *name)
 {
-       return 0;
+       return NULL;
 }
 
 static inline void pci_ep_cfs_remove_epc_group(struct config_group *group)
@@ -28,7 +28,7 @@ static inline void pci_ep_cfs_remove_epc_group(struct config_group *group)
 
 static inline struct config_group *pci_ep_cfs_add_epf_group(const char *name)
 {
-       return 0;
+       return NULL;
 }
 
 static inline void pci_ep_cfs_remove_epf_group(struct config_group *group)
index 835530605c0d7b4a4626f65c5b869bc49f48fd5c..32cd2b55073680f67d3023de43e37a683617632f 100644 (file)
@@ -373,13 +373,14 @@ struct pci_dev {
                                                      user sysfs */
        unsigned int    clear_retrain_link:1;   /* Need to clear Retrain Link
                                                   bit manually */
-       unsigned int    d3_delay;       /* D3->D0 transition time in ms */
+       unsigned int    d3hot_delay;    /* D3hot->D0 transition time in ms */
        unsigned int    d3cold_delay;   /* D3cold->D0 transition time in ms */
 
 #ifdef CONFIG_PCIEASPM
        struct pcie_link_state  *link_state;    /* ASPM link state */
        unsigned int    ltr_path:1;     /* Latency Tolerance Reporting
                                           supported from root to here */
+       int             l1ss;           /* L1SS Capability pointer */
 #endif
        unsigned int    eetlp_prefix_path:1;    /* End-to-End TLP Prefix */
 
@@ -523,6 +524,7 @@ struct pci_host_bridge {
        struct device   dev;
        struct pci_bus  *bus;           /* Root bus */
        struct pci_ops  *ops;
+       struct pci_ops  *child_ops;
        void            *sysdata;
        int             busnr;
        struct list_head windows;       /* resource_entry */
@@ -2034,10 +2036,6 @@ int pcibios_alloc_irq(struct pci_dev *dev);
 void pcibios_free_irq(struct pci_dev *dev);
 resource_size_t pcibios_default_alignment(void);
 
-#ifdef CONFIG_HIBERNATE_CALLBACKS
-extern struct dev_pm_ops pcibios_pm_ops;
-#endif
-
 #if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG)
 void __init pci_mmcfg_early_init(void);
 void __init pci_mmcfg_late_init(void);
index f9701410d3b52b7cfc549c50f08ab5478e04e385..a95d55f9f25761ab78c8ef529dc41f450f95339e 100644 (file)
@@ -76,6 +76,7 @@
 #define PCI_CACHE_LINE_SIZE    0x0c    /* 8 bits */
 #define PCI_LATENCY_TIMER      0x0d    /* 8 bits */
 #define PCI_HEADER_TYPE                0x0e    /* 8 bits */
+#define  PCI_HEADER_TYPE_MASK          0x7f
 #define  PCI_HEADER_TYPE_NORMAL                0
 #define  PCI_HEADER_TYPE_BRIDGE                1
 #define  PCI_HEADER_TYPE_CARDBUS       2
 #define  PCI_PM_CAP_PME_D0     0x0800  /* PME# from D0 */
 #define  PCI_PM_CAP_PME_D1     0x1000  /* PME# from D1 */
 #define  PCI_PM_CAP_PME_D2     0x2000  /* PME# from D2 */
-#define  PCI_PM_CAP_PME_D3     0x4000  /* PME# from D3 (hot) */
+#define  PCI_PM_CAP_PME_D3hot  0x4000  /* PME# from D3 (hot) */
 #define  PCI_PM_CAP_PME_D3cold 0x8000  /* PME# from D3 (cold) */
 #define  PCI_PM_CAP_PME_SHIFT  11      /* Start of the PME Mask in PMC */
 #define PCI_PM_CTRL            4       /* PM control and status register */
 #define  PCI_EXP_LNKCAP_SLS_32_0GB 0x00000005 /* LNKCAP2 SLS Vector bit 4 */
 #define  PCI_EXP_LNKCAP_MLW    0x000003f0 /* Maximum Link Width */
 #define  PCI_EXP_LNKCAP_ASPMS  0x00000c00 /* ASPM Support */
+#define  PCI_EXP_LNKCAP_ASPM_L0S 0x00000400 /* ASPM L0s Support */
+#define  PCI_EXP_LNKCAP_ASPM_L1  0x00000800 /* ASPM L1 Support */
 #define  PCI_EXP_LNKCAP_L0SEL  0x00007000 /* L0s Exit Latency */
 #define  PCI_EXP_LNKCAP_L1EL   0x00038000 /* L1 Exit Latency */
 #define  PCI_EXP_LNKCAP_CLKPM  0x00040000 /* Clock Power Management */
 #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_L1_2_MASK       0x00000005
 #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 */