Merge branch 'lorenzo/pci/tegra'
authorBjorn Helgaas <bhelgaas@google.com>
Mon, 23 Sep 2019 21:10:28 +0000 (16:10 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 23 Sep 2019 21:10:28 +0000 (16:10 -0500)
  - Fix Tegra OF node reference leak (Nishka Dasgupta)

  - Add #defines for PCIe Data Link Feature and Physical Layer 16.0 GT/s
    features (Vidya Sagar)

  - Disable MSI for Tegra Root Ports since they don't support using MSI for
    all Root Port events (Vidya Sagar)

  - Group DesignWare write-protected register writes together (Vidya Sagar)

  - Move DesignWare capability search interfaces so they can be used by
    both host and endpoint drivers (Vidya Sagar)

  - Add DesignWare extended capability search interfaces (Vidya Sagar)

  - Export dw_pcie_wait_for_link() so drivers can be modules (Vidya Sagar)

  - Add "snps,enable-cdm-check" DT binding for Configuration Dependent
    Module (CDM) register checking (Vidya Sagar)

  - Add DesignWare support for "snps,enable-cdm-check" CDM checking (Vidya
    Sagar)

  - Add "supports-clkreq" DT binding for host drivers to decide whether to
    advertise low power features (Vidya Sagar)

  - Add DT binding for Tegra194 (Vidya Sagar)

  - Add DT binding for Tegra194 P2U (PIPE to UPHY) block (Vidya Sagar)

  - Add support for Tegra194 P2U (PIPE to UPHY) (Vidya Sagar)

  - Add support for Tegra194 host controller (Vidya Sagar)

  - Add Tegra support for sideband PERST# and CLKREQ# for C5 (Vidya Sagar)

  - Add Tegra support for slot regulators for p2972-0000 platform (Vidya
    Sagar)

* lorenzo/pci/tegra:
  arm64: tegra: Add PCIe slot supply information in p2972-0000 platform
  arm64: tegra: Add configuration for PCIe C5 sideband signals
  PCI: tegra: Add support to enable slot regulators
  PCI: tegra: Add support to configure sideband pins
  dt-bindings: PCI: tegra: Add PCIe slot supplies regulator entries
  dt-bindings: PCI: tegra: Add sideband pins configuration entries
  PCI: tegra: Add Tegra194 PCIe support
  phy: tegra: Add PCIe PIPE2UPHY support
  dt-bindings: PHY: P2U: Add Tegra194 P2U block
  dt-bindings: PCI: tegra: Add device tree support for Tegra194
  dt-bindings: Add PCIe supports-clkreq property
  PCI: dwc: Add support to enable CDM register check
  dt-bindings: PCI: designware: Add binding for CDM register check
  PCI: dwc: Export dw_pcie_wait_for_link() API
  PCI: dwc: Add extended configuration space capability search API
  PCI: dwc: Move config space capability search API
  PCI: dwc: Group DBI registers writes requiring unlocking
  PCI: Disable MSI for Tegra root ports
  PCI: Add #defines for some of PCIe spec r4.0 features
  PCI: tegra: Fix OF node reference leak

77 files changed:
Documentation/admin-guide/kernel-parameters.txt
Documentation/devicetree/bindings/pci/designware-pcie.txt
Documentation/devicetree/bindings/pci/mediatek-pcie.txt
Documentation/devicetree/bindings/pci/pcie-al.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/boot/dts/ls1021a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
arch/microblaze/include/asm/pci.h
arch/mips/include/asm/pci.h
arch/powerpc/include/asm/pci.h
arch/sparc/include/asm/pci.h
drivers/acpi/pci_root.c
drivers/char/xillybus/xillybus_pcie.c
drivers/infiniband/core/rw.c
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/jme.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/wireless/ath/ath5k/pci.c
drivers/net/wireless/intel/iwlegacy/3945-mac.c
drivers/net/wireless/intel/iwlegacy/4965-mac.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/nvme/host/pci.c
drivers/pci/Kconfig
drivers/pci/access.c
drivers/pci/bus.c
drivers/pci/controller/dwc/Kconfig
drivers/pci/controller/dwc/Makefile
drivers/pci/controller/dwc/pci-exynos.c
drivers/pci/controller/dwc/pci-imx6.c
drivers/pci/controller/dwc/pci-layerscape-ep.c
drivers/pci/controller/dwc/pcie-al.c
drivers/pci/controller/dwc/pcie-armada8k.c
drivers/pci/controller/dwc/pcie-designware-ep.c
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-designware.c
drivers/pci/controller/dwc/pcie-histb.c
drivers/pci/controller/dwc/pcie-kirin.c
drivers/pci/controller/pci-host-common.c
drivers/pci/controller/pci-hyperv.c
drivers/pci/controller/pcie-iproc-platform.c
drivers/pci/controller/pcie-mediatek.c
drivers/pci/controller/pcie-mobiveil.c
drivers/pci/controller/pcie-rockchip-host.c
drivers/pci/hotplug/ibmphp_res.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/iov.c
drivers/pci/p2pdma.c
drivers/pci/pci-acpi.c
drivers/pci/pci-bridge-emul.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aspm.c
drivers/pci/pcie/err.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/search.c
drivers/pci/setup-bus.c
drivers/pci/vc.c
drivers/pci/vpd.c
drivers/scsi/aacraid/linit.c
drivers/scsi/hpsa.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
include/linux/memremap.h
include/linux/pci-aspm.h [deleted file]
include/linux/pci-p2pdma.h
include/linux/pci.h
include/linux/pci_hotplug.h
include/linux/pci_ids.h
include/uapi/linux/pci_regs.h

index 46b826fcb5ad55fed0d8ca92ab10751baabf64a9..7d407bdded998dedf1089b5861c5f9169e6acdf3 100644 (file)
                                specify the device is described above.
                                If <order of align> is not specified,
                                PAGE_SIZE is used as alignment.
-                               PCI-PCI bridge can be specified, if resource
+                               A PCI-PCI bridge can be specified if resource
                                windows need to be expanded.
                                To specify the alignment for several
                                instances of a device, the PCI vendor,
                                device, subvendor, and subdevice may be
-                               specified, e.g., 4096@pci:8086:9c22:103c:198f
+                               specified, e.g., 12@pci:8086:9c22:103c:198f
+                               for 4096-byte alignment.
                ecrc=           Enable/disable PCIe ECRC (transaction layer
                                end-to-end CRC checking).
                                bios: Use BIOS/firmware settings. This is the
index 3fba04da6a59a3d987d734561722f643bdb7dc2c..78494c4050f75e95391a38ef86fdf2a3c00e9c3e 100644 (file)
@@ -11,7 +11,6 @@ Required properties:
             the ATU address space.
     (The old way of getting the configuration address space from "ranges"
     is deprecated and should be avoided.)
-- num-lanes: number of lanes to use
 RC mode:
 - #address-cells: set to <3>
 - #size-cells: set to <2>
index 92437a366e5f651224d0fa672738874f3e3e45a9..7468d666763acf0317dce046a4ff93dc0f097bef 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
        "mediatek,mt2712-pcie"
        "mediatek,mt7622-pcie"
        "mediatek,mt7623-pcie"
+       "mediatek,mt7629-pcie"
 - device_type: Must be "pci"
 - reg: Base addresses and lengths of the PCIe subsys and root ports.
 - reg-names: Names of the above areas to use during resource lookup.
diff --git a/Documentation/devicetree/bindings/pci/pcie-al.txt b/Documentation/devicetree/bindings/pci/pcie-al.txt
new file mode 100644 (file)
index 0000000..557a508
--- /dev/null
@@ -0,0 +1,46 @@
+* Amazon Annapurna Labs PCIe host bridge
+
+Amazon's Annapurna Labs PCIe Host Controller is based on the Synopsys DesignWare
+PCI core. It inherits common properties defined in
+Documentation/devicetree/bindings/pci/designware-pcie.txt.
+
+Properties of the host controller node that differ from it are:
+
+- compatible:
+       Usage: required
+       Value type: <stringlist>
+       Definition: Value should contain
+                       - "amazon,al-alpine-v2-pcie" for alpine_v2
+                       - "amazon,al-alpine-v3-pcie" for alpine_v3
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: Register ranges as listed in the reg-names property
+
+- reg-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: Must include the following entries
+                       - "config"      PCIe ECAM space
+                       - "controller"  AL proprietary registers
+                       - "dbi"         Designware PCIe registers
+
+Example:
+
+       pcie-external0: pcie@fb600000 {
+               compatible = "amazon,al-alpine-v3-pcie";
+               reg = <0x0 0xfb600000 0x0 0x00100000
+                      0x0 0xfd800000 0x0 0x00010000
+                      0x0 0xfd810000 0x0 0x00001000>;
+               reg-names = "config", "controller", "dbi";
+               bus-range = <0 255>;
+               device_type = "pci";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-map-mask = <0x00 0 0 7>;
+               interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; /* INTa */
+               ranges = <0x02000000 0x0 0xc0010000 0x0 0xc0010000 0x0 0x07ff0000>;
+       };
index 783569e3c4b48752c3555e9bee6fbc87adad5117..d88e268271d7956f50abef9d7417677517d7c646 100644 (file)
@@ -12442,16 +12442,18 @@ F:    arch/x86/kernel/early-quirks.c
 
 PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
 M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+R:     Andrew Murray <andrew.murray@arm.com>
 L:     linux-pci@vger.kernel.org
 Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
 S:     Supported
 F:     drivers/pci/controller/
 
-PCIE DRIVER FOR ANNAPURNA LABS
+PCIE DRIVER FOR AMAZON ANNAPURNA LABS
 M:     Jonathan Chocron <jonnyc@amazon.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/pci/pcie-al.txt
 F:     drivers/pci/controller/dwc/pcie-al.c
 
 PCIE DRIVER FOR AMLOGIC MESON
index 464df4290ffcb5c43e717f2f47b0a4c4abeac40d..2f6977ada44762f54d493c5c4f80e490d2325598 100644 (file)
                        #address-cells = <3>;
                        #size-cells = <2>;
                        device_type = "pci";
-                       num-lanes = <4>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
                        #address-cells = <3>;
                        #size-cells = <2>;
                        device_type = "pci";
-                       num-lanes = <4>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000   /* downstream I/O */
index ec6257a5b251504f23dcd752a6fa61757a57d92e..119c597ca8679417c44cef0bf79c774775af5c54 100644 (file)
                        #address-cells = <3>;
                        #size-cells = <2>;
                        device_type = "pci";
-                       num-lanes = <4>;
                        num-viewport = <2>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
index 71d9ed9ff985a296d71243d78f9ac4e8467cab98..c084c7a4b6a6f7d81ef919e05c039c8fbb6f3e04 100644 (file)
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <4>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <2>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000   /* downstream I/O */
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <2>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000   /* downstream I/O */
index b0ef08b090ddb1161b570701a850132a64ca359f..d4c1da3d4bde280deeb309a13dfa14fb11c28006 100644 (file)
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <4>;
                        num-viewport = <8>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
                        reg-names = "regs", "addr_space";
                        num-ib-windows = <6>;
                        num-ob-windows = <8>;
-                       num-lanes = <2>;
                        status = "disabled";
                };
 
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <2>;
                        num-viewport = <8>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000   /* downstream I/O */
                        reg-names = "regs", "addr_space";
                        num-ib-windows = <6>;
                        num-ob-windows = <8>;
-                       num-lanes = <2>;
                        status = "disabled";
                };
 
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <2>;
                        num-viewport = <8>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000   /* downstream I/O */
                        reg-names = "regs", "addr_space";
                        num-ib-windows = <6>;
                        num-ob-windows = <8>;
-                       num-lanes = <2>;
                        status = "disabled";
                };
 
index dacd8cf03a7f7a77969042707893b6fe8df8f589..ce48a2323337c67f5179a41ca9dfc07409fc4fcc 100644 (file)
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <4>;
                        num-viewport = <256>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x20 0x00010000 0x0 0x00010000   /* downstream I/O */
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <4>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x28 0x00010000 0x0 0x00010000   /* downstream I/O */
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <8>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000 0x0 0x00000000 0x30 0x00010000 0x0 0x00010000   /* downstream I/O */
index 3ace91945b726fc25ede7be1e80e4737f3d37660..d4993a2b404f1147c5cb3904631f0f86442608a1 100644 (file)
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <4>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        msi-parent = <&its>;
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <4>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        msi-parent = <&its>;
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <8>;
                        num-viewport = <256>;
                        bus-range = <0x0 0xff>;
                        msi-parent = <&its>;
                        #size-cells = <2>;
                        device_type = "pci";
                        dma-coherent;
-                       num-lanes = <4>;
                        num-viewport = <6>;
                        bus-range = <0x0 0xff>;
                        msi-parent = <&its>;
index 21ddba9188b20f499f8ec09328457740a3c823fd..7c4dc5d85f531c32683163b5eec07a938d425b03 100644 (file)
@@ -66,8 +66,6 @@ extern pgprot_t       pci_phys_mem_access_prot(struct file *file,
                                         unsigned long size,
                                         pgprot_t prot);
 
-#define HAVE_ARCH_PCI_RESOURCE_TO_USER
-
 /* This part of code was originally in xilinx-pci.h */
 #ifdef CONFIG_PCI_XILINX
 extern void __init xilinx_pci_init(void);
index 436099883022127f1bc882903f4b5df956cfe9b1..6f48649201c571bb11a5ff4a059171396c99dd83 100644 (file)
@@ -108,7 +108,6 @@ extern unsigned long PCIBIOS_MIN_MEM;
 
 #define HAVE_PCI_MMAP
 #define ARCH_GENERIC_PCI_MMAP_RESOURCE
-#define HAVE_ARCH_PCI_RESOURCE_TO_USER
 
 /*
  * Dynamic DMA mapping stuff.
index 2372d35533adcc01dc0298c8158c0c5cdd1ba3d5..327567b8f7d6faa9a2ef60cf7b108358768872f7 100644 (file)
@@ -112,8 +112,6 @@ extern pgprot_t     pci_phys_mem_access_prot(struct file *file,
                                         unsigned long size,
                                         pgprot_t prot);
 
-#define HAVE_ARCH_PCI_RESOURCE_TO_USER
-
 extern resource_size_t pcibios_io_space_offset(struct pci_controller *hose);
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
 extern void pcibios_setup_bus_self(struct pci_bus *bus);
index cfec79bb1831c70bf1926e6af592c434065eab63..4deddf430e5d18cae2710cf1d74ebdb2aaf170a6 100644 (file)
@@ -38,8 +38,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 #define arch_can_pci_mmap_io() 1
 #define HAVE_ARCH_PCI_GET_UNMAPPED_AREA
 #define get_pci_unmapped_area get_fb_unmapped_area
-
-#define HAVE_ARCH_PCI_RESOURCE_TO_USER
 #endif /* CONFIG_SPARC64 */
 
 #if defined(CONFIG_SPARC64) || defined(CONFIG_LEON_PCI)
index 314a187ed5728196daea3d2469d5908c3a538626..d1e666ef3fcc886eb48772419aa891b78b039bc6 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/pci.h>
 #include <linux/pci-acpi.h>
-#include <linux/pci-aspm.h>
 #include <linux/dmar.h>
 #include <linux/acpi.h>
 #include <linux/slab.h>
index 02c15952b1030520a70ab6e5dde96bf9aabba131..18b0c392bc9325cd378b4e23d1cb7be1ce5447ad 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include "xillybus.h"
 
index dce06108c8c3fe39d9bd2d28ae9d88dd6cab82c7..5337393d4dfe78cc91728b9fb8f41378961194ea 100644 (file)
@@ -583,8 +583,10 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
                break;
        }
 
-       /* P2PDMA contexts do not need to be unmapped */
-       if (!is_pci_p2pdma_page(sg_page(sg)))
+       if (is_pci_p2pdma_page(sg_page(sg)))
+               pci_p2pdma_unmap_sg(qp->pd->device->dma_device, sg,
+                                   sg_cnt, dir);
+       else
                ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
 }
 EXPORT_SYMBOL(rdma_rw_ctx_destroy);
index 34cd67951aecdbb8e34382b15d1121477dc77c2d..6c51b1bad8c423ea243587446d3e5fc6705ca9ad 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/io.h>
 #include <linux/netdevice.h>
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/crc32.h>
 #include <linux/if_vlan.h>
 #include <linux/timecounter.h>
index 0b668357db4dd24de638dd8a995790f482d9b95f..57e8aea98969efaaa881d86cb5627756cafa04e4 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
index 0637c6752a78e7451826f08f48d30ac97ec85765..a6d8e7f5fde700738436519924d0622cb9c12a6d 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/prefetch.h>
-#include <linux/pci-aspm.h>
 #include <linux/ipv6.h>
 #include <net/ip6_checksum.h>
 
index c6156cc38940ada0cbe923da182a659f4e934023..d5ee32ce9eb3dac632e3ebc5bdb9118425ab729c 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/nl80211.h>
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/etherdevice.h>
 #include <linux/module.h>
 #include "../ath.h"
index b82da75a9ae3640ef1f295b7ffe5c9683f22355a..4fbcc7fba3cc14760fa90ac9dc8baa4c8f0734d3 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
index fa2c028819397934b7025e539f747cea635165d6..ffb705b18fb13bd3a44753087358e72ded6aea75 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
index f5df5b370d78b585dd277b61b86c00498b8e5f74..4c308e33ee21b2f73b9b39ba7ee7f1637660fef4 100644 (file)
@@ -62,7 +62,6 @@
  *
  *****************************************************************************/
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/interrupt.h>
 #include <linux/debugfs.h>
 #include <linux/sched.h>
index bb970ca82517b1213cb4922225822edb78e23b4d..2348b15f6bd0dfccf00ebd7f542f3541eb97cfc8 100644 (file)
@@ -547,8 +547,10 @@ static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
 
        WARN_ON_ONCE(!iod->nents);
 
-       /* P2PDMA requests do not need to be unmapped */
-       if (!is_pci_p2pdma_page(sg_page(iod->sg)))
+       if (is_pci_p2pdma_page(sg_page(iod->sg)))
+               pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
+                                   rq_dma_dir(req));
+       else
                dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
 
 
@@ -832,8 +834,8 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
                goto out;
 
        if (is_pci_p2pdma_page(sg_page(iod->sg)))
-               nr_mapped = pci_p2pdma_map_sg(dev->dev, iod->sg, iod->nents,
-                                             rq_dma_dir(req));
+               nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
+                               iod->nents, rq_dma_dir(req), DMA_ATTR_NO_WARN);
        else
                nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
                                             rq_dma_dir(req), DMA_ATTR_NO_WARN);
index 2ab92409210afc0cc8cf54da3bef2392abd7d5c3..23204272226133c4538411d3dce98ee1472e79e3 100644 (file)
@@ -52,7 +52,7 @@ config PCI_MSI
           If you don't know what to do here, say Y.
 
 config PCI_MSI_IRQ_DOMAIN
-       def_bool ARC || ARM || ARM64 || X86
+       def_bool ARC || ARM || ARM64 || X86 || RISCV
        depends on PCI_MSI
        select GENERIC_MSI_IRQ_DOMAIN
 
@@ -181,7 +181,7 @@ config PCI_LABEL
 
 config PCI_HYPERV
         tristate "Hyper-V PCI Frontend"
-        depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64
+        depends on X86_64 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && SYSFS
         help
           The PCI device frontend driver allows the kernel to import arbitrary
           PCI devices from a PCI backend to support PCI driver domains.
index 544922f097c044a7e434d679ddddf588f72e8467..2fccb5762c762cf34a503a96e6971760d8964bfb 100644 (file)
@@ -336,15 +336,6 @@ static inline int pcie_cap_version(const struct pci_dev *dev)
        return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
 }
 
-static bool pcie_downstream_port(const struct pci_dev *dev)
-{
-       int type = pci_pcie_type(dev);
-
-       return type == PCI_EXP_TYPE_ROOT_PORT ||
-              type == PCI_EXP_TYPE_DOWNSTREAM ||
-              type == PCI_EXP_TYPE_PCIE_BRIDGE;
-}
-
 bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
 {
        int type = pci_pcie_type(dev);
index 495059d923f7da4e360a7689349c46260e16e797..8e40b3e6da77d14ebeaa5ce1d0e40bcc9d525413 100644 (file)
@@ -417,11 +417,9 @@ struct pci_bus *pci_bus_get(struct pci_bus *bus)
                get_device(&bus->dev);
        return bus;
 }
-EXPORT_SYMBOL(pci_bus_get);
 
 void pci_bus_put(struct pci_bus *bus)
 {
        if (bus)
                put_device(&bus->dev);
 }
-EXPORT_SYMBOL(pci_bus_put);
index 49475f5c42c3ca949bb88758952d3a6c4ebc242d..0ba988b5b5bc6901fa71c261be827a953d707e4a 100644 (file)
@@ -131,13 +131,29 @@ config PCI_KEYSTONE_EP
          DesignWare core functions to implement the driver.
 
 config PCI_LAYERSCAPE
-       bool "Freescale Layerscape PCIe controller"
+       bool "Freescale Layerscape PCIe controller - Host mode"
        depends on OF && (ARM || ARCH_LAYERSCAPE || COMPILE_TEST)
        depends on PCI_MSI_IRQ_DOMAIN
        select MFD_SYSCON
        select PCIE_DW_HOST
        help
-         Say Y here if you want PCIe controller support on Layerscape SoCs.
+         Say Y here if you want to enable PCIe controller support on Layerscape
+         SoCs to work in Host mode.
+         This controller can work either as EP or RC. The RCW[HOST_AGT_PEX]
+         determines which PCIe controller works in EP mode and which PCIe
+         controller works in RC mode.
+
+config PCI_LAYERSCAPE_EP
+       bool "Freescale Layerscape PCIe controller - Endpoint mode"
+       depends on OF && (ARM || ARCH_LAYERSCAPE || COMPILE_TEST)
+       depends on PCI_ENDPOINT
+       select PCIE_DW_EP
+       help
+         Say Y here if you want to enable PCIe controller support on Layerscape
+         SoCs to work in Endpoint mode.
+         This controller can work either as EP or RC. The RCW[HOST_AGT_PEX]
+         determines which PCIe controller works in EP mode and which PCIe
+         controller works in RC mode.
 
 config PCI_HISI
        depends on OF && (ARM64 || COMPILE_TEST)
