]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branches 'pci/hotplug' and 'pci/resource' into next
authorBjorn Helgaas <bhelgaas@google.com>
Tue, 17 May 2016 19:35:38 +0000 (14:35 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 17 May 2016 19:35:38 +0000 (14:35 -0500)
* pci/hotplug:
  PCI: Use cached copy of PCI_EXP_SLTCAP_HPC bit

* pci/resource:
  PCI: Disable all BAR sizing for devices with non-compliant BARs
  x86/PCI: Mark Broadwell-EP Home Agent 1 as having non-compliant BARs
  PCI: Identify Enhanced Allocation (EA) BAR Equivalent resources in sysfs

46 files changed:
Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
Documentation/devicetree/bindings/pci/pci-armada8k.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/pci-keystone.txt
arch/alpha/kernel/pci-sysfs.c
arch/arm/boot/dts/imx6q-apalis-ixora.dts
arch/arm/boot/dts/imx6qp.dtsi
arch/x86/pci/common.c
arch/x86/pci/fixup.c
drivers/iommu/iommu.c
drivers/pci/host/Kconfig
drivers/pci/host/Makefile
drivers/pci/host/pci-dra7xx.c
drivers/pci/host/pci-hyperv.c
drivers/pci/host/pci-imx6.c
drivers/pci/host/pci-keystone-dw.c
drivers/pci/host/pci-keystone.c
drivers/pci/host/pci-keystone.h
drivers/pci/host/pci-mvebu.c
drivers/pci/host/pci-thunder-pem.c
drivers/pci/host/pcie-armada8k.c [new file with mode: 0644]
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-xilinx-nwl.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pcie/Kconfig
drivers/pci/pcie/Makefile
drivers/pci/pcie/pcie-dpc.c [new file with mode: 0644]
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_acpi.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/search.c
drivers/thunderbolt/ctl.c
drivers/thunderbolt/eeprom.c
drivers/thunderbolt/nhi.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.c
drivers/thunderbolt/tb.h
drivers/thunderbolt/tb_regs.h
include/linux/ioport.h
include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pcieport_if.h
include/uapi/linux/pci_regs.h

index 3be80c68941a7aa1e19172e23d287b8c4bddd327..83aeb1f5a645ce2fe494e14dedce27dc7085155f 100644 (file)
@@ -4,8 +4,8 @@ This PCIe host controller is based on the Synopsis Designware PCIe IP
 and thus inherits all the common properties defined in designware-pcie.txt.
 
 Required properties:
-- compatible: "fsl,imx6q-pcie"
-- reg: base addresse and length of the pcie controller
+- compatible: "fsl,imx6q-pcie", "fsl,imx6sx-pcie", "fsl,imx6qp-pcie"
+- reg: base address and length of the PCIe controller
 - interrupts: A list of interrupt outputs of the controller. Must contain an
   entry for each entry in the interrupt-names property.
 - interrupt-names: Must include the following entries:
@@ -19,6 +19,20 @@ Optional properties:
 - fsl,tx-deemph-gen2-6db: Gen2 (6db) De-emphasis value. Default: 20
 - fsl,tx-swing-full: Gen2 TX SWING FULL value. Default: 127
 - fsl,tx-swing-low: TX launch amplitude swing_low value. Default: 127
+- fsl,max-link-speed: Specify PCI gen for link capability. Must be '2' for
+  gen2, otherwise will default to gen1. Note that the IMX6 LVDS clock outputs
+  do not meet gen2 jitter requirements and thus for gen2 capability a gen2
+  compliant clock generator should be used and configured.
+- reset-gpio: Should specify the GPIO for controlling the PCI bus device reset
+  signal. It's not polarity aware and defaults to active-low reset sequence
+  (L=reset state, H=operation state).
+- reset-gpio-active-high: If present then the reset sequence using the GPIO
+  specified in the "reset-gpio" property is reversed (H=reset state,
+  L=operation state).
+
+Additional required properties for imx6sx-pcie:
+- clock names: Must include the following additional entries:
+       - "pcie_inbound_axi"
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/pci/pci-armada8k.txt b/Documentation/devicetree/bindings/pci/pci-armada8k.txt
new file mode 100644 (file)
index 0000000..598533a
--- /dev/null
@@ -0,0 +1,38 @@
+* Marvell Armada 7K/8K PCIe interface
+
+This PCIe host controller is based on the Synopsis Designware PCIe IP
+and thus inherits all the common properties defined in designware-pcie.txt.
+
+Required properties:
+- compatible: "marvell,armada8k-pcie"
+- reg: must contain two register regions
+   - the control register region
+   - the config space region
+- reg-names:
+   - "ctrl" for the control register region
+   - "config" for the config space region
+- interrupts: Interrupt specifier for the PCIe controler
+- clocks: reference to the PCIe controller clock
+
+Example:
+
+       pcie@f2600000 {
+               compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
+               reg = <0 0xf2600000 0 0x10000>, <0 0xf6f00000 0 0x80000>;
+               reg-names = "ctrl", "config";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               dma-coherent;
+
+               bus-range = <0 0xff>;
+               ranges = <0x81000000 0 0xf9000000 0  0xf9000000 0 0x10000       /* downstream I/O */
+                         0x82000000 0 0xf6000000 0  0xf6000000 0 0xf00000>;    /* non-prefetchable memory */
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+               num-lanes = <1>;
+               clocks = <&cpm_syscon0 1 13>;
+               status = "disabled";
+       };
index 54eae2938174d7e91b262f60a43753d2319da051..d08a4d51108f7419e2ec547dbed4d9b9620ccc09 100644 (file)
@@ -56,6 +56,7 @@ Optional properties:-
        phy-names: name of the Generic Keystine SerDes phy for PCI
          - If boot loader already does PCI link establishment, then phys and
            phy-names shouldn't be present.
+       interrupts: platform interrupt for error interrupts.
 
 Designware DT Properties not applicable for Keystone PCI
 
index 99e8d4796c96c6f02b50eb36c0e2c623df7ca9e3..92c0d460815b1b3f263634333aae2bf4ab4af1ba 100644 (file)
@@ -77,10 +77,10 @@ static int pci_mmap_resource(struct kobject *kobj,
        if (i >= PCI_ROM_RESOURCE)
                return -ENODEV;
 
-       if (!__pci_mmap_fits(pdev, i, vma, sparse))
+       if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
                return -EINVAL;
 
-       if (iomem_is_exclusive(res->start))
+       if (!__pci_mmap_fits(pdev, i, vma, sparse))
                return -EINVAL;
 
        pcibios_resource_to_bus(pdev->bus, &bar, res);
index 2cba82d0d859b1a9db81ee57e81583df3a3684cc..4b533cb5c82ed5af6b7b7a0f7c71c48e80743fdc 100644 (file)
 };
 
 &pcie {
-       /* active-low meaning opposite of regular PERST# active-low polarity */
-       reset-gpio = <&gpio1 28 GPIO_ACTIVE_LOW>;
+       /* active-high meaning opposite of regular PERST# active-low polarity */
+       reset-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>;
+       reset-gpio-active-high;
        status = "okay";
 };
 
index 1ada71437e49fd6735dc2e952e07d61ced7187cb..886dbf2eca49b8d24866f31cca6a5975cd71d463 100644 (file)
@@ -82,5 +82,8 @@
                                      "ldb_di0", "ldb_di1", "prg";
                };
 
+               pcie: pcie@0x01000000 {
+                       compatible = "fsl,imx6qp-pcie", "snps,dw-pcie";
+               };
        };
 };
index 381a43c40bf7671e9dcbe33e402ef7efb4ff5505..8196054fedb0450d56978936d769c7189a86ad85 100644 (file)
@@ -516,7 +516,7 @@ void __init pcibios_set_cache_line_size(void)
 
 int __init pcibios_init(void)
 {
-       if (!raw_pci_ops) {
+       if (!raw_pci_ops && !raw_pci_ext_ops) {
                printk(KERN_WARNING "PCI: System does not support PCI\n");
                return 0;
        }
index b7de1929714b7136415a6361cc6c1f3c86058bbd..837ea36a837d3063754c34c7fbb38be662b91226 100644 (file)
@@ -552,9 +552,16 @@ static void twinhead_reserve_killing_zone(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone);
 
+/*
+ * Broadwell EP Home Agent BARs erroneously return non-zero values when read.
+ *
+ * See http://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v4-spec-update.html
+ * entry BDF2.
+ */
 static void pci_bdwep_bar(struct pci_dev *dev)
 {
        dev->non_compliant_bars = 1;
 }
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_bdwep_bar);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_bdwep_bar);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_bdwep_bar);
index bfd4f7c3b1d8a9da9ce6cd2bce3decd8e27e0fca..1b49e940a31888dacf509f0137ae5a5c10cd11d5 100644 (file)
@@ -660,8 +660,8 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev,
 }
 
 /*
- * Look for aliases to or from the given device for exisiting groups.  The
- * dma_alias_devfn only supports aliases on the same bus, therefore the search
+ * Look for aliases to or from the given device for existing groups. DMA
+ * aliases are only supported on the same bus, therefore the search
  * space is quite small (especially since we're really only looking at pcie
  * device, and therefore only expect multiple slots on the root complex or
  * downstream switch ports).  It's conceivable though that a pair of
@@ -686,11 +686,7 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
                        continue;
 
                /* We alias them or they alias us */
