]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branches 'pci/host-altera', 'pci/host-designware', 'pci/host-generic', 'pci...
authorBjorn Helgaas <bhelgaas@google.com>
Thu, 29 Oct 2015 23:20:56 +0000 (18:20 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 29 Oct 2015 23:20:56 +0000 (18:20 -0500)
* pci/host-altera:
  PCI: altera: Add Altera PCIe MSI driver
  PCI: altera: Add Altera PCIe host controller driver
  ARM: Add msi.h to Kbuild

* pci/host-designware:
  PCI: designware: Make num-lanes an optional DT property
  PCI: designware: Require config accesses to be naturally aligned
  PCI: designware: Simplify dw_pcie_cfg_read/write() interfaces
  PCI: designware: Use exact access size in dw_pcie_cfg_read()
  PCI: spear: Fix dw_pcie_cfg_read/write() usage
  PCI: designware: Set up high part of MSI target address
  PCI: designware: Make get_msi_addr() return phys_addr_t, not u32
  PCI: designware: Implement multivector MSI IRQ setup
  PCI: designware: Factor out MSI msg setup
  PCI: Add msi_controller setup_irqs() method for special multivector setup
  PCI: designware: Fix PORT_LOGIC_LINK_WIDTH_MASK

* pci/host-generic:
  PCI: generic: Fix address window calculation for non-zero starting bus
  PCI: generic: Pass starting bus number to pci_scan_root_bus()
  PCI: generic: Allow multiple hosts with different map_bus() methods
  arm64: dts: Drop linux,pci-probe-only from the Seattle DTS
  powerpc/PCI: Fix lookup of linux,pci-probe-only property
  PCI: generic: Fix lookup of linux,pci-probe-only property
  of/pci: Add of_pci_check_probe_only to parse "linux,pci-probe-only"

* pci/host-imx6:
  PCI: imx6: Add PCIE_PHY_RX_ASIC_OUT_VALID definition
  PCI: imx6: Return real error code from imx6_add_pcie_port()

* pci/host-iproc:
  PCI: iproc: Fix header comment "Corporation" misspelling
  PCI: iproc: Add outbound mapping support
  PCI: iproc: Update PCIe device tree bindings
  PCI: iproc: Improve link detection logic
  PCI: iproc: Fix PCIe reset logic
  PCI: iproc: Call pci_fixup_irqs() for ARM64 as well as ARM
  PCI: iproc: Remove unused struct iproc_pcie.irqs[]
  PCI: iproc: Fix code comment to match code

* pci/host-mvebu:
  PCI: mvebu: Remove code restricting accesses to slot 0
  PCI: mvebu: Add PCI Express root complex capability block
  PCI: mvebu: Improve clock/reset handling
  PCI: mvebu: Use gpio_desc to carry around gpio
  PCI: mvebu: Use devm_kcalloc() to allocate an array
  PCI: mvebu: Use gpio_set_value_cansleep()
  PCI: mvebu: Split port parsing and resource claiming from  port setup
  PCI: mvebu: Fix memory leaks and refcount leaks
  PCI: mvebu: Move port parsing and resource claiming to  separate function
  PCI: mvebu: Use port->name rather than "PCIe%d.%d"
  PCI: mvebu: Report full node name when reporting a DT error
  PCI: mvebu: Use for_each_available_child_of_node() to walk child nodes
  PCI: mvebu: Use of_get_available_child_count()
  PCI: mvebu: Use exact config access size; don't read/modify/write
  PCI: mvebu: Return zero for reserved or unimplemented config space

* pci/host-tegra:
  PCI: tegra: Wrap static pgprot_t initializer with __pgprot()

* pci/host-xgene:
  PCI/MSI: xgene: Remove msi_controller assignment

23 files changed:
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt
Documentation/devicetree/bindings/pci/designware-pcie.txt
Documentation/devicetree/bindings/pci/host-generic-pci.txt
arch/arm64/boot/dts/amd/amd-overdrive.dts
arch/powerpc/platforms/pseries/setup.c
drivers/of/of_pci.c
drivers/pci/host/pci-exynos.c
drivers/pci/host/pci-host-generic.c
drivers/pci/host/pci-imx6.c
drivers/pci/host/pci-keystone-dw.c
drivers/pci/host/pci-keystone.h
drivers/pci/host/pci-mvebu.c
drivers/pci/host/pci-tegra.c
drivers/pci/host/pci-xgene.c
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-designware.h
drivers/pci/host/pcie-iproc-platform.c
drivers/pci/host/pcie-iproc.c
drivers/pci/host/pcie-iproc.h
drivers/pci/host/pcie-spear13xx.c
drivers/pci/msi.c
include/linux/msi.h
include/linux/of_pci.h

index f7ce50e38ed495fdda7263878e1337b557632c5d..45c2a8094a9f7f7de65b37e41675bd0af4d6fe15 100644 (file)
@@ -17,6 +17,21 @@ Optional properties:
 - phys: phandle of the PCIe PHY device
 - phy-names: must be "pcie-phy"
 
+- brcm,pcie-ob: Some iProc SoCs do not have the outbound address mapping done
+by the ASIC after power on reset. In this case, SW needs to configure it
+
+If the brcm,pcie-ob property is present, the following properties become
+effective:
+
+Required:
+- brcm,pcie-ob-axi-offset: The offset from the AXI address to the internal
+address used by the iProc PCIe core (not the PCIe address)
+- brcm,pcie-ob-window-size: The outbound address mapping window size (in MB)
+
+Optional:
+- brcm,pcie-ob-oarr-size: Some iProc SoCs need the OARR size bit to be set to
+increase the outbound window size
+
 Example:
        pcie0: pcie@18012000 {
                compatible = "brcm,iproc-pcie";
@@ -38,6 +53,11 @@ Example:
 
                phys = <&phy 0 5>;
                phy-names = "pcie-phy";
+
+               brcm,pcie-ob;
+               brcm,pcie-ob-oarr-size;
+               brcm,pcie-ob-axi-offset = <0x00000000>;
+               brcm,pcie-ob-window-size = <256>;
        };
 
        pcie1: pcie@18013000 {
index 9f4faa8e8d005ee1810f0dc4272d63f4af3e17e6..0036ab3065b8abb15d0ae2d3c7cb438478399c5f 100644 (file)
@@ -14,7 +14,6 @@ Required properties:
 - interrupt-map-mask and interrupt-map: standard PCI properties
        to define the mapping of the PCIe interface to interrupt
        numbers.
-- num-lanes: number of lanes to use
 - clocks: Must contain an entry for each entry in clock-names.
        See ../clocks/clock-bindings.txt for details.
 - clock-names: Must include the following entries:
@@ -22,6 +21,8 @@ Required properties:
        - "pcie_bus"
 
 Optional properties:
+- num-lanes: number of lanes to use (this property should be specified unless
+  the link is brought already up in BIOS)
 - reset-gpio: gpio pin number of power good signal
 - bus-range: PCI bus numbers covered (it is recommended for new devicetrees to
   specify this property, to keep backwards compatibility a range of 0x00-0xff
index cf3e205e0b7e0de18e8e6650bdc347d996807960..3f1d3fca62bbf6a62afd1d270d271582c6c2e20e 100644 (file)
@@ -34,8 +34,9 @@ Properties of the host controller node:
 - #size-cells    : Must be 2.
 
 - reg            : The Configuration Space base address and size, as accessed
-                   from the parent bus.
-
+                   from the parent bus.  The base address corresponds to
+                   the first bus in the "bus-range" property.  If no
+                   "bus-range" is specified, this will be bus 0 (the default).
 
 Properties of the /chosen node:
 
index 564a3f7df71d76992c04e210b40077a3f4adda69..128fa942f09e9f5adccf6ac214f0e10510ca2015 100644 (file)
@@ -14,7 +14,6 @@
 
        chosen {
                stdout-path = &serial0;
-               linux,pci-probe-only;
        };
 };
 
index 39a74fad3e04526eb73222d51a6bf4812c64b034..60167096fd10d1348a4d415342e343f133ad5010 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/of.h>
+#include <linux/of_pci.h>
 #include <linux/kexec.h>
 
 #include <asm/mmu.h>
@@ -495,18 +496,7 @@ static void __init find_and_init_phbs(void)
         * PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties
         * in chosen.
         */
-       if (of_chosen) {
-               const int *prop;
-
-               prop = of_get_property(of_chosen,
-                               "linux,pci-probe-only", NULL);
-               if (prop) {
-                       if (*prop)
-                               pci_add_flags(PCI_PROBE_ONLY);
-                       else
-                               pci_clear_flags(PCI_PROBE_ONLY);
-               }
-       }
+       of_pci_check_probe_only();
 }
 
 static void __init pSeries_setup_arch(void)
index 5751dc5b6494d41fd0ed9fd88cc877f3d10707a0..d0c8902dfbf4c564cf50af70b5b6cbb6798905c5 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/of_device.h>
 #include <linux/of_pci.h>
 #include <linux/slab.h>
+#include <asm-generic/pci-bridge.h>
 
 static inline int __of_pci_pci_compare(struct device_node *node,
                                       unsigned int data)
@@ -117,6 +118,31 @@ int of_get_pci_domain_nr(struct device_node *node)
 }
 EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
 