@@ -240,4 +256,16 @@ config PCIE_UNIPHIER
          Say Y here if you want PCIe controller support on UniPhier SoCs.
          This driver supports LD20 and PXs3 SoCs.
 
+config PCIE_AL
+       bool "Amazon Annapurna Labs PCIe controller"
+       depends on OF && (ARM64 || COMPILE_TEST)
+       depends on PCI_MSI_IRQ_DOMAIN
+       select PCIE_DW_HOST
+       help
+         Say Y here to enable support of the Amazon's Annapurna Labs PCIe
+         controller IP on Amazon SoCs. The PCIe controller uses the DesignWare
+         core plus Annapurna Labs proprietary hardware wrappers. This is
+         required only for DT-based platforms. ACPI platforms with the
+         Annapurna Labs PCIe controller don't need to enable this.
+
 endmenu
index b30336181d46f0620306c59d47aa8aebd944841e..69faff371f118f133a1973b52cc093cbb6ec1840 100644 (file)
@@ -8,7 +8,8 @@ obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
 obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
 obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
-obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o pci-layerscape-ep.o
+obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
+obj-$(CONFIG_PCI_LAYERSCAPE_EP) += pci-layerscape-ep.o
 obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
 obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
index cee5f2f590e2d4c51e9531383225d16e69f0d15d..14a6ba4067fbec47c3c2ea5609e591b8c689faff 100644 (file)
@@ -465,7 +465,7 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
 
        ep->phy = devm_of_phy_get(dev, np, NULL);
        if (IS_ERR(ep->phy)) {
-               if (PTR_ERR(ep->phy) == -EPROBE_DEFER)
+               if (PTR_ERR(ep->phy) != -ENODEV)
                        return PTR_ERR(ep->phy);
 
                ep->phy = NULL;
index 9b5cb5b703890f3e6e2d17fe06d1ae29b8be11bb..acfbd34032a86253d7d0d565014cb5c4339a1934 100644 (file)
@@ -57,6 +57,7 @@ enum imx6_pcie_variants {
 struct imx6_pcie_drvdata {
        enum imx6_pcie_variants variant;
        u32 flags;
+       int dbi_length;
 };
 
 struct imx6_pcie {
@@ -1173,8 +1174,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
 
        imx6_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie");
        if (IS_ERR(imx6_pcie->vpcie)) {
-               if (PTR_ERR(imx6_pcie->vpcie) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
+               if (PTR_ERR(imx6_pcie->vpcie) != -ENODEV)
+                       return PTR_ERR(imx6_pcie->vpcie);
                imx6_pcie->vpcie = NULL;
        }
 
@@ -1212,6 +1213,7 @@ static const struct imx6_pcie_drvdata drvdata[] = {
                .variant = IMX6Q,
                .flags = IMX6_PCIE_FLAG_IMX6_PHY |
                         IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
+               .dbi_length = 0x200,
        },
        [IMX6SX] = {
                .variant = IMX6SX,
@@ -1254,6 +1256,37 @@ static struct platform_driver imx6_pcie_driver = {
        .shutdown = imx6_pcie_shutdown,
 };
 
+static void imx6_pcie_quirk(struct pci_dev *dev)
+{
+       struct pci_bus *bus = dev->bus;
+       struct pcie_port *pp = bus->sysdata;
+
+       /* Bus parent is the PCI bridge, its parent is this platform driver */
+       if (!bus->dev.parent || !bus->dev.parent->parent)
+               return;
+
+       /* Make sure we only quirk devices associated with this driver */
+       if (bus->dev.parent->parent->driver != &imx6_pcie_driver.driver)
+               return;
+
+       if (bus->number == pp->root_bus_nr) {
+               struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+               struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
+
+               /*
+                * Limit config length to avoid the kernel reading beyond
+                * the register set and causing an abort on i.MX 6Quad
+                */
+               if (imx6_pcie->drvdata->dbi_length) {
+                       dev->cfg_size = imx6_pcie->drvdata->dbi_length;
+                       dev_info(&dev->dev, "Limiting cfg_size to %d\n",
+                                       dev->cfg_size);
+               }
+       }
+}
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_SYNOPSYS, 0xabcd,
+                       PCI_CLASS_BRIDGE_PCI, 8, imx6_pcie_quirk);
+
 static int __init imx6_pcie_init(void)
 {
 #ifdef CONFIG_ARM
index be61d96cc95ed036e765d05afc0ab37b2707c742..ca9aa4501e7e98aa9f7a3c9a2e997b4c96aafedb 100644 (file)
@@ -44,6 +44,7 @@ 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*
index 3ab58f0584a8e058f5c0dc9567f0cc8c2d16b4ac..1eeda2f6371f1d9261eb46b987132f893d22a25e 100644 (file)
@@ -91,3 +91,368 @@ struct pci_ecam_ops al_pcie_ops = {
 };
 
 #endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */
+
+#ifdef CONFIG_PCIE_AL
+
+#include <linux/of_pci.h>
+#include "pcie-designware.h"
+
+#define AL_PCIE_REV_ID_2       2
+#define AL_PCIE_REV_ID_3       3
+#define AL_PCIE_REV_ID_4       4
+
+#define AXI_BASE_OFFSET                0x0
+
+#define DEVICE_ID_OFFSET       0x16c
+
+#define DEVICE_REV_ID                  0x0
+#define DEVICE_REV_ID_DEV_ID_MASK      GENMASK(31, 16)
+
+#define DEVICE_REV_ID_DEV_ID_X4                0
+#define DEVICE_REV_ID_DEV_ID_X8                2
+#define DEVICE_REV_ID_DEV_ID_X16       4
+
+#define OB_CTRL_REV1_2_OFFSET  0x0040
+#define OB_CTRL_REV3_5_OFFSET  0x0030
+
+#define CFG_TARGET_BUS                 0x0
+#define CFG_TARGET_BUS_MASK_MASK       GENMASK(7, 0)
+#define CFG_TARGET_BUS_BUSNUM_MASK     GENMASK(15, 8)
+
+#define CFG_CONTROL                    0x4
+#define CFG_CONTROL_SUBBUS_MASK                GENMASK(15, 8)
+#define CFG_CONTROL_SEC_BUS_MASK       GENMASK(23, 16)
+
+struct al_pcie_reg_offsets {
+       unsigned int ob_ctrl;
+};
+
+struct al_pcie_target_bus_cfg {
+       u8 reg_val;
+       u8 reg_mask;
+       u8 ecam_mask;
+};
+
+struct al_pcie {
+       struct dw_pcie *pci;
+       void __iomem *controller_base; /* base of PCIe unit (not DW core) */
+       struct device *dev;
+       resource_size_t ecam_size;
+       unsigned int controller_rev_id;
+       struct al_pcie_reg_offsets reg_offsets;
+       struct al_pcie_target_bus_cfg target_bus_cfg;
+};
+
+#define PCIE_ECAM_DEVFN(x)             (((x) & 0xff) << 12)
+
+#define to_al_pcie(x)          dev_get_drvdata((x)->dev)
+
+static inline u32 al_pcie_controller_readl(struct al_pcie *pcie, u32 offset)
+{
+       return readl_relaxed(pcie->controller_base + offset);
+}
+
+static inline void al_pcie_controller_writel(struct al_pcie *pcie, u32 offset,
+                                            u32 val)
+{
+       writel_relaxed(val, pcie->controller_base + offset);
+}
+
+static int al_pcie_rev_id_get(struct al_pcie *pcie, unsigned int *rev_id)
+{
+       u32 dev_rev_id_val;
+       u32 dev_id_val;
+
+       dev_rev_id_val = al_pcie_controller_readl(pcie, AXI_BASE_OFFSET +
+                                                 DEVICE_ID_OFFSET +
+                                                 DEVICE_REV_ID);
+       dev_id_val = FIELD_GET(DEVICE_REV_ID_DEV_ID_MASK, dev_rev_id_val);
+
+       switch (dev_id_val) {
+       case DEVICE_REV_ID_DEV_ID_X4:
+               *rev_id = AL_PCIE_REV_ID_2;
+               break;
+       case DEVICE_REV_ID_DEV_ID_X8:
+               *rev_id = AL_PCIE_REV_ID_3;
+               break;
+       case DEVICE_REV_ID_DEV_ID_X16:
+               *rev_id = AL_PCIE_REV_ID_4;
+               break;
+       default:
+               dev_err(pcie->dev, "Unsupported dev_id_val (0x%x)\n",
+                       dev_id_val);
+               return -EINVAL;
+       }
+
+       dev_dbg(pcie->dev, "dev_id_val: 0x%x\n", dev_id_val);
+
+       return 0;
+}
+
+static int al_pcie_reg_offsets_set(struct al_pcie *pcie)
+{
+       switch (pcie->controller_rev_id) {
+       case AL_PCIE_REV_ID_2:
+               pcie->reg_offsets.ob_ctrl = OB_CTRL_REV1_2_OFFSET;
+               break;
+       case AL_PCIE_REV_ID_3:
+       case AL_PCIE_REV_ID_4:
+               pcie->reg_offsets.ob_ctrl = OB_CTRL_REV3_5_OFFSET;
+               break;
+       default:
+               dev_err(pcie->dev, "Unsupported controller rev_id: 0x%x\n",
+                       pcie->controller_rev_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static inline void al_pcie_target_bus_set(struct al_pcie *pcie,
+                                         u8 target_bus,
+                                         u8 mask_target_bus)
+{
+       u32 reg;
+
+       reg = FIELD_PREP(CFG_TARGET_BUS_MASK_MASK, mask_target_bus) |
+             FIELD_PREP(CFG_TARGET_BUS_BUSNUM_MASK, target_bus);
+
+       al_pcie_controller_writel(pcie, AXI_BASE_OFFSET +
+                                 pcie->reg_offsets.ob_ctrl + CFG_TARGET_BUS,
+                                 reg);
+}
+
+static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie,
+                                          unsigned int busnr,
+                                          unsigned int devfn)
+{
+       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 +
+                                        (busnr_ecam << 20) +
+                                        PCIE_ECAM_DEVFN(devfn));
+
+       if (busnr_reg != target_bus_cfg->reg_val) {
+               dev_dbg(pcie->pci->dev, "Changing target bus busnum val from 0x%x to 0x%x\n",
+                       target_bus_cfg->reg_val, busnr_reg);
+               target_bus_cfg->reg_val = busnr_reg;
+               al_pcie_target_bus_set(pcie,
+                                      target_bus_cfg->reg_val,
+                                      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;
+}
+
+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 void al_pcie_config_prepare(struct al_pcie *pcie)
+{
+       struct al_pcie_target_bus_cfg *target_bus_cfg;
+       struct pcie_port *pp = &pcie->pci->pp;
+       unsigned int ecam_bus_mask;
+       u32 cfg_control_offset;
+       u8 subordinate_bus;
+       u8 secondary_bus;
+       u32 cfg_control;
+       u32 reg;
+
+       target_bus_cfg = &pcie->target_bus_cfg;
+
+       ecam_bus_mask = (pcie->ecam_size >> 20) - 1;
+       if (ecam_bus_mask > 255) {
+               dev_warn(pcie->dev, "ECAM window size is larger than 256MB. Cutting off at 256\n");
+               ecam_bus_mask = 255;
+       }
+
+       /* This portion is taken from the transaction address */
+       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;
+
+       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;
+
+       /* Set the valid values of secondary and subordinate buses */
+       cfg_control_offset = AXI_BASE_OFFSET + pcie->reg_offsets.ob_ctrl +
+                            CFG_CONTROL;
+
+       cfg_control = al_pcie_controller_readl(pcie, cfg_control_offset);
+
+       reg = cfg_control &
+             ~(CFG_CONTROL_SEC_BUS_MASK | CFG_CONTROL_SUBBUS_MASK);
+
+       reg |= FIELD_PREP(CFG_CONTROL_SUBBUS_MASK, subordinate_bus) |
+              FIELD_PREP(CFG_CONTROL_SEC_BUS_MASK, secondary_bus);
+
+       al_pcie_controller_writel(pcie, cfg_control_offset, reg);
+}
+
+static int al_pcie_host_init(struct pcie_port *pp)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct al_pcie *pcie = to_al_pcie(pci);
+       int rc;
+
+       rc = al_pcie_rev_id_get(pcie, &pcie->controller_rev_id);
+       if (rc)
+               return rc;
+
+       rc = al_pcie_reg_offsets_set(pcie);
+       if (rc)
+               return rc;
+
+       al_pcie_config_prepare(pcie);
+
+       return 0;
+}
+
+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,
+};
+
+static int al_add_pcie_port(struct pcie_port *pp,
+                           struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       pp->ops = &al_pcie_host_ops;
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(dev, "failed to initialize host\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+};
+
+static int al_pcie_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *controller_res;
+       struct resource *ecam_res;
+       struct resource *dbi_res;
+       struct al_pcie *al_pcie;
+       struct dw_pcie *pci;
+
+       al_pcie = devm_kzalloc(dev, sizeof(*al_pcie), GFP_KERNEL);
+       if (!al_pcie)
+               return -ENOMEM;
+
+       pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+       if (!pci)
+               return -ENOMEM;
+
+       pci->dev = dev;
+       pci->ops = &dw_pcie_ops;
+
+       al_pcie->pci = pci;
+       al_pcie->dev = dev;
+
+       dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+       pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
+       if (IS_ERR(pci->dbi_base)) {
+               dev_err(dev, "couldn't remap dbi base %pR\n", dbi_res);
+               return PTR_ERR(pci->dbi_base);
+       }
+
+       ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
+       if (!ecam_res) {
+               dev_err(dev, "couldn't find 'config' reg in DT\n");
+               return -ENOENT;
+       }
+       al_pcie->ecam_size = resource_size(ecam_res);
+
+       controller_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                     "controller");
+       al_pcie->controller_base = devm_ioremap_resource(dev, controller_res);
+       if (IS_ERR(al_pcie->controller_base)) {
+               dev_err(dev, "couldn't remap controller base %pR\n",
+                       controller_res);
+               return PTR_ERR(al_pcie->controller_base);
+       }
+
+       dev_dbg(dev, "From DT: dbi_base: %pR, controller_base: %pR\n",
+               dbi_res, controller_res);
+
+       platform_set_drvdata(pdev, al_pcie);
+
+       return al_add_pcie_port(&pci->pp, pdev);
+}
+
+static const struct of_device_id al_pcie_of_match[] = {
+       { .compatible = "amazon,al-alpine-v2-pcie",
+       },
+       { .compatible = "amazon,al-alpine-v3-pcie",
+       },
+       {},
+};
+
+static struct platform_driver al_pcie_driver = {
+       .driver = {
+               .name   = "al-pcie",
+               .of_match_table = al_pcie_of_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = al_pcie_probe,
+};
+builtin_platform_driver(al_pcie_driver);
+
+#endif /* CONFIG_PCIE_AL*/
index 3d55dc78d999ce9395c3baba4a788dae51fb6fb6..49596547e8c297d056fb49d12e0e1cce011760ba 100644 (file)
@@ -118,11 +118,10 @@ static int armada8k_pcie_setup_phys(struct armada8k_pcie *pcie)
 
        for (i = 0; i < ARMADA8K_PCIE_MAX_LANES; i++) {
                pcie->phy[i] = devm_of_phy_get_by_index(dev, node, i);
-               if (IS_ERR(pcie->phy[i]) &&
-                   (PTR_ERR(pcie->phy[i]) == -EPROBE_DEFER))
-                       return PTR_ERR(pcie->phy[i]);
-
                if (IS_ERR(pcie->phy[i])) {
+                       if (PTR_ERR(pcie->phy[i]) != -ENODEV)
+                               return PTR_ERR(pcie->phy[i]);
+
                        pcie->phy[i] = NULL;
                        continue;
                }
index 65f479250087c9c4a6384ebd6578fc33bcc18f67..3dd2e26972948dbf5db2086f1dd6eedb3c6df7c3 100644 (file)
@@ -498,6 +498,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
        int ret;
        u32 reg;
        void *addr;
+       u8 hdr_type;
        unsigned int nbars;
        unsigned int offset;
        struct pci_epc *epc;
@@ -562,6 +563,13 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
        if (ep->ops->ep_init)
                ep->ops->ep_init(ep);
 
+       hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE);
+       if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
+               dev_err(pci->dev, "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n",
+                       hdr_type);
+               return -EIO;
+       }
+
        ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
        if (ret < 0)
                epc->max_functions = 1;
index d3156446ff270a2527c69b9fd1fdcb87a887f521..0f36a926059a14d65b5e7103f317b8022ff2e99e 100644 (file)
@@ -323,6 +323,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
        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);
@@ -464,6 +465,21 @@ int dw_pcie_host_init(struct pcie_port *pp)
                        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;
+       }
+
        pp->root_bus_nr = pp->busn->start;
 
        bridge->dev.parent = dev;
index 4d6690b6ca36cbd68b798ad2684390019440b5fb..820488dfeaed1191c612e9f0a810539b78fcd23a 100644 (file)
@@ -504,8 +504,10 @@ void dw_pcie_setup(struct dw_pcie *pci)
 
 
        ret = of_property_read_u32(np, "num-lanes", &lanes);
-       if (ret)
-               lanes = 0;
+       if (ret) {
+               dev_dbg(pci->dev, "property num-lanes isn't found\n");
+               return;
+       }
 
        /* Set the number of lanes */
        val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
index 954bc2b74bbcd60727395ca523a5a4f98242c4a9..811b5c6d62eae26a7d5991fb88aee61e5cc965ab 100644 (file)
@@ -340,8 +340,8 @@ static int histb_pcie_probe(struct platform_device *pdev)
 
        hipcie->vpcie = devm_regulator_get_optional(dev, "vpcie");
        if (IS_ERR(hipcie->vpcie)) {
-               if (PTR_ERR(hipcie->vpcie) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
+               if (PTR_ERR(hipcie->vpcie) != -ENODEV)
+                       return PTR_ERR(hipcie->vpcie);
                hipcie->vpcie = NULL;
        }
 
index 8df1914226be94d22caf31cc15474368419b043b..c19617a912bd577a1717f7b29c932ea03be0e6ef 100644 (file)
@@ -436,7 +436,7 @@ static int kirin_pcie_host_init(struct pcie_port *pp)
        return 0;
 }
 
-static struct dw_pcie_ops kirin_dw_pcie_ops = {
+static const struct dw_pcie_ops kirin_dw_pcie_ops = {
        .read_dbi = kirin_pcie_read_dbi,
        .write_dbi = kirin_pcie_write_dbi,
        .link_up = kirin_pcie_link_up,
index c742881b5061a7be0cdae6b485c10b9d3816fa84..c8cb9c5188a415aaa9f03495c169e660404060fc 100644 (file)
@@ -43,9 +43,8 @@ static struct pci_config_window *gen_pci_init(struct device *dev,
                goto err_out;
        }
 
-       err = devm_add_action(dev, gen_pci_unmap_cfg, cfg);
+       err = devm_add_action_or_reset(dev, gen_pci_unmap_cfg, cfg);
        if (err) {
-               gen_pci_unmap_cfg(cfg);
                goto err_out;
        }
        return cfg;
index 40b625458afa5edbbb98adadf4a6a8b317aea7ce..3a56de6b2ec2ca20e348cd083fad8574c6a5a4b9 100644 (file)
@@ -2510,6 +2510,48 @@ static void put_hvpcibus(struct hv_pcibus_device *hbus)
                complete(&hbus->remove_event);
 }
 
+#define HVPCI_DOM_MAP_SIZE (64 * 1024)
+static DECLARE_BITMAP(hvpci_dom_map, HVPCI_DOM_MAP_SIZE);
+
+/*
+ * PCI domain number 0 is used by emulated devices on Gen1 VMs, so define 0
+ * as invalid for passthrough PCI devices of this driver.
+ */
+#define HVPCI_DOM_INVALID 0
+
+/**
+ * hv_get_dom_num() - Get a valid PCI domain number
+ * Check if the PCI domain number is in use, and return another number if
+ * it is in use.
+ *
+ * @dom: Requested domain number
+ *
+ * return: domain number on success, HVPCI_DOM_INVALID on failure
+ */
+static u16 hv_get_dom_num(u16 dom)
+{
+       unsigned int i;
+
+       if (test_and_set_bit(dom, hvpci_dom_map) == 0)
+               return dom;
+
+       for_each_clear_bit(i, hvpci_dom_map, HVPCI_DOM_MAP_SIZE) {
+               if (test_and_set_bit(i, hvpci_dom_map) == 0)
+                       return i;
+       }
+
+       return HVPCI_DOM_INVALID;
+}
+
+/**
+ * hv_put_dom_num() - Mark the PCI domain number as free
+ * @dom: Domain number to be freed
+ */
+static void hv_put_dom_num(u16 dom)
+{
+       clear_bit(dom, hvpci_dom_map);
+}
+
 /**
  * hv_pci_probe() - New VMBus channel probe, for a root PCI bus
  * @hdev:      VMBus's tracking struct for this root PCI bus
@@ -2521,6 +2563,7 @@ static int hv_pci_probe(struct hv_device *hdev,
                        const struct hv_vmbus_device_id *dev_id)
 {
        struct hv_pcibus_device *hbus;
+       u16 dom_req, dom;
        int ret;
 
        /*
@@ -2535,19 +2578,34 @@ static int hv_pci_probe(struct hv_device *hdev,
        hbus->state = hv_pcibus_init;
 
        /*
-        * The PCI bus "domain" is what is called "segment" in ACPI and
-        * other specs.  Pull it from the instance ID, to get something
-        * unique.  Bytes 8 and 9 are what is used in Windows guests, so
-        * do the same thing for consistency.  Note that, since this code
-        * only runs in a Hyper-V VM, Hyper-V can (and does) guarantee
-        * that (1) the only domain in use for something that looks like
-        * a physical PCI bus (which is actually emulated by the
-        * hypervisor) is domain 0 and (2) there will be no overlap
-        * between domains derived from these instance IDs in the same
-        * VM.
+        * The PCI bus "domain" is what is called "segment" in ACPI and other
+        * specs. Pull it from the instance ID, to get something usually
+        * unique. In rare cases of collision, we will find out another number
+        * not in use.
+        *
+        * Note that, since this code only runs in a Hyper-V VM, Hyper-V
+        * together with this guest driver can guarantee that (1) The only
+        * domain used by Gen1 VMs for something that looks like a physical
+        * PCI bus (which is actually emulated by the hypervisor) is domain 0.
+        * (2) There will be no overlap between domains (after fixing possible
+        * collisions) in the same VM.
         */
-       hbus->sysdata.domain = hdev->dev_instance.b[9] |
-                              hdev->dev_instance.b[8] << 8;
+       dom_req = hdev->dev_instance.b[5] << 8 | hdev->dev_instance.b[4];
+       dom = hv_get_dom_num(dom_req);
+
+       if (dom == HVPCI_DOM_INVALID) {
+               dev_err(&hdev->device,
+                       "Unable to use dom# 0x%hx or other numbers", dom_req);
+               ret = -EINVAL;
+               goto free_bus;
+       }
+
+       if (dom != dom_req)
+               dev_info(&hdev->device,
+                        "PCI dom# 0x%hx has collision, using 0x%hx",
+                        dom_req, dom);
+
+       hbus->sysdata.domain = dom;
 
        hbus->hdev = hdev;
        refcount_set(&hbus->remove_lock, 1);
@@ -2562,7 +2620,7 @@ static int hv_pci_probe(struct hv_device *hdev,
                                           hbus->sysdata.domain);
        if (!hbus->wq) {
                ret = -ENOMEM;
-               goto free_bus;
+               goto free_dom;
        }
 
        ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0,
@@ -2639,6 +2697,8 @@ close:
        vmbus_close(hdev->channel);
 destroy_wq:
        destroy_workqueue(hbus->wq);
+free_dom:
+       hv_put_dom_num(hbus->sysdata.domain);
 free_bus:
        free_page((unsigned long)hbus);
        return ret;
@@ -2701,8 +2761,8 @@ static int hv_pci_remove(struct hv_device *hdev)
                /* Remove the bus from PCI's point of view. */
                pci_lock_rescan_remove();
                pci_stop_root_bus(hbus->pci_bus);
-               pci_remove_root_bus(hbus->pci_bus);
                hv_pci_remove_slots(hbus);
+               pci_remove_root_bus(hbus->pci_bus);
                pci_unlock_rescan_remove();
                hbus->state = hv_pcibus_removed;
        }
@@ -2720,6 +2780,9 @@ static int hv_pci_remove(struct hv_device *hdev)
        put_hvpcibus(hbus);
        wait_for_completion(&hbus->remove_event);
        destroy_workqueue(hbus->wq);
+
+       hv_put_dom_num(hbus->sysdata.domain);
+
        free_page((unsigned long)hbus);
        return 0;
 }
@@ -2747,6 +2810,9 @@ static void __exit exit_hv_pci_drv(void)
 
 static int __init init_hv_pci_drv(void)
 {
+       /* Set the invalid domain number's bit, so it will not be used */
+       set_bit(HVPCI_DOM_INVALID, hvpci_dom_map);
+
        return vmbus_driver_register(&hv_pci_drv);
 }
 
index 5a3550b6bb29cd4e2952def17be53ebbe36837cd..9ee6200a66f402f69fbc2dfa1b3e0e9bf83c6c49 100644 (file)
@@ -93,12 +93,9 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
        pcie->need_ib_cfg = of_property_read_bool(np, "dma-ranges");
 
        /* PHY use is optional */
-       pcie->phy = devm_phy_get(dev, "pcie-phy");
-       if (IS_ERR(pcie->phy)) {
-               if (PTR_ERR(pcie->phy) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-               pcie->phy = NULL;
-       }
+       pcie->phy = devm_phy_optional_get(dev, "pcie-phy");
+       if (IS_ERR(pcie->phy))
+               return PTR_ERR(pcie->phy);
 
        ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources,
                                                    &iobase);
index 80601e1b939eba94f29daa8b5437e54f77b19947..3eaa7081ab2a5ec3aadb836e089227246a54af50 100644 (file)
@@ -73,6 +73,7 @@
 #define PCIE_MSI_VECTOR                0x0c0
 
 #define PCIE_CONF_VEND_ID      0x100
+#define PCIE_CONF_DEVICE_ID    0x102
 #define PCIE_CONF_CLASS_ID     0x106
 
 #define PCIE_INT_MASK          0x420
@@ -141,12 +142,16 @@ struct mtk_pcie_port;
 /**
  * struct mtk_pcie_soc - differentiate between host generations
  * @need_fix_class_id: whether this host's class ID needed to be fixed or not
+ * @need_fix_device_id: whether this host's device ID needed to be fixed or not
+ * @device_id: device ID which this host need to be fixed
  * @ops: pointer to configuration access functions
  * @startup: pointer to controller setting functions
  * @setup_irq: pointer to initialize IRQ functions
  */
 struct mtk_pcie_soc {
        bool need_fix_class_id;
+       bool need_fix_device_id;
+       unsigned int device_id;
        struct pci_ops *ops;
        int (*startup)(struct mtk_pcie_port *port);
        int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
@@ -696,6 +701,9 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
                writew(val, port->base + PCIE_CONF_CLASS_ID);
        }
 
+       if (soc->need_fix_device_id)
+               writew(soc->device_id, port->base + PCIE_CONF_DEVICE_ID);
+
        /* 100ms timeout value should be enough for Gen1/2 training */
        err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
                                 !!(val & PCIE_PORT_LINKUP_V2), 20,
@@ -1216,11 +1224,21 @@ static const struct mtk_pcie_soc mtk_pcie_soc_mt7622 = {
        .setup_irq = mtk_pcie_setup_irq,
 };
 
+static const struct mtk_pcie_soc mtk_pcie_soc_mt7629 = {
+       .need_fix_class_id = true,
+       .need_fix_device_id = true,
+       .device_id = PCI_DEVICE_ID_MEDIATEK_7629,
+       .ops = &mtk_pcie_ops_v2,
+       .startup = mtk_pcie_startup_port_v2,
+       .setup_irq = mtk_pcie_setup_irq,
+};
+
 static const struct of_device_id mtk_pcie_ids[] = {
        { .compatible = "mediatek,mt2701-pcie", .data = &mtk_pcie_soc_v1 },
        { .compatible = "mediatek,mt7623-pcie", .data = &mtk_pcie_soc_v1 },
        { .compatible = "mediatek,mt2712-pcie", .data = &mtk_pcie_soc_mt2712 },
        { .compatible = "mediatek,mt7622-pcie", .data = &mtk_pcie_soc_mt7622 },
+       { .compatible = "mediatek,mt7629-pcie", .data = &mtk_pcie_soc_mt7629 },
        {},
 };
 
index 672e633601c7821e96b42142662d28a5efbe7f80..a45a6447b01d96dc4b66bce573ce37c962e7b882 100644 (file)
@@ -88,6 +88,7 @@
 #define  AMAP_CTRL_TYPE_MASK           3
 
 #define PAB_EXT_PEX_AMAP_SIZEN(win)    PAB_EXT_REG_ADDR(0xbef0, win)
+#define PAB_EXT_PEX_AMAP_AXI_WIN(win)  PAB_EXT_REG_ADDR(0xb4a0, win)
 #define PAB_PEX_AMAP_AXI_WIN(win)      PAB_REG_ADDR(0x4ba4, win)
 #define PAB_PEX_AMAP_PEX_WIN_L(win)    PAB_REG_ADDR(0x4ba8, win)
 #define PAB_PEX_AMAP_PEX_WIN_H(win)    PAB_REG_ADDR(0x4bac, win)
@@ -462,7 +463,7 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
 }
 
 static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
-                              u64 pci_addr, u32 type, u64 size)
+                              u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
 {
        u32 value;
        u64 size64 = ~(size - 1);
@@ -482,7 +483,10 @@ static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
        csr_writel(pcie, upper_32_bits(size64),
                   PAB_EXT_PEX_AMAP_SIZEN(win_num));
 
-       csr_writel(pcie, pci_addr, PAB_PEX_AMAP_AXI_WIN(win_num));
+       csr_writel(pcie, lower_32_bits(cpu_addr),
+                  PAB_PEX_AMAP_AXI_WIN(win_num));
+       csr_writel(pcie, upper_32_bits(cpu_addr),
+                  PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
 
        csr_writel(pcie, lower_32_bits(pci_addr),
                   PAB_PEX_AMAP_PEX_WIN_L(win_num));
@@ -624,7 +628,7 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
                           CFG_WINDOW_TYPE, resource_size(pcie->ob_io_res));
 
        /* memory inbound translation window */
-       program_ib_windows(pcie, WIN_NUM_0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
+       program_ib_windows(pcie, WIN_NUM_0, 0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
 
        /* Get the I/O and memory ranges from DT */
        resource_list_for_each_entry(win, &pcie->resources) {
index 8d20f1793a61837e7f2bdbe58a17474ceafafb6f..ef8e677ce9d11af857f9bee96fec59de9d49213d 100644 (file)
@@ -608,29 +608,29 @@ static int rockchip_pcie_parse_host_dt(struct rockchip_pcie *rockchip)
 
        rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v");
        if (IS_ERR(rockchip->vpcie12v)) {
-               if (PTR_ERR(rockchip->vpcie12v) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
+               if (PTR_ERR(rockchip->vpcie12v) != -ENODEV)
+                       return PTR_ERR(rockchip->vpcie12v);
                dev_info(dev, "no vpcie12v regulator found\n");
        }
 
        rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3");
        if (IS_ERR(rockchip->vpcie3v3)) {
-               if (PTR_ERR(rockchip->vpcie3v3) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
+               if (PTR_ERR(rockchip->vpcie3v3) != -ENODEV)
+                       return PTR_ERR(rockchip->vpcie3v3);
                dev_info(dev, "no vpcie3v3 regulator found\n");
        }
 
        rockchip->vpcie1v8 = devm_regulator_get_optional(dev, "vpcie1v8");
        if (IS_ERR(rockchip->vpcie1v8)) {
-               if (PTR_ERR(rockchip->vpcie1v8) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
+               if (PTR_ERR(rockchip->vpcie1v8) != -ENODEV)
+                       return PTR_ERR(rockchip->vpcie1v8);
                dev_info(dev, "no vpcie1v8 regulator found\n");
        }
 
        rockchip->vpcie0v9 = devm_regulator_get_optional(dev, "vpcie0v9");
        if (IS_ERR(rockchip->vpcie0v9)) {
-               if (PTR_ERR(rockchip->vpcie0v9) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
+               if (PTR_ERR(rockchip->vpcie0v9) != -ENODEV)
+                       return PTR_ERR(rockchip->vpcie0v9);
                dev_info(dev, "no vpcie0v9 regulator found\n");
        }
 
index 5e8caf7a4452b2e2df2f4c9f23a5547979327200..5c93aa14f0de21ff008345037b2307fbeb7c3ed7 100644 (file)
@@ -1941,6 +1941,7 @@ static int __init update_bridge_ranges(struct bus_node **bus)
                                                break;
                                        case PCI_HEADER_TYPE_BRIDGE:
                                                function = 0x8;
+                                               /* fall through */
                                        case PCI_HEADER_TYPE_MULTIBRIDGE:
                                                /* We assume here that only 1 bus behind the bridge
                                                   TO DO: add functionality for several:
index 8c51a04b8083e1d1d7a4894b90a95b8231214199..654c972b8ea0c3f3117cd27a495a1f1dd99ee685 100644 (file)
@@ -110,9 +110,9 @@ struct controller {
  *
  * @OFF_STATE: slot is powered off, no subordinate devices are enumerated
  * @BLINKINGON_STATE: slot will be powered on after the 5 second delay,
- *     green led is blinking
+ *     Power Indicator is blinking
  * @BLINKINGOFF_STATE: slot will be powered off after the 5 second delay,
- *     green led is blinking
+ *     Power Indicator is blinking
  * @POWERON_STATE: slot is currently powering on
  * @POWEROFF_STATE: slot is currently powering off
  * @ON_STATE: slot is powered on, subordinate devices have been enumerated
@@ -167,12 +167,11 @@ int pciehp_power_on_slot(struct controller *ctrl);
 void pciehp_power_off_slot(struct controller *ctrl);
 void pciehp_get_power_status(struct controller *ctrl, u8 *status);
 
-void pciehp_set_attention_status(struct controller *ctrl, u8 status);
+#define INDICATOR_NOOP -1      /* Leave indicator unchanged */
+void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn);
+
 void pciehp_get_latch_status(struct controller *ctrl, u8 *status);
 int pciehp_query_power_fault(struct controller *ctrl);
-void pciehp_green_led_on(struct controller *ctrl);
-void pciehp_green_led_off(struct controller *ctrl);
-void pciehp_green_led_blink(struct controller *ctrl);
 bool pciehp_card_present(struct controller *ctrl);
 bool pciehp_card_present_or_link_active(struct controller *ctrl);
 int pciehp_check_link_status(struct controller *ctrl);
index 6ad0d86762cb5b48a4280384ae3ecbf133bf171e..b3122c151b8035872337cc34f0195582e436b132 100644 (file)
@@ -95,15 +95,20 @@ static void cleanup_slot(struct controller *ctrl)
 }
 
 /*
- * set_attention_status - Turns the Amber LED for a slot on, off or blink
+ * set_attention_status - Turns the Attention Indicator on, off or blinking
  */
 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
 {
        struct controller *ctrl = to_ctrl(hotplug_slot);
        struct pci_dev *pdev = ctrl->pcie->port;
 
+       if (status)
+               status <<= PCI_EXP_SLTCTL_ATTN_IND_SHIFT;
+       else
+               status = PCI_EXP_SLTCTL_ATTN_IND_OFF;
+
        pci_config_pm_runtime_get(pdev);
-       pciehp_set_attention_status(ctrl, status);
+       pciehp_set_indicators(ctrl, INDICATOR_NOOP, status);
        pci_config_pm_runtime_put(pdev);
        return 0;
 }
index 631ced0ab28a0be5fd83f7bedeb279ca3bbc1988..21af7b16d7a4f258e04d48f78a351cd88e5a9718 100644 (file)
 
 static void set_slot_off(struct controller *ctrl)
 {
-       /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
+       /*
+        * Turn off slot, turn on attention indicator, turn off power
+        * indicator
+        */
        if (POWER_CTRL(ctrl)) {
                pciehp_power_off_slot(ctrl);
 
@@ -42,8 +45,8 @@ static void set_slot_off(struct controller *ctrl)
                msleep(1000);
        }
 
-       pciehp_green_led_off(ctrl);
-       pciehp_set_attention_status(ctrl, 1);
+       pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+                             PCI_EXP_SLTCTL_ATTN_IND_ON);
 }
 
 /**
@@ -65,7 +68,8 @@ static int board_added(struct controller *ctrl)
                        return retval;
        }
 
-       pciehp_green_led_blink(ctrl);
+       pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
+                             INDICATOR_NOOP);
 
        /* Check link training status */
        retval = pciehp_check_link_status(ctrl);
@@ -90,8 +94,8 @@ static int board_added(struct controller *ctrl)
                }
        }
 
-       pciehp_green_led_on(ctrl);
-       pciehp_set_attention_status(ctrl, 0);
+       pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
+                             PCI_EXP_SLTCTL_ATTN_IND_OFF);
        return 0;
 
 err_exit:
@@ -100,7 +104,7 @@ err_exit:
 }
 
 /**
- * remove_board - Turns off slot and LEDs
+ * remove_board - Turn off slot and Power Indicator
  * @ctrl: PCIe hotplug controller where board is being removed
  * @safe_removal: whether the board is safely removed (versus surprise removed)
  */
@@ -123,8 +127,8 @@ static void remove_board(struct controller *ctrl, bool safe_removal)
                           &ctrl->pending_events);
        }
 