-               if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) &&
-                    pdev->dma_alias_devfn == tmp->devfn) ||
-                   ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) &&
-                    tmp->dma_alias_devfn == pdev->devfn)) {
-
+               if (pci_devs_are_dma_aliases(pdev, tmp)) {
                        group = get_pci_alias_group(tmp, devfns);
                        if (group) {
                                pci_dev_put(tmp);
index 7a0780d56d2dc28f1f64e7c7a49a048b060e6b87..bd6f11aaefd9c0ad153e405d800b8d0f1cfa41c5 100644 (file)
@@ -72,6 +72,8 @@ config PCI_RCAR_GEN2
 config PCI_RCAR_GEN2_PCIE
        bool "Renesas R-Car PCIe controller"
        depends on ARCH_RENESAS || (ARM && COMPILE_TEST)
+       select PCI_MSI
+       select PCI_MSI_IRQ_DOMAIN
        help
          Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
 
@@ -231,4 +233,15 @@ config PCI_HOST_THUNDER_ECAM
        help
          Say Y here if you want ECAM support for CN88XX-Pass-1.x Cavium Thunder SoCs.
 
+config PCIE_ARMADA_8K
+       bool "Marvell Armada-8K PCIe controller"
+       depends on ARCH_MVEBU
+       select PCIE_DW
+       select PCIEPORTBUS
+       help
+         Say Y here if you want to enable PCIe controller support on
+         Armada-8K SoCs. The PCIe controller on Armada-8K is based on
+         Designware hardware and therefore the driver re-uses the
+         Designware core functions to implement the driver.
+
 endmenu
index d85b5faf9bbc86089ee91a4bee114a3d7be40baf..a6f85e3987c040effd58920985d06f0c6881344a 100644 (file)
@@ -28,3 +28,4 @@ obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
 obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
 obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
+obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
index 2ca3a1f30ebf2770f1db370955c2c11f33245001..f441130407e77d2e33c645a42c9972c69a3d0462 100644 (file)
@@ -142,13 +142,13 @@ static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
 
 static void dra7xx_pcie_host_init(struct pcie_port *pp)
 {
-       dw_pcie_setup_rc(pp);
-
        pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR;
        pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR;
        pp->cfg0_base &= DRA7XX_CPU_TO_BUS_ADDR;
        pp->cfg1_base &= DRA7XX_CPU_TO_BUS_ADDR;
 
+       dw_pcie_setup_rc(pp);
+
        dra7xx_pcie_establish_link(pp);
        if (IS_ENABLED(CONFIG_PCI_MSI))
                dw_pcie_msi_init(pp);
index ed651baa7c50033b6dd048e6f9bca3ba5d85105d..328c653d75036f4ed582fb0aac45aa0ebfb4a9b1 100644 (file)
@@ -2268,11 +2268,6 @@ static int hv_pci_remove(struct hv_device *hdev)
 
        hbus = hv_get_drvdata(hdev);
 
-       ret = hv_send_resources_released(hdev);
-       if (ret)
-               dev_err(&hdev->device,
-                       "Couldn't send resources released packet(s)\n");
-
        memset(&pkt.teardown_packet, 0, sizeof(pkt.teardown_packet));
        init_completion(&comp_pkt.host_event);
        pkt.teardown_packet.completion_func = hv_pci_generic_compl;
@@ -2295,6 +2290,11 @@ static int hv_pci_remove(struct hv_device *hdev)
                pci_unlock_rescan_remove();
        }
 
+       ret = hv_send_resources_released(hdev);
+       if (ret)
+               dev_err(&hdev->device,
+                       "Couldn't send resources released packet(s)\n");
+
        vmbus_close(hdev->channel);
 
        /* Delete any children which might still exist. */
index eb5a2755a1646649a7e1aaea263a1cf118a45af4..b741a36a67f3c0ba77acfaa3606ea2031a7742f7 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <linux/module.h>
 #include <linux/of_gpio.h>
+#include <linux/of_device.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #define to_imx6_pcie(x)        container_of(x, struct imx6_pcie, pp)
 
+enum imx6_pcie_variants {
+       IMX6Q,
+       IMX6SX,
+       IMX6QP,
+};
+
 struct imx6_pcie {
-       struct gpio_desc        *reset_gpio;
+       int                     reset_gpio;
+       bool                    gpio_active_high;
        struct clk              *pcie_bus;
        struct clk              *pcie_phy;
+       struct clk              *pcie_inbound_axi;
        struct clk              *pcie;
        struct pcie_port        pp;
        struct regmap           *iomuxc_gpr;
+       enum imx6_pcie_variants variant;
        void __iomem            *mem_base;
        u32                     tx_deemph_gen1;
        u32                     tx_deemph_gen2_3p5db;
        u32                     tx_deemph_gen2_6db;
        u32                     tx_swing_full;
        u32                     tx_swing_low;
+       int                     link_gen;
 };
 
 /* PCIe Root Complex registers (memory-mapped) */
@@ -236,37 +247,93 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
        struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
        u32 val, gpr1, gpr12;
 
-       /*
-        * If the bootloader already enabled the link we need some special
-        * handling to get the core back into a state where it is safe to
-        * touch it for configuration.  As there is no dedicated reset signal
-        * wired up for MX6QDL, we need to manually force LTSSM into "detect"
-        * state before completely disabling LTSSM, which is a prerequisite
-        * for core configuration.
-        *
-        * If both LTSSM_ENABLE and REF_SSP_ENABLE are active we have a strong
-        * indication that the bootloader activated the link.
-        */
-       regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, &gpr1);
-       regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, &gpr12);
+       switch (imx6_pcie->variant) {
+       case IMX6SX:
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+                                  IMX6SX_GPR12_PCIE_TEST_POWERDOWN,
+                                  IMX6SX_GPR12_PCIE_TEST_POWERDOWN);
+               /* Force PCIe PHY reset */
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+                                  IMX6SX_GPR5_PCIE_BTNRST_RESET,
+                                  IMX6SX_GPR5_PCIE_BTNRST_RESET);
+               break;
+       case IMX6QP:
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+                                  IMX6Q_GPR1_PCIE_SW_RST,
+                                  IMX6Q_GPR1_PCIE_SW_RST);
+               break;
+       case IMX6Q:
+               /*
+                * If the bootloader already enabled the link we need some
+                * special handling to get the core back into a state where
+                * it is safe to touch it for configuration.  As there is
+                * no dedicated reset signal wired up for MX6QDL, we need
+                * to manually force LTSSM into "detect" state before
+                * completely disabling LTSSM, which is a prerequisite for
+                * core configuration.
+                *
+                * If both LTSSM_ENABLE and REF_SSP_ENABLE are active we
+                * have a strong indication that the bootloader activated
+                * the link.
+                */
+               regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, &gpr1);
+               regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, &gpr12);
+
+               if ((gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN) &&
+                   (gpr12 & IMX6Q_GPR12_PCIE_CTL_2)) {
+                       val = readl(pp->dbi_base + PCIE_PL_PFLR);
+                       val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
+                       val |= PCIE_PL_PFLR_FORCE_LINK;
+                       writel(val, pp->dbi_base + PCIE_PL_PFLR);
+
+                       regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+                                          IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
+               }
+
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+                                  IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18);
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+                                  IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);
+               break;
+       }
+
+       return 0;
+}
 
-       if ((gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN) &&
-           (gpr12 & IMX6Q_GPR12_PCIE_CTL_2)) {
-               val = readl(pp->dbi_base + PCIE_PL_PFLR);
-               val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
-               val |= PCIE_PL_PFLR_FORCE_LINK;
-               writel(val, pp->dbi_base + PCIE_PL_PFLR);
+static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
+{
+       struct pcie_port *pp = &imx6_pcie->pp;
+       int ret = 0;
+
+       switch (imx6_pcie->variant) {
+       case IMX6SX:
+               ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);
+               if (ret) {
+                       dev_err(pp->dev, "unable to enable pcie_axi clock\n");
+                       break;
+               }
 
                regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
-                               IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
+                                  IMX6SX_GPR12_PCIE_TEST_POWERDOWN, 0);
+               break;
+       case IMX6QP:            /* FALLTHROUGH */
+       case IMX6Q:
+               /* power up core phy and enable ref clock */
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+                                  IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
+               /*
+                * the async reset input need ref clock to sync internally,
+                * when the ref clock comes after reset, internal synced
+                * reset time is too short, cannot meet the requirement.
+                * add one ~10us delay here.
+                */
+               udelay(10);
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+                                  IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+               break;
        }
 
-       regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
-                       IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18);
-       regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
-                       IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);
-
-       return 0;
+       return ret;
 }
 
 static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
@@ -292,43 +359,60 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
                goto err_pcie;
        }
 
-       /* power up core phy and enable ref clock */
-       regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
-                       IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
-       /*
-        * the async reset input need ref clock to sync internally,
-        * when the ref clock comes after reset, internal synced
-        * reset time is too short, cannot meet the requirement.
-        * add one ~10us delay here.
-        */
-       udelay(10);
-       regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
-                       IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+       ret = imx6_pcie_enable_ref_clk(imx6_pcie);
+       if (ret) {
+               dev_err(pp->dev, "unable to enable pcie ref clock\n");
+               goto err_ref_clk;
+       }
 
        /* allow the clocks to stabilize */
        usleep_range(200, 500);
 
        /* Some boards don't have PCIe reset GPIO. */
-       if (imx6_pcie->reset_gpio) {
-               gpiod_set_value_cansleep(imx6_pcie->reset_gpio, 0);
+       if (gpio_is_valid(imx6_pcie->reset_gpio)) {
+               gpio_set_value_cansleep(imx6_pcie->reset_gpio,
+                                       imx6_pcie->gpio_active_high);
                msleep(100);
-               gpiod_set_value_cansleep(imx6_pcie->reset_gpio, 1);
+               gpio_set_value_cansleep(imx6_pcie->reset_gpio,
+                                       !imx6_pcie->gpio_active_high);
        }
+
+       switch (imx6_pcie->variant) {
+       case IMX6SX:
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+                                  IMX6SX_GPR5_PCIE_BTNRST_RESET, 0);
+               break;
+       case IMX6QP:
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+                                  IMX6Q_GPR1_PCIE_SW_RST, 0);
+
+               usleep_range(200, 500);
+               break;
+       case IMX6Q:             /* Nothing to do */
+               break;
+       }
+
        return 0;
 
+err_ref_clk:
+       clk_disable_unprepare(imx6_pcie->pcie);
 err_pcie:
        clk_disable_unprepare(imx6_pcie->pcie_bus);
 err_pcie_bus:
        clk_disable_unprepare(imx6_pcie->pcie_phy);
 err_pcie_phy:
        return ret;
-
 }
 
 static void imx6_pcie_init_phy(struct pcie_port *pp)
 {
        struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
 
+       if (imx6_pcie->variant == IMX6SX)
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+                                  IMX6SX_GPR12_PCIE_RX_EQ_MASK,
+                                  IMX6SX_GPR12_PCIE_RX_EQ_2);
+
        regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
                        IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
 
@@ -417,11 +501,15 @@ static int imx6_pcie_establish_link(struct pcie_port *pp)
                goto err_reset_phy;
        }
 
-       /* Allow Gen2 mode after the link is up. */
-       tmp = readl(pp->dbi_base + PCIE_RC_LCR);
-       tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
-       tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
-       writel(tmp, pp->dbi_base + PCIE_RC_LCR);
+       if (imx6_pcie->link_gen == 2) {
+               /* Allow Gen2 mode after the link is up. */
+               tmp = readl(pp->dbi_base + PCIE_RC_LCR);
+               tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
+               tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
+               writel(tmp, pp->dbi_base + PCIE_RC_LCR);
+       } else {
+               dev_info(pp->dev, "Link: Gen2 disabled\n");
+       }
 
        /*
         * Start Directed Speed Change so the best possible speed both link
@@ -445,8 +533,7 @@ static int imx6_pcie_establish_link(struct pcie_port *pp)
        }
 
        tmp = readl(pp->dbi_base + PCIE_RC_LCSR);
-       dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf);
-
+       dev_info(pp->dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf);
        return 0;
 
 err_reset_phy:
@@ -523,6 +610,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
 {
        struct imx6_pcie *imx6_pcie;
        struct pcie_port *pp;
+       struct device_node *np = pdev->dev.of_node;
        struct resource *dbi_base;
        struct device_node *node = pdev->dev.of_node;
        int ret;
@@ -534,6 +622,9 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
        pp = &imx6_pcie->pp;
        pp->dev = &pdev->dev;
 
+       imx6_pcie->variant =
+               (enum imx6_pcie_variants)of_device_get_match_data(&pdev->dev);
+
        /* Added for PCI abort handling */
        hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
                "imprecise external abort");
@@ -544,8 +635,20 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
                return PTR_ERR(pp->dbi_base);
 
        /* Fetch GPIOs */
-       imx6_pcie->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
-                                                       GPIOD_OUT_LOW);
+       imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+       imx6_pcie->gpio_active_high = of_property_read_bool(np,
+                                               "reset-gpio-active-high");
+       if (gpio_is_valid(imx6_pcie->reset_gpio)) {
+               ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->reset_gpio,
+                               imx6_pcie->gpio_active_high ?
+                                       GPIOF_OUT_INIT_HIGH :
+                                       GPIOF_OUT_INIT_LOW,
+                               "PCIe reset");
+               if (ret) {
+                       dev_err(&pdev->dev, "unable to get reset gpio\n");
+                       return ret;
+               }
+       }
 
        /* Fetch clocks */
        imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");