+/**
+ * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only
+ *                           is present and valid
+ */
+void of_pci_check_probe_only(void)
+{
+       u32 val;
+       int ret;
+
+       ret = of_property_read_u32(of_chosen, "linux,pci-probe-only", &val);
+       if (ret) {
+               if (ret == -ENODATA || ret == -EOVERFLOW)
+                       pr_warn("linux,pci-probe-only without valid value, ignoring\n");
+               return;
+       }
+
+       if (val)
+               pci_add_flags(PCI_PROBE_ONLY);
+       else
+               pci_clear_flags(PCI_PROBE_ONLY);
+
+       pr_info("PCI: PROBE_ONLY %sabled\n", val ? "en" : "dis");
+}
+EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
+
 /**
  * of_pci_dma_configure - Setup DMA configuration
  * @dev: ptr to pci_dev struct of the PCI device
index f9f468d9a819d8402244e31805d51a034fb6392f..01095e1160a474b414112cdc1dddae1d8f3b9434 100644 (file)
@@ -454,7 +454,7 @@ static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
        int ret;
 
        exynos_pcie_sideband_dbi_r_mode(pp, true);
-       ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
+       ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val);
        exynos_pcie_sideband_dbi_r_mode(pp, false);
        return ret;
 }
@@ -465,8 +465,7 @@ static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
        int ret;
 
        exynos_pcie_sideband_dbi_w_mode(pp, true);
-       ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),
-                       where, size, val);
+       ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val);
        exynos_pcie_sideband_dbi_w_mode(pp, false);
        return ret;
 }
index 265dd25169bff9d2edfe827cd9321442d7c1e47d..5434c90db24345bc73ad5e00ecc00d599c40ddaf 100644 (file)
@@ -27,7 +27,7 @@
 
 struct gen_pci_cfg_bus_ops {
        u32 bus_shift;
-       void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int);
+       struct pci_ops ops;
 };
 
 struct gen_pci_cfg_windows {
@@ -35,7 +35,7 @@ struct gen_pci_cfg_windows {
        struct resource                         *bus_range;
        void __iomem                            **win;
 
-       const struct gen_pci_cfg_bus_ops        *ops;
+       struct gen_pci_cfg_bus_ops              *ops;
 };
 
 /*
@@ -65,7 +65,11 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
 
 static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = {
        .bus_shift      = 16,
-       .map_bus        = gen_pci_map_cfg_bus_cam,
+       .ops            = {
+               .map_bus        = gen_pci_map_cfg_bus_cam,
+               .read           = pci_generic_config_read,
+               .write          = pci_generic_config_write,
+       }
 };
 
 static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
@@ -80,12 +84,11 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
 
 static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
        .bus_shift      = 20,
-       .map_bus        = gen_pci_map_cfg_bus_ecam,
-};
-
-static struct pci_ops gen_pci_ops = {
-       .read   = pci_generic_config_read,
-       .write  = pci_generic_config_write,
+       .ops            = {
+               .map_bus        = gen_pci_map_cfg_bus_ecam,
+               .read           = pci_generic_config_read,
+               .write          = pci_generic_config_write,
+       }
 };
 
 static const struct of_device_id gen_pci_of_match[] = {
@@ -166,6 +169,7 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
        struct resource *bus_range;
        struct device *dev = pci->host.dev.parent;
        struct device_node *np = dev->of_node;
+       u32 sz = 1 << pci->cfg.ops->bus_shift;
 
        err = of_address_to_resource(np, 0, &pci->cfg.res);
        if (err) {
@@ -193,10 +197,9 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
        bus_range = pci->cfg.bus_range;
        for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
                u32 idx = busn - bus_range->start;
-               u32 sz = 1 << pci->cfg.ops->bus_shift;
 
                pci->cfg.win[idx] = devm_ioremap(dev,
-                                                pci->cfg.res.start + busn * sz,
+                                                pci->cfg.res.start + idx * sz,
                                                 sz);
                if (!pci->cfg.win[idx])
                        return -ENOMEM;
@@ -210,7 +213,6 @@ static int gen_pci_probe(struct platform_device *pdev)
        int err;
        const char *type;
        const struct of_device_id *of_id;
-       const int *prop;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
@@ -225,17 +227,10 @@ static int gen_pci_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
-       if (prop) {
-               if (*prop)
-                       pci_add_flags(PCI_PROBE_ONLY);
-               else
-                       pci_clear_flags(PCI_PROBE_ONLY);
-       }
+       of_pci_check_probe_only();
 
        of_id = of_match_node(gen_pci_of_match, np);
-       pci->cfg.ops = of_id->data;
-       gen_pci_ops.map_bus = pci->cfg.ops->map_bus;
+       pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
        pci->host.dev.parent = dev;
        INIT_LIST_HEAD(&pci->host.windows);
        INIT_LIST_HEAD(&pci->resources);
@@ -256,7 +251,9 @@ static int gen_pci_probe(struct platform_device *pdev)
        if (!pci_has_flag(PCI_PROBE_ONLY))
                pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
 
-       bus = pci_scan_root_bus(dev, 0, &gen_pci_ops, pci, &pci->resources);
+
+       bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start,
+                               &pci->cfg.ops->ops, pci, &pci->resources);
        if (!bus) {
                dev_err(dev, "Scanning rootbus failed");
                return -ENODEV;
index 8f3a9813c4e55a5f16ee48e3b54ccd1ec4985702..22e8224126fd9d9885ee06f2fb81cbf1f023b06b 100644 (file)
@@ -74,6 +74,7 @@ struct imx6_pcie {
 
 /* PHY registers (not memory-mapped) */
 #define PCIE_PHY_RX_ASIC_OUT 0x100D
+#define PCIE_PHY_RX_ASIC_OUT_VALID     (1 << 0)
 
 #define PHY_RX_OVRD_IN_LO 0x1005
 #define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
@@ -503,7 +504,7 @@ static int imx6_pcie_link_up(struct pcie_port *pp)
        pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
        debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
 
-       if (rx_valid & 0x01)
+       if (rx_valid & PCIE_PHY_RX_ASIC_OUT_VALID)
                return 0;
 
        if ((debug_r0 & 0x3f) != 0x0d)
@@ -539,7 +540,7 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp,
                                       IRQF_SHARED, "mx6-pcie-msi", pp);
                if (ret) {
                        dev_err(&pdev->dev, "failed to request MSI irq\n");
-                       return -ENODEV;
+                       return ret;
                }
        }
 
index e71da991949b1d598444a81dd775b3117c1c4744..0146b4121d49716c4e2ff704355ce8a37ced3ab7 100644 (file)
@@ -70,7 +70,7 @@ static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
        *bit_pos = offset >> 3;
 }
 