-       /* turn off Green LED */
-       pciehp_green_led_off(ctrl);
+       pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+                             INDICATOR_NOOP);
 }
 
 static int pciehp_enable_slot(struct controller *ctrl);
@@ -171,9 +175,9 @@ void pciehp_handle_button_press(struct controller *ctrl)
                        ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
                                  slot_name(ctrl));
                }
-               /* blink green LED and turn off amber */
-               pciehp_green_led_blink(ctrl);
-               pciehp_set_attention_status(ctrl, 0);
+               /* blink power indicator and turn off attention */
+               pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
+                                     PCI_EXP_SLTCTL_ATTN_IND_OFF);
                schedule_delayed_work(&ctrl->button_work, 5 * HZ);
                break;
        case BLINKINGOFF_STATE:
@@ -187,12 +191,13 @@ void pciehp_handle_button_press(struct controller *ctrl)
                cancel_delayed_work(&ctrl->button_work);
                if (ctrl->state == BLINKINGOFF_STATE) {
                        ctrl->state = ON_STATE;
-                       pciehp_green_led_on(ctrl);
+                       pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
+                                             PCI_EXP_SLTCTL_ATTN_IND_OFF);
                } else {
                        ctrl->state = OFF_STATE;
-                       pciehp_green_led_off(ctrl);
+                       pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+                                             PCI_EXP_SLTCTL_ATTN_IND_OFF);
                }
-               pciehp_set_attention_status(ctrl, 0);
                ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
                          slot_name(ctrl));
                break;
@@ -310,7 +315,9 @@ static int pciehp_enable_slot(struct controller *ctrl)
        pm_runtime_get_sync(&ctrl->pcie->port->dev);
        ret = __pciehp_enable_slot(ctrl);
        if (ret && ATTN_BUTTN(ctrl))
-               pciehp_green_led_off(ctrl); /* may be blinking */
+               /* may be blinking */
+               pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+                                     INDICATOR_NOOP);
        pm_runtime_put(&ctrl->pcie->port->dev);
 
        mutex_lock(&ctrl->state_lock);
index bd990e3371e31afa9ba130134c7741c765931b26..1a522c1c41772ed33828a366afd899356c42bd90 100644 (file)
@@ -418,65 +418,40 @@ int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
        return 0;
 }
 
-void pciehp_set_attention_status(struct controller *ctrl, u8 value)
+/**
+ * pciehp_set_indicators() - set attention indicator, power indicator, or both
+ * @ctrl: PCIe hotplug controller
+ * @pwr: one of:
+ *     PCI_EXP_SLTCTL_PWR_IND_ON
+ *     PCI_EXP_SLTCTL_PWR_IND_BLINK
+ *     PCI_EXP_SLTCTL_PWR_IND_OFF
+ * @attn: one of:
+ *     PCI_EXP_SLTCTL_ATTN_IND_ON
+ *     PCI_EXP_SLTCTL_ATTN_IND_BLINK
+ *     PCI_EXP_SLTCTL_ATTN_IND_OFF
+ *
+ * Either @pwr or @attn can also be INDICATOR_NOOP to leave that indicator
+ * unchanged.
+ */
+void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn)
 {
-       u16 slot_cmd;
+       u16 cmd = 0, mask = 0;
 
-       if (!ATTN_LED(ctrl))
-               return;
-
-       switch (value) {
-       case 0:         /* turn off */
-               slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_OFF;
-               break;
-       case 1:         /* turn on */
-               slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_ON;
-               break;
-       case 2:         /* turn blink */
-               slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_BLINK;
-               break;
-       default:
-               return;
+       if (PWR_LED(ctrl) && pwr != INDICATOR_NOOP) {
+               cmd |= (pwr & PCI_EXP_SLTCTL_PIC);
+               mask |= PCI_EXP_SLTCTL_PIC;
        }
-       pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC);
-       ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
-                pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
-}
 
-void pciehp_green_led_on(struct controller *ctrl)
-{
-       if (!PWR_LED(ctrl))
-               return;
-
-       pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
-                             PCI_EXP_SLTCTL_PIC);
-       ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
-                pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
-                PCI_EXP_SLTCTL_PWR_IND_ON);
-}
-
-void pciehp_green_led_off(struct controller *ctrl)
-{
-       if (!PWR_LED(ctrl))
-               return;
-
-       pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
-                             PCI_EXP_SLTCTL_PIC);
-       ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
-                pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
-                PCI_EXP_SLTCTL_PWR_IND_OFF);
-}
-
-void pciehp_green_led_blink(struct controller *ctrl)
-{
-       if (!PWR_LED(ctrl))
-               return;
+       if (ATTN_LED(ctrl) && attn != INDICATOR_NOOP) {
+               cmd |= (attn & PCI_EXP_SLTCTL_AIC);
+               mask |= PCI_EXP_SLTCTL_AIC;
+       }
 
-       pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
-                             PCI_EXP_SLTCTL_PIC);
-       ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
-                pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
-                PCI_EXP_SLTCTL_PWR_IND_BLINK);
+       if (cmd) {
+               pcie_write_cmd_nowait(ctrl, cmd, mask);
+               ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
+                        pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
+       }
 }
 
 int pciehp_power_on_slot(struct controller *ctrl)
@@ -638,8 +613,8 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
        if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
                ctrl->power_fault_detected = 1;
                ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