@@ -569,6 +672,16 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
                return PTR_ERR(imx6_pcie->pcie);
        }
 
+       if (imx6_pcie->variant == IMX6SX) {
+               imx6_pcie->pcie_inbound_axi = devm_clk_get(&pdev->dev,
+                                                          "pcie_inbound_axi");
+               if (IS_ERR(imx6_pcie->pcie_inbound_axi)) {
+                       dev_err(&pdev->dev,
+                               "pcie_incbound_axi clock missing or invalid\n");
+                       return PTR_ERR(imx6_pcie->pcie_inbound_axi);
+               }
+       }
+
        /* Grab GPR config register range */
        imx6_pcie->iomuxc_gpr =
                 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
@@ -598,6 +711,12 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
                                 &imx6_pcie->tx_swing_low))
                imx6_pcie->tx_swing_low = 127;
 
+       /* Limit link speed */
+       ret = of_property_read_u32(pp->dev->of_node, "fsl,max-link-speed",
+                                  &imx6_pcie->link_gen);
+       if (ret)
+               imx6_pcie->link_gen = 1;
+
        ret = imx6_add_pcie_port(pp, pdev);
        if (ret < 0)
                return ret;
@@ -615,7 +734,9 @@ static void imx6_pcie_shutdown(struct platform_device *pdev)
 }
 
 static const struct of_device_id imx6_pcie_of_match[] = {
-       { .compatible = "fsl,imx6q-pcie", },
+       { .compatible = "fsl,imx6q-pcie",  .data = (void *)IMX6Q,  },
+       { .compatible = "fsl,imx6sx-pcie", .data = (void *)IMX6SX, },
+       { .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, },
        {},
 };
 MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
index 6153853ca9c31e319f4c6aae6dd92ed05215ba07..41515092eb0de7992769b3ea5ddec8117c44d2ec 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
+#include <linux/irqreturn.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_pci.h>
 #define IRQ_STATUS                     0x184
 #define MSI_IRQ_OFFSET                 4
 
+/* Error IRQ bits */
+#define ERR_AER                BIT(5)  /* ECRC error */
+#define ERR_AXI                BIT(4)  /* AXI tag lookup fatal error */
+#define ERR_CORR       BIT(3)  /* Correctable error */
+#define ERR_NONFATAL   BIT(2)  /* Non-fatal error */
+#define ERR_FATAL      BIT(1)  /* Fatal error */
+#define ERR_SYS                BIT(0)  /* System (fatal, non-fatal, or correctable) */
+#define ERR_IRQ_ALL    (ERR_AER | ERR_AXI | ERR_CORR | \
+                        ERR_NONFATAL | ERR_FATAL | ERR_SYS)
+#define ERR_FATAL_IRQ  (ERR_FATAL | ERR_AXI)
+#define ERR_IRQ_STATUS_RAW             0x1c0
+#define ERR_IRQ_STATUS                 0x1c4
+#define ERR_IRQ_ENABLE_SET             0x1c8
+#define ERR_IRQ_ENABLE_CLR             0x1cc
+
 /* Config space registers */
 #define DEBUG0                         0x728
 
@@ -243,6 +259,28 @@ void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
        writel(offset, ks_pcie->va_app_base + IRQ_EOI);
 }
 
+void ks_dw_pcie_enable_error_irq(void __iomem *reg_base)
+{
+       writel(ERR_IRQ_ALL, reg_base + ERR_IRQ_ENABLE_SET);
+}
+
+irqreturn_t ks_dw_pcie_handle_error_irq(struct device *dev,
+                                       void __iomem *reg_base)
+{
+       u32 status;
+
+       status = readl(reg_base + ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL;
+       if (!status)
+               return IRQ_NONE;
+
+       if (status & ERR_FATAL_IRQ)
+               dev_err(dev, "fatal error (status %#010x)\n", status);
+
+       /* Ack the IRQ; status bits are RW1C */
+       writel(status, reg_base + ERR_IRQ_STATUS);
+       return IRQ_HANDLED;
+}
+
 static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
 {
 }
index b71f55bb03156479d365892aa343858e1720e960..6b8301ef21ca1f84bcd142275561b60f1f71a3fc 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/msi.h>
@@ -159,7 +160,7 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
 static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
                                           char *controller, int *num_irqs)
 {
-       int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL;
+       int temp, max_host_irqs, legacy = 1, *host_irqs;
        struct device *dev = ks_pcie->pp.dev;
        struct device_node *np_pcie = dev->of_node, **np_temp;
 
@@ -180,11 +181,15 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
        *np_temp = of_find_node_by_name(np_pcie, controller);
        if (!(*np_temp)) {
                dev_err(dev, "Node for %s is absent\n", controller);
-               goto out;
+               return -EINVAL;
        }
+
        temp = of_irq_count(*np_temp);
-       if (!temp)
-               goto out;
+       if (!temp) {
+               dev_err(dev, "No IRQ entries in %s\n", controller);
+               return -EINVAL;
+       }
+
        if (temp > max_host_irqs)
                dev_warn(dev, "Too many %s interrupts defined %u\n",
                        (legacy ? "legacy" : "MSI"), temp);
@@ -198,12 +203,13 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
                if (!host_irqs[temp])
                        break;
        }
+
        if (temp) {
                *num_irqs = temp;
-               ret = 0;
+               return 0;
        }
-out:
-       return ret;
+
+       return -EINVAL;
 }
 
 static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
@@ -226,6 +232,9 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
                                                         ks_pcie);
                }
        }
+
+       if (ks_pcie->error_irq > 0)
+               ks_dw_pcie_enable_error_irq(ks_pcie->va_app_base);
 }
 
 /*
@@ -289,6 +298,14 @@ static struct pcie_host_ops keystone_pcie_host_ops = {
        .scan_bus = ks_dw_pcie_v3_65_scan_bus,
 };
 
+static irqreturn_t pcie_err_irq_handler(int irq, void *priv)
+{
+       struct keystone_pcie *ks_pcie = priv;
+
+       return ks_dw_pcie_handle_error_irq(ks_pcie->pp.dev,
+                                          ks_pcie->va_app_base);
+}
+
 static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
                         struct platform_device *pdev)
 {
@@ -309,6 +326,22 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
                        return ret;
        }
 
+       /*
+        * Index 0 is the platform interrupt for error interrupt
+        * from RC.  This is optional.
+        */
+       ks_pcie->error_irq = irq_of_parse_and_map(ks_pcie->np, 0);
+       if (ks_pcie->error_irq <= 0)
+               dev_info(&pdev->dev, "no error IRQ defined\n");
+       else {
+               if (request_irq(ks_pcie->error_irq, pcie_err_irq_handler,
+                               IRQF_SHARED, "pcie-error-irq", ks_pcie) < 0) {
+                       dev_err(&pdev->dev, "failed to request error IRQ %d\n",
+                               ks_pcie->error_irq);
+                       return ret;
+               }
+       }
+
        pp->root_bus_nr = -1;
        pp->ops = &keystone_pcie_host_ops;
        ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
@@ -317,7 +350,7 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
                return ret;
        }
 
-       return ret;
+       return 0;
 }
 
 static const struct of_device_id ks_pcie_of_match[] = {
@@ -346,7 +379,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
        struct resource *res;
        void __iomem *reg_p;
        struct phy *phy;
-       int ret = 0;
+       int ret;
 
        ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
                                GFP_KERNEL);
@@ -376,6 +409,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
        devm_release_mem_region(dev, res->start, resource_size(res));
 
        pp->dev = dev;
+       ks_pcie->np = dev->of_node;
        platform_set_drvdata(pdev, ks_pcie);
        ks_pcie->clk = devm_clk_get(dev, "pcie");
        if (IS_ERR(ks_pcie->clk)) {
index f0944e8c4b02f4e481a9178e9dfe4107d64c83b9..a5b0cb2ba4d78e1455668e087afb4be6fe3f6009 100644 (file)
@@ -29,6 +29,9 @@ struct keystone_pcie {
        int                     msi_host_irqs[MAX_MSI_HOST_IRQS];
        struct                  device_node *msi_intc_np;
        struct irq_domain       *legacy_irq_domain;
+       struct device_node      *np;
+
+       int error_irq;
 
        /* Application register space */
        void __iomem            *va_app_base;
@@ -42,6 +45,9 @@ phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp);
 /* Keystone specific PCI controller APIs */
 void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
 void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
+void ks_dw_pcie_enable_error_irq(void __iomem *reg_base);
+irqreturn_t ks_dw_pcie_handle_error_irq(struct device *dev,
+                                       void __iomem *reg_base);
 int  ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
                        struct device_node *msi_intc_np);
 int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