-u32 ks_dw_pcie_get_msi_addr(struct pcie_port *pp)
+phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp)
 {
        struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
 
@@ -398,7 +398,7 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 
        addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
 
-       return dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
+       return dw_pcie_cfg_read(addr + where, size, val);
 }
 
 int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
@@ -410,7 +410,7 @@ int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 
        addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
 
-       return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
+       return dw_pcie_cfg_write(addr + where, size, val);
 }
 
 /**
index 478d932b602d40cc81dd7061b103ba0973c060b3..f0944e8c4b02f4e481a9178e9dfe4107d64c83b9 100644 (file)
@@ -37,7 +37,7 @@ struct keystone_pcie {
 
 /* Keystone DW specific MSI controller APIs/definitions */
 void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
-u32 ks_dw_pcie_get_msi_addr(struct pcie_port *pp);
+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);
index 67ec5e1c99dbbb75a6f14943b25539ca50dc0f1e..53b79c5f055998761b837094b3ad43bd6c56de82 100644 (file)
@@ -30,6 +30,7 @@
 #define PCIE_DEV_REV_OFF       0x0008
 #define PCIE_BAR_LO_OFF(n)     (0x0010 + ((n) << 3))
 #define PCIE_BAR_HI_OFF(n)     (0x0014 + ((n) << 3))
+#define PCIE_CAP_PCIEXP                0x0060
 #define PCIE_HEADER_LOG_4_OFF  0x0128
 #define PCIE_BAR_CTRL_OFF(n)   (0x1804 + (((n) - 1) * 4))
 #define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
 #define  PCIE_STAT_BUS                  0xff00
 #define  PCIE_STAT_DEV                  0x1f0000
 #define  PCIE_STAT_LINK_DOWN           BIT(0)
+#define PCIE_RC_RTSTA          0x1a14
 #define PCIE_DEBUG_CTRL         0x1a60
 #define  PCIE_DEBUG_SOFT_RESET         BIT(20)
 
+enum {
+       PCISWCAP = PCI_BRIDGE_CONTROL + 2,
+       PCISWCAP_EXP_LIST_ID    = PCISWCAP + PCI_CAP_LIST_ID,
+       PCISWCAP_EXP_DEVCAP     = PCISWCAP + PCI_EXP_DEVCAP,
+       PCISWCAP_EXP_DEVCTL     = PCISWCAP + PCI_EXP_DEVCTL,
+       PCISWCAP_EXP_LNKCAP     = PCISWCAP + PCI_EXP_LNKCAP,
+       PCISWCAP_EXP_LNKCTL     = PCISWCAP + PCI_EXP_LNKCTL,
+       PCISWCAP_EXP_SLTCAP     = PCISWCAP + PCI_EXP_SLTCAP,
+       PCISWCAP_EXP_SLTCTL     = PCISWCAP + PCI_EXP_SLTCTL,
+       PCISWCAP_EXP_RTCTL      = PCISWCAP + PCI_EXP_RTCTL,
+       PCISWCAP_EXP_RTSTA      = PCISWCAP + PCI_EXP_RTSTA,
+       PCISWCAP_EXP_DEVCAP2    = PCISWCAP + PCI_EXP_DEVCAP2,
+       PCISWCAP_EXP_DEVCTL2    = PCISWCAP + PCI_EXP_DEVCTL2,
+       PCISWCAP_EXP_LNKCAP2    = PCISWCAP + PCI_EXP_LNKCAP2,
+       PCISWCAP_EXP_LNKCTL2    = PCISWCAP + PCI_EXP_LNKCTL2,
+       PCISWCAP_EXP_SLTCAP2    = PCISWCAP + PCI_EXP_SLTCAP2,
+       PCISWCAP_EXP_SLTCTL2    = PCISWCAP + PCI_EXP_SLTCTL2,
+};
+
 /* PCI configuration space of a PCI-to-PCI bridge */
 struct mvebu_sw_pci_bridge {
        u16 vendor;
        u16 device;
        u16 command;
+       u16 status;
        u16 class;
        u8 interface;
        u8 revision;
@@ -84,13 +106,15 @@ struct mvebu_sw_pci_bridge {
        u16 memlimit;
        u16 iobaseupper;
        u16 iolimitupper;
-       u8 cappointer;
-       u8 reserved1;
-       u16 reserved2;
        u32 romaddr;
        u8 intline;
        u8 intpin;
        u16 bridgectrl;
+
+       /* PCI express capability */
+       u32 pcie_sltcap;
+       u16 pcie_devctl;
+       u16 pcie_rtctl;
 };
 
 struct mvebu_pcie_port;
@@ -119,8 +143,7 @@ struct mvebu_pcie_port {
        unsigned int io_target;
        unsigned int io_attr;
        struct clk *clk;
-       int reset_gpio;
-       int reset_active_low;
+       struct gpio_desc *reset_gpio;
        char *reset_name;
        struct mvebu_sw_pci_bridge bridge;
        struct device_node *dn;
@@ -254,15 +277,22 @@ static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port,
                                 struct pci_bus *bus,
                                 u32 devfn, int where, int size, u32 *val)
 {
+       void __iomem *conf_data = port->base + PCIE_CONF_DATA_OFF;
+
        mvebu_writel(port, PCIE_CONF_ADDR(bus->number, devfn, where),
                     PCIE_CONF_ADDR_OFF);
 
-       *val = mvebu_readl(port, PCIE_CONF_DATA_OFF);
-
-       if (size == 1)
-               *val = (*val >> (8 * (where & 3))) & 0xff;
-       else if (size == 2)
-               *val = (*val >> (8 * (where & 3))) & 0xffff;
+       switch (size) {
+       case 1:
+               *val = readb_relaxed(conf_data + (where & 3));
+               break;
+       case 2:
+               *val = readw_relaxed(conf_data + (where & 2));
+               break;
+       case 4:
+               *val = readl_relaxed(conf_data);
+               break;
+       }
 
        return PCIBIOS_SUCCESSFUL;
 }
@@ -271,22 +301,24 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port,
                                 struct pci_bus *bus,
                                 u32 devfn, int where, int size, u32 val)
 {
-       u32 _val, shift = 8 * (where & 3);
+       void __iomem *conf_data = port->base + PCIE_CONF_DATA_OFF;
 
        mvebu_writel(port, PCIE_CONF_ADDR(bus->number, devfn, where),
                     PCIE_CONF_ADDR_OFF);
-       _val = mvebu_readl(port, PCIE_CONF_DATA_OFF);
 
-       if (size == 4)
-               _val = val;
-       else if (size == 2)
-               _val = (_val & ~(0xffff << shift)) | ((val & 0xffff) << shift);
-       else if (size == 1)
-               _val = (_val & ~(0xff << shift)) | ((val & 0xff) << shift);
-       else
+       switch (size) {
+       case 1:
+               writeb(val, conf_data + (where & 3));
+               break;
+       case 2:
+               writew(val, conf_data + (where & 2));
+               break;
+       case 4:
+               writel(val, conf_data);
+               break;
+       default:
                return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       mvebu_writel(port, _val, PCIE_CONF_DATA_OFF);
+       }
 
        return PCIBIOS_SUCCESSFUL;
 }
@@ -443,6 +475,9 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
        /* We support 32 bits I/O addressing */
        bridge->iobase = PCI_IO_RANGE_TYPE_32;
        bridge->iolimit = PCI_IO_RANGE_TYPE_32;