-               pciehp_set_attention_status(ctrl, 1);
-               pciehp_green_led_off(ctrl);
+               pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+                                     PCI_EXP_SLTCTL_ATTN_IND_ON);
        }
 
        /*
index 525fd3f272b3c1f35dbd1f0c2d380a734cca2e37..b3f972e8cfed6ed69b145c719e852a1beb8209ce 100644 (file)
@@ -240,6 +240,173 @@ void pci_iov_remove_virtfn(struct pci_dev *dev, int id)
        pci_dev_put(dev);
 }
 
+static ssize_t sriov_totalvfs_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev));
+}
+
+static ssize_t sriov_numvfs_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n", pdev->sriov->num_VFs);
+}
+
+/*
+ * num_vfs > 0; number of VFs to enable
+ * num_vfs = 0; disable all VFs
+ *
+ * Note: SRIOV spec does not allow partial VF
+ *      disable, so it's all or none.
+ */
+static ssize_t sriov_numvfs_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       int ret;
+       u16 num_vfs;
+
+       ret = kstrtou16(buf, 0, &num_vfs);
+       if (ret < 0)
+               return ret;
+
+       if (num_vfs > pci_sriov_get_totalvfs(pdev))
+               return -ERANGE;
+
+       device_lock(&pdev->dev);
+
+       if (num_vfs == pdev->sriov->num_VFs)
+               goto exit;
+
+       /* is PF driver loaded w/callback */
+       if (!pdev->driver || !pdev->driver->sriov_configure) {
+               pci_info(pdev, "Driver does not support SRIOV configuration via sysfs\n");
+               ret = -ENOENT;
+               goto exit;
+       }
+
+       if (num_vfs == 0) {
+               /* disable VFs */
+               ret = pdev->driver->sriov_configure(pdev, 0);
+               goto exit;
+       }
+
+       /* enable VFs */
+       if (pdev->sriov->num_VFs) {
+               pci_warn(pdev, "%d VFs already enabled. Disable before enabling %d VFs\n",
+                        pdev->sriov->num_VFs, num_vfs);
+               ret = -EBUSY;
+               goto exit;
+       }
+
+       ret = pdev->driver->sriov_configure(pdev, num_vfs);
+       if (ret < 0)
+               goto exit;
+
+       if (ret != num_vfs)
+               pci_warn(pdev, "%d VFs requested; only %d enabled\n",
+                        num_vfs, ret);
+
+exit:
+       device_unlock(&pdev->dev);
+
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static ssize_t sriov_offset_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n", pdev->sriov->offset);
+}
+
+static ssize_t sriov_stride_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n", pdev->sriov->stride);
+}
+
+static ssize_t sriov_vf_device_show(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%x\n", pdev->sriov->vf_device);
+}
+
+static ssize_t sriov_drivers_autoprobe_show(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n", pdev->sriov->drivers_autoprobe);
+}
+
+static ssize_t sriov_drivers_autoprobe_store(struct device *dev,
+                                            struct device_attribute *attr,
+                                            const char *buf, size_t count)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       bool drivers_autoprobe;
+
+       if (kstrtobool(buf, &drivers_autoprobe) < 0)
+               return -EINVAL;
+
+       pdev->sriov->drivers_autoprobe = drivers_autoprobe;
+
+       return count;
+}
+
+static DEVICE_ATTR_RO(sriov_totalvfs);
+static DEVICE_ATTR_RW(sriov_numvfs);
+static DEVICE_ATTR_RO(sriov_offset);
+static DEVICE_ATTR_RO(sriov_stride);
+static DEVICE_ATTR_RO(sriov_vf_device);
+static DEVICE_ATTR_RW(sriov_drivers_autoprobe);
+
+static struct attribute *sriov_dev_attrs[] = {
+       &dev_attr_sriov_totalvfs.attr,
+       &dev_attr_sriov_numvfs.attr,
+       &dev_attr_sriov_offset.attr,
+       &dev_attr_sriov_stride.attr,
+       &dev_attr_sriov_vf_device.attr,
+       &dev_attr_sriov_drivers_autoprobe.attr,
+       NULL,
+};
+
+static umode_t sriov_attrs_are_visible(struct kobject *kobj,
+                                      struct attribute *a, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+
+       if (!dev_is_pf(dev))
+               return 0;
+
+       return a->mode;
+}
+
+const struct attribute_group sriov_dev_attr_group = {
+       .attrs = sriov_dev_attrs,
+       .is_visible = sriov_attrs_are_visible,
+};
+
 int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
 {
        return 0;
@@ -557,8 +724,8 @@ static void sriov_restore_state(struct pci_dev *dev)
        ctrl |= iov->ctrl & PCI_SRIOV_CTRL_ARI;
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl);
 
-       for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++)
-               pci_update_resource(dev, i);
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
+               pci_update_resource(dev, i + PCI_IOV_RESOURCES);
 
        pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
        pci_iov_set_numvfs(dev, iov->num_VFs);
index 23447622652924e32f30a6dfe9a85c8e5aee863c..0608aae72ccccfd67e5b4187e87a02593db19485 100644 (file)
 #include <linux/percpu-refcount.h>
 #include <linux/random.h>
 #include <linux/seq_buf.h>
-#include <linux/iommu.h>
+#include <linux/xarray.h>
+
+enum pci_p2pdma_map_type {
+       PCI_P2PDMA_MAP_UNKNOWN = 0,
+       PCI_P2PDMA_MAP_NOT_SUPPORTED,
+       PCI_P2PDMA_MAP_BUS_ADDR,
+       PCI_P2PDMA_MAP_THRU_HOST_BRIDGE,
+};
 
 struct pci_p2pdma {
        struct gen_pool *pool;
        bool p2pmem_published;
+       struct xarray map_types;
 };
 
+struct pci_p2pdma_pagemap {
+       struct dev_pagemap pgmap;
+       struct pci_dev *provider;
+       u64 bus_offset;
+};
+
+static struct pci_p2pdma_pagemap *to_p2p_pgmap(struct dev_pagemap *pgmap)
+{
+       return container_of(pgmap, struct pci_p2pdma_pagemap, pgmap);
+}
+
 static ssize_t size_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
@@ -87,6 +106,7 @@ static void pci_p2pdma_release(void *data)
 
        gen_pool_destroy(p2pdma->pool);
        sysfs_remove_group(&pdev->dev.kobj, &p2pmem_group);
+       xa_destroy(&p2pdma->map_types);
 }
 
 static int pci_p2pdma_setup(struct pci_dev *pdev)
@@ -98,6 +118,8 @@ static int pci_p2pdma_setup(struct pci_dev *pdev)
        if (!p2p)
                return -ENOMEM;
 
+       xa_init(&p2p->map_types);
+
        p2p->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(&pdev->dev));
        if (!p2p->pool)
                goto out;
@@ -135,6 +157,7 @@ out:
 int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
                            u64 offset)
 {
+       struct pci_p2pdma_pagemap *p2p_pgmap;
        struct dev_pagemap *pgmap;
        void *addr;
        int error;
@@ -157,14 +180,18 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
                        return error;
        }
 
-       pgmap = devm_kzalloc(&pdev->dev, sizeof(*pgmap), GFP_KERNEL);
-       if (!pgmap)
+       p2p_pgmap = devm_kzalloc(&pdev->dev, sizeof(*p2p_pgmap), GFP_KERNEL);
+       if (!p2p_pgmap)
                return -ENOMEM;
+
+       pgmap = &p2p_pgmap->pgmap;
        pgmap->res.start = pci_resource_start(pdev, bar) + offset;
        pgmap->res.end = pgmap->res.start + size - 1;
        pgmap->res.flags = pci_resource_flags(pdev, bar);
        pgmap->type = MEMORY_DEVICE_PCI_P2PDMA;
-       pgmap->pci_p2pdma_bus_offset = pci_bus_address(pdev, bar) -
+
+       p2p_pgmap->provider = pdev;
+       p2p_pgmap->bus_offset = pci_bus_address(pdev, bar) -
                pci_resource_start(pdev, bar);
 
        addr = devm_memremap_pages(&pdev->dev, pgmap);
@@ -246,19 +273,32 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
        seq_buf_printf(buf, "%s;", pci_name(pdev));
 }
 
-/*
- * If we can't find a common upstream bridge take a look at the root
- * complex and compare it to a whitelist of known good hardware.
- */
-static bool root_complex_whitelist(struct pci_dev *dev)
+static const struct pci_p2pdma_whitelist_entry {
+       unsigned short vendor;
+       unsigned short device;
+       enum {
+               REQ_SAME_HOST_BRIDGE    = 1 << 0,
+       } flags;
+} pci_p2pdma_whitelist[] = {
+       /* AMD ZEN */
+       {PCI_VENDOR_ID_AMD,     0x1450, 0},
+
+       /* Intel Xeon E5/Core i7 */
+       {PCI_VENDOR_ID_INTEL,   0x3c00, REQ_SAME_HOST_BRIDGE},
+       {PCI_VENDOR_ID_INTEL,   0x3c01, REQ_SAME_HOST_BRIDGE},
+       /* Intel Xeon E7 v3/Xeon E5 v3/Core i7 */
+       {PCI_VENDOR_ID_INTEL,   0x2f00, REQ_SAME_HOST_BRIDGE},
+       {PCI_VENDOR_ID_INTEL,   0x2f01, REQ_SAME_HOST_BRIDGE},
+       {}
+};
+
+static bool __host_bridge_whitelist(struct pci_host_bridge *host,
+                                   bool same_host_bridge)
 {
-       struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
        struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0));
+       const struct pci_p2pdma_whitelist_entry *entry;
        unsigned short vendor, device;
 
-       if (iommu_present(dev->dev.bus))
-               return false;
-
        if (!root)
                return false;
 
@@ -266,65 +306,49 @@ static bool root_complex_whitelist(struct pci_dev *dev)
        device = root->device;
        pci_dev_put(root);
 
-       /* AMD ZEN host bridges can do peer to peer */
-       if (vendor == PCI_VENDOR_ID_AMD && device == 0x1450)
+       for (entry = pci_p2pdma_whitelist; entry->vendor; entry++) {
+               if (vendor != entry->vendor || device != entry->device)
+                       continue;
+               if (entry->flags & REQ_SAME_HOST_BRIDGE && !same_host_bridge)
+                       return false;
+
                return true;
+       }
 
        return false;
 }
 
 /*
- * Find the distance through the nearest common upstream bridge between
- * two PCI devices.
- *
- * If the two devices are the same device then 0 will be returned.
- *
- * If there are two virtual functions of the same device behind the same
- * bridge port then 2 will be returned (one step down to the PCIe switch,
- * then one step back to the same device).
- *
- * In the case where two devices are connected to the same PCIe switch, the
- * value 4 will be returned. This corresponds to the following PCI tree:
- *
- *     -+  Root Port
- *      \+ Switch Upstream Port
- *       +-+ Switch Downstream Port
- *       + \- Device A
- *       \-+ Switch Downstream Port
- *         \- Device B
- *
- * The distance is 4 because we traverse from Device A through the downstream
- * port of the switch, to the common upstream port, back up to the second
- * downstream port and then to Device B.
- *
- * Any two devices that don't have a common upstream bridge will return -1.
- * In this way devices on separate PCIe root ports will be rejected, which
- * is what we want for peer-to-peer seeing each PCIe root port defines a
- * separate hierarchy domain and there's no way to determine whether the root
- * complex supports forwarding between them.
- *
- * In the case where two devices are connected to different PCIe switches,
- * this function will still return a positive distance as long as both
- * switches eventually have a common upstream bridge. Note this covers
- * the case of using multiple PCIe switches to achieve a desired level of
- * fan-out from a root port. The exact distance will be a function of the
- * number of switches between Device A and Device B.
- *
- * If a bridge which has any ACS redirection bits set is in the path
- * then this functions will return -2. This is so we reject any
- * cases where the TLPs are forwarded up into the root complex.
- * In this case, a list of all infringing bridge addresses will be
- * populated in acs_list (assuming it's non-null) for printk purposes.
+ * If we can't find a common upstream bridge take a look at the root
+ * complex and compare it to a whitelist of known good hardware.
  */
-static int upstream_bridge_distance(struct pci_dev *provider,
-                                   struct pci_dev *client,
-                                   struct seq_buf *acs_list)
+static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b)
+{
+       struct pci_host_bridge *host_a = pci_find_host_bridge(a->bus);
+       struct pci_host_bridge *host_b = pci_find_host_bridge(b->bus);
+
+       if (host_a == host_b)
+               return __host_bridge_whitelist(host_a, true);
+
+       if (__host_bridge_whitelist(host_a, false) &&
+           __host_bridge_whitelist(host_b, false))
+               return true;
+
+       return false;
+}
+
+static enum pci_p2pdma_map_type
+__upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
+               int *dist, bool *acs_redirects, struct seq_buf *acs_list)
 {
        struct pci_dev *a = provider, *b = client, *bb;
        int dist_a = 0;
        int dist_b = 0;
        int acs_cnt = 0;
 
+       if (acs_redirects)
+               *acs_redirects = false;
+
        /*
         * Note, we don't need to take references to devices returned by
         * pci_upstream_bridge() seeing we hold a reference to a child
@@ -353,15 +377,10 @@ static int upstream_bridge_distance(struct pci_dev *provider,
                dist_a++;
        }
 
-       /*
-        * Allow the connection if both devices are on a whitelisted root
-        * complex, but add an arbitrary large value to the distance.
-        */
-       if (root_complex_whitelist(provider) &&
-           root_complex_whitelist(client))
-               return 0x1000 + dist_a + dist_b;
+       if (dist)
+               *dist = dist_a + dist_b;
 
-       return -1;
+       return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
 
 check_b_path_acs:
        bb = b;
@@ -378,33 +397,110 @@ check_b_path_acs:
                bb = pci_upstream_bridge(bb);
        }
 
-       if (acs_cnt)
-               return -2;
+       if (dist)
+               *dist = dist_a + dist_b;
+
+       if (acs_cnt) {
+               if (acs_redirects)
+                       *acs_redirects = true;
+
+               return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
+       }
+
+       return PCI_P2PDMA_MAP_BUS_ADDR;
+}
+
+static unsigned long map_types_idx(struct pci_dev *client)
+{
+       return (pci_domain_nr(client->bus) << 16) |
+               (client->bus->number << 8) | client->devfn;
+}
+
+/*
+ * Find the distance through the nearest common upstream bridge between
+ * two PCI devices.
+ *
+ * If the two devices are the same device then 0 will be returned.
+ *
+ * If there are two virtual functions of the same device behind the same
+ * bridge port then 2 will be returned (one step down to the PCIe switch,
+ * then one step back to the same device).
+ *
+ * In the case where two devices are connected to the same PCIe switch, the
+ * value 4 will be returned. This corresponds to the following PCI tree:
+ *
+ *     -+  Root Port
+ *      \+ Switch Upstream Port
+ *       +-+ Switch Downstream Port
+ *       + \- Device A
+ *       \-+ Switch Downstream Port
+ *         \- Device B
+ *
+ * The distance is 4 because we traverse from Device A through the downstream
+ * port of the switch, to the common upstream port, back up to the second
+ * downstream port and then to Device B.
+ *
+ * Any two devices that cannot communicate using p2pdma will return
+ * PCI_P2PDMA_MAP_NOT_SUPPORTED.
+ *
+ * Any two devices that have a data path that goes through the host bridge
+ * will consult a whitelist. If the host bridges are on the whitelist,
+ * this function will return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE.
+ *
+ * If either bridge is not on the whitelist this function returns
+ * PCI_P2PDMA_MAP_NOT_SUPPORTED.
+ *
+ * If a bridge which has any ACS redirection bits set is in the path,
+ * acs_redirects will be set to true. In this case, a list of all infringing
+ * bridge addresses will be populated in acs_list (assuming it's non-null)
+ * for printk purposes.
+ */
+static enum pci_p2pdma_map_type
+upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
+               int *dist, bool *acs_redirects, struct seq_buf *acs_list)
+{
+       enum pci_p2pdma_map_type map_type;
+
+       map_type = __upstream_bridge_distance(provider, client, dist,
+                                             acs_redirects, acs_list);
+
+       if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) {
+               if (!host_bridge_whitelist(provider, client))
+                       map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
+       }
+
+       if (provider->p2pdma)
+               xa_store(&provider->p2pdma->map_types, map_types_idx(client),
+                        xa_mk_value(map_type), GFP_KERNEL);
 
-       return dist_a + dist_b;
+       return map_type;
 }
 
-static int upstream_bridge_distance_warn(struct pci_dev *provider,
-                                        struct pci_dev *client)
+static enum pci_p2pdma_map_type
+upstream_bridge_distance_warn(struct pci_dev *provider, struct pci_dev *client,
+                             int *dist)
 {
        struct seq_buf acs_list;
+       bool acs_redirects;
        int ret;
 
        seq_buf_init(&acs_list, kmalloc(PAGE_SIZE, GFP_KERNEL), PAGE_SIZE);
        if (!acs_list.buffer)
                return -ENOMEM;
 
-       ret = upstream_bridge_distance(provider, client, &acs_list);
-       if (ret == -2) {
-               pci_warn(client, "cannot be used for peer-to-peer DMA as ACS redirect is set between the client and provider (%s)\n",
+       ret = upstream_bridge_distance(provider, client, dist, &acs_redirects,
+                                      &acs_list);
+       if (acs_redirects) {
+               pci_warn(client, "ACS redirect is set between the client and provider (%s)\n",
                         pci_name(provider));
                /* Drop final semicolon */
                acs_list.buffer[acs_list.len-1] = 0;
                pci_warn(client, "to disable ACS redirect for this path, add the kernel parameter: pci=disable_acs_redir=%s\n",
                         acs_list.buffer);
+       }
 
-       } else if (ret < 0) {
-               pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge\n",
+       if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED) {
+               pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
                         pci_name(provider));
        }
 
@@ -421,22 +517,22 @@ static int upstream_bridge_distance_warn(struct pci_dev *provider,
  * @num_clients: number of clients in the array
  * @verbose: if true, print warnings for devices when we return -1
  *
- * Returns -1 if any of the clients are not compatible (behind the same
- * root port as the provider), otherwise returns a positive number where
- * a lower number is the preferable choice. (If there's one client
- * that's the same as the provider it will return 0, which is best choice).
+ * Returns -1 if any of the clients are not compatible, otherwise returns a
+ * positive number where a lower number is the preferable choice. (If there's
+ * one client that's the same as the provider it will return 0, which is best
+ * choice).
  *
- * For now, "compatible" means the provider and the clients are all behind
- * the same PCI root port. This cuts out cases that may work but is safest
- * for the user. Future work can expand this to white-list root complexes that
- * can safely forward between each ports.
+ * "compatible" means the provider and the clients are either all behind
+ * the same PCI root port or the host bridges connected to each of the devices
+ * are listed in the 'pci_p2pdma_whitelist'.
  */
 int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
                             int num_clients, bool verbose)
 {
        bool not_supported = false;
        struct pci_dev *pci_client;
-       int distance = 0;
+       int total_dist = 0;
+       int distance;
        int i, ret;
 
        if (num_clients == 0)
@@ -461,26 +557,26 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
 
                if (verbose)
                        ret = upstream_bridge_distance_warn(provider,
-                                                           pci_client);
+                                       pci_client, &distance);
                else
                        ret = upstream_bridge_distance(provider, pci_client,
-                                                      NULL);
+                                                      &distance, NULL, NULL);
 
                pci_dev_put(pci_client);
 
-               if (ret < 0)
+               if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED)
                        not_supported = true;
 
                if (not_supported && !verbose)
                        break;
 
-               distance += ret;
+               total_dist += distance;
        }
 
        if (not_supported)
                return -1;
 
-       return distance;
+       return total_dist;
 }
 EXPORT_SYMBOL_GPL(pci_p2pdma_distance_many);
 
@@ -706,21 +802,19 @@ void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
 }
 EXPORT_SYMBOL_GPL(pci_p2pmem_publish);
 
-/**
- * pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA
- * @dev: device doing the DMA request
- * @sg: scatter list to map
- * @nents: elements in the scatterlist
- * @dir: DMA direction
- *
- * Scatterlists mapped with this function should not be unmapped in any way.
- *
- * Returns the number of SG entries mapped or 0 on error.
- */
-int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-                     enum dma_data_direction dir)
+static enum pci_p2pdma_map_type pci_p2pdma_map_type(struct pci_dev *provider,
+                                                   struct pci_dev *client)
+{
+       if (!provider->p2pdma)
+               return PCI_P2PDMA_MAP_NOT_SUPPORTED;
+
+       return xa_to_value(xa_load(&provider->p2pdma->map_types,
+                                  map_types_idx(client)));
+}
+
+static int __pci_p2pdma_map_sg(struct pci_p2pdma_pagemap *p2p_pgmap,
+               struct device *dev, struct scatterlist *sg, int nents)
 {
-       struct dev_pagemap *pgmap;
        struct scatterlist *s;
        phys_addr_t paddr;
        int i;
@@ -736,16 +830,80 @@ int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
                return 0;
 
        for_each_sg(sg, s, nents, i) {
-               pgmap = sg_page(s)->pgmap;
                paddr = sg_phys(s);
 
-               s->dma_address = paddr - pgmap->pci_p2pdma_bus_offset;
+               s->dma_address = paddr - p2p_pgmap->bus_offset;
                sg_dma_len(s) = s->length;
        }
 
        return nents;
 }
-EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg);
+
+/**
+ * pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA
+ * @dev: device doing the DMA request
+ * @sg: scatter list to map
+ * @nents: elements in the scatterlist
+ * @dir: DMA direction
+ * @attrs: DMA attributes passed to dma_map_sg() (if called)
+ *
+ * Scatterlists mapped with this function should be unmapped using
+ * pci_p2pdma_unmap_sg_attrs().
+ *
+ * Returns the number of SG entries mapped or 0 on error.
+ */
+int pci_p2pdma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
+               int nents, enum dma_data_direction dir, unsigned long attrs)
+{
+       struct pci_p2pdma_pagemap *p2p_pgmap =
+               to_p2p_pgmap(sg_page(sg)->pgmap);
+       struct pci_dev *client;
+
+       if (WARN_ON_ONCE(!dev_is_pci(dev)))
+               return 0;
+
+       client = to_pci_dev(dev);
+
+       switch (pci_p2pdma_map_type(p2p_pgmap->provider, client)) {
+       case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE:
+               return dma_map_sg_attrs(dev, sg, nents, dir, attrs);
+       case PCI_P2PDMA_MAP_BUS_ADDR:
+               return __pci_p2pdma_map_sg(p2p_pgmap, dev, sg, nents);
+       default:
+               WARN_ON_ONCE(1);
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg_attrs);
+
+/**
+ * pci_p2pdma_unmap_sg - unmap a PCI peer-to-peer scatterlist that was
+ *     mapped with pci_p2pdma_map_sg()
+ * @dev: device doing the DMA request
+ * @sg: scatter list to map
+ * @nents: number of elements returned by pci_p2pdma_map_sg()
+ * @dir: DMA direction
+ * @attrs: DMA attributes passed to dma_unmap_sg() (if called)
+ */
+void pci_p2pdma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
+               int nents, enum dma_data_direction dir, unsigned long attrs)
+{
+       struct pci_p2pdma_pagemap *p2p_pgmap =
+               to_p2p_pgmap(sg_page(sg)->pgmap);
+       enum pci_p2pdma_map_type map_type;
+       struct pci_dev *client;
+
+       if (WARN_ON_ONCE(!dev_is_pci(dev)))
+               return;
+
+       client = to_pci_dev(dev);
+
+       map_type = pci_p2pdma_map_type(p2p_pgmap->provider, client);
+
+       if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE)
+               dma_unmap_sg_attrs(dev, sg, nents, dir, attrs);
+}
+EXPORT_SYMBOL_GPL(pci_p2pdma_unmap_sg_attrs);
 
 /**
  * pci_p2pdma_enable_store - parse a configfs/sysfs attribute store
index 45049f558860bfb32ffc2447f4d060a28324d1ee..0c02d500158f066d93ceb07d6e5df32f28d2dd9c 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/msi.h>
 #include <linux/pci_hotplug.h>
 #include <linux/module.h>
-#include <linux/pci-aspm.h>
 #include <linux/pci-acpi.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_qos.h>
@@ -118,8 +117,58 @@ phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
        return (phys_addr_t)mcfg_addr;
 }
 
+/* _HPX PCI Setting Record (Type 0); same as _HPP */
+struct hpx_type0 {
+       u32 revision;           /* Not present in _HPP */
+       u8  cache_line_size;    /* Not applicable to PCIe */
+       u8  latency_timer;      /* Not applicable to PCIe */
+       u8  enable_serr;
+       u8  enable_perr;
+};
+
+static struct hpx_type0 pci_default_type0 = {
+       .revision = 1,
+       .cache_line_size = 8,
+       .latency_timer = 0x40,
+       .enable_serr = 0,
+       .enable_perr = 0,
+};
+
+static void program_hpx_type0(struct pci_dev *dev, struct hpx_type0 *hpx)
+{
+       u16 pci_cmd, pci_bctl;
+
+       if (!hpx)
+               hpx = &pci_default_type0;
+
+       if (hpx->revision > 1) {
+               pci_warn(dev, "PCI settings rev %d not supported; using defaults\n",
+                        hpx->revision);
+               hpx = &pci_default_type0;
+       }
+
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpx->cache_line_size);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpx->latency_timer);
+       pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
+       if (hpx->enable_serr)
+               pci_cmd |= PCI_COMMAND_SERR;
+       if (hpx->enable_perr)
+               pci_cmd |= PCI_COMMAND_PARITY;
+       pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
+
+       /* Program bridge control value */
+       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
+                                     hpx->latency_timer);
+               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
+               if (hpx->enable_perr)
+                       pci_bctl |= PCI_BRIDGE_CTL_PARITY;
+               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
+       }
+}
+
 static acpi_status decode_type0_hpx_record(union acpi_object *record,
-                                          struct hpp_type0 *hpx0)
+                                          struct hpx_type0 *hpx0)
 {
        int i;
        union acpi_object *fields = record->package.elements;
@@ -146,8 +195,30 @@ static acpi_status decode_type0_hpx_record(union acpi_object *record,
        return AE_OK;
 }
 
+/* _HPX PCI-X Setting Record (Type 1) */
+struct hpx_type1 {
+       u32 revision;
+       u8  max_mem_read;
+       u8  avg_max_split;
+       u16 tot_max_split;
+};
+
+static void program_hpx_type1(struct pci_dev *dev, struct hpx_type1 *hpx)
+{
+       int pos;
+
+       if (!hpx)
+               return;
+
+       pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+       if (!pos)
+               return;
+
+       pci_warn(dev, "PCI-X settings not supported\n");
+}
+
 static acpi_status decode_type1_hpx_record(union acpi_object *record,
-                                          struct hpp_type1 *hpx1)
+                                          struct hpx_type1 *hpx1)
 {
        int i;
        union acpi_object *fields = record->package.elements;
@@ -173,8 +244,130 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record,
        return AE_OK;
 }
 
+static bool pcie_root_rcb_set(struct pci_dev *dev)
+{
+       struct pci_dev *rp = pcie_find_root_port(dev);
+       u16 lnkctl;
+
+       if (!rp)
+               return false;
+
+       pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl);
+       if (lnkctl & PCI_EXP_LNKCTL_RCB)
+               return true;
+
+       return false;
+}
+
+/* _HPX PCI Express Setting Record (Type 2) */
+struct hpx_type2 {
+       u32 revision;
+       u32 unc_err_mask_and;
+       u32 unc_err_mask_or;
+       u32 unc_err_sever_and;
+       u32 unc_err_sever_or;
+       u32 cor_err_mask_and;
+       u32 cor_err_mask_or;
+       u32 adv_err_cap_and;
+       u32 adv_err_cap_or;
+       u16 pci_exp_devctl_and;
+       u16 pci_exp_devctl_or;
+       u16 pci_exp_lnkctl_and;
+       u16 pci_exp_lnkctl_or;
+       u32 sec_unc_err_sever_and;
+       u32 sec_unc_err_sever_or;
+       u32 sec_unc_err_mask_and;
+       u32 sec_unc_err_mask_or;
+};
+
+static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx)
+{
+       int pos;
+       u32 reg32;
+
+       if (!hpx)
+               return;
+
+       if (!pci_is_pcie(dev))
+               return;
+
+       if (hpx->revision > 1) {
+               pci_warn(dev, "PCIe settings rev %d not supported\n",
+                        hpx->revision);
+               return;
+       }
+
+       /*
+        * Don't allow _HPX to change MPS or MRRS settings.  We manage
+        * those to make sure they're consistent with the rest of the
+        * platform.
+        */
+       hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD |
+                                   PCI_EXP_DEVCTL_READRQ;
+       hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD |
+                                   PCI_EXP_DEVCTL_READRQ);
+
+       /* Initialize Device Control Register */
+       pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+                       ~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or);
+
+       /* Initialize Link Control Register */
+       if (pcie_cap_has_lnkctl(dev)) {
+
+               /*
+                * If the Root Port supports Read Completion Boundary of
+                * 128, set RCB to 128.  Otherwise, clear it.
+                */
+               hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB;
+               hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB;
+               if (pcie_root_rcb_set(dev))
+                       hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB;
+
+               pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
+                       ~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or);
+       }
+
+       /* Find Advanced Error Reporting Enhanced Capability */
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (!pos)
+               return;
+
+       /* Initialize Uncorrectable Error Mask Register */
+       pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &reg32);
+       reg32 = (reg32 & hpx->unc_err_mask_and) | hpx->unc_err_mask_or;
+       pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32);
+
+       /* Initialize Uncorrectable Error Severity Register */
+       pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &reg32);
+       reg32 = (reg32 & hpx->unc_err_sever_and) | hpx->unc_err_sever_or;
+       pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32);
+
+       /* Initialize Correctable Error Mask Register */
+       pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg32);
+       reg32 = (reg32 & hpx->cor_err_mask_and) | hpx->cor_err_mask_or;
+       pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32);
+
+       /* Initialize Advanced Error Capabilities and Control Register */
+       pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
+       reg32 = (reg32 & hpx->adv_err_cap_and) | hpx->adv_err_cap_or;
+
+       /* Don't enable ECRC generation or checking if unsupported */
+       if (!(reg32 & PCI_ERR_CAP_ECRC_GENC))
+               reg32 &= ~PCI_ERR_CAP_ECRC_GENE;
+       if (!(reg32 & PCI_ERR_CAP_ECRC_CHKC))
+               reg32 &= ~PCI_ERR_CAP_ECRC_CHKE;
+       pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
+
+       /*
+        * FIXME: The following two registers are not supported yet.
+        *
+        *   o Secondary Uncorrectable Error Severity Register
+        *   o Secondary Uncorrectable Error Mask Register
+        */
+}
+
 static acpi_status decode_type2_hpx_record(union acpi_object *record,
-                                          struct hpp_type2 *hpx2)
+                                          struct hpx_type2 *hpx2)
 {
        int i;
        union acpi_object *fields = record->package.elements;
@@ -213,6 +406,164 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record,
        return AE_OK;
 }
 
+/* _HPX PCI Express Setting Record (Type 3) */
+struct hpx_type3 {
+       u16 device_type;
+       u16 function_type;
+       u16 config_space_location;
+       u16 pci_exp_cap_id;
+       u16 pci_exp_cap_ver;
+       u16 pci_exp_vendor_id;
+       u16 dvsec_id;
+       u16 dvsec_rev;
+       u16 match_offset;
+       u32 match_mask_and;
+       u32 match_value;
+       u16 reg_offset;
+       u32 reg_mask_and;
+       u32 reg_mask_or;
+};
+
+enum hpx_type3_dev_type {
+       HPX_TYPE_ENDPOINT       = BIT(0),
+       HPX_TYPE_LEG_END        = BIT(1),
+       HPX_TYPE_RC_END         = BIT(2),
+       HPX_TYPE_RC_EC          = BIT(3),
+       HPX_TYPE_ROOT_PORT      = BIT(4),
+       HPX_TYPE_UPSTREAM       = BIT(5),
+       HPX_TYPE_DOWNSTREAM     = BIT(6),
+       HPX_TYPE_PCI_BRIDGE     = BIT(7),
+       HPX_TYPE_PCIE_BRIDGE    = BIT(8),
+};
+
+static u16 hpx3_device_type(struct pci_dev *dev)
+{
+       u16 pcie_type = pci_pcie_type(dev);
+       const int pcie_to_hpx3_type[] = {
+               [PCI_EXP_TYPE_ENDPOINT]    = HPX_TYPE_ENDPOINT,
+               [PCI_EXP_TYPE_LEG_END]     = HPX_TYPE_LEG_END,
+               [PCI_EXP_TYPE_RC_END]      = HPX_TYPE_RC_END,
+               [PCI_EXP_TYPE_RC_EC]       = HPX_TYPE_RC_EC,
+               [PCI_EXP_TYPE_ROOT_PORT]   = HPX_TYPE_ROOT_PORT,
+               [PCI_EXP_TYPE_UPSTREAM]    = HPX_TYPE_UPSTREAM,
+               [PCI_EXP_TYPE_DOWNSTREAM]  = HPX_TYPE_DOWNSTREAM,
+               [PCI_EXP_TYPE_PCI_BRIDGE]  = HPX_TYPE_PCI_BRIDGE,
+               [PCI_EXP_TYPE_PCIE_BRIDGE] = HPX_TYPE_PCIE_BRIDGE,
+       };
+
+       if (pcie_type >= ARRAY_SIZE(pcie_to_hpx3_type))
+               return 0;
+
+       return pcie_to_hpx3_type[pcie_type];
+}
+
+enum hpx_type3_fn_type {
+       HPX_FN_NORMAL           = BIT(0),
+       HPX_FN_SRIOV_PHYS       = BIT(1),
+       HPX_FN_SRIOV_VIRT       = BIT(2),
+};
+
+static u8 hpx3_function_type(struct pci_dev *dev)
+{
+       if (dev->is_virtfn)
+               return HPX_FN_SRIOV_VIRT;
+       else if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV) > 0)
+               return HPX_FN_SRIOV_PHYS;
+       else
+               return HPX_FN_NORMAL;
+}
+
+static bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id)
+{
+       u8 cap_ver = hpx3_cap_id & 0xf;
+
+       if ((hpx3_cap_id & BIT(4)) && cap_ver >= pcie_cap_id)
+               return true;
+       else if (cap_ver == pcie_cap_id)
+               return true;
+
+       return false;
+}
+
+enum hpx_type3_cfg_loc {
+       HPX_CFG_PCICFG          = 0,
+       HPX_CFG_PCIE_CAP        = 1,
+       HPX_CFG_PCIE_CAP_EXT    = 2,
+       HPX_CFG_VEND_CAP        = 3,
+       HPX_CFG_DVSEC           = 4,
+       HPX_CFG_MAX,
+};
+
+static void program_hpx_type3_register(struct pci_dev *dev,
+                                      const struct hpx_type3 *reg)
+{
+       u32 match_reg, write_reg, header, orig_value;
+       u16 pos;
+
+       if (!(hpx3_device_type(dev) & reg->device_type))
+               return;
+
+       if (!(hpx3_function_type(dev) & reg->function_type))
+               return;
+
+       switch (reg->config_space_location) {
+       case HPX_CFG_PCICFG:
+               pos = 0;
+               break;
+       case HPX_CFG_PCIE_CAP:
+               pos = pci_find_capability(dev, reg->pci_exp_cap_id);
+               if (pos == 0)
+                       return;
+
+               break;
+       case HPX_CFG_PCIE_CAP_EXT:
+               pos = pci_find_ext_capability(dev, reg->pci_exp_cap_id);
+               if (pos == 0)
+                       return;
+
+               pci_read_config_dword(dev, pos, &header);
+               if (!hpx3_cap_ver_matches(PCI_EXT_CAP_VER(header),
+                                         reg->pci_exp_cap_ver))
+                       return;
+
+               break;
+       case HPX_CFG_VEND_CAP:  /* Fall through */
+       case HPX_CFG_DVSEC:     /* Fall through */
+       default:
+               pci_warn(dev, "Encountered _HPX type 3 with unsupported config space location");
+               return;
+       }
+
+       pci_read_config_dword(dev, pos + reg->match_offset, &match_reg);
+
+       if ((match_reg & reg->match_mask_and) != reg->match_value)
+               return;
+
+       pci_read_config_dword(dev, pos + reg->reg_offset, &write_reg);
+       orig_value = write_reg;
+       write_reg &= reg->reg_mask_and;
+       write_reg |= reg->reg_mask_or;
+
+       if (orig_value == write_reg)
+               return;
+
+       pci_write_config_dword(dev, pos + reg->reg_offset, write_reg);
+
+       pci_dbg(dev, "Applied _HPX3 at [0x%x]: 0x%08x -> 0x%08x",
+               pos, orig_value, write_reg);
+}
+
+static void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx)
+{
+       if (!hpx)
+               return;
+
+       if (!pci_is_pcie(dev))
+               return;
+
+       program_hpx_type3_register(dev, hpx);
+}
+
 static void parse_hpx3_register(struct hpx_type3 *hpx3_reg,
                                union acpi_object *reg_fields)
 {
@@ -233,8 +584,7 @@ static void parse_hpx3_register(struct hpx_type3 *hpx3_reg,
 }
 
 static acpi_status program_type3_hpx_record(struct pci_dev *dev,
-                                          union acpi_object *record,
-                                          const struct hotplug_program_ops *hp_ops)
+                                          union acpi_object *record)
 {
        union acpi_object *fields = record->package.elements;
        u32 desc_count, expected_length, revision;
@@ -258,7 +608,7 @@ static acpi_status program_type3_hpx_record(struct pci_dev *dev,
                for (i = 0; i < desc_count; i++) {
                        reg_fields = fields + 3 + i * 14;
                        parse_hpx3_register(&hpx3, reg_fields);
-                       hp_ops->program_type3(dev, &hpx3);
+                       program_hpx_type3(dev, &hpx3);
                }
 
                break;
@@ -271,15 +621,14 @@ static acpi_status program_type3_hpx_record(struct pci_dev *dev,
        return AE_OK;
 }
 
-static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle,
-                               const struct hotplug_program_ops *hp_ops)
+static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle)
 {
        acpi_status status;
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
        union acpi_object *package, *record, *fields;
-       struct hpp_type0 hpx0;
-       struct hpp_type1 hpx1;
-       struct hpp_type2 hpx2;
+       struct hpx_type0 hpx0;
+       struct hpx_type1 hpx1;
+       struct hpx_type2 hpx2;
        u32 type;
        int i;
 
@@ -314,24 +663,24 @@ static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle,
                        status = decode_type0_hpx_record(record, &hpx0);
                        if (ACPI_FAILURE(status))
                                goto exit;
-                       hp_ops->program_type0(dev, &hpx0);
+                       program_hpx_type0(dev, &hpx0);
                        break;
                case 1:
                        memset(&hpx1, 0, sizeof(hpx1));
                        status = decode_type1_hpx_record(record, &hpx1);
                        if (ACPI_FAILURE(status))
                                goto exit;
-                       hp_ops->program_type1(dev, &hpx1);
+                       program_hpx_type1(dev, &hpx1);
                        break;
                case 2:
                        memset(&hpx2, 0, sizeof(hpx2));
                        status = decode_type2_hpx_record(record, &hpx2);
                        if (ACPI_FAILURE(status))
                                goto exit;
-                       hp_ops->program_type2(dev, &hpx2);
+                       program_hpx_type2(dev, &hpx2);
                        break;
                case 3:
-                       status = program_type3_hpx_record(dev, record, hp_ops);
+                       status = program_type3_hpx_record(dev, record);
                        if (ACPI_FAILURE(status))
                                goto exit;
                        break;
@@ -347,16 +696,15 @@ static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle,
        return status;
 }
 
-static acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle,
-                               const struct hotplug_program_ops *hp_ops)
+static acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle)
 {
        acpi_status status;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *package, *fields;
-       struct hpp_type0 hpp0;
+       struct hpx_type0 hpx0;
        int i;
 
-       memset(&hpp0, 0, sizeof(hpp0));
+       memset(&hpx0, 0, sizeof(hpx0));
 
        status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
        if (ACPI_FAILURE(status))
@@ -377,26 +725,24 @@ static acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle,
                }
        }
 
-       hpp0.revision        = 1;
-       hpp0.cache_line_size = fields[0].integer.value;
-       hpp0.latency_timer   = fields[1].integer.value;
-       hpp0.enable_serr     = fields[2].integer.value;
-       hpp0.enable_perr     = fields[3].integer.value;
+       hpx0.revision        = 1;
+       hpx0.cache_line_size = fields[0].integer.value;
+       hpx0.latency_timer   = fields[1].integer.value;
+       hpx0.enable_serr     = fields[2].integer.value;
+       hpx0.enable_perr     = fields[3].integer.value;
 
-       hp_ops->program_type0(dev, &hpp0);
+       program_hpx_type0(dev, &hpx0);
 
 exit:
        kfree(buffer.pointer);
        return status;
 }
 
-/* pci_get_hp_params
+/* pci_acpi_program_hp_params
  *
  * @dev - the pci_dev for which we want parameters
- * @hpp - allocated by the caller
  */