index 53b79c5f055998761b837094b3ad43bd6c56de82..6b451df6502c700d64278bec4f5b706ee63260e2 100644 (file)
@@ -1003,6 +1003,7 @@ static void mvebu_pcie_msi_enable(struct mvebu_pcie *pcie)
                pcie->msi->dev = &pcie->pdev->dev;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int mvebu_pcie_suspend(struct device *dev)
 {
        struct mvebu_pcie *pcie;
@@ -1031,6 +1032,7 @@ static int mvebu_pcie_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static void mvebu_pcie_port_clk_put(void *data)
 {
@@ -1298,9 +1300,8 @@ static const struct of_device_id mvebu_pcie_of_match_table[] = {
 };
 MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
 
-static struct dev_pm_ops mvebu_pcie_pm_ops = {
-       .suspend_noirq = mvebu_pcie_suspend,
-       .resume_noirq = mvebu_pcie_resume,
+static const struct dev_pm_ops mvebu_pcie_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mvebu_pcie_suspend, mvebu_pcie_resume)
 };
 
 static struct platform_driver mvebu_pcie_driver = {
index cabb92a514ac85788d0d684f8032cfab0a42af40..d4a7797614725d153776fc1c7ea079b6deeacbac 100644 (file)
@@ -153,11 +153,11 @@ static int thunder_pem_config_read(struct pci_bus *bus, unsigned int devfn,
  * reserved bits, this makes the code simpler and is OK as the bits
  * are not affected by writing zeros to them.
  */
-static u32 thunder_pem_bridge_w1c_bits(int where)
+static u32 thunder_pem_bridge_w1c_bits(u64 where_aligned)
 {
        u32 w1c_bits = 0;
 
-       switch (where & ~3) {
+       switch (where_aligned) {
        case 0x04: /* Command/Status */
        case 0x1c: /* Base and I/O Limit/Secondary Status */
                w1c_bits = 0xff000000;
@@ -184,12 +184,34 @@ static u32 thunder_pem_bridge_w1c_bits(int where)
        return w1c_bits;
 }
 
+/* Some bits must be written to one so they appear to be read-only. */
+static u32 thunder_pem_bridge_w1_bits(u64 where_aligned)
+{
+       u32 w1_bits;
+
+       switch (where_aligned) {
+       case 0x1c: /* I/O Base / I/O Limit, Secondary Status */
+               /* Force 32-bit I/O addressing. */
+               w1_bits = 0x0101;
+               break;
+       case 0x24: /* Prefetchable Memory Base / Prefetchable Memory Limit */
+               /* Force 64-bit addressing */
+               w1_bits = 0x00010001;
+               break;
+       default:
+               w1_bits = 0;
+               break;
+       }
+       return w1_bits;
+}
+
 static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
                                    int where, int size, u32 val)
 {
        struct gen_pci *pci = bus->sysdata;
        struct thunder_pem_pci *pem_pci;
        u64 write_val, read_val;
+       u64 where_aligned = where & ~3ull;
        u32 mask = 0;
 
        pem_pci = container_of(pci, struct thunder_pem_pci, gen_pci);
@@ -205,8 +227,7 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
         */
        switch (size) {
        case 1:
-               read_val = where & ~3ull;
-               writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+               writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
                read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
                read_val >>= 32;
                mask = ~(0xff << (8 * (where & 3)));
@@ -215,8 +236,7 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
                val |= (u32)read_val;
                break;
        case 2:
-               read_val = where & ~3ull;
-               writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+               writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
                read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
                read_val >>= 32;
                mask = ~(0xffff << (8 * (where & 3)));
@@ -243,12 +263,18 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
                }
        }
 
+       /*
+        * Some bits must be read-only with value of one.  Since the
+        * access method allows these to be cleared if a zero is
+        * written, force them to one before writing.
+        */
+       val |= thunder_pem_bridge_w1_bits(where_aligned);
+
        /*
         * Low order bits are the config address, the high order 32
         * bits are the data to be written.
         */
-       write_val = where & ~3ull;
-       write_val |= (((u64)val) << 32);
+       write_val = (((u64)val) << 32) | where_aligned;
        writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR);
        return PCIBIOS_SUCCESSFUL;
 }
diff --git a/drivers/pci/host/pcie-armada8k.c b/drivers/pci/host/pcie-armada8k.c
new file mode 100644 (file)
index 0000000..5572356
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * PCIe host controller driver for Marvell Armada-8K SoCs
+ *
+ * Armada-8K PCIe Glue Layer Source Code
+ *
+ * Copyright (C) 2016 Marvell Technology Group Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/of_pci.h>
+#include <linux/of_irq.h>
+
+#include "pcie-designware.h"
+
+struct armada8k_pcie {
+       void __iomem *base;
+       struct clk *clk;
+       struct pcie_port pp;
+};
+
+#define PCIE_VENDOR_REGS_OFFSET                0x8000
+
+#define PCIE_GLOBAL_CONTROL_REG                0x0
+#define PCIE_APP_LTSSM_EN              BIT(2)
+#define PCIE_DEVICE_TYPE_SHIFT         4
+#define PCIE_DEVICE_TYPE_MASK          0xF
+#define PCIE_DEVICE_TYPE_RC            0x4 /* Root complex */
+
+#define PCIE_GLOBAL_STATUS_REG         0x8
+#define PCIE_GLB_STS_RDLH_LINK_UP      BIT(1)
+#define PCIE_GLB_STS_PHY_LINK_UP       BIT(9)
+
+#define PCIE_GLOBAL_INT_CAUSE1_REG     0x1C
+#define PCIE_GLOBAL_INT_MASK1_REG      0x20
+#define PCIE_INT_A_ASSERT_MASK         BIT(9)
+#define PCIE_INT_B_ASSERT_MASK         BIT(10)
+#define PCIE_INT_C_ASSERT_MASK         BIT(11)
+#define PCIE_INT_D_ASSERT_MASK         BIT(12)
+
+#define PCIE_ARCACHE_TRC_REG           0x50
+#define PCIE_AWCACHE_TRC_REG           0x54
+#define PCIE_ARUSER_REG                        0x5C
+#define PCIE_AWUSER_REG                        0x60
+/*
+ * AR/AW Cache defauls: Normal memory, Write-Back, Read / Write
+ * allocate
+ */
+#define ARCACHE_DEFAULT_VALUE          0x3511
+#define AWCACHE_DEFAULT_VALUE          0x5311
+
+#define DOMAIN_OUTER_SHAREABLE         0x2
+#define AX_USER_DOMAIN_MASK            0x3
+#define AX_USER_DOMAIN_SHIFT           4
+
+#define to_armada8k_pcie(x)    container_of(x, struct armada8k_pcie, pp)
+
+static int armada8k_pcie_link_up(struct pcie_port *pp)
+{
+       struct armada8k_pcie *pcie = to_armada8k_pcie(pp);
+       u32 reg;
+       u32 mask = PCIE_GLB_STS_RDLH_LINK_UP | PCIE_GLB_STS_PHY_LINK_UP;
+
+       reg = readl(pcie->base + PCIE_GLOBAL_STATUS_REG);
+
+       if ((reg & mask) == mask)
+               return 1;
+
+       dev_dbg(pp->dev, "No link detected (Global-Status: 0x%08x).\n", reg);
+       return 0;
+}
+
+static void armada8k_pcie_establish_link(struct pcie_port *pp)
+{
+       struct armada8k_pcie *pcie = to_armada8k_pcie(pp);
+       void __iomem *base = pcie->base;
+       u32 reg;
+
+       if (!dw_pcie_link_up(pp)) {
+               /* Disable LTSSM state machine to enable configuration */
+               reg = readl(base + PCIE_GLOBAL_CONTROL_REG);
+               reg &= ~(PCIE_APP_LTSSM_EN);
+               writel(reg, base + PCIE_GLOBAL_CONTROL_REG);
+       }
+
+       /* Set the device to root complex mode */
+       reg = readl(base + PCIE_GLOBAL_CONTROL_REG);
+       reg &= ~(PCIE_DEVICE_TYPE_MASK << PCIE_DEVICE_TYPE_SHIFT);
+       reg |= PCIE_DEVICE_TYPE_RC << PCIE_DEVICE_TYPE_SHIFT;
+       writel(reg, base + PCIE_GLOBAL_CONTROL_REG);
+
+       /* Set the PCIe master AxCache attributes */
+       writel(ARCACHE_DEFAULT_VALUE, base + PCIE_ARCACHE_TRC_REG);
+       writel(AWCACHE_DEFAULT_VALUE, base + PCIE_AWCACHE_TRC_REG);
+
+       /* Set the PCIe master AxDomain attributes */
+       reg = readl(base + PCIE_ARUSER_REG);
+       reg &= ~(AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT);
+       reg |= DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT;
+       writel(reg, base + PCIE_ARUSER_REG);
+
+       reg = readl(base + PCIE_AWUSER_REG);
+       reg &= ~(AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT);
+       reg |= DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT;
+       writel(reg, base + PCIE_AWUSER_REG);
+
+       /* Enable INT A-D interrupts */
+       reg = readl(base + PCIE_GLOBAL_INT_MASK1_REG);
+       reg |= PCIE_INT_A_ASSERT_MASK | PCIE_INT_B_ASSERT_MASK |
+              PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK;
+       writel(reg, base + PCIE_GLOBAL_INT_MASK1_REG);
+
+       if (!dw_pcie_link_up(pp)) {
+               /* Configuration done. Start LTSSM */
+               reg = readl(base + PCIE_GLOBAL_CONTROL_REG);
+               reg |= PCIE_APP_LTSSM_EN;
+               writel(reg, base + PCIE_GLOBAL_CONTROL_REG);
+       }
+
+       /* Wait until the link becomes active again */
+       if (dw_pcie_wait_for_link(pp))
+               dev_err(pp->dev, "Link not up after reconfiguration\n");
+}
+
+static void armada8k_pcie_host_init(struct pcie_port *pp)
+{
+       dw_pcie_setup_rc(pp);
+       armada8k_pcie_establish_link(pp);
+}
+
+static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg)
+{
+       struct pcie_port *pp = arg;
+       struct armada8k_pcie *pcie = to_armada8k_pcie(pp);
+       void __iomem *base = pcie->base;
+       u32 val;
+
+       /*
+        * Interrupts are directly handled by the device driver of the
+        * PCI device. However, they are also latched into the PCIe
+        * controller, so we simply discard them.
+        */
+       val = readl(base + PCIE_GLOBAL_INT_CAUSE1_REG);
+       writel(val, base + PCIE_GLOBAL_INT_CAUSE1_REG);
+
+       return IRQ_HANDLED;
+}
+
+static struct pcie_host_ops armada8k_pcie_host_ops = {
+       .link_up = armada8k_pcie_link_up,
+       .host_init = armada8k_pcie_host_init,
+};
+
+static int armada8k_add_pcie_port(struct pcie_port *pp,
+                                 struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       pp->root_bus_nr = -1;
+       pp->ops = &armada8k_pcie_host_ops;
+
+       pp->irq = platform_get_irq(pdev, 0);
+       if (!pp->irq) {
+               dev_err(dev, "failed to get irq for port\n");
+               return -ENODEV;
+       }
+
+       ret = devm_request_irq(dev, pp->irq, armada8k_pcie_irq_handler,
+                              IRQF_SHARED, "armada8k-pcie", pp);
+       if (ret) {
+               dev_err(dev, "failed to request irq %d\n", pp->irq);
+               return ret;
+       }
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(dev, "failed to initialize host: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int armada8k_pcie_probe(struct platform_device *pdev)
+{
+       struct armada8k_pcie *pcie;
+       struct pcie_port *pp;
+       struct device *dev = &pdev->dev;
+       struct resource *base;
+       int ret;
+
+       pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+       if (!pcie)
+               return -ENOMEM;
+
+       pcie->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(pcie->clk))
+               return PTR_ERR(pcie->clk);
+
+       clk_prepare_enable(pcie->clk);
+
+       pp = &pcie->pp;
+       pp->dev = dev;
+       platform_set_drvdata(pdev, pcie);
+
+       /* Get the dw-pcie unit configuration/control registers base. */
+       base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
+       pp->dbi_base = devm_ioremap_resource(dev, base);
+       if (IS_ERR(pp->dbi_base)) {
+               dev_err(dev, "couldn't remap regs base %p\n", base);
+               ret = PTR_ERR(pp->dbi_base);
+               goto fail;
+       }
+
+       pcie->base = pp->dbi_base + PCIE_VENDOR_REGS_OFFSET;
+
+       ret = armada8k_add_pcie_port(pp, pdev);
+       if (ret)
+               goto fail;
+
+       return 0;
+
+fail:
+       if (!IS_ERR(pcie->clk))
+               clk_disable_unprepare(pcie->clk);
+
+       return ret;
+}
+
+static const struct of_device_id armada8k_pcie_of_match[] = {
+       { .compatible = "marvell,armada8k-pcie", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, armada8k_pcie_of_match);
+
+static struct platform_driver armada8k_pcie_driver = {
+       .probe          = armada8k_pcie_probe,
+       .driver = {
+               .name   = "armada8k-pcie",
+               .of_match_table = of_match_ptr(armada8k_pcie_of_match),
+       },
+};
+
+module_platform_driver(armada8k_pcie_driver);
+
+MODULE_DESCRIPTION("Armada 8k PCIe host controller driver");
+MODULE_AUTHOR("Yehuda Yitshak <yehuday@marvell.com>");
+MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");
+MODULE_LICENSE("GPL v2");
index a4cccd356304662fc52c5efef682723960428195..aafd766546f38737d3845339944bbaee29883ec5 100644 (file)
@@ -434,7 +434,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
        struct platform_device *pdev = to_platform_device(pp->dev);
        struct pci_bus *bus, *child;
        struct resource *cfg_res;
-       u32 val;
        int i, ret;
        LIST_HEAD(res);
        struct resource_entry *win;
@@ -544,25 +543,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
        if (pp->ops->host_init)
                pp->ops->host_init(pp);
 
-       /*
-        * If the platform provides ->rd_other_conf, it means the platform
-        * uses its own address translation component rather than ATU, so
-        * we should not program the ATU here.
-        */
-       if (!pp->ops->rd_other_conf)
-               dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
-                                         PCIE_ATU_TYPE_MEM, pp->mem_base,
-                                         pp->mem_bus_addr, pp->mem_size);
-
-       dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
-
-       /* program correct class for RC */
-       dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
-
-       dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
-       val |= PORT_LOGIC_SPEED_CHANGE;
-       dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
-
        pp->root_bus_nr = pp->busn->start;
        if (IS_ENABLED(CONFIG_PCI_MSI)) {
                bus = pci_scan_root_bus_msi(pp->dev, pp->root_bus_nr,
@@ -728,8 +708,6 @@ static struct pci_ops dw_pcie_ops = {
 void dw_pcie_setup_rc(struct pcie_port *pp)
 {
        u32 val;
-       u32 membase;
-       u32 memlimit;
 
        /* set the number of lanes */
        dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val);
@@ -788,18 +766,31 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
        val |= 0x00010100;
        dw_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS);
 
-       /* setup memory base, memory limit */
-       membase = ((u32)pp->mem_base & 0xfff00000) >> 16;
-       memlimit = (pp->mem_size + (u32)pp->mem_base) & 0xfff00000;
-       val = memlimit | membase;
-       dw_pcie_writel_rc(pp, val, PCI_MEMORY_BASE);
-
        /* setup command register */
        dw_pcie_readl_rc(pp, PCI_COMMAND, &val);
        val &= 0xffff0000;
        val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
                PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
        dw_pcie_writel_rc(pp, val, PCI_COMMAND);
+
+       /*
+        * If the platform provides ->rd_other_conf, it means the platform
+        * uses its own address translation component rather than ATU, so
+        * we should not program the ATU here.
+        */
+       if (!pp->ops->rd_other_conf)
+               dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
+                                         PCIE_ATU_TYPE_MEM, pp->mem_base,
+                                         pp->mem_bus_addr, pp->mem_size);
+
+       dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
+
+       /* program correct class for RC */
+       dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
+
+       dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
+       val |= PORT_LOGIC_SPEED_CHANGE;
+       dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
 }
 
 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
index 5139e6443bbd36cecaeb01c86fc5afe549b0a654..3479d30e2be86cbfccd108da69377899e1e1cd92 100644 (file)
@@ -819,7 +819,7 @@ static int nwl_pcie_probe(struct platform_device *pdev)
 
        err = nwl_pcie_bridge_init(pcie);
        if (err) {
-               dev_err(pcie->dev, "HW Initalization failed\n");
+               dev_err(pcie->dev, "HW Initialization failed\n");
                return err;
        }
 
index e982010f0ed19e0d0379da4a1c02334a1db9f175..cbb13be1ba282c8310e0cf03445821eb08acc0aa 100644 (file)
@@ -1008,6 +1008,9 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
        if (i >= PCI_ROM_RESOURCE)
                return -ENODEV;
 
+       if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
+               return -EINVAL;
+
        if (!pci_mmap_fits(pdev, i, vma, PCI_MMAP_SYSFS)) {
                WARN(1, "process \"%s\" tried to map 0x%08lx bytes at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n",
                        current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff,
@@ -1024,10 +1027,6 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
        pci_resource_to_user(pdev, i, res, &start, &end);
        vma->vm_pgoff += start >> PAGE_SHIFT;
        mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
-
-       if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start))
-               return -EINVAL;
-
        return pci_mmap_page_range(pdev, vma, mmap_type, write_combine);
 }
 
index 25e0327d4429bfc00a694f66f4a28fc7233fb7df..73be010bafa70e4fe291aa7f8cca9905e3c91352 100644 (file)
@@ -2228,7 +2228,7 @@ void pci_pm_init(struct pci_dev *dev)
 
 static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop)
 {
-       unsigned long flags = IORESOURCE_PCI_FIXED;
+       unsigned long flags = IORESOURCE_PCI_FIXED | IORESOURCE_PCI_EA_BEI;
 
        switch (prop) {
        case PCI_EA_P_MEM:
@@ -2389,7 +2389,7 @@ out:
        return offset + ent_size;
 }
 
-/* Enhanced Allocation Initalization */
+/* Enhanced Allocation Initialization */
 void pci_ea_init(struct pci_dev *dev)
 {
        int ea;
@@ -2547,7 +2547,7 @@ void pci_request_acs(void)
  * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
  * @dev: the PCI device
  */
-static int pci_std_enable_acs(struct pci_dev *dev)
+static void pci_std_enable_acs(struct pci_dev *dev)
 {
        int pos;
        u16 cap;
@@ -2555,7 +2555,7 @@ static int pci_std_enable_acs(struct pci_dev *dev)
 
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
        if (!pos)
-               return -ENODEV;
+               return;
 
        pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
        pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
@@ -2573,8 +2573,6 @@ static int pci_std_enable_acs(struct pci_dev *dev)
        ctrl |= (cap & PCI_ACS_UF);
 
        pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
-
-       return 0;
 }
 
 /**
@@ -2586,10 +2584,10 @@ void pci_enable_acs(struct pci_dev *dev)
        if (!pci_acs_enable)
                return;
 
-       if (!pci_std_enable_acs(dev))
+       if (!pci_dev_specific_enable_acs(dev))
                return;
 
-       pci_dev_specific_enable_acs(dev);
+       pci_std_enable_acs(dev);
 }
 
 static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
@@ -4578,6 +4576,37 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
        return 0;
 }
 
+/**
+ * pci_add_dma_alias - Add a DMA devfn alias for a device
+ * @dev: the PCI device for which alias is added
+ * @devfn: alias slot and function
+ *
+ * This helper encodes 8-bit devfn as bit number in dma_alias_mask.
+ * It should be called early, preferably as PCI fixup header quirk.
+ */
+void pci_add_dma_alias(struct pci_dev *dev, u8 devfn)
+{
+       if (!dev->dma_alias_mask)
+               dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX),
+                                             sizeof(long), GFP_KERNEL);
+       if (!dev->dma_alias_mask) {
+               dev_warn(&dev->dev, "Unable to allocate DMA alias mask\n");
+               return;
+       }
+
+       set_bit(devfn, dev->dma_alias_mask);
+       dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n",
+                PCI_SLOT(devfn), PCI_FUNC(devfn));
+}
+
+bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2)
+{
+       return (dev1->dma_alias_mask &&
+               test_bit(dev2->devfn, dev1->dma_alias_mask)) ||
+              (dev2->dma_alias_mask &&
+               test_bit(dev1->devfn, dev2->dma_alias_mask));
+}
+
 bool pci_device_is_present(struct pci_dev *pdev)
 {
        u32 v;
index 72db7f4209cad52181cc80b38558f4827955a866..22ca6412bd15c5e36d8965783f79531c58907cf6 100644 (file)
@@ -81,3 +81,17 @@ endchoice
 config PCIE_PME
        def_bool y
        depends on PCIEPORTBUS && PM
+
+config PCIE_DPC
+       tristate "PCIe Downstream Port Containment support"
+       depends on PCIEPORTBUS
+       default n
+       help
+         This enables PCI Express Downstream Port Containment (DPC)
+         driver support.  DPC events from Root and Downstream ports
+         will be handled by the DPC driver.  If your system doesn't
+         have this capability or you do not want to use this feature,
+         it is safe to answer N.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pcie-dpc.
index 00c62df5a9fc4773405c74aca96d894f7515c108..b24525b3dec1a8833f76c9d5ef491357ebf8a6cf 100644 (file)
@@ -14,3 +14,5 @@ obj-$(CONFIG_PCIEPORTBUS)     += pcieportdrv.o
 obj-$(CONFIG_PCIEAER)          += aer/
 
 obj-$(CONFIG_PCIE_PME) += pme.o
+
+obj-$(CONFIG_PCIE_DPC) += pcie-dpc.o
diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c
new file mode 100644 (file)
index 0000000..ab552f1
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * PCI Express Downstream Port Containment services driver
+ * Copyright (C) 2016 Intel Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pcieport_if.h>
+
+struct dpc_dev {
+       struct pcie_device      *dev;
+       struct work_struct      work;
+       int                     cap_pos;
+};
+
+static void dpc_wait_link_inactive(struct pci_dev *pdev)
+{
+       unsigned long timeout = jiffies + HZ;
+       u16 lnk_status;
+
+       pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
+       while (lnk_status & PCI_EXP_LNKSTA_DLLLA &&
+                                       !time_after(jiffies, timeout)) {
+               msleep(10);
+               pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
+       }
+       if (lnk_status & PCI_EXP_LNKSTA_DLLLA)
+               dev_warn(&pdev->dev, "Link state not disabled for DPC event");
+}
+
+static void interrupt_event_handler(struct work_struct *work)
+{
+       struct dpc_dev *dpc = container_of(work, struct dpc_dev, work);
+       struct pci_dev *dev, *temp, *pdev = dpc->dev->port;
+       struct pci_bus *parent = pdev->subordinate;
+
+       pci_lock_rescan_remove();
+       list_for_each_entry_safe_reverse(dev, temp, &parent->devices,
+                                        bus_list) {
+               pci_dev_get(dev);
+               pci_stop_and_remove_bus_device(dev);
+               pci_dev_put(dev);
+       }
+       pci_unlock_rescan_remove();
+
+       dpc_wait_link_inactive(pdev);
+       pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS,
+               PCI_EXP_DPC_STATUS_TRIGGER | PCI_EXP_DPC_STATUS_INTERRUPT);
+}
+
+static irqreturn_t dpc_irq(int irq, void *context)
+{
+       struct dpc_dev *dpc = (struct dpc_dev *)context;
+       struct pci_dev *pdev = dpc->dev->port;
+       u16 status, source;
+
+       pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status);
+       pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_SOURCE_ID,
+                            &source);
+       if (!status)
+               return IRQ_NONE;
+
+       dev_info(&dpc->dev->device, "DPC containment event, status:%#06x source:%#06x\n",
+               status, source);
+
+       if (status & PCI_EXP_DPC_STATUS_TRIGGER) {
+               u16 reason = (status >> 1) & 0x3;
+
+               dev_warn(&dpc->dev->device, "DPC %s triggered, remove downstream devices\n",
+                        (reason == 0) ? "unmasked uncorrectable error" :
+                        (reason == 1) ? "ERR_NONFATAL" :
+                        (reason == 2) ? "ERR_FATAL" : "extended error");
+               schedule_work(&dpc->work);
+       }
+       return IRQ_HANDLED;
+}
+
+#define FLAG(x, y) (((x) & (y)) ? '+' : '-')
+static int dpc_probe(struct pcie_device *dev)
+{
+       struct dpc_dev *dpc;
+       struct pci_dev *pdev = dev->port;
+       int status;
+       u16 ctl, cap;
+
+       dpc = kzalloc(sizeof(*dpc), GFP_KERNEL);
+       if (!dpc)
+               return -ENOMEM;
+
+       dpc->cap_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC);
+       dpc->dev = dev;
+       INIT_WORK(&dpc->work, interrupt_event_handler);
+       set_service_data(dev, dpc);
+
+       status = request_irq(dev->irq, dpc_irq, IRQF_SHARED, "pcie-dpc", dpc);
+       if (status) {
+               dev_warn(&dev->device, "request IRQ%d failed: %d\n", dev->irq,
+                        status);
+               goto out;
+       }
+
+       pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap);
+       pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl);
+
+       ctl |= PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN;
+       pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
+
+       dev_info(&dev->device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
+               cap & 0xf, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT),
+               FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP),
+               FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), (cap >> 8) & 0xf,
+               FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE));
+       return status;
+ out:
+       kfree(dpc);
+       return status;
+}
+
+static void dpc_remove(struct pcie_device *dev)
+{
+       struct dpc_dev *dpc = get_service_data(dev);
+       struct pci_dev *pdev = dev->port;
+       u16 ctl;
+
+       pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl);
+       ctl &= ~(PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN);
+       pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
+
+       free_irq(dev->irq, dpc);
+       kfree(dpc);
+}
+
+static struct pcie_port_service_driver dpcdriver = {
+       .name           = "dpc",
+       .port_type      = PCI_EXP_TYPE_ROOT_PORT | PCI_EXP_TYPE_DOWNSTREAM,
+       .service        = PCIE_PORT_SERVICE_DPC,
+       .probe          = dpc_probe,
+       .remove         = dpc_remove,
+};
+
+static int __init dpc_service_init(void)
+{
+       return pcie_port_service_register(&dpcdriver);
+}
+
+static void __exit dpc_service_exit(void)
+{
+       pcie_port_service_unregister(&dpcdriver);
+}
+
+MODULE_DESCRIPTION("PCI Express Downstream Port Containment driver");
+MODULE_AUTHOR("Keith Busch <keith.busch@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+module_init(dpc_service_init);
+module_exit(dpc_service_exit);
index d525548404d69eda837d1cbe69e668b72116d56e..587aef36030dbbabe591b7dc98c3f5f16f75f378 100644 (file)
 
 #include <linux/compiler.h>
 
-#define PCIE_PORT_DEVICE_MAXSERVICES   4
+#define PCIE_PORT_DEVICE_MAXSERVICES   5
 /*
  * According to the PCI Express Base Specification 2.0, the indices of
  * the MSI-X table entries used by port services must not exceed 31
  */
 #define PCIE_PORT_MAX_MSIX_ENTRIES     32
 
-#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
+#define get_descriptor_id(type, service) (((type - 4) << 8) | service)
 
 extern struct bus_type pcie_port_bus_type;
 int pcie_port_device_register(struct pci_dev *dev);
@@ -67,17 +67,14 @@ static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
 #endif /* !CONFIG_PCIE_PME */
 
 #ifdef CONFIG_ACPI
-int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
+void pcie_port_acpi_setup(struct pci_dev *port, int *mask);
 
-static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+static inline void pcie_port_platform_notify(struct pci_dev *port, int *mask)
 {
-       return pcie_port_acpi_setup(port, mask);
+       pcie_port_acpi_setup(port, mask);
 }
 #else /* !CONFIG_ACPI */
-static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
-{
-       return 0;
-}
+static inline void pcie_port_platform_notify(struct pci_dev *port, int *mask){}
 #endif /* !CONFIG_ACPI */
 
 #endif /* _PORTDRV_H_ */
index b4d2894ee3fc83c8e60a1fc8159452d8a54ad8dd..6b8c2f1d0e71eaa035b4fd0c4c8cadc3c6b3ddef 100644 (file)
  * NOTE: It turns out that we cannot do that for individual port services
  * separately, because that would make some systems work incorrectly.
  */
-int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
+void pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
 {
        struct acpi_pci_root *root;
        acpi_handle handle;
        u32 flags;
 
        if (acpi_pci_disabled)
-               return 0;
+               return;
 
        handle = acpi_find_root_bridge_handle(port);
        if (!handle)
-               return -EINVAL;
+               return;
 
        root = acpi_pci_find_root(handle);
        if (!root)
-               return -ENODEV;
+               return;
 
        flags = root->osc_control_set;
 
-       *srv_mask = PCIE_PORT_SERVICE_VC;
+       *srv_mask = PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_DPC;
        if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)
                *srv_mask |= PCIE_PORT_SERVICE_HP;
        if (flags & OSC_PCI_EXPRESS_PME_CONTROL)
                *srv_mask |= PCIE_PORT_SERVICE_PME;
        if (flags & OSC_PCI_EXPRESS_AER_CONTROL)
                *srv_mask |= PCIE_PORT_SERVICE_AER;
-
-       return 0;
 }