+
+       /* Add capabilities */
+       bridge->status = PCI_STATUS_CAP_LIST;
 }
 
 /*
@@ -460,7 +495,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                break;
 
        case PCI_COMMAND:
-               *value = bridge->command;
+               *value = bridge->command | bridge->status << 16;
                break;
 
        case PCI_CLASS_REVISION:
@@ -505,6 +540,10 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                *value = (bridge->iolimitupper << 16 | bridge->iobaseupper);
                break;
 
+       case PCI_CAPABILITY_LIST:
+               *value = PCISWCAP;
+               break;
+
        case PCI_ROM_ADDRESS1:
                *value = 0;
                break;
@@ -514,9 +553,67 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                *value = 0;
                break;
 
+       case PCISWCAP_EXP_LIST_ID:
+               /* Set PCIe v2, root port, slot support */
+               *value = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2 |
+                         PCI_EXP_FLAGS_SLOT) << 16 | PCI_CAP_ID_EXP;
+               break;
+
+       case PCISWCAP_EXP_DEVCAP:
+               *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCAP);
+               break;
+
+       case PCISWCAP_EXP_DEVCTL:
+               *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL) &
+                                ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
+                                  PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
+               *value |= bridge->pcie_devctl;
+               break;
+
+       case PCISWCAP_EXP_LNKCAP:
+               /*
+                * PCIe requires the clock power management capability to be
+                * hard-wired to zero for downstream ports
+                */
+               *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCAP) &
+                        ~PCI_EXP_LNKCAP_CLKPM;
+               break;
+
+       case PCISWCAP_EXP_LNKCTL:
+               *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
+               break;
+
+       case PCISWCAP_EXP_SLTCAP:
+               *value = bridge->pcie_sltcap;
+               break;
+
+       case PCISWCAP_EXP_SLTCTL:
+               *value = PCI_EXP_SLTSTA_PDS << 16;
+               break;
+
+       case PCISWCAP_EXP_RTCTL:
+               *value = bridge->pcie_rtctl;
+               break;
+
+       case PCISWCAP_EXP_RTSTA:
+               *value = mvebu_readl(port, PCIE_RC_RTSTA);
+               break;
+
+       /* PCIe requires the v2 fields to be hard-wired to zero */
+       case PCISWCAP_EXP_DEVCAP2:
+       case PCISWCAP_EXP_DEVCTL2:
+       case PCISWCAP_EXP_LNKCAP2:
+       case PCISWCAP_EXP_LNKCTL2:
+       case PCISWCAP_EXP_SLTCAP2:
+       case PCISWCAP_EXP_SLTCTL2:
        default:
-               *value = 0xffffffff;
-               return PCIBIOS_BAD_REGISTER_NUMBER;
+               /*
+                * PCI defines configuration read accesses to reserved or
+                * unimplemented registers to read as zero and complete
+                * normally.
+                */
+               *value = 0;
+               return PCIBIOS_SUCCESSFUL;
        }
 
        if (size == 2)
@@ -601,6 +698,51 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
                mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus);
                break;
 
+       case PCISWCAP_EXP_DEVCTL:
+               /*
+                * Armada370 data says these bits must always
+                * be zero when in root complex mode.
+                */
+               value &= ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
+                          PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
+
+               /*
+                * If the mask is 0xffff0000, then we only want to write
+                * the device control register, rather than clearing the
+                * RW1C bits in the device status register.  Mask out the
+                * status register bits.
+                */
+               if (mask == 0xffff0000)
+                       value &= 0xffff;
+
+               mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL);
+               break;
+
+       case PCISWCAP_EXP_LNKCTL:
+               /*
+                * If we don't support CLKREQ, we must ensure that the
+                * CLKREQ enable bit always reads zero.  Since we haven't
+                * had this capability, and it's dependent on board wiring,
+                * disable it for the time being.
+                */
+               value &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
+
+               /*
+                * If the mask is 0xffff0000, then we only want to write
+                * the link control register, rather than clearing the
+                * RW1C bits in the link status register.  Mask out the
+                * status register bits.
+                */
+               if (mask == 0xffff0000)
+                       value &= 0xffff;
+
+               mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
+               break;
+
+       case PCISWCAP_EXP_RTSTA:
+               mvebu_writel(port, value, PCIE_RC_RTSTA);
+               break;
+
        default:
                break;
        }
@@ -652,17 +794,6 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
        if (!mvebu_pcie_link_up(port))
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       /*
-        * On the secondary bus, we don't want to expose any other
-        * device than the device physically connected in the PCIe
-        * slot, visible in slot 0. In slot 1, there's a special
-        * Marvell device that only makes sense when the Armada is
-        * used as a PCIe endpoint.
-        */
-       if (bus->number == port->bridge.secondary_bus &&
-           PCI_SLOT(devfn) != 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
        /* Access the real PCIe interface */
        ret = mvebu_pcie_hw_wr_conf(port, bus, devfn,
                                    where, size, val);
@@ -693,19 +824,6 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
                return PCIBIOS_DEVICE_NOT_FOUND;
        }
 
-       /*
-        * On the secondary bus, we don't want to expose any other
-        * device than the device physically connected in the PCIe
-        * slot, visible in slot 0. In slot 1, there's a special
-        * Marvell device that only makes sense when the Armada is
-        * used as a PCIe endpoint.
-        */
-       if (bus->number == port->bridge.secondary_bus &&
-           PCI_SLOT(devfn) != 0) {
-               *val = 0xffffffff;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       }
-
        /* Access the real PCIe interface */
        ret = mvebu_pcie_hw_rd_conf(port, bus, devfn,
                                    where, size, val);
@@ -914,12 +1032,167 @@ static int mvebu_pcie_resume(struct device *dev)
        return 0;
 }
 
+static void mvebu_pcie_port_clk_put(void *data)
+{
+       struct mvebu_pcie_port *port = data;
+
+       clk_put(port->clk);
+}
+
+static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
+       struct mvebu_pcie_port *port, struct device_node *child)
+{
+       struct device *dev = &pcie->pdev->dev;
+       enum of_gpio_flags flags;
+       int reset_gpio, ret;
+
+       port->pcie = pcie;
+
+       if (of_property_read_u32(child, "marvell,pcie-port", &port->port)) {
+               dev_warn(dev, "ignoring %s, missing pcie-port property\n",
+                        of_node_full_name(child));
+               goto skip;
+       }
+
+       if (of_property_read_u32(child, "marvell,pcie-lane", &port->lane))
+               port->lane = 0;
+
+       port->name = devm_kasprintf(dev, GFP_KERNEL, "pcie%d.%d", port->port,
+                                   port->lane);
+       if (!port->name) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       port->devfn = of_pci_get_devfn(child);
+       if (port->devfn < 0)
+               goto skip;
+
+       ret = mvebu_get_tgt_attr(dev->of_node, port->devfn, IORESOURCE_MEM,
+                                &port->mem_target, &port->mem_attr);
+       if (ret < 0) {
+               dev_err(dev, "%s: cannot get tgt/attr for mem window\n",
+                       port->name);
+               goto skip;
+       }
+
+       if (resource_size(&pcie->io) != 0) {
+               mvebu_get_tgt_attr(dev->of_node, port->devfn, IORESOURCE_IO,
+                                  &port->io_target, &port->io_attr);
+       } else {
+               port->io_target = -1;
+               port->io_attr = -1;
+       }
+
+       reset_gpio = of_get_named_gpio_flags(child, "reset-gpios", 0, &flags);
+       if (reset_gpio == -EPROBE_DEFER) {
+               ret = reset_gpio;
+               goto err;
+       }
+
+       if (gpio_is_valid(reset_gpio)) {
+               unsigned long gpio_flags;
+
+               port->reset_name = devm_kasprintf(dev, GFP_KERNEL, "%s-reset",
+                                                 port->name);
+               if (!port->reset_name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               if (flags & OF_GPIO_ACTIVE_LOW) {
+                       dev_info(dev, "%s: reset gpio is active low\n",
+                                of_node_full_name(child));
+                       gpio_flags = GPIOF_ACTIVE_LOW |
+                                    GPIOF_OUT_INIT_LOW;
+               } else {
+                       gpio_flags = GPIOF_OUT_INIT_HIGH;
+               }
+
+               ret = devm_gpio_request_one(dev, reset_gpio, gpio_flags,
+                                           port->reset_name);
+               if (ret) {
+                       if (ret == -EPROBE_DEFER)
+                               goto err;
+                       goto skip;
+               }
+
+               port->reset_gpio = gpio_to_desc(reset_gpio);
+       }
+
+       port->clk = of_clk_get_by_name(child, NULL);
+       if (IS_ERR(port->clk)) {
+               dev_err(dev, "%s: cannot get clock\n", port->name);
+               goto skip;
+       }
+
+       ret = devm_add_action(dev, mvebu_pcie_port_clk_put, port);
+       if (ret < 0) {
+               clk_put(port->clk);
+               goto err;
+       }
+
+       return 1;
+
+skip:
+       ret = 0;
+
+       /* In the case of skipping, we need to free these */
+       devm_kfree(dev, port->reset_name);
+       port->reset_name = NULL;
+       devm_kfree(dev, port->name);
+       port->name = NULL;
+
+err:
+       return ret;
+}
+
+/*
+ * Power up a PCIe port.  PCIe requires the refclk to be stable for 100µs
+ * prior to releasing PERST.  See table 2-4 in section 2.6.2 AC Specifications
+ * of the PCI Express Card Electromechanical Specification, 1.1.
+ */
+static int mvebu_pcie_powerup(struct mvebu_pcie_port *port)
+{
+       int ret;
+
+       ret = clk_prepare_enable(port->clk);
+       if (ret < 0)
+               return ret;
+
+       if (port->reset_gpio) {
+               u32 reset_udelay = 20000;
+
+               of_property_read_u32(port->dn, "reset-delay-us",
+                                    &reset_udelay);
+
+               udelay(100);
+
+               gpiod_set_value_cansleep(port->reset_gpio, 0);
+               msleep(reset_udelay / 1000);
+       }
+
+       return 0;
+}
+
+/*
+ * Power down a PCIe port.  Strictly, PCIe requires us to place the card
+ * in D3hot state before asserting PERST#.
+ */
+static void mvebu_pcie_powerdown(struct mvebu_pcie_port *port)
+{
+       if (port->reset_gpio)
+               gpiod_set_value_cansleep(port->reset_gpio, 1);
+
+       clk_disable_unprepare(port->clk);
+}
+
 static int mvebu_pcie_probe(struct platform_device *pdev)
 {
        struct mvebu_pcie *pcie;
        struct device_node *np = pdev->dev.of_node;
        struct device_node *child;
-       int i, ret;
+       int num, i, ret;
 
        pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie),
                            GFP_KERNEL);