-int pci_acpi_program_hp_params(struct pci_dev *dev,
-                              const struct hotplug_program_ops *hp_ops)
+int pci_acpi_program_hp_params(struct pci_dev *dev)
 {
        acpi_status status;
        acpi_handle handle, phandle;
@@ -419,10 +765,10 @@ int pci_acpi_program_hp_params(struct pci_dev *dev,
         * this pci dev.
         */
        while (handle) {
-               status = acpi_run_hpx(dev, handle, hp_ops);
+               status = acpi_run_hpx(dev, handle);
                if (ACPI_SUCCESS(status))
                        return 0;
-               status = acpi_run_hpp(dev, handle, hp_ops);
+               status = acpi_run_hpp(dev, handle);
                if (ACPI_SUCCESS(status))
                        return 0;
                if (acpi_is_root_bridge(handle))
index 06083b86d4f45607271c318088d03bc50ddfc4b5..5fd90105510d93c89e01c5550b5cfe2c689886c5 100644 (file)
@@ -38,7 +38,7 @@ struct pci_bridge_reg_behavior {
        u32 rsvd;
 };
 
-const static struct pci_bridge_reg_behavior pci_regs_behavior[] = {
+static const struct pci_bridge_reg_behavior pci_regs_behavior[] = {
        [PCI_VENDOR_ID / 4] = { .ro = ~0 },
        [PCI_COMMAND / 4] = {
                .rw = (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
@@ -173,7 +173,7 @@ const static struct pci_bridge_reg_behavior pci_regs_behavior[] = {
        },
 };
 
-const static struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = {
+static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = {
        [PCI_CAP_LIST_ID / 4] = {
                /*
                 * Capability ID, Next Capability Pointer and
index 965c721041508328702a0d97696672c692632476..868e351092844f8bf63f3c730cf50226833efea7 100644 (file)
@@ -464,9 +464,7 @@ static ssize_t dev_rescan_store(struct device *dev,
        }
        return count;
 }
-static struct device_attribute dev_rescan_attr = __ATTR(rescan,
-                                                       (S_IWUSR|S_IWGRP),
-                                                       NULL, dev_rescan_store);
+static DEVICE_ATTR_WO(dev_rescan);
 
 static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
@@ -480,13 +478,12 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
                pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
        return count;
 }
-static struct device_attribute dev_remove_attr = __ATTR_IGNORE_LOCKDEP(remove,
-                                                       (S_IWUSR|S_IWGRP),
-                                                       NULL, remove_store);
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0220, NULL,
+                                 remove_store);
 
-static ssize_t dev_bus_rescan_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
+static ssize_t bus_rescan_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
 {
        unsigned long val;
        struct pci_bus *bus = to_pci_bus(dev);
@@ -504,7 +501,7 @@ static ssize_t dev_bus_rescan_store(struct device *dev,
        }
        return count;
 }
-static DEVICE_ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store);
+static DEVICE_ATTR_WO(bus_rescan);
 
 #if defined(CONFIG_PM) && defined(CONFIG_ACPI)
 static ssize_t d3cold_allowed_store(struct device *dev,
@@ -551,154 +548,6 @@ static ssize_t devspec_show(struct device *dev,
 static DEVICE_ATTR_RO(devspec);
 #endif
 
-#ifdef CONFIG_PCI_IOV
-static ssize_t sriov_totalvfs_show(struct device *dev,
-                                  struct device_attribute *attr,
-                                  char *buf)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-
-       return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev));
-}
-
-
-static ssize_t sriov_numvfs_show(struct device *dev,
-                                struct device_attribute *attr,
-                                char *buf)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-
-       return sprintf(buf, "%u\n", pdev->sriov->num_VFs);
-}
-
-/*
- * num_vfs > 0; number of VFs to enable
- * num_vfs = 0; disable all VFs
- *
- * Note: SRIOV spec doesn't allow partial VF
- *       disable, so it's all or none.
- */
-static ssize_t sriov_numvfs_store(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       int ret;
-       u16 num_vfs;
-
-       ret = kstrtou16(buf, 0, &num_vfs);
-       if (ret < 0)
-               return ret;
-
-       if (num_vfs > pci_sriov_get_totalvfs(pdev))
-               return -ERANGE;
-
-       device_lock(&pdev->dev);
-
-       if (num_vfs == pdev->sriov->num_VFs)
-               goto exit;
-
-       /* is PF driver loaded w/callback */
-       if (!pdev->driver || !pdev->driver->sriov_configure) {
-               pci_info(pdev, "Driver doesn't support SRIOV configuration via sysfs\n");
-               ret = -ENOENT;
-               goto exit;
-       }
-
-       if (num_vfs == 0) {
-               /* disable VFs */
-               ret = pdev->driver->sriov_configure(pdev, 0);
-               goto exit;
-       }
-
-       /* enable VFs */
-       if (pdev->sriov->num_VFs) {
-               pci_warn(pdev, "%d VFs already enabled. Disable before enabling %d VFs\n",
-                        pdev->sriov->num_VFs, num_vfs);
-               ret = -EBUSY;
-               goto exit;
-       }
-
-       ret = pdev->driver->sriov_configure(pdev, num_vfs);
-       if (ret < 0)
-               goto exit;
-
-       if (ret != num_vfs)
-               pci_warn(pdev, "%d VFs requested; only %d enabled\n",
-                        num_vfs, ret);
-
-exit:
-       device_unlock(&pdev->dev);
-
-       if (ret < 0)
-               return ret;
-
-       return count;
-}
-
-static ssize_t sriov_offset_show(struct device *dev,
-                                struct device_attribute *attr,
-                                char *buf)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-
-       return sprintf(buf, "%u\n", pdev->sriov->offset);
-}
-
-static ssize_t sriov_stride_show(struct device *dev,
-                                struct device_attribute *attr,
-                                char *buf)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-
-       return sprintf(buf, "%u\n", pdev->sriov->stride);
-}
-
-static ssize_t sriov_vf_device_show(struct device *dev,
-                                   struct device_attribute *attr,
-                                   char *buf)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-
-       return sprintf(buf, "%x\n", pdev->sriov->vf_device);
-}
-
-static ssize_t sriov_drivers_autoprobe_show(struct device *dev,
-                                           struct device_attribute *attr,
-                                           char *buf)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-
-       return sprintf(buf, "%u\n", pdev->sriov->drivers_autoprobe);
-}
-
-static ssize_t sriov_drivers_autoprobe_store(struct device *dev,
-                                            struct device_attribute *attr,
-                                            const char *buf, size_t count)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       bool drivers_autoprobe;
-
-       if (kstrtobool(buf, &drivers_autoprobe) < 0)
-               return -EINVAL;
-
-       pdev->sriov->drivers_autoprobe = drivers_autoprobe;
-
-       return count;
-}
-
-static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs);
-static struct device_attribute sriov_numvfs_attr =
-               __ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP),
-                      sriov_numvfs_show, sriov_numvfs_store);
-static struct device_attribute sriov_offset_attr = __ATTR_RO(sriov_offset);
-static struct device_attribute sriov_stride_attr = __ATTR_RO(sriov_stride);
-static struct device_attribute sriov_vf_device_attr = __ATTR_RO(sriov_vf_device);
-static struct device_attribute sriov_drivers_autoprobe_attr =
-               __ATTR(sriov_drivers_autoprobe, (S_IRUGO|S_IWUSR|S_IWGRP),
-                      sriov_drivers_autoprobe_show, sriov_drivers_autoprobe_store);
-#endif /* CONFIG_PCI_IOV */
-
 static ssize_t driver_override_store(struct device *dev,
                                     struct device_attribute *attr,
                                     const char *buf, size_t count)
@@ -792,7 +641,7 @@ static struct attribute *pcie_dev_attrs[] = {
 };
 
 static struct attribute *pcibus_attrs[] = {
-       &dev_attr_rescan.attr,
+       &dev_attr_bus_rescan.attr,
        &dev_attr_cpuaffinity.attr,
        &dev_attr_cpulistaffinity.attr,
        NULL,
@@ -820,7 +669,7 @@ static ssize_t boot_vga_show(struct device *dev, struct device_attribute *attr,
                !!(pdev->resource[PCI_ROM_RESOURCE].flags &
                   IORESOURCE_ROM_SHADOW));
 }
-static struct device_attribute vga_attr = __ATTR_RO(boot_vga);
+static DEVICE_ATTR_RO(boot_vga);
 
 static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
                               struct bin_attribute *bin_attr, char *buf,
@@ -1085,7 +934,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        sysfs_bin_attr_init(b->legacy_io);
        b->legacy_io->attr.name = "legacy_io";
        b->legacy_io->size = 0xffff;
-       b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
+       b->legacy_io->attr.mode = 0600;
        b->legacy_io->read = pci_read_legacy_io;
        b->legacy_io->write = pci_write_legacy_io;
        b->legacy_io->mmap = pci_mmap_legacy_io;
@@ -1099,7 +948,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        sysfs_bin_attr_init(b->legacy_mem);
        b->legacy_mem->attr.name = "legacy_mem";
        b->legacy_mem->size = 1024*1024;
-       b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
+       b->legacy_mem->attr.mode = 0600;
        b->legacy_mem->mmap = pci_mmap_legacy_mem;
        pci_adjust_legacy_attr(b, pci_mmap_mem);
        error = device_create_bin_file(&b->dev, b->legacy_mem);
@@ -1306,7 +1155,7 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
                }
        }
        res_attr->attr.name = res_attr_name;
-       res_attr->attr.mode = S_IRUSR | S_IWUSR;
+       res_attr->attr.mode = 0600;
        res_attr->size = pci_resource_len(pdev, num);
        res_attr->private = (void *)(unsigned long)num;
        retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
@@ -1419,7 +1268,7 @@ static ssize_t pci_read_rom(struct file *filp, struct kobject *kobj,
 static const struct bin_attribute pci_config_attr = {
        .attr = {
                .name = "config",
-               .mode = S_IRUGO | S_IWUSR,
+               .mode = 0644,
        },
        .size = PCI_CFG_SPACE_SIZE,
        .read = pci_read_config,
@@ -1429,7 +1278,7 @@ static const struct bin_attribute pci_config_attr = {
 static const struct bin_attribute pcie_config_attr = {
        .attr = {
                .name = "config",
-               .mode = S_IRUGO | S_IWUSR,
+               .mode = 0644,
        },
        .size = PCI_CFG_SPACE_EXP_SIZE,
        .read = pci_read_config,
@@ -1458,7 +1307,7 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_store);
+static DEVICE_ATTR(reset, 0200, NULL, reset_store);
 
 static int pci_create_capabilities_sysfs(struct pci_dev *dev)
 {
@@ -1468,7 +1317,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
        pcie_aspm_create_sysfs_dev_files(dev);
 
        if (dev->reset_fn) {
-               retval = device_create_file(&dev->dev, &reset_attr);
+               retval = device_create_file(&dev->dev, &dev_attr_reset);
                if (retval)
                        goto error;
        }
@@ -1511,7 +1360,7 @@ int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
                sysfs_bin_attr_init(attr);
                attr->size = rom_size;
                attr->attr.name = "rom";
-               attr->attr.mode = S_IRUSR | S_IWUSR;
+               attr->attr.mode = 0600;
                attr->read = pci_read_rom;
                attr->write = pci_write_rom;
                retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
@@ -1553,7 +1402,7 @@ static void pci_remove_capabilities_sysfs(struct pci_dev *dev)
        pcie_vpd_remove_sysfs_dev_files(dev);
        pcie_aspm_remove_sysfs_dev_files(dev);
        if (dev->reset_fn) {
-               device_remove_file(&dev->dev, &reset_attr);
+               device_remove_file(&dev->dev, &dev_attr_reset);
                dev->reset_fn = 0;
        }
 }
@@ -1606,7 +1455,7 @@ static int __init pci_sysfs_init(void)
 late_initcall(pci_sysfs_init);
 
 static struct attribute *pci_dev_dev_attrs[] = {
-       &vga_attr.attr,
+       &dev_attr_boot_vga.attr,
        NULL,
 };
 
@@ -1616,7 +1465,7 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
        struct device *dev = kobj_to_dev(kobj);
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       if (a == &vga_attr.attr)
+       if (a == &dev_attr_boot_vga.attr)
                if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
                        return 0;
 
@@ -1624,8 +1473,8 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
 }
 
 static struct attribute *pci_dev_hp_attrs[] = {
-       &dev_remove_attr.attr,
-       &dev_rescan_attr.attr,
+       &dev_attr_remove.attr,
+       &dev_attr_dev_rescan.attr,
        NULL,
 };
 
@@ -1697,34 +1546,6 @@ static const struct attribute_group pci_dev_hp_attr_group = {
        .is_visible = pci_dev_hp_attrs_are_visible,
 };
 
-#ifdef CONFIG_PCI_IOV
-static struct attribute *sriov_dev_attrs[] = {
-       &sriov_totalvfs_attr.attr,
-       &sriov_numvfs_attr.attr,
-       &sriov_offset_attr.attr,
-       &sriov_stride_attr.attr,
-       &sriov_vf_device_attr.attr,
-       &sriov_drivers_autoprobe_attr.attr,
-       NULL,
-};
-
-static umode_t sriov_attrs_are_visible(struct kobject *kobj,
-                                      struct attribute *a, int n)
-{
-       struct device *dev = kobj_to_dev(kobj);
-
-       if (!dev_is_pf(dev))
-               return 0;
-
-       return a->mode;
-}
-
-static const struct attribute_group sriov_dev_attr_group = {
-       .attrs = sriov_dev_attrs,
-       .is_visible = sriov_attrs_are_visible,
-};
-#endif /* CONFIG_PCI_IOV */
-
 static const struct attribute_group pci_dev_attr_group = {
        .attrs = pci_dev_dev_attrs,
        .is_visible = pci_dev_attrs_are_visible,
index 29ed5ec1ac27bf1c1d0b2d4028123a992594a513..80fe2d24fa37afaccc1dc7ea2309e92f8940d660 100644 (file)
@@ -890,8 +890,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
 
        pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
        dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
-       if (dev->current_state != state && printk_ratelimit())
-               pci_info(dev, "Refused to change power state, currently in D%d\n",
+       if (dev->current_state != state)
+               pci_info_ratelimited(dev, "Refused to change power state, currently in D%d\n",
                         dev->current_state);
 
        /*
@@ -1438,7 +1438,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev)
                pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
                bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
                res = pdev->resource + bar_idx;
-               size = order_base_2((resource_size(res) >> 20) | 1) - 1;
+               size = ilog2(resource_size(res)) - 20;
                ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
                ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
                pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
@@ -3576,7 +3576,7 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
                }
 
                /* Ensure upstream ports don't block AtomicOps on egress */
-               if (!bridge->has_secondary_link) {
+               if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) {
                        pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2,
                                                   &ctl2);
                        if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK)
@@ -5932,8 +5932,19 @@ resource_size_t __weak pcibios_default_alignment(void)
        return 0;
 }
 
-#define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE
-static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0};
+/*
+ * Arches that don't want to expose struct resource to userland as-is in
+ * sysfs and /proc can implement their own pci_resource_to_user().
+ */
+void __weak pci_resource_to_user(const struct pci_dev *dev, int bar,
+                                const struct resource *rsrc,
+                                resource_size_t *start, resource_size_t *end)
+{
+       *start = rsrc->start;
+       *end = rsrc->end;
+}
+
+static char *resource_alignment_param;
 static DEFINE_SPINLOCK(resource_alignment_lock);
 
 /**
@@ -5954,7 +5965,7 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
 
        spin_lock(&resource_alignment_lock);
        p = resource_alignment_param;
-       if (!*p && !align)
+       if (!p || !*p)
                goto out;
        if (pci_has_flag(PCI_PROBE_ONLY)) {
                align = 0;
@@ -6118,35 +6129,41 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
        }
 }
 
-static ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
+static ssize_t resource_alignment_show(struct bus_type *bus, char *buf)
 {
-       if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
-               count = RESOURCE_ALIGNMENT_PARAM_SIZE - 1;
-       spin_lock(&resource_alignment_lock);
-       strncpy(resource_alignment_param, buf, count);
-       resource_alignment_param[count] = '\0';
-       spin_unlock(&resource_alignment_lock);
-       return count;
-}
+       size_t count = 0;
 
-static ssize_t pci_get_resource_alignment_param(char *buf, size_t size)
-{
-       size_t count;
        spin_lock(&resource_alignment_lock);
-       count = snprintf(buf, size, "%s", resource_alignment_param);
+       if (resource_alignment_param)
+               count = snprintf(buf, PAGE_SIZE, "%s", resource_alignment_param);
        spin_unlock(&resource_alignment_lock);
-       return count;
-}
 
-static ssize_t resource_alignment_show(struct bus_type *bus, char *buf)
-{
-       return pci_get_resource_alignment_param(buf, PAGE_SIZE);
+       /*
+        * When set by the command line, resource_alignment_param will not
+        * have a trailing line feed, which is ugly. So conditionally add
+        * it here.
+        */
+       if (count >= 2 && buf[count - 2] != '\n' && count < PAGE_SIZE - 1) {
+               buf[count - 1] = '\n';
+               buf[count++] = 0;
+       }
+
+       return count;
 }
 
 static ssize_t resource_alignment_store(struct bus_type *bus,
                                        const char *buf, size_t count)
 {
-       return pci_set_resource_alignment_param(buf, count);
+       char *param = kstrndup(buf, count, GFP_KERNEL);
+
+       if (!param)
+               return -ENOMEM;
+
+       spin_lock(&resource_alignment_lock);
+       kfree(resource_alignment_param);
+       resource_alignment_param = param;
+       spin_unlock(&resource_alignment_lock);
+       return count;
 }
 
 static BUS_ATTR_RW(resource_alignment);
@@ -6275,8 +6292,7 @@ static int __init pci_setup(char *str)
                        } else if (!strncmp(str, "cbmemsize=", 10)) {
                                pci_cardbus_mem_size = memparse(str + 10, &str);
                        } else if (!strncmp(str, "resource_alignment=", 19)) {
-                               pci_set_resource_alignment_param(str + 19,
-                                                       strlen(str + 19));
+                               resource_alignment_param = str + 19;
                        } else if (!strncmp(str, "ecrc=", 5)) {
                                pcie_ecrc_get_policy(str + 5);
                        } else if (!strncmp(str, "hpiosize=", 9)) {
@@ -6311,15 +6327,18 @@ static int __init pci_setup(char *str)
 early_param("pci", pci_setup);
 
 /*
- * 'disable_acs_redir_param' is initialized in pci_setup(), above, to point
- * to data in the __initdata section which will be freed after the init
- * sequence is complete. We can't allocate memory in pci_setup() because some
- * architectures do not have any memory allocation service available during
- * an early_param() call. So we allocate memory and copy the variable here
- * before the init section is freed.
+ * 'resource_alignment_param' and 'disable_acs_redir_param' are initialized
+ * in pci_setup(), above, to point to data in the __initdata section which
+ * will be freed after the init sequence is complete. We can't allocate memory
+ * in pci_setup() because some architectures do not have any memory allocation
+ * service available during an early_param() call. So we allocate memory and
+ * copy the variable here before the init section is freed.
+ *
  */
 static int __init pci_realloc_setup_params(void)
 {
+       resource_alignment_param = kstrdup(resource_alignment_param,
+                                          GFP_KERNEL);
        disable_acs_redir_param = kstrdup(disable_acs_redir_param, GFP_KERNEL);
 
        return 0;
index 1be03a97cb92c1ce9486a4b6ea0f037f7c18067f..0113343cfd1e7eae8adf7595e93a876786d96ef4 100644 (file)
@@ -39,6 +39,11 @@ 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
+
 /**
  * struct pci_platform_pm_ops - Firmware PM callbacks
  *
@@ -84,6 +89,8 @@ void pci_power_up(struct pci_dev *dev);
 void pci_disable_enabled_device(struct pci_dev *dev);
 int pci_finish_runtime_suspend(struct pci_dev *dev);
 void pcie_clear_root_pme_status(struct pci_dev *dev);
+bool pci_check_pme_status(struct pci_dev *dev);
+void pci_pme_wakeup_bus(struct pci_bus *bus);
 int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
 void pci_pme_restore(struct pci_dev *dev);
 bool pci_dev_need_resume(struct pci_dev *dev);
@@ -118,11 +125,25 @@ static inline bool pci_power_manageable(struct pci_dev *pci_dev)
        return !pci_has_subordinate(pci_dev) || pci_dev->bridge_d3;
 }
 
+static inline bool pcie_downstream_port(const struct pci_dev *dev)
+{
+       int type = pci_pcie_type(dev);
+
+       return type == PCI_EXP_TYPE_ROOT_PORT ||
+              type == PCI_EXP_TYPE_DOWNSTREAM ||
+              type == PCI_EXP_TYPE_PCIE_BRIDGE;
+}
+
 int pci_vpd_init(struct pci_dev *dev);
 void pci_vpd_release(struct pci_dev *dev);
 void pcie_vpd_create_sysfs_dev_files(struct pci_dev *dev);
 void pcie_vpd_remove_sysfs_dev_files(struct pci_dev *dev);
 
+/* PCI Virtual Channel */
+int pci_save_vc_state(struct pci_dev *dev);
+void pci_restore_vc_state(struct pci_dev *dev);
+void pci_allocate_vc_save_buffers(struct pci_dev *dev);
+
 /* PCI /proc functions */
 #ifdef CONFIG_PROC_FS
 int pci_proc_attach_device(struct pci_dev *dev);
@@ -196,6 +217,9 @@ extern const struct attribute_group *pcibus_groups[];
 extern const struct device_type pci_dev_type;
 extern const struct attribute_group *pci_bus_groups[];
 
+extern unsigned long pci_hotplug_io_size;
+extern unsigned long pci_hotplug_mem_size;
+extern unsigned long pci_hotplug_bus_size;
 
 /**
  * pci_match_one_device - Tell if a PCI device structure has a matching
@@ -236,6 +260,9 @@ enum pci_bar_type {
        pci_bar_mem64,          /* A 64-bit memory BAR */
 };
 
+struct device *pci_get_host_bridge_device(struct pci_dev *dev);
+void pci_put_host_bridge_device(struct device *dev);
+
 int pci_configure_extended_tags(struct pci_dev *dev, void *ign);
 bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
                                int crs_timeout);
@@ -256,6 +283,8 @@ bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
 
 void pci_reassigndev_resource_alignment(struct pci_dev *dev);
 void pci_disable_bridge_window(struct pci_dev *dev);
+struct pci_bus *pci_bus_get(struct pci_bus *bus);
+void pci_bus_put(struct pci_bus *bus);
 
 /* PCIe link information */
 #define PCIE_SPEED2STR(speed) \
@@ -279,6 +308,7 @@ u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
                           enum pcie_link_width *width);
 void __pcie_print_link_status(struct pci_dev *dev, bool verbose);
 void pcie_report_downtraining(struct pci_dev *dev);
+void pcie_update_link_speed(struct pci_bus *bus, u16 link_status);
 
 /* Single Root I/O Virtualization */
 struct pci_sriov {
@@ -418,11 +448,12 @@ static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
 #endif
 
 #ifdef CONFIG_PCI_ATS
+/* Address Translation Service */
+void pci_ats_init(struct pci_dev *dev);
 void pci_restore_ats_state(struct pci_dev *dev);
 #else
-static inline void pci_restore_ats_state(struct pci_dev *dev)
-{
-}
+static inline void pci_ats_init(struct pci_dev *d) { }
+static inline void pci_restore_ats_state(struct pci_dev *dev) { }
 #endif /* CONFIG_PCI_ATS */
 
 #ifdef CONFIG_PCI_IOV
@@ -433,7 +464,7 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
 resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
 void pci_restore_iov_state(struct pci_dev *dev);
 int pci_iov_bus_range(struct pci_bus *bus);
-
+extern const struct attribute_group sriov_dev_attr_group;
 #else
 static inline int pci_iov_init(struct pci_dev *dev)
 {
@@ -519,10 +550,21 @@ static inline void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) { }
 static inline void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) { }
 #endif
 
+#ifdef CONFIG_PCIE_ECRC
+void pcie_set_ecrc_checking(struct pci_dev *dev);
+void pcie_ecrc_get_policy(char *str);
+#else
+static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { }
+static inline void pcie_ecrc_get_policy(char *str) { }
+#endif
+
 #ifdef CONFIG_PCIE_PTM
 void pci_ptm_init(struct pci_dev *dev);