index 847f4fdca50ca1a216eb62b2dcfaa0ba0a63eb80..32d4d0a3d20e5f2b5b2e78a90adc77081ad451be 100644 (file)
@@ -255,21 +255,17 @@ static int get_port_device_capability(struct pci_dev *dev)
 {
        int services = 0;
        int cap_mask = 0;
-       int err;
 
        if (pcie_ports_disabled)
                return 0;
 
        cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
-                       | PCIE_PORT_SERVICE_VC;
+                       | PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_DPC;
        if (pci_aer_available())
                cap_mask |= PCIE_PORT_SERVICE_AER;
 
-       if (pcie_ports_auto) {
-               err = pcie_port_platform_notify(dev, &cap_mask);
-               if (err)
-                       return 0;
-       }
+       if (pcie_ports_auto)
+               pcie_port_platform_notify(dev, &cap_mask);
 
        /* Hot-Plug Capable */
        if ((cap_mask & PCIE_PORT_SERVICE_HP) && dev->is_hotplug_bridge) {
@@ -305,6 +301,8 @@ static int get_port_device_capability(struct pci_dev *dev)
                 */
                pcie_pme_interrupt_enable(dev, false);
        }
+       if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC))
+               services |= PCIE_PORT_SERVICE_DPC;
 
        return services;
 }