@@ -955,112 +1228,52 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
-       i = 0;
-       for_each_child_of_node(pdev->dev.of_node, child) {
-               if (!of_device_is_available(child))
-                       continue;
-               i++;
-       }
+       num = of_get_available_child_count(pdev->dev.of_node);
 
-       pcie->ports = devm_kzalloc(&pdev->dev, i *
-                                  sizeof(struct mvebu_pcie_port),
+       pcie->ports = devm_kcalloc(&pdev->dev, num, sizeof(*pcie->ports),
                                   GFP_KERNEL);
        if (!pcie->ports)
                return -ENOMEM;
 
        i = 0;
-       for_each_child_of_node(pdev->dev.of_node, child) {
+       for_each_available_child_of_node(pdev->dev.of_node, child) {
                struct mvebu_pcie_port *port = &pcie->ports[i];
-               enum of_gpio_flags flags;
-
-               if (!of_device_is_available(child))
-                       continue;
 
-               port->pcie = pcie;
-
-               if (of_property_read_u32(child, "marvell,pcie-port",
-                                        &port->port)) {
-                       dev_warn(&pdev->dev,
-                                "ignoring PCIe DT node, missing pcie-port property\n");
-                       continue;
-               }
-
-               if (of_property_read_u32(child, "marvell,pcie-lane",
-                                        &port->lane))
-                       port->lane = 0;
-
-               port->name = kasprintf(GFP_KERNEL, "pcie%d.%d",
-                                      port->port, port->lane);
-
-               port->devfn = of_pci_get_devfn(child);
-               if (port->devfn < 0)
-                       continue;
-
-               ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_MEM,
-                                        &port->mem_target, &port->mem_attr);
+               ret = mvebu_pcie_parse_port(pcie, port, child);
                if (ret < 0) {
-                       dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for mem window\n",
-                               port->port, port->lane);
+                       of_node_put(child);
+                       return ret;
+               } else if (ret == 0) {
                        continue;
                }
 
-               if (resource_size(&pcie->io) != 0)
-                       mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO,
-                                          &port->io_target, &port->io_attr);
-               else {
-                       port->io_target = -1;
-                       port->io_attr = -1;
-               }
+               port->dn = child;
+               i++;
+       }
+       pcie->nports = i;
 
-               port->reset_gpio = of_get_named_gpio_flags(child,
-                                                  "reset-gpios", 0, &flags);
-               if (gpio_is_valid(port->reset_gpio)) {
-                       u32 reset_udelay = 20000;
-
-                       port->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
-                       port->reset_name = kasprintf(GFP_KERNEL,
-                                    "pcie%d.%d-reset", port->port, port->lane);
-                       of_property_read_u32(child, "reset-delay-us",
-                                            &reset_udelay);
-
-                       ret = devm_gpio_request_one(&pdev->dev,
-                           port->reset_gpio, GPIOF_DIR_OUT, port->reset_name);
-                       if (ret) {
-                               if (ret == -EPROBE_DEFER)
-                                       return ret;
-                               continue;
-                       }
-
-                       gpio_set_value(port->reset_gpio,
-                                      (port->reset_active_low) ? 1 : 0);
-                       msleep(reset_udelay/1000);
-               }
+       for (i = 0; i < pcie->nports; i++) {
+               struct mvebu_pcie_port *port = &pcie->ports[i];
 
-               port->clk = of_clk_get_by_name(child, NULL);
-               if (IS_ERR(port->clk)) {
-                       dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
-                              port->port, port->lane);
+               child = port->dn;
+               if (!child)
                        continue;
-               }
 
-               ret = clk_prepare_enable(port->clk);
-               if (ret)
+               ret = mvebu_pcie_powerup(port);
+               if (ret < 0)
                        continue;
 
                port->base = mvebu_pcie_map_registers(pdev, child, port);
                if (IS_ERR(port->base)) {
-                       dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
-                               port->port, port->lane);
+                       dev_err(&pdev->dev, "%s: cannot map registers\n",
+                               port->name);
                        port->base = NULL;
-                       clk_disable_unprepare(port->clk);
+                       mvebu_pcie_powerdown(port);
                        continue;
                }
 
                mvebu_pcie_set_local_dev_nr(port, 1);
-
-               port->dn = child;
                mvebu_sw_pci_bridge_init(port);
-               i++;
        }
 
        pcie->nports = i;
index 81df0c1fe063ff164aef16eb2cfc449539a8a107..3018ae52e0923d4e2e8c8c2dc75f07d5528598bc 100644 (file)
@@ -382,8 +382,8 @@ static unsigned long tegra_pcie_conf_offset(unsigned int devfn, int where)
 static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie,
                                                   unsigned int busnr)
 {
-       pgprot_t prot = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN |
-                       L_PTE_MT_DEV_SHARED | L_PTE_SHARED;
+       pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+                                L_PTE_XN | L_PTE_MT_DEV_SHARED | L_PTE_SHARED);
        phys_addr_t cs = pcie->cs->start;
        struct tegra_pcie_bus *bus;
        unsigned int i;
index 0236ab9d5720133b57536c916591aab580157b28..ae00ce22d5a6eb2c7c2263f13a3fe0113c45da27 100644 (file)
@@ -509,24 +509,6 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port,
        return 0;
 }
 