+int pci_enable_ptm(struct pci_dev *dev, u8 *granularity);
 #else
 static inline void pci_ptm_init(struct pci_dev *dev) { }
+static inline int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
+{ return -EINVAL; }
 #endif
 
 struct pci_dev_reset_methods {
@@ -559,6 +601,10 @@ struct device_node;
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
 int of_get_pci_domain_nr(struct device_node *node);
 int of_pci_get_max_link_speed(struct device_node *node);
+void pci_set_of_node(struct pci_dev *dev);
+void pci_release_of_node(struct pci_dev *dev);
+void pci_set_bus_of_node(struct pci_bus *bus);
+void pci_release_bus_of_node(struct pci_bus *bus);
 
 #else
 static inline int
@@ -578,6 +624,11 @@ of_pci_get_max_link_speed(struct device_node *node)
 {
        return -EINVAL;
 }
+
+static inline void pci_set_of_node(struct pci_dev *dev) { }
+static inline void pci_release_of_node(struct pci_dev *dev) { }
+static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
+static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
 #endif /* CONFIG_OF */
 
 #if defined(CONFIG_OF_ADDRESS)
@@ -608,4 +659,13 @@ static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
 static inline void pci_aer_clear_device_status(struct pci_dev *dev) { }
 #endif
 
+#ifdef CONFIG_ACPI
+int pci_acpi_program_hp_params(struct pci_dev *dev);
+#else
+static inline int pci_acpi_program_hp_params(struct pci_dev *dev)
+{
+       return -ENODEV;
+}
+#endif
+
 #endif /* DRIVERS_PCI_H */
index e44af7f4d37ff48c050daeaeab33326ec1a52067..55a6951cedd167d2a26e983eef993dbb555fdb20 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/delay.h>
-#include <linux/pci-aspm.h>
 #include "../pci.h"
 
 #ifdef MODULE_PARAM_PREFIX
@@ -913,10 +912,10 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
 
        /*
         * We allocate pcie_link_state for the component on the upstream
-        * end of a Link, so there's nothing to do unless this device has a
-        * Link on its secondary side.
+        * end of a Link, so there's nothing to do unless this device is
+        * downstream port.
         */
-       if (!pdev->has_secondary_link)
+       if (!pcie_downstream_port(pdev))
                return;
 
        /* VIA has a strange chipset, root port is under a bridge */
@@ -1070,7 +1069,7 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
        if (!pci_is_pcie(pdev))
                return 0;
 
-       if (pdev->has_secondary_link)
+       if (pcie_downstream_port(pdev))
                parent = pdev;
        if (!parent || !parent->link_state)
                return -EINVAL;
index 773197a12568e1e9d2ebcb1dd4e707de059ccec5..b0e6048a9208d1eef95134a83b35ae17b8f78cf0 100644 (file)
@@ -166,7 +166,7 @@ static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service)
        driver = pcie_port_find_service(dev, service);
        if (driver && driver->reset_link) {
                status = driver->reset_link(dev);
-       } else if (dev->has_secondary_link) {
+       } else if (pcie_downstream_port(dev)) {
                status = default_reset_link(dev);
        } else {
                pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n",
index a3c7338fad86413374f0f40c19df6974f82acd46..3bfa57d58402bd8a09a5a346025fa9edb03015e3 100644 (file)
@@ -1431,26 +1431,38 @@ void set_pcie_port_type(struct pci_dev *pdev)
        pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
        pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
 
+       parent = pci_upstream_bridge(pdev);
+       if (!parent)
+               return;
+
        /*
-        * A Root Port or a PCI-to-PCIe bridge is always the upstream end
-        * of a Link.  No PCIe component has two Links.  Two Links are
-        * connected by a Switch that has a Port on each Link and internal
-        * logic to connect the two Ports.
+        * Some systems do not identify their upstream/downstream ports
+        * correctly so detect impossible configurations here and correct
+        * the port type accordingly.
         */
        type = pci_pcie_type(pdev);
-       if (type == PCI_EXP_TYPE_ROOT_PORT ||
-           type == PCI_EXP_TYPE_PCIE_BRIDGE)
-               pdev->has_secondary_link = 1;
-       else if (type == PCI_EXP_TYPE_UPSTREAM ||
-                type == PCI_EXP_TYPE_DOWNSTREAM) {
-               parent = pci_upstream_bridge(pdev);
-
+       if (type == PCI_EXP_TYPE_DOWNSTREAM) {
                /*
-                * Usually there's an upstream device (Root Port or Switch
-                * Downstream Port), but we can't assume one exists.
+                * If pdev claims to be downstream port but the parent
+                * device is also downstream port assume pdev is actually
+                * upstream port.
                 */
-               if (parent && !parent->has_secondary_link)
-                       pdev->has_secondary_link = 1;
+               if (pcie_downstream_port(parent)) {
+                       pci_info(pdev, "claims to be downstream port but is acting as upstream port, correcting type\n");
+                       pdev->pcie_flags_reg &= ~PCI_EXP_FLAGS_TYPE;
+                       pdev->pcie_flags_reg |= PCI_EXP_TYPE_UPSTREAM;
+               }
+       } else if (type == PCI_EXP_TYPE_UPSTREAM) {
+               /*
+                * If pdev claims to be upstream port but the parent
+                * device is also upstream port assume pdev is actually
+                * downstream port.
+                */
+               if (pci_pcie_type(parent) == PCI_EXP_TYPE_UPSTREAM) {
+                       pci_info(pdev, "claims to be upstream port but is acting as downstream port, correcting type\n");
+                       pdev->pcie_flags_reg &= ~PCI_EXP_FLAGS_TYPE;
+                       pdev->pcie_flags_reg |= PCI_EXP_TYPE_DOWNSTREAM;
+               }
        }
 }
 
@@ -1920,275 +1932,6 @@ static void pci_configure_mps(struct pci_dev *dev)
                 p_mps, mps, mpss);
 }
 
-static struct hpp_type0 pci_default_type0 = {
-       .revision = 1,
-       .cache_line_size = 8,
-       .latency_timer = 0x40,
-       .enable_serr = 0,
-       .enable_perr = 0,
-};
-
-static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp)
-{
-       u16 pci_cmd, pci_bctl;
-
-       if (!hpp)
-               hpp = &pci_default_type0;
-
-       if (hpp->revision > 1) {
-               pci_warn(dev, "PCI settings rev %d not supported; using defaults\n",
-                        hpp->revision);
-               hpp = &pci_default_type0;
-       }
-
-       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp->cache_line_size);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp->latency_timer);
-       pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
-       if (hpp->enable_serr)
-               pci_cmd |= PCI_COMMAND_SERR;
-       if (hpp->enable_perr)
-               pci_cmd |= PCI_COMMAND_PARITY;
-       pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
-
-       /* Program bridge control value */
-       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
-               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
-                                     hpp->latency_timer);
-               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
-               if (hpp->enable_perr)
-                       pci_bctl |= PCI_BRIDGE_CTL_PARITY;
-               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
-       }
-}
-
-static void program_hpp_type1(struct pci_dev *dev, struct hpp_type1 *hpp)
-{
-       int pos;
-
-       if (!hpp)
-               return;
-
-       pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
-       if (!pos)
-               return;
-
-       pci_warn(dev, "PCI-X settings not supported\n");
-}
-
-static bool pcie_root_rcb_set(struct pci_dev *dev)
-{
-       struct pci_dev *rp = pcie_find_root_port(dev);
-       u16 lnkctl;
-
-       if (!rp)
-               return false;
-
-       pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl);
-       if (lnkctl & PCI_EXP_LNKCTL_RCB)
-               return true;
-
-       return false;
-}
-
-static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
-{
-       int pos;
-       u32 reg32;
-
-       if (!hpp)
-               return;
-
-       if (!pci_is_pcie(dev))
-               return;
-
-       if (hpp->revision > 1) {
-               pci_warn(dev, "PCIe settings rev %d not supported\n",
-                        hpp->revision);
-               return;
-       }
-
-       /*
-        * Don't allow _HPX to change MPS or MRRS settings.  We manage
-        * those to make sure they're consistent with the rest of the
-        * platform.
-        */
-       hpp->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD |
-                                   PCI_EXP_DEVCTL_READRQ;
-       hpp->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD |
-                                   PCI_EXP_DEVCTL_READRQ);
-
-       /* Initialize Device Control Register */
-       pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
-                       ~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or);
-
-       /* Initialize Link Control Register */
-       if (pcie_cap_has_lnkctl(dev)) {
-
-               /*
-                * If the Root Port supports Read Completion Boundary of
-                * 128, set RCB to 128.  Otherwise, clear it.
-                */
-               hpp->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB;
-               hpp->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB;
-               if (pcie_root_rcb_set(dev))
-                       hpp->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB;
-
-               pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
-                       ~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or);
-       }
-
-       /* Find Advanced Error Reporting Enhanced Capability */
-       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
-       if (!pos)
-               return;
-
-       /* Initialize Uncorrectable Error Mask Register */
-       pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &reg32);
-       reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or;
-       pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32);
-
-       /* Initialize Uncorrectable Error Severity Register */
-       pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &reg32);
-       reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or;
-       pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32);
-
-       /* Initialize Correctable Error Mask Register */
-       pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg32);
-       reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or;
-       pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32);
-
-       /* Initialize Advanced Error Capabilities and Control Register */
-       pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
-       reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or;
-
-       /* Don't enable ECRC generation or checking if unsupported */
-       if (!(reg32 & PCI_ERR_CAP_ECRC_GENC))
-               reg32 &= ~PCI_ERR_CAP_ECRC_GENE;
-       if (!(reg32 & PCI_ERR_CAP_ECRC_CHKC))
-               reg32 &= ~PCI_ERR_CAP_ECRC_CHKE;
-       pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
-
-       /*
-        * FIXME: The following two registers are not supported yet.
-        *
-        *   o Secondary Uncorrectable Error Severity Register
-        *   o Secondary Uncorrectable Error Mask Register
-        */
-}
-
-static u16 hpx3_device_type(struct pci_dev *dev)
-{
-       u16 pcie_type = pci_pcie_type(dev);
-       const int pcie_to_hpx3_type[] = {
-               [PCI_EXP_TYPE_ENDPOINT]    = HPX_TYPE_ENDPOINT,
-               [PCI_EXP_TYPE_LEG_END]     = HPX_TYPE_LEG_END,
-               [PCI_EXP_TYPE_RC_END]      = HPX_TYPE_RC_END,
-               [PCI_EXP_TYPE_RC_EC]       = HPX_TYPE_RC_EC,
-               [PCI_EXP_TYPE_ROOT_PORT]   = HPX_TYPE_ROOT_PORT,
-               [PCI_EXP_TYPE_UPSTREAM]    = HPX_TYPE_UPSTREAM,
-               [PCI_EXP_TYPE_DOWNSTREAM]  = HPX_TYPE_DOWNSTREAM,
-               [PCI_EXP_TYPE_PCI_BRIDGE]  = HPX_TYPE_PCI_BRIDGE,
-               [PCI_EXP_TYPE_PCIE_BRIDGE] = HPX_TYPE_PCIE_BRIDGE,
-       };
-
-       if (pcie_type >= ARRAY_SIZE(pcie_to_hpx3_type))
-               return 0;
-
-       return pcie_to_hpx3_type[pcie_type];
-}
-
-static u8 hpx3_function_type(struct pci_dev *dev)
-{
-       if (dev->is_virtfn)
-               return HPX_FN_SRIOV_VIRT;
-       else if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV) > 0)
-               return HPX_FN_SRIOV_PHYS;
-       else
-               return HPX_FN_NORMAL;
-}
-
-static bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id)
-{
-       u8 cap_ver = hpx3_cap_id & 0xf;
-
-       if ((hpx3_cap_id & BIT(4)) && cap_ver >= pcie_cap_id)
-               return true;
-       else if (cap_ver == pcie_cap_id)
-               return true;
-
-       return false;
-}
-
-static void program_hpx_type3_register(struct pci_dev *dev,
-                                      const struct hpx_type3 *reg)
-{
-       u32 match_reg, write_reg, header, orig_value;
-       u16 pos;
-
-       if (!(hpx3_device_type(dev) & reg->device_type))
-               return;
-
-       if (!(hpx3_function_type(dev) & reg->function_type))
-               return;
-
-       switch (reg->config_space_location) {
-       case HPX_CFG_PCICFG:
-               pos = 0;
-               break;
-       case HPX_CFG_PCIE_CAP:
-               pos = pci_find_capability(dev, reg->pci_exp_cap_id);
-               if (pos == 0)
-                       return;
-
-               break;
-       case HPX_CFG_PCIE_CAP_EXT:
-               pos = pci_find_ext_capability(dev, reg->pci_exp_cap_id);
-               if (pos == 0)
-                       return;
-
-               pci_read_config_dword(dev, pos, &header);
-               if (!hpx3_cap_ver_matches(PCI_EXT_CAP_VER(header),
-                                         reg->pci_exp_cap_ver))
-                       return;
-
-               break;
-       case HPX_CFG_VEND_CAP:  /* Fall through */
-       case HPX_CFG_DVSEC:     /* Fall through */
-       default:
-               pci_warn(dev, "Encountered _HPX type 3 with unsupported config space location");
-               return;
-       }
-
-       pci_read_config_dword(dev, pos + reg->match_offset, &match_reg);
-
-       if ((match_reg & reg->match_mask_and) != reg->match_value)
-               return;
-
-       pci_read_config_dword(dev, pos + reg->reg_offset, &write_reg);
-       orig_value = write_reg;
-       write_reg &= reg->reg_mask_and;
-       write_reg |= reg->reg_mask_or;
-
-       if (orig_value == write_reg)
-               return;
-
-       pci_write_config_dword(dev, pos + reg->reg_offset, write_reg);
-
-       pci_dbg(dev, "Applied _HPX3 at [0x%x]: 0x%08x -> 0x%08x",
-               pos, orig_value, write_reg);
-}
-
-static void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx3)
-{
-       if (!hpx3)
-               return;
-
-       if (!pci_is_pcie(dev))
-               return;
-
-       program_hpx_type3_register(dev, hpx3);
-}
-
 int pci_configure_extended_tags(struct pci_dev *dev, void *ign)
 {
        struct pci_host_bridge *host;
@@ -2369,13 +2112,6 @@ static void pci_configure_serr(struct pci_dev *dev)
 
 static void pci_configure_device(struct pci_dev *dev)
 {
-       static const struct hotplug_program_ops hp_ops = {
-               .program_type0 = program_hpp_type0,
-               .program_type1 = program_hpp_type1,
-               .program_type2 = program_hpp_type2,
-               .program_type3 = program_hpx_type3,
-       };
-
        pci_configure_mps(dev);
        pci_configure_extended_tags(dev, NULL);
        pci_configure_relaxed_ordering(dev);
@@ -2383,7 +2119,7 @@ static void pci_configure_device(struct pci_dev *dev)
        pci_configure_eetlp_prefix(dev);
        pci_configure_serr(dev);
 
-       pci_acpi_program_hp_params(dev, &hp_ops);
+       pci_acpi_program_hp_params(dev);
 }
 
 static void pci_release_capabilities(struct pci_dev *dev)
@@ -2764,12 +2500,8 @@ static int only_one_child(struct pci_bus *bus)
         * A PCIe Downstream Port normally leads to a Link with only Device
         * 0 on it (PCIe spec r3.1, sec 7.3.1).  As an optimization, scan
         * only for Device 0 in that situation.
-        *
-        * Checking has_secondary_link is a hack to identify Downstream
-        * Ports because sometimes Switches are configured such that the
-        * PCIe Port Type labels are backwards.
         */
-       if (bridge && pci_is_pcie(bridge) && bridge->has_secondary_link)
+       if (bridge && pci_is_pcie(bridge) && pcie_downstream_port(bridge))
                return 1;
 
        return 0;
index 168782c5d23bfe7056ce91bb6d1768389a2da3d9..304d98e0a96dda685823d474bfcd6c8532e242f1 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/delay.h>
 #include <linux/acpi.h>
 #include <linux/dmi.h>
-#include <linux/pci-aspm.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/ktime.h>
@@ -2978,6 +2977,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x10a1,
                        quirk_msi_intx_disable_qca_bug);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0xe091,
                        quirk_msi_intx_disable_qca_bug);
+
+/*
+ * Amazon's Annapurna Labs 1c36:0031 Root Ports don't support MSI-X, so it
+ * should be disabled on platforms where the device (mistakenly) advertises it.
+ *
+ * Notice that this quirk also disables MSI (which may work, but hasn't been
+ * tested), since currently there is no standard way to disable only MSI-X.
+ *
+ * The 0031 device id is reused for other non Root Port device types,
+ * therefore the quirk is registered for the PCI_CLASS_BRIDGE_PCI class.
+ */
+static void quirk_al_msi_disable(struct pci_dev *dev)
+{
+       dev->no_msi = 1;
+       pci_warn(dev, "Disabling MSI/MSI-X\n");
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031,
+                             PCI_CLASS_BRIDGE_PCI, 8, quirk_al_msi_disable);
 #endif /* CONFIG_PCI_MSI */
 
 /*
@@ -4419,6 +4436,24 @@ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags)
        return ret;
 }
 
+static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags)
+{
+       if (pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
+               return -ENOTTY;
+
+       /*
+        * Amazon's Annapurna Labs root ports don't include an ACS capability,
+        * but do include ACS-like functionality. The hardware doesn't support
+        * peer-to-peer transactions via the root port and each has a unique
+        * segment number.
+        *
+        * Additionally, the root ports cannot send traffic to each other.
+        */
+       acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+
+       return acs_flags ? 0 : 1;
+}
+
 /*
  * Sunrise Point PCH root ports implement ACS, but unfortunately as shown in
  * the datasheet (Intel 100 Series Chipset Family PCH Datasheet, Vol. 2,
@@ -4519,6 +4554,19 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
        return acs_flags ? 0 : 1;
 }
 
+static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
+{
+       /*
+        * iProc PAXB Root Ports don't advertise an ACS capability, but
+        * they do not allow peer-to-peer transactions between Root Ports.
+        * Allow each Root Port to be in a separate IOMMU group by masking
+        * SV/RR/CR/UF bits.
+        */
+       acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+
+       return acs_flags ? 0 : 1;
+}
+
 static const struct pci_dev_acs_enabled {
        u16 vendor;
        u16 device;
@@ -4612,6 +4660,9 @@ static const struct pci_dev_acs_enabled {
        { PCI_VENDOR_ID_AMPERE, 0xE00A, pci_quirk_xgene_acs },
        { PCI_VENDOR_ID_AMPERE, 0xE00B, pci_quirk_xgene_acs },
        { PCI_VENDOR_ID_AMPERE, 0xE00C, pci_quirk_xgene_acs },
+       { PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs },
+       /* Amazon Annapurna Labs */
+       { PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031, pci_quirk_al_acs },
        { 0 }
 };
 
index 7f4e65872b8daf640886d9887f9be804779f0dc4..bade14002fd8ad9afa5f3910458d4b3fcd9ea924 100644 (file)
@@ -15,7 +15,6 @@
 #include "pci.h"
 
 DECLARE_RWSEM(pci_bus_sem);
-EXPORT_SYMBOL_GPL(pci_bus_sem);
 
 /*
  * pci_for_each_dma_alias - Iterate over DMA aliases for a device
index 79b1fa6519be7bc831d53a8c1e2c7c597fbb76e1..e7dbe21705ba5b0f9c906287656bd2c03f4ece5d 100644 (file)
@@ -1662,8 +1662,8 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data)
        int i;
        bool *unassigned = data;
 
-       for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
-               struct resource *r = &dev->resource[i];
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               struct resource *r = &dev->resource[i + PCI_IOV_RESOURCES];
                struct pci_bus_region region;
 
                /* Not assigned or rejected by kernel? */
index 5acd9c02683af78dd96fffa7d8613c7fc9d582fd..9ae9fb9339e80b6136c3281bcd55cd7acbfba429 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/pci_regs.h>
 #include <linux/types.h>
 
+#include "pci.h"
+
 /**
  * pci_vc_save_restore_dwords - Save or restore a series of dwords
  * @dev: device
@@ -105,7 +107,7 @@ static void pci_vc_enable(struct pci_dev *dev, int pos, int res)
        struct pci_dev *link = NULL;
 
        /* Enable VCs from the downstream device */
-       if (!dev->has_secondary_link)
+       if (!pci_is_pcie(dev) || !pcie_downstream_port(dev))
                return;
 
        ctrl_pos = pos + PCI_VC_RES_CTRL + (res * PCI_CAP_VC_PER_VC_SIZEOF);
index 4963c2e2bd4ce292654c1445470aeff50ed808b5..7915d10f9aa103813c40709d87f014d229b25c8d 100644 (file)
@@ -571,6 +571,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, quirk_blacklist_vpd);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, PCI_ANY_ID,
                quirk_blacklist_vpd);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_QLOGIC, 0x2261, quirk_blacklist_vpd);