@@ -332,7 +330,7 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
        device = &pcie->device;
        device->bus = &pcie_port_bus_type;
        device->release = release_pcie_device;  /* callback to free pcie dev */
-       dev_set_name(device, "%s:pcie%02x",
+       dev_set_name(device, "%s:pcie%03x",
                     pci_name(pdev),
                     get_descriptor_id(pci_pcie_type(pdev), service));
        device->parent = &pdev->dev;
index 8004f67c57ec6ae59157714e507f06429127765e..8e3ef720997dfba2858c4dae77b2a0651f678c2d 100644 (file)
@@ -179,9 +179,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
        u16 orig_cmd;
        struct pci_bus_region region, inverted_region;
 
-       if (dev->non_compliant_bars)
-               return 0;
-
        mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
 
        /* No printks while decoding is disabled! */
@@ -322,6 +319,9 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
 {
        unsigned int pos, reg;
 
+       if (dev->non_compliant_bars)
+               return;
+
        for (pos = 0; pos < howmany; pos++) {
                struct resource *res = &dev->resource[pos];
                reg = PCI_BASE_ADDRESS_0 + (pos << 2);
@@ -1537,6 +1537,7 @@ static void pci_release_dev(struct device *dev)
        pcibios_release_device(pci_dev);
        pci_bus_put(pci_dev->bus);
        kfree(pci_dev->driver_override);
+       kfree(pci_dev->dma_alias_mask);
        kfree(pci_dev);
 }
 
index 8e678027b9008ee15e741967313332db2818c8d8..ee72ebe18f4b5a6510d043da9abcee50cbada987 100644 (file)
@@ -3150,6 +3150,39 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169,
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID,
                         quirk_broken_intx_masking);
 
+/*
+ * Intel i40e (XL710/X710) 10/20/40GbE NICs all have broken INTx masking,
+ * DisINTx can be set but the interrupt status bit is non-functional.
+ */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1572,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1574,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1580,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1581,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1583,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1584,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1585,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1586,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1587,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1588,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1589,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x37d0,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x37d1,
+                        quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x37d2,
+                        quirk_broken_intx_masking);
+
 static void quirk_no_bus_reset(struct pci_dev *dev)
 {
        dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
@@ -3185,6 +3218,29 @@ static void quirk_no_pm_reset(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
                               PCI_CLASS_DISPLAY_VGA, 8, quirk_no_pm_reset);
 
+/*
+ * Thunderbolt controllers with broken MSI hotplug signaling:
+ * Entire 1st generation (Light Ridge, Eagle Ridge, Light Peak) and part
+ * of the 2nd generation (Cactus Ridge 4C up to revision 1, Port Ridge).
+ */
+static void quirk_thunderbolt_hotplug_msi(struct pci_dev *pdev)
+{
+       if (pdev->is_hotplug_bridge &&
+           (pdev->device != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C ||
+            pdev->revision <= 1))
+               pdev->no_msi = 1;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LIGHT_RIDGE,
+                       quirk_thunderbolt_hotplug_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EAGLE_RIDGE,
+                       quirk_thunderbolt_hotplug_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LIGHT_PEAK,
+                       quirk_thunderbolt_hotplug_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C,
+                       quirk_thunderbolt_hotplug_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PORT_RIDGE,
+                       quirk_thunderbolt_hotplug_msi);
+
 #ifdef CONFIG_ACPI
 /*
  * Apple: Shutdown Cactus Ridge Thunderbolt controller.
@@ -3232,7 +3288,8 @@ static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev)
        acpi_execute_simple_method(SXIO, NULL, 0);
        acpi_execute_simple_method(SXLV, NULL, 0);
 }
-DECLARE_PCI_FIXUP_SUSPEND_LATE(PCI_VENDOR_ID_INTEL, 0x1547,
+DECLARE_PCI_FIXUP_SUSPEND_LATE(PCI_VENDOR_ID_INTEL,
+                              PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C,
                               quirk_apple_poweroff_thunderbolt);
 
 /*
@@ -3266,9 +3323,11 @@ static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev)
        if (!nhi)
                goto out;
        if (nhi->vendor != PCI_VENDOR_ID_INTEL
-                       || (nhi->device != 0x1547 && nhi->device != 0x156c)
-                       || nhi->subsystem_vendor != 0x2222
-                       || nhi->subsystem_device != 0x1111)
+                   || (nhi->device != PCI_DEVICE_ID_INTEL_LIGHT_RIDGE &&
+                       nhi->device != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C &&
+                       nhi->device != PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI)
+                   || nhi->subsystem_vendor != 0x2222
+                   || nhi->subsystem_device != 0x1111)
                goto out;
        dev_info(&dev->dev, "quirk: waiting for thunderbolt to reestablish PCI tunnels...\n");
        device_pm_wait_for_dev(&dev->dev, &nhi->dev);
@@ -3276,9 +3335,14 @@ out:
        pci_dev_put(nhi);
        pci_dev_put(sibling);
 }
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, 0x1547,
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL,
+                              PCI_DEVICE_ID_INTEL_LIGHT_RIDGE,
                               quirk_apple_wait_for_thunderbolt);
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, 0x156d,
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL,
+                              PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C,
+                              quirk_apple_wait_for_thunderbolt);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL,
+                              PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_BRIDGE,
                               quirk_apple_wait_for_thunderbolt);
 #endif
 
@@ -3610,10 +3674,8 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe)
 
 static void quirk_dma_func0_alias(struct pci_dev *dev)
 {
-       if (PCI_FUNC(dev->devfn) != 0) {
-               dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0);
-               dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
-       }
+       if (PCI_FUNC(dev->devfn) != 0)
+               pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
 }
 
 /*
@@ -3626,10 +3688,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe476, quirk_dma_func0_alias);
 
 static void quirk_dma_func1_alias(struct pci_dev *dev)
 {
-       if (PCI_FUNC(dev->devfn) != 1) {
-               dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 1);
-               dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
-       }
+       if (PCI_FUNC(dev->devfn) != 1)
+               pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
 }
 
 /*
@@ -3695,13 +3755,8 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev)
        const struct pci_device_id *id;
 
        id = pci_match_id(fixed_dma_alias_tbl, dev);
-       if (id) {
-               dev->dma_alias_devfn = id->driver_data;
-               dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
-               dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n",
-                        PCI_SLOT(dev->dma_alias_devfn),
-                        PCI_FUNC(dev->dma_alias_devfn));
-       }
+       if (id)
+               pci_add_dma_alias(dev, id->driver_data);
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias);
@@ -3733,6 +3788,21 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias);
 /* Intel 82801, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c49 */
 DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias);
 