-static int xgene_pcie_msi_enable(struct pci_bus *bus)
-{
-       struct device_node *msi_node;
-
-       msi_node = of_parse_phandle(bus->dev.of_node,
-                                       "msi-parent", 0);
-       if (!msi_node)
-               return -ENODEV;
-
-       bus->msi = of_pci_find_msi_chip_by_node(msi_node);
-       if (!bus->msi)
-               return -ENODEV;
-
-       of_node_put(msi_node);
-       bus->msi->dev = &bus->dev;
-       return 0;
-}
-
 static int xgene_pcie_probe_bridge(struct platform_device *pdev)
 {
        struct device_node *dn = pdev->dev.of_node;
@@ -567,10 +549,6 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
        if (!bus)
                return -ENOMEM;
 
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               if (xgene_pcie_msi_enable(bus))
-                       dev_info(port->dev, "failed to enable MSI\n");
-
        pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
        pci_bus_add_devices(bus);
index 52aa6e34002bc2543f20b8607efdab9e2a5a669a..fb89ca23d9a8926e35547f650688deb76e8e870e 100644 (file)
@@ -35,7 +35,7 @@
 
 #define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
 #define PORT_LOGIC_SPEED_CHANGE                (0x1 << 17)
-#define PORT_LOGIC_LINK_WIDTH_MASK     (0x1ff << 8)
+#define PORT_LOGIC_LINK_WIDTH_MASK     (0x1f << 8)
 #define PORT_LOGIC_LINK_WIDTH_1_LANES  (0x1 << 8)
 #define PORT_LOGIC_LINK_WIDTH_2_LANES  (0x2 << 8)
 #define PORT_LOGIC_LINK_WIDTH_4_LANES  (0x4 << 8)
@@ -80,28 +80,38 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
        return sys->private_data;
 }
 
-int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
+int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 {
-       *val = readl(addr);
+       if ((uintptr_t)addr & (size - 1)) {
+               *val = 0;
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
 
-       if (size == 1)
-               *val = (*val >> (8 * (where & 3))) & 0xff;
+       if (size == 4)
+               *val = readl(addr);
        else if (size == 2)
-               *val = (*val >> (8 * (where & 3))) & 0xffff;
-       else if (size != 4)
+               *val = readw(addr);
+       else if (size == 1)
+               *val = readb(addr);
+       else {
+               *val = 0;
                return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
 
        return PCIBIOS_SUCCESSFUL;
 }
 
-int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
+int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
 {
+       if ((uintptr_t)addr & (size - 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
        if (size == 4)
                writel(val, addr);
        else if (size == 2)
-               writew(val, addr + (where & 2));
+               writew(val, addr);
        else if (size == 1)
-               writeb(val, addr + (where & 3));
+               writeb(val, addr);
        else
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -132,8 +142,7 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
        if (pp->ops->rd_own_conf)
                ret = pp->ops->rd_own_conf(pp, where, size, val);
        else
-               ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
-                               size, val);
+               ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val);
 
        return ret;
 }
@@ -146,8 +155,7 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
        if (pp->ops->wr_own_conf)
                ret = pp->ops->wr_own_conf(pp, where, size, val);
        else
-               ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where,
-                               size, val);
+               ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val);
 
        return ret;
 }
@@ -205,12 +213,16 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 
 void dw_pcie_msi_init(struct pcie_port *pp)
 {
+       u64 msi_target;
+
        pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
+       msi_target = virt_to_phys((void *)pp->msi_data);
 
        /* program the msi_data */
        dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
-                       virt_to_phys((void *)pp->msi_data));
-       dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
+                           (u32)(msi_target & 0xffffffff));
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
+                           (u32)(msi_target >> 32 & 0xffffffff));
 }
 
 static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
@@ -286,6 +298,9 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
        }
 
        *pos = pos0;
+       desc->nvec_used = no_irqs;
+       desc->msi_attrib.multiple = order_base_2(no_irqs);
+
        return irq;
 
 no_valid_irq:
@@ -293,11 +308,31 @@ no_valid_irq:
        return -ENOSPC;
 }
 
+static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
+{
+       struct msi_msg msg;
+       u64 msi_target;
+
+       if (pp->ops->get_msi_addr)
+               msi_target = pp->ops->get_msi_addr(pp);
+       else
+               msi_target = virt_to_phys((void *)pp->msi_data);
+
+       msg.address_lo = (u32)(msi_target & 0xffffffff);
+       msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+
+       if (pp->ops->get_msi_data)
+               msg.data = pp->ops->get_msi_data(pp, pos);
+       else
+               msg.data = pos;
+
+       pci_write_msi_msg(irq, &msg);
+}
+
 static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
                        struct msi_desc *desc)
 {
        int irq, pos;
-       struct msi_msg msg;
        struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
 
        if (desc->msi_attrib.is_msix)
@@ -307,20 +342,36 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
        if (irq < 0)
                return irq;
 
-       if (pp->ops->get_msi_addr)
-               msg.address_lo = pp->ops->get_msi_addr(pp);
-       else
-               msg.address_lo = virt_to_phys((void *)pp->msi_data);
-       msg.address_hi = 0x0;
+       dw_msi_setup_msg(pp, irq, pos);
 
-       if (pp->ops->get_msi_data)
-               msg.data = pp->ops->get_msi_data(pp, pos);
-       else
-               msg.data = pos;
+       return 0;
+}
 
-       pci_write_msi_msg(irq, &msg);
+static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
+                            int nvec, int type)
+{
+#ifdef CONFIG_PCI_MSI
+       int irq, pos;
+       struct msi_desc *desc;
+       struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
+
+       /* MSI-X interrupts are not supported */
+       if (type == PCI_CAP_ID_MSIX)
+               return -EINVAL;
+
+       WARN_ON(!list_is_singular(&pdev->dev.msi_list));
+       desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
+
+       irq = assign_irq(nvec, desc, &pos);
+       if (irq < 0)
+               return irq;
+
+       dw_msi_setup_msg(pp, irq, pos);
 
        return 0;
+#else
+       return -EINVAL;
+#endif
 }
 
 static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
@@ -334,6 +385,7 @@ static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
 
 static struct msi_controller dw_pcie_msi_chip = {
        .setup_irq = dw_msi_setup_irq,
+       .setup_irqs = dw_msi_setup_irqs,
        .teardown_irq = dw_msi_teardown_irq,
 };
 
@@ -482,10 +534,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
                }
        }
 
-       if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
-               dev_err(pp->dev, "Failed to parse the number of lanes\n");
-               return -EINVAL;
-       }
+       ret = of_property_read_u32(np, "num-lanes", &pp->lanes);
+       if (ret)
+               pp->lanes = 0;
 
        if (IS_ENABLED(CONFIG_PCI_MSI)) {
                if (!pp->ops->msi_host_init) {
@@ -539,13 +590,12 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
                u32 devfn, int where, int size, u32 *val)
 {
        int ret, type;
-       u32 address, busdev, cfg_size;
+       u32 busdev, cfg_size;
        u64 cpu_addr;
        void __iomem *va_cfg_base;
 
        busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
                 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-       address = where & ~0x3;
 
        if (bus->parent->number == pp->root_bus_nr) {
                type = PCIE_ATU_TYPE_CFG0;
@@ -562,7 +612,7 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
        dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
                                  type, cpu_addr,
                                  busdev, cfg_size);
-       ret = dw_pcie_cfg_read(va_cfg_base + address, where, size, val);
+       ret = dw_pcie_cfg_read(va_cfg_base + where, size, val);
        dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
                                  PCIE_ATU_TYPE_IO, pp->io_mod_base,
                                  pp->io_bus_addr, pp->io_size);
@@ -574,13 +624,12 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
                u32 devfn, int where, int size, u32 val)
 {
        int ret, type;
-       u32 address, busdev, cfg_size;
+       u32 busdev, cfg_size;
        u64 cpu_addr;
        void __iomem *va_cfg_base;
 
        busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
                 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-       address = where & ~0x3;
 
        if (bus->parent->number == pp->root_bus_nr) {
                type = PCIE_ATU_TYPE_CFG0;
@@ -597,7 +646,7 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
        dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
                                  type, cpu_addr,
                                  busdev, cfg_size);
-       ret = dw_pcie_cfg_write(va_cfg_base + address, where, size, val);
+       ret = dw_pcie_cfg_write(va_cfg_base + where, size, val);
        dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
                                  PCIE_ATU_TYPE_IO, pp->io_mod_base,
                                  pp->io_bus_addr, pp->io_size);