+/*
+ * The Amazon Annapurna Labs 0x0031 device id is reused for other non Root Port
+ * device types, so the quirk is registered for the PCI_CLASS_BRIDGE_PCI class.
+ */
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031,
+                             PCI_CLASS_BRIDGE_PCI, 8, quirk_blacklist_vpd);
 
 /*
  * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the
index 644f7f5c61a224439d1217cb3c7625f17b389cff..4a858789e6c5e32bac19172e427bc82a1013c072 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/aer.h>
-#include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
index 43a6b535077546f1d1bbabb77a15abcb7d6a8cbc..148663373f7d31961e471f594d2dcd342df7e5e9 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
index 717ba0845a2afc379bed1ea07646f07702e39773..27fdbc1654463d0d6d50781f976771270d8005f8 100644 (file)
@@ -51,7 +51,6 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/interrupt.h>
 #include <linux/aer.h>
 #include <linux/raid_class.h>
index f8a5b2a199459c71bdfa343f48a9665f34aff080..b459518ce4755db0b640d7076784cf49782e55b8 100644 (file)
@@ -112,7 +112,6 @@ struct dev_pagemap {
        struct device *dev;
        enum memory_type type;
        unsigned int flags;
-       u64 pci_p2pdma_bus_offset;
        const struct dev_pagemap_ops *ops;
 };
 
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
deleted file mode 100644 (file)
index 6706414..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *     aspm.h
- *
- *     PCI Express ASPM defines and function prototypes
- *
- *     Copyright (C) 2007 Intel Corp.
- *             Zhang Yanmin (yanmin.zhang@intel.com)
- *             Shaohua Li (shaohua.li@intel.com)
- *
- *     For more information, please consult the following manuals (look at
- *     http://www.pcisig.com/ for how to get them):
- *
- *     PCI Express Specification
- */
-
-#ifndef LINUX_ASPM_H
-#define LINUX_ASPM_H
-
-#include <linux/pci.h>
-
-#define PCIE_LINK_STATE_L0S    1
-#define PCIE_LINK_STATE_L1     2
-#define PCIE_LINK_STATE_CLKPM  4
-
-#ifdef CONFIG_PCIEASPM
-int pci_disable_link_state(struct pci_dev *pdev, int state);
-int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
-void pcie_no_aspm(void);
-#else
-static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
-{ return 0; }
-static inline void pcie_no_aspm(void) { }
-#endif
-
-#endif /* LINUX_ASPM_H */
index bca9bc3e5be7929cad7eec9987f1089173351658..8318a97c9c61e6b4caf922cce5c1da8e5a525937 100644 (file)
@@ -30,8 +30,10 @@ struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
                                         unsigned int *nents, u32 length);
 void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl);
 void pci_p2pmem_publish(struct pci_dev *pdev, bool publish);
-int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-                     enum dma_data_direction dir);
+int pci_p2pdma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
+               int nents, enum dma_data_direction dir, unsigned long attrs);
+void pci_p2pdma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
+               int nents, enum dma_data_direction dir, unsigned long attrs);
 int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev,
                            bool *use_p2pdma);
 ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev,
@@ -81,11 +83,17 @@ static inline void pci_p2pmem_free_sgl(struct pci_dev *pdev,
 static inline void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
 {
 }
-static inline int pci_p2pdma_map_sg(struct device *dev,
-               struct scatterlist *sg, int nents, enum dma_data_direction dir)
+static inline int pci_p2pdma_map_sg_attrs(struct device *dev,
+               struct scatterlist *sg, int nents, enum dma_data_direction dir,
+               unsigned long attrs)
 {
        return 0;
 }
+static inline void pci_p2pdma_unmap_sg_attrs(struct device *dev,
+               struct scatterlist *sg, int nents, enum dma_data_direction dir,
+               unsigned long attrs)
+{
+}
 static inline int pci_p2pdma_enable_store(const char *page,
                struct pci_dev **p2p_dev, bool *use_p2pdma)
 {
@@ -111,4 +119,16 @@ static inline struct pci_dev *pci_p2pmem_find(struct device *client)
        return pci_p2pmem_find_many(&client, 1);
 }
 
+static inline int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg,
+                                   int nents, enum dma_data_direction dir)
+{
+       return pci_p2pdma_map_sg_attrs(dev, sg, nents, dir, 0);
+}
+
+static inline void pci_p2pdma_unmap_sg(struct device *dev,
+               struct scatterlist *sg, int nents, enum dma_data_direction dir)
+{
+       pci_p2pdma_unmap_sg_attrs(dev, sg, nents, dir, 0);
+}
+
 #endif /* _LINUX_PCI_P2P_H */
index 9e700d9f9f287d0db0bf770cd5c4ee2a564db94c..c1c2e4c7242a22735c8194431e8d57416af181f5 100644 (file)
@@ -6,12 +6,18 @@
  *     Copyright 1994, Drew Eckhardt
  *     Copyright 1997--1999 Martin Mares <mj@ucw.cz>
  *
+ *     PCI Express ASPM defines and function prototypes
+ *     Copyright (c) 2007 Intel Corp.
+ *             Zhang Yanmin (yanmin.zhang@intel.com)
+ *             Shaohua Li (shaohua.li@intel.com)
+ *
  *     For more information, please consult the following manuals (look at
  *     http://www.pcisig.com/ for how to get them):
  *
  *     PCI BIOS Specification
  *     PCI Local Bus Specification
  *     PCI to PCI Bridge Specification
+ *     PCI Express Specification
  *     PCI System Design Guide
  */
 #ifndef LINUX_PCI_H
@@ -145,11 +151,6 @@ static inline const char *pci_power_name(pci_power_t state)
        return pci_power_names[1 + (__force int) state];
 }
 
-#define PCI_PM_D2_DELAY                200
-#define PCI_PM_D3_WAIT         10
-#define PCI_PM_D3COLD_WAIT     100
-#define PCI_PM_BUS_WAIT                50
-
 /**
  * typedef pci_channel_state_t
  *
@@ -418,7 +419,6 @@ struct pci_dev {
        unsigned int    broken_intx_masking:1;  /* INTx masking can't be used */
        unsigned int    io_window_1k:1;         /* Intel bridge 1K I/O windows */
        unsigned int    irq_managed:1;
-       unsigned int    has_secondary_link:1;
        unsigned int    non_compliant_bars:1;   /* Broken BARs; ignore them */
        unsigned int    is_probed:1;            /* Device probing in progress */
        unsigned int    link_active_reporting:1;/* Device capable of reporting link active */
@@ -649,9 +649,6 @@ static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev)
        return dev->bus->self;
 }
 
-struct device *pci_get_host_bridge_device(struct pci_dev *dev);
-void pci_put_host_bridge_device(struct device *dev);
-
 #ifdef CONFIG_PCI_MSI
 static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev)
 {
@@ -925,6 +922,11 @@ enum {
        PCI_SCAN_ALL_PCIE_DEVS  = 0x00000040,   /* Scan all, not just dev 0 */
 };
 
+#define PCI_IRQ_LEGACY         (1 << 0) /* Allow legacy interrupts */
+#define PCI_IRQ_MSI            (1 << 1) /* Allow MSI interrupts */
+#define PCI_IRQ_MSIX           (1 << 2) /* Allow MSI-X interrupts */
+#define PCI_IRQ_AFFINITY       (1 << 3) /* Auto-assign affinity */
+
 /* These external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
 
@@ -995,7 +997,6 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
 int pci_scan_root_bus_bridge(struct pci_host_bridge *bridge);
 struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
                                int busnr);
-void pcie_update_link_speed(struct pci_bus *bus, u16 link_status);
 struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
                                 const char *name,
                                 struct hotplug_slot *hotplug);
@@ -1241,19 +1242,12 @@ int pci_wake_from_d3(struct pci_dev *dev, bool enable);
 int pci_prepare_to_sleep(struct pci_dev *dev);
 int pci_back_from_sleep(struct pci_dev *dev);
 bool pci_dev_run_wake(struct pci_dev *dev);
-bool pci_check_pme_status(struct pci_dev *dev);
-void pci_pme_wakeup_bus(struct pci_bus *bus);
 void pci_d3cold_enable(struct pci_dev *dev);
 void pci_d3cold_disable(struct pci_dev *dev);
 bool pcie_relaxed_ordering_enabled(struct pci_dev *dev);
 void pci_wakeup_bus(struct pci_bus *bus);
 void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state);
 
-/* PCI Virtual Channel */
-int pci_save_vc_state(struct pci_dev *dev);
-void pci_restore_vc_state(struct pci_dev *dev);
-void pci_allocate_vc_save_buffers(struct pci_dev *dev);
-
 /* For use by arch with custom probe code */
 void set_pcie_port_type(struct pci_dev *pdev);
 void set_pcie_hotplug_bridge(struct pci_dev *pdev);
@@ -1297,8 +1291,6 @@ int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
 void pci_release_selected_regions(struct pci_dev *, int);
 
 /* drivers/pci/bus.c */
-struct pci_bus *pci_bus_get(struct pci_bus *bus);
-void pci_bus_put(struct pci_bus *bus);
 void pci_add_resource(struct list_head *resources, struct resource *res);
 void pci_add_resource_offset(struct list_head *resources, struct resource *res,
                             resource_size_t offset);
@@ -1408,11 +1400,6 @@ resource_size_t pcibios_window_alignment(struct pci_bus *bus,
 int pci_set_vga_state(struct pci_dev *pdev, bool decode,
                      unsigned int command_bits, u32 flags);
 
-#define PCI_IRQ_LEGACY         (1 << 0) /* Allow legacy interrupts */
-#define PCI_IRQ_MSI            (1 << 1) /* Allow MSI interrupts */
-#define PCI_IRQ_MSIX           (1 << 2) /* Allow MSI-X interrupts */
-#define PCI_IRQ_AFFINITY       (1 << 3) /* Auto-assign affinity */
-
 /*
  * Virtual interrupts allow for more interrupts to be allocated
  * than the device has interrupts for. These are not programmed
@@ -1517,14 +1504,6 @@ static inline int pci_irq_get_node(struct pci_dev *pdev, int vec)
 }
 #endif
 
-static inline int
-pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
-                     unsigned int max_vecs, unsigned int flags)
-{
-       return pci_alloc_irq_vectors_affinity(dev, min_vecs, max_vecs, flags,
-                                             NULL);
-}
-
 /**
  * pci_irqd_intx_xlate() - Translate PCI INTx value to an IRQ domain hwirq
  * @d: the INTx IRQ domain
@@ -1565,9 +1544,21 @@ extern bool pcie_ports_native;
 #define pcie_ports_native      false
 #endif
 
+#define PCIE_LINK_STATE_L0S    1
+#define PCIE_LINK_STATE_L1     2
+#define PCIE_LINK_STATE_CLKPM  4
+
 #ifdef CONFIG_PCIEASPM
+int pci_disable_link_state(struct pci_dev *pdev, int state);
+int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
+void pcie_no_aspm(void);
 bool pcie_aspm_support_enabled(void);
 #else
+static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
+{ return 0; }
+static inline int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
+{ return 0; }
+static inline void pcie_no_aspm(void) { }
 static inline bool pcie_aspm_support_enabled(void) { return false; }
 #endif
 
@@ -1577,23 +1568,8 @@ bool pci_aer_available(void);
 static inline bool pci_aer_available(void) { return false; }
 #endif
 
-#ifdef CONFIG_PCIE_ECRC
-void pcie_set_ecrc_checking(struct pci_dev *dev);
-void pcie_ecrc_get_policy(char *str);
-#else
-static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { }
-static inline void pcie_ecrc_get_policy(char *str) { }
-#endif
-
 bool pci_ats_disabled(void);
 
-#ifdef CONFIG_PCIE_PTM
-int pci_enable_ptm(struct pci_dev *dev, u8 *granularity);
-#else
-static inline int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
-{ return -EINVAL; }
-#endif
-
 void pci_cfg_access_lock(struct pci_dev *dev);
 bool pci_cfg_access_trylock(struct pci_dev *dev);
 void pci_cfg_access_unlock(struct pci_dev *dev);
@@ -1747,11 +1723,6 @@ static inline void pci_release_regions(struct pci_dev *dev) { }
 
 static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
 
-static inline void pci_block_cfg_access(struct pci_dev *dev) { }
-static inline int pci_block_cfg_access_in_atomic(struct pci_dev *dev)
-{ return 0; }
-static inline void pci_unblock_cfg_access(struct pci_dev *dev) { }
-
 static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
 { return NULL; }
 static inline struct pci_dev *pci_get_slot(struct pci_bus *bus,
@@ -1780,17 +1751,36 @@ static inline const struct pci_device_id *pci_match_id(const struct pci_device_i
                                                         struct pci_dev *dev)
 { return NULL; }
 static inline bool pci_ats_disabled(void) { return true; }
+
+static inline int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
+{
+       return -EINVAL;
+}
+
+static inline int
+pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
+                              unsigned int max_vecs, unsigned int flags,
+                              struct irq_affinity *aff_desc)
+{
+       return -ENOSPC;
+}
 #endif /* CONFIG_PCI */
 
+static inline int
+pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+                     unsigned int max_vecs, unsigned int flags)
+{
+       return pci_alloc_irq_vectors_affinity(dev, min_vecs, max_vecs, flags,
+                                             NULL);
+}
+
 #ifdef CONFIG_PCI_ATS
 /* Address Translation Service */
-void pci_ats_init(struct pci_dev *dev);
 int pci_enable_ats(struct pci_dev *dev, int ps);
 void pci_disable_ats(struct pci_dev *dev);
 int pci_ats_queue_depth(struct pci_dev *dev);
 int pci_ats_page_aligned(struct pci_dev *dev);
 #else
-static inline void pci_ats_init(struct pci_dev *d) { }
 static inline int pci_enable_ats(struct pci_dev *d, int ps) { return -ENODEV; }
 static inline void pci_disable_ats(struct pci_dev *d) { }
 static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; }
@@ -1870,25 +1860,9 @@ static inline const char *pci_name(const struct pci_dev *pdev)
        return dev_name(&pdev->dev);
 }
 
-
-/*
- * Some archs don't want to expose struct resource to userland as-is
- * in sysfs and /proc
- */
-#ifdef HAVE_ARCH_PCI_RESOURCE_TO_USER
 void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
                          resource_size_t *start, resource_size_t *end);
-#else
-static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
-               const struct resource *rsrc, resource_size_t *start,
-               resource_size_t *end)
-{
-       *start = rsrc->start;
-       *end = rsrc->end;
-}
-#endif /* HAVE_ARCH_PCI_RESOURCE_TO_USER */
-
 
 /*
  * The world is not perfect and supplies us with broken PCI devices.
@@ -2030,10 +2004,6 @@ extern unsigned long pci_cardbus_mem_size;
 extern u8 pci_dfl_cache_line_size;
 extern u8 pci_cache_line_size;
 
-extern unsigned long pci_hotplug_io_size;
-extern unsigned long pci_hotplug_mem_size;
-extern unsigned long pci_hotplug_bus_size;
-
 /* Architecture-specific versions may override these (weak) */
 void pcibios_disable_device(struct pci_dev *dev);
 void pcibios_set_master(struct pci_dev *dev);
@@ -2303,10 +2273,6 @@ int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
 #ifdef CONFIG_OF
 struct device_node;
 struct irq_domain;
-void pci_set_of_node(struct pci_dev *dev);
-void pci_release_of_node(struct pci_dev *dev);
-void pci_set_bus_of_node(struct pci_bus *bus);
-void pci_release_bus_of_node(struct pci_bus *bus);
 struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus);
 int pci_parse_request_of_pci_ranges(struct device *dev,
                                    struct list_head *resources,
@@ -2316,10 +2282,6 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
 struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus);
 
 #else  /* CONFIG_OF */
-static inline void pci_set_of_node(struct pci_dev *dev) { }
-static inline void pci_release_of_node(struct pci_dev *dev) { }
-static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
-static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
 static inline struct irq_domain *
 pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; }
 static inline int pci_parse_request_of_pci_ranges(struct device *dev,
@@ -2433,4 +2395,7 @@ void pci_uevent_ers(struct pci_dev *pdev, enum  pci_ers_result err_type);
 #define pci_notice_ratelimited(pdev, fmt, arg...) \
        dev_notice_ratelimited(&(pdev)->dev, fmt, ##arg)
 
+#define pci_info_ratelimited(pdev, fmt, arg...) \
+       dev_info_ratelimited(&(pdev)->dev, fmt, ##arg)
+
 #endif /* LINUX_PCI_H */
index f694eb2ca97815982165c0f6ba1d3757cb0a550e..b482e42d715356cd79a7f1cd1e69decac0afa985 100644 (file)
@@ -86,114 +86,14 @@ void pci_hp_deregister(struct hotplug_slot *slot);
 #define pci_hp_initialize(slot, bus, nr, name) \
        __pci_hp_initialize(slot, bus, nr, name, THIS_MODULE, KBUILD_MODNAME)
 
-/* PCI Setting Record (Type 0) */
-struct hpp_type0 {
-       u32 revision;
-       u8  cache_line_size;
-       u8  latency_timer;
-       u8  enable_serr;
-       u8  enable_perr;
-};
-
-/* PCI-X Setting Record (Type 1) */
-struct hpp_type1 {
-       u32 revision;
-       u8  max_mem_read;
-       u8  avg_max_split;
-       u16 tot_max_split;
-};
-
-/* PCI Express Setting Record (Type 2) */
-struct hpp_type2 {
-       u32 revision;
-       u32 unc_err_mask_and;
-       u32 unc_err_mask_or;
-       u32 unc_err_sever_and;
-       u32 unc_err_sever_or;
-       u32 cor_err_mask_and;
-       u32 cor_err_mask_or;
-       u32 adv_err_cap_and;
-       u32 adv_err_cap_or;
-       u16 pci_exp_devctl_and;
-       u16 pci_exp_devctl_or;
-       u16 pci_exp_lnkctl_and;
-       u16 pci_exp_lnkctl_or;
-       u32 sec_unc_err_sever_and;
-       u32 sec_unc_err_sever_or;
-       u32 sec_unc_err_mask_and;
-       u32 sec_unc_err_mask_or;
-};
-
-/*
- * _HPX PCI Express Setting Record (Type 3)
- */
-struct hpx_type3 {
-       u16 device_type;
-       u16 function_type;
-       u16 config_space_location;
-       u16 pci_exp_cap_id;
-       u16 pci_exp_cap_ver;
-       u16 pci_exp_vendor_id;
-       u16 dvsec_id;
-       u16 dvsec_rev;
-       u16 match_offset;
-       u32 match_mask_and;
-       u32 match_value;
-       u16 reg_offset;
-       u32 reg_mask_and;
-       u32 reg_mask_or;
-};
-
-struct hotplug_program_ops {
-       void (*program_type0)(struct pci_dev *dev, struct hpp_type0 *hpp);
-       void (*program_type1)(struct pci_dev *dev, struct hpp_type1 *hpp);
-       void (*program_type2)(struct pci_dev *dev, struct hpp_type2 *hpp);
-       void (*program_type3)(struct pci_dev *dev, struct hpx_type3 *hpp);
-};
-
-enum hpx_type3_dev_type {
-       HPX_TYPE_ENDPOINT       = BIT(0),
-       HPX_TYPE_LEG_END        = BIT(1),
-       HPX_TYPE_RC_END         = BIT(2),
-       HPX_TYPE_RC_EC          = BIT(3),
-       HPX_TYPE_ROOT_PORT      = BIT(4),
-       HPX_TYPE_UPSTREAM       = BIT(5),
-       HPX_TYPE_DOWNSTREAM     = BIT(6),
-       HPX_TYPE_PCI_BRIDGE     = BIT(7),
-       HPX_TYPE_PCIE_BRIDGE    = BIT(8),
-};
-
-enum hpx_type3_fn_type {
-       HPX_FN_NORMAL           = BIT(0),
-       HPX_FN_SRIOV_PHYS       = BIT(1),
-       HPX_FN_SRIOV_VIRT       = BIT(2),
-};
-
-enum hpx_type3_cfg_loc {
-       HPX_CFG_PCICFG          = 0,
-       HPX_CFG_PCIE_CAP        = 1,
-       HPX_CFG_PCIE_CAP_EXT    = 2,
-       HPX_CFG_VEND_CAP        = 3,
-       HPX_CFG_DVSEC           = 4,
-       HPX_CFG_MAX,
-};
-
 #ifdef CONFIG_ACPI
 #include <linux/acpi.h>
-int pci_acpi_program_hp_params(struct pci_dev *dev,
-                              const struct hotplug_program_ops *hp_ops);
 bool pciehp_is_native(struct pci_dev *bridge);
 int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge);
 bool shpchp_is_native(struct pci_dev *bridge);
 int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle);
 int acpi_pci_detect_ejectable(acpi_handle handle);
 #else
-static inline int pci_acpi_program_hp_params(struct pci_dev *dev,
-                                   const struct hotplug_program_ops *hp_ops)
-{
-       return -ENODEV;
-}
-
 static inline int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge)
 {
        return 0;
index c842735a4f45a41d4ce305d236d08a8b2d0ef3b6..f3130542c752a8ed8cdc03a89a0bc5bfaa8c15d9 100644 (file)
 #define PCI_VENDOR_ID_MYRICOM          0x14c1
 
 #define PCI_VENDOR_ID_MEDIATEK         0x14c3
+#define PCI_DEVICE_ID_MEDIATEK_7629    0x7629
 
 #define PCI_VENDOR_ID_TITAN            0x14D2
 #define PCI_DEVICE_ID_TITAN_010L       0x8001
 
 #define PCI_VENDOR_ID_ASMEDIA          0x1b21
 
+#define PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS    0x1c36
+
 #define PCI_VENDOR_ID_CIRCUITCO                0x1cc8
 #define PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD 0x0001
 
index d28d0319d932835b608db90ebf18eebbaf6cfdc5..29d6e93fd15e3616f5969d0dc0db3b98506cf490 100644 (file)
 #define  PCI_EXP_SLTCTL_CCIE   0x0010  /* Command Completed Interrupt Enable */
 #define  PCI_EXP_SLTCTL_HPIE   0x0020  /* Hot-Plug Interrupt Enable */
 #define  PCI_EXP_SLTCTL_AIC    0x00c0  /* Attention Indicator Control */
+#define  PCI_EXP_SLTCTL_ATTN_IND_SHIFT 6      /* Attention Indicator shift */
 #define  PCI_EXP_SLTCTL_ATTN_IND_ON    0x0040 /* Attention Indicator on */
 #define  PCI_EXP_SLTCTL_ATTN_IND_BLINK 0x0080 /* Attention Indicator blinking */
 #define  PCI_EXP_SLTCTL_ATTN_IND_OFF   0x00c0 /* Attention Indicator off */