+/*
+ * MIC x200 NTB forwards PCIe traffic using multiple alien RIDs. They have to
+ * be added as aliases to the DMA device in order to allow buffer access
+ * when IOMMU is enabled. Following devfns have to match RIT-LUT table
+ * programmed in the EEPROM.
+ */
+static void quirk_mic_x200_dma_alias(struct pci_dev *pdev)
+{
+       pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0));
+       pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0));
+       pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3));
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2260, quirk_mic_x200_dma_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias);
+
 /*
  * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero)
  * class code.  Fix it.
@@ -3936,6 +4006,55 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
        return acs_flags & ~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,
+ * 12.1.46, 12.1.47)[1] this chipset uses dwords for the ACS capability and
+ * control registers whereas the PCIe spec packs them into words (Rev 3.0,
+ * 7.16 ACS Extended Capability).  The bit definitions are correct, but the
+ * control register is at offset 8 instead of 6 and we should probably use
+ * dword accesses to them.  This applies to the following PCI Device IDs, as
+ * found in volume 1 of the datasheet[2]:
+ *
+ * 0xa110-0xa11f Sunrise Point-H PCI Express Root Port #{0-16}
+ * 0xa167-0xa16a Sunrise Point-H PCI Express Root Port #{17-20}
+ *
+ * N.B. This doesn't fix what lspci shows.
+ *
+ * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html
+ * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html
+ */
+static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev)
+{
+       return pci_is_pcie(dev) &&
+               pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT &&
+               ((dev->device & ~0xf) == 0xa110 ||
+                (dev->device >= 0xa167 && dev->device <= 0xa16a));
+}
+
+#define INTEL_SPT_ACS_CTRL (PCI_ACS_CAP + 4)
+
+static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags)
+{
+       int pos;
+       u32 cap, ctrl;
+
+       if (!pci_quirk_intel_spt_pch_acs_match(dev))
+               return -ENOTTY;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+       if (!pos)
+               return -ENOTTY;
+
+       /* see pci_acs_flags_enabled() */
+       pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap);
+       acs_flags &= (cap | PCI_ACS_EC);
+
+       pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
+
+       return acs_flags & ~ctrl ? 0 : 1;
+}
+
 static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
 {
        /*
@@ -4024,6 +4143,7 @@ static const struct pci_dev_acs_enabled {
        { PCI_VENDOR_ID_INTEL, 0x15b8, pci_quirk_mf_endpoint_acs },
        /* Intel PCH root ports */
        { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
+       { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_spt_pch_acs },
        { 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */
        { 0x10df, 0x720, pci_quirk_mf_endpoint_acs }, /* Emulex Skyhawk-R */
        /* Cavium ThunderX */
@@ -4159,16 +4279,44 @@ static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
        return 0;
 }
 
+static int pci_quirk_enable_intel_spt_pch_acs(struct pci_dev *dev)
+{
+       int pos;
+       u32 cap, ctrl;
+
+       if (!pci_quirk_intel_spt_pch_acs_match(dev))
+               return -ENOTTY;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+       if (!pos)
+               return -ENOTTY;
+
+       pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap);
+       pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
+
+       ctrl |= (cap & PCI_ACS_SV);
+       ctrl |= (cap & PCI_ACS_RR);
+       ctrl |= (cap & PCI_ACS_CR);
+       ctrl |= (cap & PCI_ACS_UF);
+
+       pci_write_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, ctrl);
+
+       dev_info(&dev->dev, "Intel SPT PCH root port ACS workaround enabled\n");
+
+       return 0;
+}
+
 static const struct pci_dev_enable_acs {
        u16 vendor;
        u16 device;
        int (*enable_acs)(struct pci_dev *dev);
 } pci_dev_enable_acs[] = {
        { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs },
+       { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_spt_pch_acs },
        { 0 }
 };
 
-void pci_dev_specific_enable_acs(struct pci_dev *dev)
+int pci_dev_specific_enable_acs(struct pci_dev *dev)
 {
        const struct pci_dev_enable_acs *i;
        int ret;
@@ -4180,9 +4328,11 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
                     i->device == (u16)PCI_ANY_ID)) {
                        ret = i->enable_acs(dev);
                        if (ret >= 0)
-                               return;
+                               return ret;
                }
        }
+
+       return -ENOTTY;
 }
 
 /*
index a20ce7d5e2a718551554a1e860457b852756d97b..33e0f033a48e7e2f6097b13d4425d8d17b1cabb7 100644 (file)
@@ -40,11 +40,15 @@ int pci_for_each_dma_alias(struct pci_dev *pdev,
         * If the device is broken and uses an alias requester ID for
         * DMA, iterate over that too.
         */
-       if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) {
-               ret = fn(pdev, PCI_DEVID(pdev->bus->number,
-                                        pdev->dma_alias_devfn), data);
-               if (ret)
-                       return ret;
+       if (unlikely(pdev->dma_alias_mask)) {
+               u8 devfn;
+
+               for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) {
+                       ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn),
+                                data);
+                       if (ret)
+                               return ret;
+               }
        }
 
        for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
index 799634b382c6f0a131fb9eadd31dc89984f16830..1146ff4210a9345eb349e742e6f192f2a5451475 100644 (file)
@@ -249,7 +249,7 @@ static void tb_cfg_print_error(struct tb_ctl *ctl,
                 * cfg_read/cfg_write.
                 */
                tb_ctl_WARN(ctl,
-                       "CFG_ERROR(%llx:%x): Invalid config space of offset\n",
+                       "CFG_ERROR(%llx:%x): Invalid config space or offset\n",
                        res->response_route, res->response_port);
                return;
        case TB_CFG_ERROR_NO_SUCH_PORT:
index 0dde34e3a7c5aa793e8bec8239f297b30ace2d95..2b9602c2c35515aa91c53df8687abc9474253cec 100644 (file)
@@ -221,7 +221,7 @@ struct tb_drom_entry_port {
        u8 micro1:4;
        u8 micro3;
 
-       /* BYTES 5-6, TODO: verify (find hardware that has these set) */
+       /* BYTES 6-7, TODO: verify (find hardware that has these set) */
        u8 peer_port_rid:4;
        u8 unknown3:3;
        bool has_peer_port:1;
@@ -388,6 +388,11 @@ int tb_drom_read(struct tb_switch *sw)
                sw->ports[4].link_nr = 1;
                sw->ports[3].dual_link_port = &sw->ports[4];
                sw->ports[4].dual_link_port = &sw->ports[3];
+
+               /* Port 5 is inaccessible on this gen 1 controller */
+               if (sw->config.device_id == PCI_DEVICE_ID_INTEL_LIGHT_RIDGE)
+                       sw->ports[5].disabled = true;
+
                return 0;
        }
 
@@ -444,6 +449,7 @@ int tb_drom_read(struct tb_switch *sw)
        return tb_drom_parse_entries(sw);
 err:
        kfree(sw->drom);
+       sw->drom = NULL;
        return -EIO;
 
 }