@@ -764,6 +813,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
        case 8:
                val |= PORT_LINK_MODE_8_LANES;
                break;
+       default:
+               dev_err(pp->dev, "num-lanes %u: invalid value\n", pp->lanes);
+               return;
        }
        dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL);
 
index d0bbd276840dfcac4e7a66ba7ca7ad1f7a623e6e..e7b3279c3ff09ab5665fd251c4fdc695b4887eae 100644 (file)
@@ -70,14 +70,14 @@ struct pcie_host_ops {
        void (*host_init)(struct pcie_port *pp);
        void (*msi_set_irq)(struct pcie_port *pp, int irq);
        void (*msi_clear_irq)(struct pcie_port *pp, int irq);
-       u32 (*get_msi_addr)(struct pcie_port *pp);
+       phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
        u32 (*get_msi_data)(struct pcie_port *pp, int pos);
        void (*scan_bus)(struct pcie_port *pp);
        int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
 };
 
-int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
-int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val);
+int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
+int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
index 9aedc8eb2c6eaa3ffcb29dc562171f9a75161e52..c9550dc8b8ed4b8fc330d1d21cefed43989db030 100644 (file)
@@ -54,6 +54,33 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       if (of_property_read_bool(np, "brcm,pcie-ob")) {
+               u32 val;
+
+               ret = of_property_read_u32(np, "brcm,pcie-ob-axi-offset",
+                                          &val);
+               if (ret) {
+                       dev_err(pcie->dev,
+                               "missing brcm,pcie-ob-axi-offset property\n");
+                       return ret;
+               }
+               pcie->ob.axi_offset = val;
+
+               ret = of_property_read_u32(np, "brcm,pcie-ob-window-size",
+                                          &val);
+               if (ret) {
+                       dev_err(pcie->dev,
+                               "missing brcm,pcie-ob-window-size property\n");
+                       return ret;
+               }
+               pcie->ob.window_size = (resource_size_t)val * SZ_1M;
+
+               if (of_property_read_bool(np, "brcm,pcie-ob-oarr-size"))
+                       pcie->ob.set_oarr_size = true;
+
+               pcie->need_ob_cfg = true;
+       }
+
        /* PHY use is optional */
        pcie->phy = devm_phy_get(&pdev->dev, "pcie-phy");
        if (IS_ERR(pcie->phy)) {
index fe2efb141a9bd3b74c22af5764ead81dcfc2ce6d..eac719af16aa835fa61f8ee96cd5c87ee737d520 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de>
- * Copyright (C) 2015 Broadcom Corporatcommon ion
+ * Copyright (C) 2015 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -31,6 +31,8 @@
 #include "pcie-iproc.h"
 
 #define CLK_CONTROL_OFFSET           0x000
+#define EP_PERST_SOURCE_SELECT_SHIFT 2
+#define EP_PERST_SOURCE_SELECT       BIT(EP_PERST_SOURCE_SELECT_SHIFT)
 #define EP_MODE_SURVIVE_PERST_SHIFT  1
 #define EP_MODE_SURVIVE_PERST        BIT(EP_MODE_SURVIVE_PERST_SHIFT)
 #define RC_PCIE_RST_OUTPUT_SHIFT     0
 #define SYS_RC_INTX_EN               0x330
 #define SYS_RC_INTX_MASK             0xf
 
+#define PCIE_LINK_STATUS_OFFSET      0xf0c
+#define PCIE_PHYLINKUP_SHIFT         3
+#define PCIE_PHYLINKUP               BIT(PCIE_PHYLINKUP_SHIFT)
+#define PCIE_DL_ACTIVE_SHIFT         2
+#define PCIE_DL_ACTIVE               BIT(PCIE_DL_ACTIVE_SHIFT)
+
+#define OARR_VALID_SHIFT             0
+#define OARR_VALID                   BIT(OARR_VALID_SHIFT)
+#define OARR_SIZE_CFG_SHIFT          1
+#define OARR_SIZE_CFG                BIT(OARR_SIZE_CFG_SHIFT)
+
+#define OARR_LO(window)              (0xd20 + (window) * 8)
+#define OARR_HI(window)              (0xd24 + (window) * 8)
+#define OMAP_LO(window)              (0xd40 + (window) * 8)
+#define OMAP_HI(window)              (0xd44 + (window) * 8)
+
+#define MAX_NUM_OB_WINDOWS           2
+
 static inline struct iproc_pcie *iproc_data(struct pci_bus *bus)
 {
        struct iproc_pcie *pcie;
@@ -119,23 +139,32 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie)
        u32 val;
 
        /*
-        * Configure the PCIe controller as root complex and send a downstream
-        * reset
+        * Select perst_b signal as reset source. Put the device into reset,
+        * and then bring it out of reset
         */
-       val = EP_MODE_SURVIVE_PERST | RC_PCIE_RST_OUTPUT;
+       val = readl(pcie->base + CLK_CONTROL_OFFSET);
+       val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
+               ~RC_PCIE_RST_OUTPUT;
        writel(val, pcie->base + CLK_CONTROL_OFFSET);
        udelay(250);
-       val &= ~EP_MODE_SURVIVE_PERST;
+
+       val |= RC_PCIE_RST_OUTPUT;
        writel(val, pcie->base + CLK_CONTROL_OFFSET);
-       msleep(250);
+       msleep(100);
 }
 
 static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
 {
        u8 hdr_type;
-       u32 link_ctrl;
+       u32 link_ctrl, class, val;
        u16 pos, link_status;
-       int link_is_active = 0;
+       bool link_is_active = false;
+
+       val = readl(pcie->base + PCIE_LINK_STATUS_OFFSET);
+       if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) {
+               dev_err(pcie->dev, "PHY or data link is INACTIVE!\n");
+               return -ENODEV;
+       }
 
        /* make sure we are not in EP mode */
        pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type);
@@ -145,14 +174,19 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
        }
 
        /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
-       pci_bus_write_config_word(bus, 0, PCI_CLASS_DEVICE,
-                                 PCI_CLASS_BRIDGE_PCI);
+#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
+#define PCI_CLASS_BRIDGE_MASK      0xffff00
+#define PCI_CLASS_BRIDGE_SHIFT     8
+       pci_bus_read_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, &class);
+       class &= ~PCI_CLASS_BRIDGE_MASK;
+       class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT);
+       pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class);
 
        /* check link status to see if link is active */
        pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP);
        pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status);
        if (link_status & PCI_EXP_LNKSTA_NLW)
-               link_is_active = 1;
+               link_is_active = true;
 
        if (!link_is_active) {
                /* try GEN 1 link speed */
@@ -176,7 +210,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
                        pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA,
                                                 &link_status);
                        if (link_status & PCI_EXP_LNKSTA_NLW)
-                               link_is_active = 1;
+                               link_is_active = true;
                }
        }
 
@@ -190,6 +224,101 @@ static void iproc_pcie_enable(struct iproc_pcie *pcie)
        writel(SYS_RC_INTX_MASK, pcie->base + SYS_RC_INTX_EN);
 }
 