index 20a41f7de76f687d39329c2f4ea58ae30dc8fc6d..9c15344b657acebb240e8555af47e572314acd5c 100644 (file)
@@ -37,7 +37,8 @@ static int ring_interrupt_index(struct tb_ring *ring)
  */
 static void ring_interrupt_active(struct tb_ring *ring, bool active)
 {
-       int reg = REG_RING_INTERRUPT_BASE + ring_interrupt_index(ring) / 32;
+       int reg = REG_RING_INTERRUPT_BASE +
+                 ring_interrupt_index(ring) / 32 * 4;
        int bit = ring_interrupt_index(ring) & 31;
        int mask = 1 << bit;
        u32 old, new;
@@ -564,7 +565,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        /* cannot fail - table is allocated bin pcim_iomap_regions */
        nhi->iobase = pcim_iomap_table(pdev)[0];
        nhi->hop_count = ioread32(nhi->iobase + REG_HOP_COUNT) & 0x3ff;
-       if (nhi->hop_count != 12)
+       if (nhi->hop_count != 12 && nhi->hop_count != 32)
                dev_warn(&pdev->dev, "unexpected hop count: %d\n",
                         nhi->hop_count);
        INIT_WORK(&nhi->interrupt_work, nhi_interrupt_work);
@@ -633,16 +634,24 @@ static const struct dev_pm_ops nhi_pm_ops = {
 static struct pci_device_id nhi_ids[] = {
        /*
         * We have to specify class, the TB bridges use the same device and
-        * vendor (sub)id.
+        * vendor (sub)id on gen 1 and gen 2 controllers.
         */
        {
                .class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
-               .vendor = PCI_VENDOR_ID_INTEL, .device = 0x1547,
+               .vendor = PCI_VENDOR_ID_INTEL,
+               .device = PCI_DEVICE_ID_INTEL_LIGHT_RIDGE,
                .subvendor = 0x2222, .subdevice = 0x1111,
        },
        {
                .class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
-               .vendor = PCI_VENDOR_ID_INTEL, .device = 0x156c,
+               .vendor = PCI_VENDOR_ID_INTEL,
+               .device = PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C,
+               .subvendor = 0x2222, .subdevice = 0x1111,
+       },
+       {
+               .class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
+               .vendor = PCI_VENDOR_ID_INTEL,
+               .device = PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI,
                .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
        },
        { 0,}
index aeb9829696292a454fa3f721f0a0d6a6baaf1760..1e116f53d6dddb254c465ebd5362d2c6162066a1 100644 (file)
@@ -293,9 +293,9 @@ static int tb_plug_events_active(struct tb_switch *sw, bool active)
        if (active) {
                data = data & 0xFFFFFF83;
                switch (sw->config.device_id) {
-               case 0x1513:
-               case 0x151a:
-               case 0x1549:
+               case PCI_DEVICE_ID_INTEL_LIGHT_RIDGE:
+               case PCI_DEVICE_ID_INTEL_EAGLE_RIDGE:
+               case PCI_DEVICE_ID_INTEL_PORT_RIDGE:
                        break;
                default:
                        data |= 4;
@@ -350,7 +350,7 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route)
                return NULL;
 
        sw->tb = tb;
-       if (tb_cfg_read(tb->ctl, &sw->config, route, 0, 2, 0, 5))
+       if (tb_cfg_read(tb->ctl, &sw->config, route, 0, TB_CFG_SWITCH, 0, 5))
                goto err;
        tb_info(tb,
                "initializing Switch at %#llx (depth: %d, up port: %d)\n",
@@ -370,7 +370,9 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route)
                tb_sw_warn(sw, "unknown switch vendor id %#x\n",
                           sw->config.vendor_id);
 
-       if (sw->config.device_id != 0x1547 && sw->config.device_id != 0x1549)
+       if (sw->config.device_id != PCI_DEVICE_ID_INTEL_LIGHT_RIDGE &&
+           sw->config.device_id != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C &&
+           sw->config.device_id != PCI_DEVICE_ID_INTEL_PORT_RIDGE)
                tb_sw_warn(sw, "unsupported switch device id %#x\n",
                           sw->config.device_id);
 
@@ -425,9 +427,9 @@ err:
 }
 
 /**
- * tb_sw_set_unpplugged() - set is_unplugged on switch and downstream switches
+ * tb_sw_set_unplugged() - set is_unplugged on switch and downstream switches
  */
-void tb_sw_set_unpplugged(struct tb_switch *sw)
+void tb_sw_set_unplugged(struct tb_switch *sw)
 {
        int i;
        if (sw == sw->tb->root_switch) {
@@ -441,7 +443,7 @@ void tb_sw_set_unpplugged(struct tb_switch *sw)
        sw->is_unplugged = true;
        for (i = 0; i <= sw->config.max_port_number; i++) {
                if (!tb_is_upstream_port(&sw->ports[i]) && sw->ports[i].remote)
-                       tb_sw_set_unpplugged(sw->ports[i].remote->sw);
+                       tb_sw_set_unplugged(sw->ports[i].remote->sw);
        }
 }
 
@@ -483,7 +485,7 @@ int tb_switch_resume(struct tb_switch *sw)
                        || tb_switch_resume(port->remote->sw)) {
                        tb_port_warn(port,
                                     "lost during suspend, disconnecting\n");
-                       tb_sw_set_unpplugged(port->remote->sw);
+                       tb_sw_set_unplugged(port->remote->sw);
                }
        }
        return 0;
index d2c3fe346e91230e423cdeb88fc3f3fc2a5682c2..24b6d30c3c862676c33186a2411587a7b407467f 100644 (file)
@@ -246,7 +246,7 @@ static void tb_handle_hotplug(struct work_struct *work)
        if (ev->unplug) {
                if (port->remote) {
                        tb_port_info(port, "unplugged\n");
-                       tb_sw_set_unpplugged(port->remote->sw);
+                       tb_sw_set_unplugged(port->remote->sw);
                        tb_free_invalid_tunnels(tb);
                        tb_switch_free(port->remote->sw);
                        port->remote = NULL;
index 8b0d7cf2b6d6d68ab6dd30398c838c44aaf04781..61d57ba64035752f9b73e90082c16415de49463f 100644 (file)
@@ -226,7 +226,7 @@ void tb_switch_free(struct tb_switch *sw);
 void tb_switch_suspend(struct tb_switch *sw);
 int tb_switch_resume(struct tb_switch *sw);
 int tb_switch_reset(struct tb *tb, u64 route);
-void tb_sw_set_unpplugged(struct tb_switch *sw);
+void tb_sw_set_unplugged(struct tb_switch *sw);
 struct tb_switch *get_switch_at_route(struct tb_switch *sw, u64 route);
 
 int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged);
index 6577af75d9dce6d77ad5c6185ee1de896b015041..1e2a4a8046be046addb3751a6ca54da4013ef4ba 100644 (file)
@@ -30,7 +30,7 @@ enum tb_cap {
        TB_CAP_I2C              = 0x0005,
        TB_CAP_PLUG_EVENTS      = 0x0105, /* also EEPROM */
        TB_CAP_TIME2            = 0x0305,
-       TB_CAL_IECS             = 0x0405,
+       TB_CAP_IECS             = 0x0405,
        TB_CAP_LINK_CONTROLLER  = 0x0605, /* also IECS */
 };
 
index 0b65543dc6cf5b98e0b9e6b745ed349af3ce1bb0..6230064d7f95d072d61e2bc0eedd341463880d32 100644 (file)
@@ -26,6 +26,9 @@ struct resource {
 
 /*
  * IO resources have these defined flags.
+ *
+ * PCI devices expose these flags to userspace in the "resource" sysfs file,
+ * so don't move them.
  */
 #define IORESOURCE_BITS                0x000000ff      /* Bus-specific bits */
 
@@ -110,6 +113,7 @@ struct resource {
 
 /* PCI control bits.  Shares IORESOURCE_BITS with above PCI ROM.  */
 #define IORESOURCE_PCI_FIXED           (1<<4)  /* Do not move resource */
+#define IORESOURCE_PCI_EA_BEI          (1<<5)  /* BAR Equivalent Indicator */
 
 /*
  * I/O Resource Descriptors
index 238c8db953eba25d61151709062968d669ae0b6d..5b08e3c5325f0a7d7bbc011ad157f96b6d7effc5 100644 (file)
@@ -95,6 +95,7 @@
 #define IMX6Q_GPR0_DMAREQ_MUX_SEL0_IOMUX       BIT(0)
 
 #define IMX6Q_GPR1_PCIE_REQ_MASK               (0x3 << 30)
+#define IMX6Q_GPR1_PCIE_SW_RST                 BIT(29)
 #define IMX6Q_GPR1_PCIE_EXIT_L1                        BIT(28)
 #define IMX6Q_GPR1_PCIE_RDY_L23                        BIT(27)
 #define IMX6Q_GPR1_PCIE_ENTER_L1               BIT(26)
index 004b8133417dc9dd54315b1ca5f15a9cc28e9a2a..8e10efb99d1f5a7909acfbb1b3618c0074c2a6e9 100644 (file)
@@ -166,8 +166,6 @@ enum pci_dev_flags {
        PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2),
        /* Flag for quirk use to store if quirk-specific ACS is enabled */
        PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3),
-       /* Flag to indicate the device uses dma_alias_devfn */
-       PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4),
        /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */
        PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5),
        /* Do not use bus resets for device */
@@ -273,7 +271,7 @@ struct pci_dev {
        u8              rom_base_reg;   /* which config register controls the ROM */
        u8              pin;            /* which interrupt pin this device uses */
        u16             pcie_flags_reg; /* cached PCIe Capabilities Register */
-       u8              dma_alias_devfn;/* devfn of DMA alias, if any */
+       unsigned long   *dma_alias_mask;/* mask of enabled devfn aliases */
 
        struct pci_driver *driver;      /* which driver has allocated this device */
        u64             dma_mask;       /* Mask of the bits of bus address this
@@ -1663,7 +1661,7 @@ enum pci_fixup_pass {
 #ifdef CONFIG_PCI_QUIRKS
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
 int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
-void pci_dev_specific_enable_acs(struct pci_dev *dev);
+int pci_dev_specific_enable_acs(struct pci_dev *dev);
 #else
 static inline void pci_fixup_device(enum pci_fixup_pass pass,
                                    struct pci_dev *dev) { }
@@ -1672,7 +1670,10 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
 {
        return -ENOTTY;
 }
-static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) { }
+static inline int pci_dev_specific_enable_acs(struct pci_dev *dev)
+{
+       return -ENOTTY;
+}
 #endif
 
 void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
@@ -1988,6 +1989,8 @@ static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
 }
 #endif
 
+void pci_add_dma_alias(struct pci_dev *dev, u8 devfn);
+bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2);
 int pci_for_each_dma_alias(struct pci_dev *pdev,
                           int (*fn)(struct pci_dev *pdev,
                                     u16 alias, void *data), void *data);
index 247da8c9586073d6759d333051909c5c4d050315..c58752fe16c43110b736a0e21fe9a702459d8a34 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82441      0x1237
 #define PCI_DEVICE_ID_INTEL_82380FB    0x124b
 #define PCI_DEVICE_ID_INTEL_82439      0x1250
+#define PCI_DEVICE_ID_INTEL_LIGHT_RIDGE             0x1513 /* Tbt 1 Gen 1 */
+#define PCI_DEVICE_ID_INTEL_EAGLE_RIDGE             0x151a
+#define PCI_DEVICE_ID_INTEL_LIGHT_PEAK              0x151b
+#define PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C         0x1547 /* Tbt 1 Gen 2 */
+#define PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_2C         0x1548
+#define PCI_DEVICE_ID_INTEL_PORT_RIDGE              0x1549
+#define PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_2C_NHI    0x1566 /* Tbt 1 Gen 3 */
+#define PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_2C_BRIDGE 0x1567
+#define PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_4C_NHI    0x1568
+#define PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_4C_BRIDGE 0x1569
+#define PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_NHI     0x156a /* Thunderbolt 2 */
+#define PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_BRIDGE  0x156b
+#define PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI     0x156c
+#define PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_BRIDGE  0x156d
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_NHI     0x1575 /* Thunderbolt 3 */
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_BRIDGE  0x1576
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_NHI     0x1577
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE  0x1578
 #define PCI_DEVICE_ID_INTEL_80960_RP   0x1960
 #define PCI_DEVICE_ID_INTEL_82840_HB   0x1a21
 #define PCI_DEVICE_ID_INTEL_82845_HB   0x1a30
index 4f1089f2cc98b6b4690ac67aedce42ef4350e122..afcd130ab3a914c6a8af4736ae8cdc6cac11b703 100644 (file)
@@ -21,6 +21,8 @@
 #define PCIE_PORT_SERVICE_HP           (1 << PCIE_PORT_SERVICE_HP_SHIFT)
 #define PCIE_PORT_SERVICE_VC_SHIFT     3       /* Virtual Channel */
 #define PCIE_PORT_SERVICE_VC           (1 << PCIE_PORT_SERVICE_VC_SHIFT)
+#define PCIE_PORT_SERVICE_DPC_SHIFT    4       /* Downstream Port Containment */
+#define PCIE_PORT_SERVICE_DPC          (1 << PCIE_PORT_SERVICE_DPC_SHIFT)
 
 struct pcie_device {
        int             irq;        /* Service IRQ/MSI/MSI-X Vector */
index 1becea86c73c9d217ef867fac0cce73e075c6427..404095124ae203c7d8ca0e4e206416368af39cb5 100644 (file)
 #define PCI_EXT_CAP_ID_SECPCI  0x19    /* Secondary PCIe Capability */
 #define PCI_EXT_CAP_ID_PMUX    0x1A    /* Protocol Multiplexing */
 #define PCI_EXT_CAP_ID_PASID   0x1B    /* Process Address Space ID */
-#define PCI_EXT_CAP_ID_MAX     PCI_EXT_CAP_ID_PASID
+#define PCI_EXT_CAP_ID_DPC     0x1D    /* Downstream Port Containment */
+#define PCI_EXT_CAP_ID_MAX     PCI_EXT_CAP_ID_DPC
 
 #define PCI_EXT_CAP_DSN_SIZEOF 12
 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
 #define PCI_TPH_CAP_ST_SHIFT   16      /* st table shift */
 #define PCI_TPH_BASE_SIZEOF    12      /* size with no st table */
 
+/* Downstream Port Containment */
+#define PCI_EXP_DPC_CAP                        4       /* DPC Capability */
+#define  PCI_EXP_DPC_CAP_RP_EXT                0x20    /* Root Port Extensions for DPC */
+#define  PCI_EXP_DPC_CAP_POISONED_TLP  0x40    /* Poisoned TLP Egress Blocking Supported */
+#define  PCI_EXP_DPC_CAP_SW_TRIGGER    0x80    /* Software Triggering Supported */
+#define  PCI_EXP_DPC_CAP_DL_ACTIVE     0x1000  /* ERR_COR signal on DL_Active supported */
+
+#define PCI_EXP_DPC_CTL                        6       /* DPC control */
+#define  PCI_EXP_DPC_CTL_EN_NONFATAL   0x02    /* Enable trigger on ERR_NONFATAL message */
+#define  PCI_EXP_DPC_CTL_INT_EN        0x08    /* DPC Interrupt Enable */
+
+#define PCI_EXP_DPC_STATUS             8       /* DPC Status */
+#define  PCI_EXP_DPC_STATUS_TRIGGER    0x01    /* Trigger Status */
+#define  PCI_EXP_DPC_STATUS_INTERRUPT  0x08    /* Interrupt Status */
+
+#define PCI_EXP_DPC_SOURCE_ID          10      /* DPC Source Identifier */
+
 #endif /* LINUX_PCI_REGS_H */