+/**
+ * Some iProc SoCs require the SW to configure the outbound address mapping
+ *
+ * Outbound address translation:
+ *
+ * iproc_pcie_address = axi_address - axi_offset
+ * OARR = iproc_pcie_address
+ * OMAP = pci_addr
+ *
+ * axi_addr -> iproc_pcie_address -> OARR -> OMAP -> pci_address
+ */
+static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr,
+                              u64 pci_addr, resource_size_t size)
+{
+       struct iproc_pcie_ob *ob = &pcie->ob;
+       unsigned i;
+       u64 max_size = (u64)ob->window_size * MAX_NUM_OB_WINDOWS;
+       u64 remainder;
+
+       if (size > max_size) {
+               dev_err(pcie->dev,
+                       "res size 0x%pap exceeds max supported size 0x%llx\n",
+                       &size, max_size);
+               return -EINVAL;
+       }
+
+       div64_u64_rem(size, ob->window_size, &remainder);
+       if (remainder) {
+               dev_err(pcie->dev,
+                       "res size %pap needs to be multiple of window size %pap\n",
+                       &size, &ob->window_size);
+               return -EINVAL;
+       }
+
+       if (axi_addr < ob->axi_offset) {
+               dev_err(pcie->dev,
+                       "axi address %pap less than offset %pap\n",
+                       &axi_addr, &ob->axi_offset);
+               return -EINVAL;
+       }
+
+       /*
+        * Translate the AXI address to the internal address used by the iProc
+        * PCIe core before programming the OARR
+        */
+       axi_addr -= ob->axi_offset;
+
+       for (i = 0; i < MAX_NUM_OB_WINDOWS; i++) {
+               writel(lower_32_bits(axi_addr) | OARR_VALID |
+                      (ob->set_oarr_size ? 1 : 0), pcie->base + OARR_LO(i));
+               writel(upper_32_bits(axi_addr), pcie->base + OARR_HI(i));
+               writel(lower_32_bits(pci_addr), pcie->base + OMAP_LO(i));
+               writel(upper_32_bits(pci_addr), pcie->base + OMAP_HI(i));
+
+               size -= ob->window_size;
+               if (size == 0)
+                       break;
+
+               axi_addr += ob->window_size;
+               pci_addr += ob->window_size;
+       }
+
+       return 0;
+}
+
+static int iproc_pcie_map_ranges(struct iproc_pcie *pcie,
+                                struct list_head *resources)
+{
+       struct resource_entry *window;
+       int ret;
+
+       resource_list_for_each_entry(window, resources) {
+               struct resource *res = window->res;
+               u64 res_type = resource_type(res);
+
+               switch (res_type) {
+               case IORESOURCE_IO:
+               case IORESOURCE_BUS:
+                       break;
+               case IORESOURCE_MEM:
+                       ret = iproc_pcie_setup_ob(pcie, res->start,
+                                                 res->start - window->offset,
+                                                 resource_size(res));
+                       if (ret)
+                               return ret;
+                       break;
+               default:
+                       dev_err(pcie->dev, "invalid resource %pR\n", res);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
 {
        int ret;
@@ -213,6 +342,14 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
 
        iproc_pcie_reset(pcie);
 
+       if (pcie->need_ob_cfg) {
+               ret = iproc_pcie_map_ranges(pcie, res);
+               if (ret) {
+                       dev_err(pcie->dev, "map failed\n");
+                       goto err_power_off_phy;
+               }
+       }
+
 #ifdef CONFIG_ARM
        pcie->sysdata.private_data = pcie;
        sysdata = &pcie->sysdata;
@@ -238,9 +375,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
 
        pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
-#ifdef CONFIG_ARM
        pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
-#endif
        pci_bus_add_devices(bus);
 
        return 0;
index c9e4c10a462e80897eafec3fbbf3ba119c2307e3..d3dc940f773a2279d13ad295bc9bd70a86638d23 100644 (file)
 #ifndef _PCIE_IPROC_H
 #define _PCIE_IPROC_H
 
-#define IPROC_PCIE_MAX_NUM_IRQS 6
+/**
+ * iProc PCIe outbound mapping
+ * @set_oarr_size: indicates the OARR size bit needs to be set
+ * @axi_offset: offset from the AXI address to the internal address used by
+ * the iProc PCIe core
+ * @window_size: outbound window size
+ */
+struct iproc_pcie_ob {
+       bool set_oarr_size;
+       resource_size_t axi_offset;
+       resource_size_t window_size;
+};
 
 /**
  * iProc PCIe device
  * @dev: pointer to device data structure
  * @base: PCIe host controller I/O register base
- * @resources: linked list of all PCI resources
  * @sysdata: Per PCI controller data (ARM-specific)
  * @root_bus: pointer to root bus
  * @phy: optional PHY device that controls the Serdes
  * @irqs: interrupt IDs
+ * @map_irq: function callback to map interrupts
+ * @need_ob_cfg: indidates SW needs to configure the outbound mapping window
+ * @ob: outbound mapping parameters
  */
 struct iproc_pcie {
        struct device *dev;
@@ -34,8 +47,9 @@ struct iproc_pcie {
 #endif
        struct pci_bus *root_bus;
        struct phy *phy;
-       int irqs[IPROC_PCIE_MAX_NUM_IRQS];
        int (*map_irq)(const struct pci_dev *, u8, u8);
+       bool need_ob_cfg;
+       struct iproc_pcie_ob ob;
 };
 
 int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res);
index 98d2683181bc5fbbbff05b89170d864c02e12cb3..b95b7563c052135bbad5407073685d9ff8930df6 100644 (file)
@@ -163,34 +163,34 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
         * default value in capability register is 512 bytes. So force
         * it to 128 here.
         */
-       dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, &val);
+       dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
        val &= ~PCI_EXP_DEVCTL_READRQ;
-       dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, val);
+       dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
 
-       dw_pcie_cfg_write(pp->dbi_base, PCI_VENDOR_ID, 2, 0x104A);
-       dw_pcie_cfg_write(pp->dbi_base, PCI_DEVICE_ID, 2, 0xCD80);
+       dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
+       dw_pcie_cfg_write(pp->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
 
        /*
         * if is_gen1 is set then handle it, so that some buggy card
         * also works
         */
        if (spear13xx_pcie->is_gen1) {
-               dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCAP, 4,
-                                &val);
+               dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
+                                       4, &val);
                if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
                        val &= ~((u32)PCI_EXP_LNKCAP_SLS);
                        val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-                       dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
-                                         PCI_EXP_LNKCAP, 4, val);
+                       dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
+                               PCI_EXP_LNKCAP, 4, val);
                }
 
-               dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCTL2, 4,
-                                &val);
+               dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
+                                       2, &val);
                if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
                        val &= ~((u32)PCI_EXP_LNKCAP_SLS);
                        val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-                       dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
-                                         PCI_EXP_LNKCTL2, 4, val);
+                       dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
+                                       PCI_EXP_LNKCTL2, 2, val);
                }
        }
 
index d4497141d083a71d5d5206496fee58fbddc5cb13..74319f49765670fd64098897b09227ce3bf1d8da 100644 (file)
@@ -105,9 +105,12 @@ void __weak arch_teardown_msi_irq(unsigned int irq)
 
 int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
+       struct msi_controller *chip = dev->bus->msi;
        struct msi_desc *entry;
        int ret;
 
+       if (chip && chip->setup_irqs)
+               return chip->setup_irqs(chip, dev, nvec, type);
        /*
         * If an architecture wants to support multiple MSI, it needs to
         * override arch_setup_msi_irqs()
index ad939d0ba816372b975d5c44d9582617b7b618e0..0be5db110bfabdab9341348ddda38d8e760ec5ce 100644 (file)
@@ -163,6 +163,8 @@ struct msi_controller {
 
        int (*setup_irq)(struct msi_controller *chip, struct pci_dev *dev,
                         struct msi_desc *desc);
+       int (*setup_irqs)(struct msi_controller *chip, struct pci_dev *dev,
+                         int nvec, int type);
        void (*teardown_irq)(struct msi_controller *chip, unsigned int irq);
 };
 
index 29fd3fe1c035d10361e9926ee879d9b6c4c70662..38c0533a33598bc8891af481589687c282739b37 100644 (file)
@@ -17,6 +17,7 @@ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
 int of_get_pci_domain_nr(struct device_node *node);
 void of_pci_dma_configure(struct pci_dev *pci_dev);
+void of_pci_check_probe_only(void);
 #else
 static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
 {
@@ -53,6 +54,8 @@ of_get_pci_domain_nr(struct device_node *node)
 }
 
 static inline void of_pci_dma_configure(struct pci_dev *pci_dev) { }
+
+static inline void of_pci_check_probe_only(void) { }
 #endif
 
 #if defined(CONFIG_OF_ADDRESS)