From: Anders Berg <anders.b...@lsi.com>

Also fixed the PCIe driver to respect the outbound window configuration via the
ranges property in the device-tree.

Signed-off-by: Anders Berg <anders.b...@lsi.com>
---
 arch/arm/boot/dts/axm55xx.dts           |    4 +-
 arch/arm/boot/dts/axm55xxsim.dts        |    4 +-
 arch/arm/mach-axxia/include/mach/irqs.h |    4 +-
 arch/arm/mach-axxia/include/mach/pci.h  |    6 +
 arch/arm/mach-axxia/pci.c               | 1145 +++++++++++++++++--------------
 5 files changed, 642 insertions(+), 521 deletions(-)
 create mode 100644 arch/arm/mach-axxia/include/mach/pci.h

diff --git a/arch/arm/boot/dts/axm55xx.dts b/arch/arm/boot/dts/axm55xx.dts
index 305e79c..f397394 100644
--- a/arch/arm/boot/dts/axm55xx.dts
+++ b/arch/arm/boot/dts/axm55xx.dts
@@ -194,7 +194,7 @@
 /
                 ranges = <0x03000000 0x00000000 0xa0000000
                           0x30 0x00000000
-                          0x00 0x10000000>;
+                          0x00 0x20000000>;
                 /* Inbound ranges */
                 /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
                 dma-ranges = <0x03000000 0x00000000 0x00000000
@@ -236,7 +236,7 @@
                 /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> > 
*/
                 ranges = <0x03000000 0x00000000 0xa0000000
                           0x30 0x80000000
-                          0x00 0x10000000>;
+                          0x00 0x20000000>;
                 /* Inbound ranges */
                 /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
                 dma-ranges = <0x03000000 0x00000000 0x00000000
diff --git a/arch/arm/boot/dts/axm55xxsim.dts b/arch/arm/boot/dts/axm55xxsim.dts
index ee6f852..4972da9 100644
--- a/arch/arm/boot/dts/axm55xxsim.dts
+++ b/arch/arm/boot/dts/axm55xxsim.dts
@@ -306,7 +306,7 @@
                 /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> 
>*/
                 ranges = <0x03000000 0x00000000 0xa0000000
                           0x30 0x00000000
-                          0x00 0x10000000>;
+                          0x00 0x20000000>;
                 /* Inbound ranges */
                 /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
                 dma-ranges = <0x03000000 0x00000000 0x00000000
@@ -346,7 +346,7 @@
                 /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> > 
*/
                 ranges = <0x03000000 0x00000000 0xa0000000
                           0x30 0x80000000
-                          0x00 0x10000000>;
+                          0x00 0x20000000>;
                 /* Inbound ranges */
                 /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
                 dma-ranges = <0x03000000 0x00000000 0x00000000
diff --git a/arch/arm/mach-axxia/include/mach/irqs.h 
b/arch/arm/mach-axxia/include/mach/irqs.h
index 4b10ee7..5f25c95 100644
--- a/arch/arm/mach-axxia/include/mach/irqs.h
+++ b/arch/arm/mach-axxia/include/mach/irqs.h
@@ -1,4 +1,4 @@
 #define IRQ_LOCALTIMER         29
 #define IRQ_LOCALWDOG          30
-
-#define NR_IRQS        256
+#define AXXIA_MSI_FIRST         224
+#define NR_IRQS                        256
diff --git a/arch/arm/mach-axxia/include/mach/pci.h 
b/arch/arm/mach-axxia/include/mach/pci.h
new file mode 100644
index 0000000..3260654
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/pci.h
@@ -0,0 +1,6 @@
+#ifndef _AXXIA_PCI_H
+#define _AXXIA_PCI_H
+
+void __init axxia_pcie_init(void);
+
+#endif
diff --git a/arch/arm/mach-axxia/pci.c b/arch/arm/mach-axxia/pci.c
index 2b39e0d..a405b79 100644
--- a/arch/arm/mach-axxia/pci.c
+++ b/arch/arm/mach-axxia/pci.c
@@ -1,84 +1,163 @@
 /*
- * PCI / PCI-X / PCI-Express support for ARM A15 Cortex parts
+ * arch/arm/mach-axxia/pci.c
+ *
+ * PCIe support for AXM55xx.
+ *
+ * Copyright (C) 2013 LSI
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-#undef DEBUG
-
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/bootmem.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/of_irq.h>
 #include <linux/interrupt.h>
-
 #include <linux/io.h>
-
+#include <linux/msi.h>
+#include <linux/kernel_stat.h>
 #include <asm/sizes.h>
 #include <asm/mach/pci.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm-generic/errno-base.h>
+#include <mach/pci.h>
+
+#define PCIE_CONFIG              (0x1000)
+#define PCIE_STATUS              (0x1004)
+#define PCIE_CORE_DEBUG          (0x1008)
+#define PCIE_LOOPBACK_FAIL       (0x100C)
+#define PCIE_MPAGE_U(n)          (0x1010 + (n * 8)) /* n = 0..7 */
+#define PCIE_MPAGE_L(n)          (0x1014 + (n * 8)) /* n = 0..7 */
+#define PCIE_TPAGE_BAR0(n)       (0x1050 + (n * 4)) /* n = 0..7 */
+#define   PCIE_TPAGE_32          (0<<31) /* AXI 32-bit access */
+#define   PCIE_TPAGE_128        (1<<31) /* AXI 128-bit access */
+#define PCIE_TPAGE_BAR1(n)       (0x1070 + (n * 4)) /* n = 0..7 */
+#define PCIE_TPAGE_BAR2(n)       (0x1090 + (n * 4)) /* n = 0..7 */
+#define PCIE_MSG_IN_FIFO         (0x10B0)
+#define PCIE_MSG_IN_FIFO_STATUS  (0x10B4)
+#define PCIE_MSG_OUT             (0x10B8)
+#define PCIE_TRN_ORDER_STATUS    (0x10BC)
+#define PCIE_INT0_STATUS         (0x10C0)
+#define PCIE_INT0_ENABLE         (0x10C4)
+#define PCIE_INT0_FORCE          (0x10C8)
+#define    INT0_MSI              0x80000000U
+#define    INT0_INT_ASSERTED     0x08000000U
+#define    INT0_INT_DEASSERTED   0x04000000U
+#define    INT0_ERROR            0x73FFFFABU
+#define PCIE_PHY_STATUS0         (0x10CC)
+#define PCIE_PHY_STATUS1         (0x10D0)
+#define PCIE_PHY_CONTROL0        (0x10D4)
+#define PCIE_PHY_CONTROL1        (0x10D8)
+#define PCIE_PHY_CONTROL2        (0x10DC)
+#define PCIE_RESERVED_E0         (0x10E0)
+#define PCIE_RESERVED_E4         (0x10E4)
+#define PCIE_RESERVED_E8         (0x10E8)
+#define PCIE_AXI_MASTER_WR       (0x10EC)
+#define PCIE_LINK_STATUS         (0x117C)
+#define PCIE_EP_BAR2_CFG         (0x1184)
+#define PCIE_AXI_MSI_ADDR        (0x1190)
+#define PCIE_INT1_STATUS         (0x11C4)
+#define PCIE_INT1_ENABLE         (0x11C8)
+#define PCIE_INT1_FORCE          (0x11CC)
+#define PCIE_RC_BAR0_SIZE        (0x11F4)
+#define PCIE_MSI0_STATUS         (0x1230)
+#define PCIE_MSI0_ENABLE         (0x1234)
+#define PCIE_MSI0_FORCE          (0x1238)
+#define PCIE_MSI1_STATUS(_grp)   (0x123C+(_grp)*12)
+#define PCIE_MSI1_ENABLE(_grp)   (0x1240+(_grp)*12)
+#define PCIE_MSI1_FORCE(_grp)    (0x1244+(_grp)*12)
+
+/* Every MPAGE register maps 128MB in the AXI memory range */
+#define MPAGE_SIZE               (128U<<20)
+
+/* We have 7 MPAGE registers available for outbound window (one reserved for
+ * mapping PCI configuration space).
+ */
+#define MAX_OUTBOUND_SIZE       (7 * MPAGE_SIZE)
 
-#include <linux/msi.h>
-
-#undef PRINT_CONFIG_ACCESSES
-/*#define PRINT_CONFIG_ACCESSES*/
-
-static u32 last_mpage;
-static u32 last_port;
+/* Number of IRQs allocated to MSI */
+#define NUM_MSI_IRQ (NR_IRQS - AXXIA_MSI_FIRST)
 
-#define U64_TO_U32_LOW(val)    ((u32)((val) & 0x00000000ffffffffULL))
-#define U64_TO_U32_HIGH(val)   ((u32)((val) >> 32))
+/* Bitmap for allocated MSIs */
+static DECLARE_BITMAP(msi_irq_in_use, NUM_MSI_IRQ);
 
-#define ACPX1_PCIE_MPAGE_UPPER(n) (0x1010 + (n * 8))
-#define ACPX1_PCIE_MPAGE_LOWER(n) (0x1014 + (n * 8))
+static const struct resource pcie_outbound_default[] = {
+       [0] = {
+               .start = 0,
+               .end   = 0,
+               .flags = IORESOURCE_MEM
+       },
+       [1] = {
+               .start = 0,
+               .end   = 0,
+               .flags = IORESOURCE_MEM
+       }
+};
 
 struct axxia_pciex_port {
-       unsigned int    index;
-       u8 root_bus_nr;
-       bool link_up;
-       void __iomem    *cfg_addr;
-       void __iomem    *cfg_data;
-       u64 pci_addr;
-       int endpoint;
-       struct device_node      *node;
-       struct resource utl_regs;
-       struct resource cfg_space;
-       struct resource outbound, inbound;
-       dma_addr_t msi_phys;
+       char                name[16];
+       unsigned int        index;
+       u8                  root_bus_nr;
+       bool                link_up;
+       int                 irq[17]; /* 1 legacy, 16 MSI */
+       void __iomem        *regs;
+       void __iomem        *cfg_data;
+       u32                 last_mpage;
+       int                 endpoint;
+       struct device_node  *node;
+       struct resource     utl_regs;
+       struct resource     cfg_space;
+       /* Outbound PCI base address */
+       u64                 pci_addr;
+       /* Outbound range in (physical) CPU addresses */
+       struct resource     outbound;
+       /* Inbound PCI base address */
+       u64                 pci_bar;
+       /* Inbound range in (physical) CPU addresses */
+       struct resource     inbound;
+       /* Virtual and physical (CPU space) address for MSI table */
+       void                *msi_virt;
+       dma_addr_t          msi_phys;
+       /* PCI memory space address for MSI table */
+       u32                 msi_pci_addr;
 };
 
+#define PCIE_MAX_PORTS 2
 static struct axxia_pciex_port *axxia_pciex_ports;
-static unsigned int axxia_pciex_port_count = 2;
 
-static void axxia_probe_pciex_bridge(struct device_node *np);
 
 static void __init
 fixup_axxia_pci_bridge(struct pci_dev *dev)
 {
        /* if we aren't a PCIe don't bother */
        if (!pci_find_capability(dev, PCI_CAP_ID_EXP))
-               return ;
+               return;
 
-       /*
-        * Set the class appropriately for a bridge device
-        */
-       printk(KERN_INFO
-              "PCI: Setting PCI Class to PCI_CLASS_BRIDGE_HOST for "
-               "%04x:%04x\n", dev->vendor, dev->device);
+       /* Set the class appropriately for a bridge device */
+       dev_info(&dev->dev,
+                "Fixup PCI Class to PCI_CLASS_BRIDGE_HOST for %04x:%04x\n",
+                dev->vendor, dev->device);
        dev->class = PCI_CLASS_BRIDGE_HOST << 8;
-       /*
-        * Make the bridge transparent
-        */
+       /* Make the bridge transparent */
        dev->transparent = 1;
-
-       return ;
 }
 
 DECLARE_PCI_FIXUP_HEADER(0x1000, 0x5101, fixup_axxia_pci_bridge);
@@ -91,8 +170,12 @@ static struct axxia_pciex_port *bus_to_port(struct pci_bus 
*bus)
        return axxia_pciex_ports + pci_domain_nr(bus);
 }
 
-/* Validate the Bus#/Device#/Function# */
-static int axxia_pciex_validate_bdf(struct pci_bus *bus, unsigned int devfn)
+
+/*
+ * Validate the Bus#/Device#/Function#
+ */
+static int
+axxia_pciex_validate_bdf(struct pci_bus *bus, unsigned int devfn)
 {
        struct axxia_pciex_port *port;
 
@@ -111,58 +194,52 @@ static int axxia_pciex_validate_bdf(struct pci_bus *bus, 
unsigned int devfn)
        return 0;
 }
 
-/* Get the configuration access base address */
-static void __iomem *axxia_pciex_get_config_base(struct axxia_pciex_port *port,
-                       struct pci_bus *bus, unsigned int devfn)
+/*
+ * Return the configuration access base address
+ */
+static void __iomem *
+axxia_pciex_get_config_base(struct axxia_pciex_port *port,
+                           struct pci_bus *bus,
+                           unsigned int devfn)
 {
+       int relbus, dev, fn;
        unsigned mpage;
-       u32 addr;
-       int dev, fn;
-       int cfg_type;
-       int relbus;
 
-       if (bus->number == port->root_bus_nr) {
-               return port->cfg_addr;
-       } else {
-               relbus = bus->number - (port->root_bus_nr + 1);
-               dev = ((PCI_SLOT(devfn) & 0xf8) >> 3);
-               fn  = PCI_FUNC(devfn) & 0x7;
-
-               if (dev > 31)
-                       return NULL;
-
-               /* Primary bus */
-               if (relbus && (bus->number != port->root_bus_nr))
-                       cfg_type = 1;
-               else
-                       cfg_type = 0;
-
-               /* build the mpage register */
-               mpage = (bus->number << 11) | (dev << 6) | (cfg_type << 5);
-               mpage |= 0x10;   /* enable MPAGE for configuration access */
-               mpage |= (fn << 19);
-
-               if ((mpage != last_mpage) || (port->index != last_port)) {
-                       addr = ((u32)port->cfg_addr)
-                                       + ACPX1_PCIE_MPAGE_UPPER(7);
-                       writel(0x0, (u32 *) addr);
-                       addr = ((u32)port->cfg_addr)
-                                       + ACPX1_PCIE_MPAGE_LOWER(7);
-                       writel(mpage, (u32 *) addr);
-                       /* printk("pcie_get_base: %02x:%02x:%02x setting
-                               mpage = 0x%08x in addr = 0x%08x\n", bus->number,
-                               dev, fn, mpage, addr);*/
-                       last_mpage = mpage;
-                       last_port = port->index;
-               }
-               return port->cfg_data;
+       if (bus->number == port->root_bus_nr)
+               return port->regs;
+
+       relbus = bus->number - (port->root_bus_nr + 1);
+       dev    = (PCI_SLOT(devfn) & 0xf8) >> 3;
+       fn     = (PCI_FUNC(devfn) & 0x7);
+
+       if (dev > 31)
+               return NULL;
+
+       /* Build the mpage register (MPAGE[4]=1 for cfg access) */
+       mpage = (fn << 19) | (bus->number << 11) | (dev << 6) | (1<<4);
+
+       /* Primary bus */
+       if (relbus && (bus->number != port->root_bus_nr))
+               mpage |= 1<<5;
+
+       if (mpage != port->last_mpage) {
+               writel(0,     port->regs + PCIE_MPAGE_U(7));
+               writel(mpage, port->regs + PCIE_MPAGE_L(7));
+               port->last_mpage = mpage;
        }
+
+       return port->cfg_data;
 }
 
-/* Read the config space */
+/*
+ * Read PCI config space
+ */
 static int
-arm_pciex_axxia_read_config(struct pci_bus *bus, unsigned int devfn,
-               int offset, int len, u32 *val)
+arm_pciex_axxia_read_config(struct pci_bus *bus,
+                           unsigned int devfn,
+                           int offset,
+                           int len,
+                           u32 *val)
 {
        struct axxia_pciex_port *port = bus_to_port(bus);
        void __iomem *addr;
@@ -188,7 +265,7 @@ arm_pciex_axxia_read_config(struct pci_bus *bus, unsigned 
int devfn,
         */
        if (bus->number == 0) {
                int wo = offset & 0xfffffffc;
-               bus_addr = (u32) addr + wo;
+               bus_addr = (u32)addr + wo;
                bus_addr1 = bus_addr;
        } else {
                /*
@@ -220,7 +297,7 @@ arm_pciex_axxia_read_config(struct pci_bus *bus, unsigned 
int devfn,
        /*
         * do the read
         */
-       val32 = readl((u32 *)bus_addr);
+       val32 = readl((u32 __iomem *)bus_addr);
 
        switch (len) {
        case 1:
@@ -236,7 +313,7 @@ arm_pciex_axxia_read_config(struct pci_bus *bus, unsigned 
int devfn,
 
 #ifdef PRINT_CONFIG_ACCESSES
        printk(KERN_INFO
-               "acp_read_config for PEI%d: %3d  fn=0x%04x o=0x%04x l=%d "
+               "acp_read_config for PCIE%d: %3d  fn=0x%04x o=0x%04x l=%d "
                "a=0x%08x v=0x%08x, dev=%d\n",
                        port->index, bus->number, devfn, offset, len,
                        bus_addr, *val, PCI_SLOT(devfn));
@@ -244,9 +321,15 @@ arm_pciex_axxia_read_config(struct pci_bus *bus, unsigned 
int devfn,
        return rc;
 }
 
-/* Write the config space */
-static int arm_pciex_axxia_write_config(struct pci_bus *bus, unsigned int 
devfn,
-                       int offset, int len, u32 val)
+/*
+ * Write PCI config space.
+ */
+static int
+arm_pciex_axxia_write_config(struct pci_bus *bus,
+                            unsigned int devfn,
+                            int offset,
+                            int len,
+                            u32 val)
 {
        struct axxia_pciex_port *port = bus_to_port(bus);
        void __iomem *addr;
@@ -277,7 +360,7 @@ static int arm_pciex_axxia_write_config(struct pci_bus 
*bus, unsigned int devfn,
                        int bs = ((offset & 0x3) * 8);
 
                        bus_addr = (u32) addr + (offset & 0xfffffffc);
-                       val32 = readl((u32 *)bus_addr);
+                       val32 = readl((u32 __iomem *)bus_addr);
 
                        if (len == 2) {
                                val32 = (val32 & ~(0xffff << bs))
@@ -303,13 +386,13 @@ static int arm_pciex_axxia_write_config(struct pci_bus 
*bus, unsigned int devfn,
 
        switch (len) {
        case 1:
-               writeb(val, (u8 *)(bus_addr));
+               writeb(val, (u8 __iomem *)(bus_addr));
                break;
        case 2:
-               writew(val, (u16 *)(bus_addr));
+               writew(val, (u16 __iomem *)(bus_addr));
                break;
        default:
-               writel(val, (u32 *)(bus_addr));
+               writel(val, (u32 __iomem *)(bus_addr));
                break;
        }
        return PCIBIOS_SUCCESSFUL;
@@ -320,502 +403,428 @@ static struct pci_ops axxia_pciex_pci_ops = {
        .write = arm_pciex_axxia_write_config,
 };
 
-/* ACP PCIe ISR to handle Legacy Interrupts */
+/*
+ * pcie_legacy_isr
+ *
+ * The interrupt line for this handler is shared between the PCIE controller
+ * itself (for status and error interrupts) and devices using legacy PCI
+ * interupt signalling. Statis and error interrupts are serviced here and this
+ * handler will return IRQ_HANDLED. If the reasont is the assertion of a device
+ * legacy interrupt, this handler returns IRQ_NONE the next action on this line
+ * will be called (the PCI EP interrupt service routine).
+ */
 static irqreturn_t
-acp_pcie_isr(int irq, void *arg)
+pcie_legacy_isr(int irq, void *arg)
 {
-       u32 intr_status;
-       u8  externalPciIntr = 0;
-       struct axxia_pciex_port *port = (struct axxia_pciex_port *)arg;
-       void __iomem *mbase = (void __iomem *)port->cfg_addr;
+       struct axxia_pciex_port *port  = arg;
+       void __iomem            *mbase = port->regs;
+       u32                      intr_status;
+       irqreturn_t              retval = IRQ_HANDLED;
 
        /* read the PEI interrupt status register */
-       intr_status = readl(mbase+0x10c0);
+       intr_status = readl(mbase + PCIE_INT0_STATUS);
 
        /* check if this is a PCIe message not from an external device */
-       if (intr_status & 0xf3ffffab) {
-                       u32 t2a_err_stat;
-                       u32 t2a_other_err_stat;
+       if (intr_status & INT0_ERROR) {
                        u32 int_enb;
-                       u32 linkStatus;
                        u32 offset;
 
-                       printk(KERN_ERR
-                               "ACP_PCIE_ISR: got PEI%d error interrupt "
-                               "0x%08x\n", intr_status, port->index);
+                       pr_info("PCIE%d: Error interrupt %#x\n",
+                               port->index, intr_status);
 
-                       linkStatus = readl(mbase+0x117c);
-                       printk(KERN_ERR "link_status (0x117c) = 0x%08x\n",
-                               linkStatus);
+                       pr_info("PCIE%d: link status = %#x\n",
+                               port->index, readl(mbase + PCIE_LINK_STATUS));
 
                        if (intr_status & 0x00020000) {
-                               t2a_err_stat = readl(mbase+0x1170);
-                               printk(KERN_ERR "t2a_fn_indp_err_stat = 
0x%08x\n",
-                                       t2a_err_stat);
-
-                               int_enb = readl(mbase+0x10c4);
+                               pr_info("PCIE%d: t2a_fn_indp_err_stat = %#x\n",
+                                       port->index, readl(mbase+0x1170));
+                               int_enb = readl(mbase + PCIE_INT0_ENABLE);
                                int_enb &= 0xfffdffff;
-                               writel(int_enb, mbase + 0x10c4);
+                               writel(int_enb, mbase + PCIE_INT0_ENABLE);
                        }
 
                        if (intr_status & 0x00040000) {
-                               t2a_other_err_stat = readl(mbase+0x1174);
-                               printk(KERN_ERR "t2a_fn_indp_other_err_stat = 
0x%08x\n",
-                                       t2a_other_err_stat);
-                               int_enb = readl(mbase+0x10c4);
+                               pr_info("PCIE%d: t2a_fn_indp_other_err_stat = 
%#x\n",
+                                       port->index, readl(mbase+0x1174));
+                               int_enb = readl(mbase + PCIE_INT0_ENABLE);
                                int_enb &= 0xfffbffff;
-                               writel(int_enb, mbase + 0x10c4);
+                               writel(int_enb, mbase + PCIE_INT0_ENABLE);
                        }
 
                        if (intr_status & 0x00000800) {
-                               printk(KERN_INFO "pci_config = 0x%08x\n",
-                                       readl(mbase + 0x1000));
-                               printk(KERN_INFO "pci_status = 0x%08x\n",
-                                       readl(mbase + 0x1004));
-                               int_enb = readl(mbase + 0x10c4);
+                               pr_info("PCIE%d: config=%#x status=%#x\n",
+                                       port->index,
+                                       readl(mbase + PCIE_CONFIG),
+                                       readl(mbase + PCIE_STATUS));
+                               int_enb = readl(mbase + PCIE_INT0_ENABLE);
                                int_enb &= 0xfffff7ff;
-                               writel(int_enb, mbase + 0x10c4);
+                               writel(int_enb, mbase + PCIE_INT0_ENABLE);
                        }
+
                        /*
-                        * dump all the potentially interesting PEI registers
+                        * Dump all the potentially interesting PEI registers
                         */
                        for (offset = 0x114c; offset <= 0x1180; offset += 4) {
-                               printk(KERN_INFO "  0x%04x : 0x%08x\n", offset,
-                                       readl(mbase + offset));
+                               pr_err("  [0x%04x] = 0x%08x\n",
+                                      offset, readl(mbase + offset));
                        }
+       } else if (intr_status & INT0_INT_ASSERTED) {
+               /* Empty the message FIFO */
+               while ((readl(port->regs + PCIE_MSG_IN_FIFO_STATUS) & 1) == 0)
+                       (void) readl(port->regs + PCIE_MSG_IN_FIFO);
+               /* Next handler in chain will service this interrupt */
+               retval = IRQ_NONE;
        }
 
        /*
         *  We clear all the interrupts in the PEI status, even though
         *  interrupts from external devices have not yet been handled.
-        *  That should be okay, since the PCI IRQ in the MPIC won't be
+        *  That should be okay, since the PCI IRQ in the GIC won't be
         *  re-enabled until all external handlers have been called.
         */
-       writel(intr_status, mbase + 0x10c0);
-       return externalPciIntr ? IRQ_NONE : IRQ_HANDLED;
+       writel(intr_status, mbase + PCIE_INT0_STATUS);
+
+       return retval;
 }
 
-/* ACP PCIe ISR to handle MSI Interrupts */
-static irqreturn_t
-acp_pcie_MSI_isr(int irq, void *arg) {
-       u32 intr_status;
-       u8  msiIntr = 0, bit = 0;
-       struct axxia_pciex_port *port = (struct axxia_pciex_port *)arg;
-       void __iomem *mbase = (void __iomem *)port->cfg_addr;
-       u32 statusReg, statusVal;
-
-       /* read the PEI MSI Level2 interrupt status register */
-       intr_status = readl(mbase+0x1230);
-
-       /* check if this is a PCIe MSI interrupt */
-       if (intr_status & 0x0000ffff) {
-               msiIntr = 1;
-               for (bit = 0; bit < 16; bit++) {
-                       if (intr_status & (0x1 << bit)) {
-                               printk(KERN_INFO "PEI%d --> MSI%d-%d interrupt 
asserted\n",
-                                       port->index, bit*16, ((bit+1)*16)-1);
-                               /* MSI Level 1 interrupt status */
-                               statusReg = (0x123c + (0xc * bit));
-                               statusVal = readl(mbase+statusReg);
-                               printk(KERN_INFO "MSI status Reg 0x%x val = 
0x%x\n",
-                                       statusReg, statusVal);
-                               /* clear statusReg */
-                               writel(statusVal, mbase+statusReg);
-                       }
-               }
+/*
+ * pcie_msi_irq_handler
+ *
+ * This is the handler for PCIE MSI service. It will decode the signalled MSI
+ * using the following hierarchy of status bits. This handler is installed as a
+ * chained handler for each of the 16 interrupt lines on the top-level
+ * interrupt controller. When a pending MSI is found, this handler forwards the
+ * interrupt service to the corresponding MSI IRQs (numbered from
+ * AXXIA_MSI_FIRST..NR_IRQS).
+ *
+ *                                             PCIE_MSI1_STATUS(group)
+ *
+ *                 PCIE_MSI0_STATUS                  +----------+
+ *                                                   | MSI      |
+ *   +----------+    +----------+                    | 0..15    |
+ *   | ARM GIC  |    | GROUP    |        /-----------+          |
+ *   |          +----+ 0..15    +-------/            |          |
+ *   |          |    |          |                    |          |
+ *   |          +----+          +-------\            +----------+
+ *   |          |    |          |        \
+ *   |          +----+          |         \          +----------+
+ *   |          |    |          |          \         | MSI      |
+ *   |          +----+          |           \        | 16..31   |
+ *   |          |    |          |            \-------+          |
+ *   |          +----+          |                    |          |
+ *   |          |    |          |                    |          |
+ *   |          |    |          |                    +----------+
+ *   |          | .  |          |
+ *   |          | .  |          |                    ...
+ *   |          | .  |          |
+ *   |          |    |          |                    +----------+
+ *   |          |    |          |                    | MSI      |
+ *   |          +----+          +--------------------+ 240..255 |
+ *   |          |    |          |                    |          |
+ *   +----------+    +----------+                    |          |
+ *                                                   |          |
+ *                                                   +----------+
+ */
+static void
+pcie_msi_irq_handler(int irq, struct axxia_pciex_port *port)
+{
+       void __iomem *mbase = port->regs;
+       u32 group = irq - port->irq[1];
+       u32 status;
+
+       /* Check if interrupt is pending */
+       status = readl(mbase + PCIE_MSI0_STATUS);
+       if (!(status & (1<<group)))
+               return;
+
+       /* Check next level interrupt status */
+       status = readl(mbase + PCIE_MSI1_STATUS(group)) & 0xffff;
+       while (status) {
+               u32 line = ffs(status) - 1;
+               status &= ~(1<<line);
+               /* Clear interrupt on sub-level */
+               writel((1<<line), mbase + PCIE_MSI1_STATUS(group));
+               generic_handle_irq(AXXIA_MSI_FIRST + (group * 16) + line);
        }
-       /*
-        *  We clear all the interrupts in the PEI status, even though
-        *  interrupts from MSI devices have not yet been handled.
-        */
-       writel(intr_status, mbase + 0x1230);
-       return msiIntr ? IRQ_NONE : IRQ_HANDLED;
+
+       /* Clear interrupt on top-level*/
+       writel(1<<group, mbase + PCIE_MSI0_STATUS);
+
+}
+
+static void
+pcie_pei0_msi_handler(unsigned int irq, struct irq_desc *desc)
+{
+       kstat_incr_irqs_this_cpu(irq, desc);
+       /* Handle the PCIe interrupt */
+       pcie_msi_irq_handler(irq, &axxia_pciex_ports[0]);
+       /* Signal end-of-interrupt */
+       irq_desc_get_chip(desc)->irq_eoi(&desc->irq_data);
 }
 
 
 /* PCIe setup function */
-int axxia_pcie_setup(int portno, struct pci_sys_data *sys)
+static int axxia_pcie_setup(int portno, struct pci_sys_data *sys)
 {
-       struct axxia_pciex_port *port;
+       struct axxia_pciex_port *port = &axxia_pciex_ports[sys->domain];
        u32 pci_config, pci_status, link_state;
        int i, num_pages, err;
-       u32 mpage_lower, pciah, pcial;
-       u64 size, bar0_size;
-       void __iomem *cfg_addr = NULL, *cfg_data = NULL, *tpage_base = NULL;
-       int mappedIrq, irq_entry;
+       u32 outbound_size;
        u32 inbound_size;
+       u64 dest;
 
-       port = &axxia_pciex_ports[sys->domain];
-       printk(KERN_INFO "cfg_space start = 0x%012llx, end = 0x%012llx\n",
-               port->cfg_space.start, port->cfg_space.end);
-       printk(KERN_INFO "utl_regs start = 0x%012llx, end = 0x%012llx\n",
-               port->utl_regs.start, port->utl_regs.end);
        port->root_bus_nr = sys->busnr;
 
-       /* 1M external config */
-       cfg_data = ioremap(port->cfg_space.start, 0x100000);
-       if (cfg_data == NULL) {
-               printk(KERN_ERR "%s: Can't map external config space !",
-                       port->node->full_name);
+       /* Map PCIe bridge control registers */
+       port->regs = ioremap(port->utl_regs.start,
+                            resource_size(&port->utl_regs));
+       if (!port->regs) {
+               pr_err("PCIE%d: Failed to map control registers\n", portno);
                goto fail;
        }
-       port->cfg_data = cfg_data;
-
-       /* IORESOURCE_MEM */
-       port->outbound.name = "PCIe MEM";
-       port->outbound.start = port->cfg_space.start - 0x38000000;
-       /* allocate 256 M -- 2 MPAGEs worth */
-       port->outbound.end = port->outbound.start + 0x10000000 - 1;
-       port->outbound.flags = IORESOURCE_MEM;
-
-       if (request_resource(&iomem_resource, &port->outbound))
-               panic("Request PCIe Memory resource failed for port %d\n",
-                     portno);
 
-       pci_add_resource_offset(&sys->resources, &port->outbound,
-                       sys->mem_offset);
-       printk(KERN_INFO "port res start = 0x%012llx, end = 0x%012llx\n",
-               port->outbound.start, port->outbound.end);
-       printk(KERN_INFO "port system mem_offset start = 0x%012llx\n",
-               sys->mem_offset);
-
-       /* 4K  internal config */
-       cfg_addr = ioremap(port->utl_regs.start, 0x10000);
-       if (cfg_addr == NULL) {
-               printk(KERN_ERR "%s: Can't map external config space !",
-                       port->node->full_name);
+       /* Map range for access to PCI configuration space */
+       port->cfg_data = ioremap(port->cfg_space.start,
+                                resource_size(&port->cfg_space));
+       if (!port->cfg_data) {
+               pr_err("PCIE%d: Failed to map config space\n", portno);
                goto fail;
        }
-       port->cfg_addr = cfg_addr;
-       printk("cfg_addr for port %d = 0x%8x\n", port->index,
-               (unsigned int)port->cfg_addr);
-       pci_config = readl(cfg_addr);
-#ifdef PRINT_CONFIG_ACCESSES
-       printk(KERN_INFO "pci_vendor = 0x%08x\n", pci_config);
-#endif
 
-       /* hookup an interrupt handler */
-       printk(KERN_INFO "PCIE%d mapping interrupt\n", port->index);
-       mappedIrq = irq_of_parse_and_map(port->node, 0);
-       printk(KERN_INFO "Requesting irq#%d for PEI%d Legacy INTs\n",
-                       mappedIrq, port->index);
+       pci_add_resource_offset(&sys->resources, &port->outbound,
+                               port->outbound.start - port->pci_addr);
 
-       err = request_irq(mappedIrq, acp_pcie_isr,
-                         IRQF_SHARED, "acp_pcie", port);
+       /* Status/error interrupt */
+       port->irq[0] = irq_of_parse_and_map(port->node, 0);
+       err = request_irq(port->irq[0], pcie_legacy_isr, IRQF_SHARED,
+                         "pcie", port);
        if (err) {
-               printk(KERN_ERR "request_irq failed!!!! for IRQ# %d err = %d\n",
-                       mappedIrq, err);
+               pr_err("PCIE%d: Failed to request IRQ#%d (%d)\n",
+                      portno, port->irq[0], err);
                goto fail;
        }
 
-       /* MSI INTS for PEI0 */
+       /* MSI interrupts for PEI0 */
        if (sys->domain == 0) {
-               /* IRQ# 73-88 for PEI0 MSI INTs */
-               for (irq_entry = 1; irq_entry <= 16; irq_entry++) {
-                       mappedIrq = irq_of_parse_and_map(port->node, irq_entry);
-                       printk(KERN_INFO
-                               "Requesting irq#%d for PEI0 MSI INTs\n",
-                               mappedIrq);
-                       err = request_irq(mappedIrq, acp_pcie_MSI_isr,
-                               IRQF_SHARED, "acp_pcie_MSI", port);
-                       if (err) {
-                               printk(KERN_ERR
-                               "request_irq failed!!!! for IRQ# %d err = %d\n",
-                               mappedIrq, err);
-                               goto fail;
-                       }
+               for (i = 1; i <= 16; i++) {
+                       port->irq[i] = irq_of_parse_and_map(port->node, i);
+                       irq_set_chained_handler(port->irq[i],
+                                               pcie_pei0_msi_handler);
                }
        }
 
        /* Setup as root complex */
-       pci_config = readl(cfg_addr + 0x1000);
-#ifdef PRINT_CONFIG_ACCESSES
-       printk("pci_config = 0x%08x\n", pci_config);
-#endif
-
-       pci_status = readl(cfg_addr + 0x1004);
-       link_state = (pci_status & 0x3f00) >> 8;
-       printk(KERN_INFO
-               "PCIE%d status = 0x%08x : PCI link state = 0x%x\n",
+       pci_config = readl(port->regs + PCIE_CONFIG);
+       pci_status = readl(port->regs + PCIE_STATUS);
+       link_state = (pci_status >> 8) & 0x3f;
+       pr_info("PCIE%d: status=0x%08x, link state=%#x\n",
                port->index, pci_status, link_state);
 
        /* make sure the ACP device is configured as PCI Root Complex */
        if ((pci_status & 0x18) != 0x18) {
-               printk(KERN_INFO
-                       "ACP device is not PCI Root Complex! status = 0x%08x\n",
-                       pci_status);
+               pr_err("PCIE%d: Device is not Root Complex\n", portno);
                goto fail;
        }
 
-       /* make sure the link is up */
+       /* Make sure the link is up */
        if (link_state != 0xb) {
-               /* reset */
-               printk("PCI link in bad state - resetting\n");
+               /* Reset */
+               pr_warn("PCIE%d: Link in bad state - resetting\n", port->index);
                pci_config |= 1;
-               writel(pci_config, cfg_addr + 0x1000);
+               writel(pci_config, port->regs + PCIE_CONFIG);
                msleep(1000);
-               pci_status = readl(cfg_addr + 0x1004);
+               pci_status = readl(port->regs + PCIE_STATUS);
                link_state = (pci_status & 0x3f00) >> 8;
-               printk(KERN_INFO "PCI link state now = 0x%x\n", link_state);
+               pr_warn("PCIE%d: (after reset) link state=%#x\n",
+                       port->index, link_state);
                if (link_state != 0xb) {
-                       printk(KERN_INFO "PCI link still in bad state - giving 
up!\n");
+                       pr_warn("PCIE%d: Link in bad state - giving up!\n",
+                               port->index);
                        goto fail;
                }
        }
 
-       /* ACP X1 setup MPAGE registers */
        /*
-        * MPAGE7 is dedicated to config access, so we only
-        *  have 7 128MB pages available for memory i/o.
-        *  Calculate how many pages we need
+        * Setup outbound PCI Memory Window
         */
-       size = 7 * 1024*128*1024;
-       num_pages = ((size - 1) >> 27) + 1;
-       pciah = U64_TO_U32_HIGH(port->pci_addr);
-       pcial = U64_TO_U32_LOW(port->pci_addr);
+
+       outbound_size = resource_size(&port->outbound);
+       num_pages = (outbound_size + MPAGE_SIZE - 1) / MPAGE_SIZE;
+       dest = port->pci_addr;
        for (i = 0; i < num_pages; i++) {
-               mpage_lower = (pcial & 0xf8000000);
-               mpage_lower |= 0x0;
-               writel(pciah, cfg_addr + ACPX1_PCIE_MPAGE_UPPER(i));
-               writel(mpage_lower, cfg_addr + ACPX1_PCIE_MPAGE_LOWER(i));
-               pcial += 0x08000000;
+               u32 mpage_u = dest >> 32;
+               u32 mpage_l = (u32)dest & ~(MPAGE_SIZE-1);
+               writel(mpage_u, port->regs + PCIE_MPAGE_U(i));
+               writel(mpage_l, port->regs + PCIE_MPAGE_L(i));
+               pr_debug("PCIE%d: MPAGE(%d) = %08x %08x\n",
+                        port->index, i, mpage_u, mpage_l);
+               dest += MPAGE_SIZE;
        }
 
-       inbound_size = (u32) (port->inbound.end - port->inbound.start + 1);
+       /*
+        * Setup inbound PCI window
+        */
 
-       /* configures the RC Memory Space Configuration Register */
-       writel(inbound_size, cfg_addr + 0x11f4);
+       /* Configure the inbound window size */
+       inbound_size = (u32) resource_size(&port->inbound);
+       writel(inbound_size, port->regs + PCIE_RC_BAR0_SIZE);
+
+       /* Verify BAR0 size */
+       {
+               u32 bar0_size;
+               writel(~0, port->regs + PCI_BASE_ADDRESS_0);
+               bar0_size = readl(port->regs + PCI_BASE_ADDRESS_0);
+               if ((bar0_size & ~0xf) != inbound_size)
+                       pr_err("PCIE%d: Config BAR0 failed\n", port->index);
+       }
 
-       /* write all 1s to BAR0 register */
-       writel(0xffffffff, cfg_addr + 0x10);
+       /* Set the BASE0 address to start of PCIe base */
+       writel(port->pci_bar, port->regs + PCI_BASE_ADDRESS_0);
 
-       /* read back BAR0 */
-       bar0_size = readl(cfg_addr + 0x10);
-       if ((bar0_size & inbound_size) != inbound_size)
-               printk(KERN_INFO "Writing/Reading BAR0 reg failed\n");
+       /* Setup TPAGE registers for inbound mapping
+        *
+        * We set the MSB of each TPAGE to select 128-bit AXI access. For the
+        * address field we simply program an incrementing value to map
+        * consecutive pages
+        */
+       for (i = 0; i < 8; i++)
+               writel(PCIE_TPAGE_128 | i, port->regs + PCIE_TPAGE_BAR0(i));
 
-       /* set the BASE0 address to start of PCIe base */
-       writel(port->inbound.start, cfg_addr + 0x10);
 
-       /* setup TPAGE registers for inbound mapping */
-       /* We set the MSB of each TPAGE to select 128-bit AXI access.
-        * For the address field we simply program an incrementing value
-        * to map consecutive pages
-        */
-       tpage_base = cfg_addr + 0x1050;
-       for (i = 0; i < 8; i++) {
-               writel((0x80000000 + i), tpage_base);
-               tpage_base += 4;
-       }
+       /* Enable all legacy/status/error interrupts */
+       writel(INT0_MSI | INT0_INT_ASSERTED | INT0_ERROR,
+              port->regs + PCIE_INT0_ENABLE);
 
+       /* Enable all MSI interrupt groups */
+       writel(0xFFFF, port->regs + PCIE_MSI0_ENABLE);
+       /* Enable all lines in all subgroups */
+       for (i = 0; i < 16; i++)
+               writel(0xFFFF, port->regs + PCIE_MSI1_ENABLE(i));
 
        return 1;
 fail:
-       if (cfg_data)
-               iounmap(cfg_data);
-       if (cfg_addr)
-               iounmap(cfg_addr);
+       if (port->cfg_data)
+               iounmap(port->cfg_data);
+       if (port->regs)
+               iounmap(port->regs);
        return 0;
 }
 
-/* Just a dummy arch_setup_msi_irq() function */
-int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+/*
+ * Allocate MSI page. A MSI is generated when EP writes to this PCI address.
+ * The region must be 1Kb to manage 256 MSIs.
+ */
+static void *
+pcie_alloc_msi_table(struct pci_dev *pdev, struct axxia_pciex_port *port)
 {
-       return 0;
-}
+       u32 msi_lower;
+       void *msi_virt;
 
+       if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)) != 0 &&
+           dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
+               dev_err(&pdev->dev, "No memory for MSI table\n");
+               return NULL;
+       }
 
-void arch_teardown_msi_irq(unsigned int irq)
-{
-}
+       msi_virt = dma_alloc_coherent(&pdev->dev, 1024,
+                                     &port->msi_phys,
+                                     GFP_KERNEL);
+       if (msi_virt) {
+               msi_lower = (u32)port->msi_phys;
+               /* Please note we have 1:1 mapping for inbound */
+               port->msi_pci_addr = port->inbound.start + msi_lower;
+               writel(msi_lower>>10, port->regs + PCIE_AXI_MSI_ADDR);
+       }
 
+       return msi_virt;
+}
 
 
-/* Scan PCIe bus */
+/*
+ * Scan PCIe bus
+ */
 static struct pci_bus __init *
 axxia_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       struct pci_bus *bus;
-       struct axxia_pciex_port *port;
-
-       /* get the pointer to port struct from domain# */
-       port = &axxia_pciex_ports[sys->domain];
-
-       if (nr < axxia_pciex_port_count) {
-               bus = pci_scan_root_bus(NULL, sys->busnr,
-                       &axxia_pciex_pci_ops, sys, &sys->resources);
-       } else {
-               bus = NULL;
-               printk(KERN_WARNING "PCIE: exceeded number of supported PEI 
ports\n");
-       }
+       if (WARN_ON(nr >= PCIE_MAX_PORTS))
+               return NULL;
 
-       return bus;
+       return pci_scan_root_bus(NULL, sys->busnr, &axxia_pciex_pci_ops,
+                                sys, &sys->resources);
 }
 
-/* MSI setup */
-static void __devinit axxia_pcie_msi_enable(struct pci_dev *dev)
-{
-       u32 pci_higher = 0, msi_lower = 0;
-       u16 flag_val;
-       int pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-       struct axxia_pciex_port *port;
-       void *msi_virt;
-       int device, fn, bus_num;
-       static u32 pci_lower, msi_count;
 
-       port = bus_to_port(dev->bus);
 
-       if (pos <= 0) {
-               dev_err(&dev->dev, "skipping MSI enable\n");
-               printk(KERN_INFO "skipping MSI enable\n");
-               return;
-       }
-
-       /* MSI applicable only to PEI0 */
-       if (port->index == 0) {
-               /* MSI is generated when EP writes to address mapped */
-               if (msi_lower == 0) {
-                       /* MSI support only in PEI0 */
-                       /* allocate 1K to manage 256 MSIs
-                        * one for each endpoint */
-
-                       if ((!dma_set_coherent_mask(&dev->dev,
-                               DMA_BIT_MASK(64))) ||
-                               (!dma_set_coherent_mask(&dev->dev,
-                               DMA_BIT_MASK(32)))) {
-                               msi_virt = dma_alloc_coherent(&dev->dev,
-                                       1024, &(port->msi_phys), GFP_KERNEL);
-                       } else {
-                               printk(KERN_INFO
-                                       "No suitable DMA available. MSI cannot"
-                                       "be supported\n");
-                               return;
-                       }
-                       msi_lower = (u32)port->msi_phys;
-                       /* Please note we have 1:1 mapping for inbound */
-                       pci_lower = port->inbound.start + msi_lower;
-                       printk("PEI%d dma_alloc_coherent msiAddr = 0x%x\n",
-                               port->index, msi_lower);
-                       writel(msi_lower>>10, port->cfg_addr + 0x1190);
-               }
-               device = ((PCI_SLOT(dev->devfn) & 0xf8) >> 3);
-               fn  = PCI_FUNC(dev->devfn) & 0x7;
-               bus_num = dev->bus->number;
-
-               printk(KERN_INFO
-                       "PEI%d axxia_pcie_msi_enable Found MSI%d"
-                       ", msi_lower = 0x%x"
-                       "for bus_num = %d, dev = %d, fn = %d\n",
-                       port->index, msi_count, msi_lower,
-                       bus_num, device, fn);
-               pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
-                       pci_lower);
-               pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
-                       pci_higher);
-
-               /* Enable MSI */
-               dev->msi_enabled = 1;
-
-               pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &flag_val);
-               flag_val = flag_val | 0x1;
-               pci_write_config_word(dev, pos + PCI_MSI_FLAGS,
-                       (flag_val | 0x1));
-
-               /* for next EP MSI */
-               pci_lower = pci_lower + 0x4;
-               msi_count++;
-       }
-       return;
+static int __init
+axxia_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       struct pci_sys_data *sys = dev->sysdata;
+       struct axxia_pciex_port *port = &axxia_pciex_ports[sys->domain];
+       return port->irq[0];
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, axxia_pcie_msi_enable);
+
+/* IRQ chip ops for MSI IRQs */
+static struct irq_chip axxia_msi_chip = {
+       .name = "PCI-MSI",
+       .irq_enable  = unmask_msi_irq,
+       .irq_disable = mask_msi_irq,
+       .irq_mask    = mask_msi_irq,
+       .irq_unmask  = unmask_msi_irq,
+};
 
 
-/* Port definition struct
- * Please note: PEI core#1 is not used in AXM5500 */
+/* Port definition struct */
 static struct hw_pci axxia_pcie_hw[] = {
        [0] = {
                .nr_controllers = 1,
                .domain = 0,
                .swizzle = pci_std_swizzle,
                .setup = axxia_pcie_setup,
-               .scan = axxia_pcie_scan_bus
+               .scan = axxia_pcie_scan_bus,
+               .map_irq = axxia_pcie_map_irq
        },
        [1] = {
                .nr_controllers = 1,
                .domain = 1,
                .swizzle = pci_std_swizzle,
                .setup = axxia_pcie_setup,
-               .scan = axxia_pcie_scan_bus
+               .scan = axxia_pcie_scan_bus,
+               .map_irq = axxia_pcie_map_irq
        }
 };
 
-/* Initialize PCIe */
-void __init axxia_pcie_init(void)
-{
-       struct device_node *np;
-       int found_a_port = 0;
-
-       /* allocate memory */
-       axxia_pciex_ports = kzalloc(axxia_pciex_port_count
-               * sizeof(struct axxia_pciex_port), GFP_KERNEL);
-
-       if (!axxia_pciex_ports) {
-               printk(KERN_WARNING "PCIE: failed to allocate ports array\n");
-               return;
-       }
-
-       for_each_compatible_node(np, NULL, "lsi,plb-pciex") {
-               ++found_a_port;
-               axxia_probe_pciex_bridge(np);
-       }
-
-       if (0 != found_a_port) {
-               pci_common_init(&axxia_pcie_hw[0]);
-               pci_common_init(&axxia_pcie_hw[1]);
-       }
-
-       return;
-}
-
-static void axxia_probe_pciex_bridge(struct device_node *np)
+static void
+axxia_probe_pciex_bridge(struct device_node *np)
 {
        struct axxia_pciex_port *port;
-       u32 pval;
-       int portno;
+       u32 portno;
        const char *val;
        const u32 *field;
        int rlen;
-       int pna = of_n_addr_cells(np);
-       int num = pna + 5;
-       u64 size, pci_addr;
+       int pna = of_n_addr_cells(np); /* address-size of parent */
+       u32 pci_space;
+       u64 pci_addr;
+       u64 cpu_addr;
+       u64 size;
 
        /* Check if device is enabled */
-       if (!of_device_is_available(np)) {
-               printk(KERN_INFO "%s: Port disabled via device-tree\n",
-                       np->full_name);
+       if (!of_device_is_available(np))
                return;
-       }
 
        /* Get the port number from the device-tree */
-       if (!of_property_read_u32(np, "port", &pval)) {
-               portno = pval;
-
-               printk(KERN_INFO "PCIE Port %d found\n", portno);
-       } else {
-               printk(KERN_ERR "PCIE: Can't find port number for %s\n",
-                      np->full_name);
+       if (of_property_read_u32(np, "port", &portno) != 0) {
+               pr_err("%s: No 'port' property\n", np->full_name);
                return;
        }
 
-       if (portno > axxia_pciex_port_count) {
-               printk(KERN_ERR "PCIE: port number out of range for %s\n",
-                      np->full_name);
+       if (portno >= PCIE_MAX_PORTS) {
+               pr_err("%s: Port %d out of range\n", np->full_name, portno);
                return;
        }
 
        port = &axxia_pciex_ports[portno];
        port->index = portno;
-
+       snprintf(port->name, sizeof port->name - 1, "PCIE%d", portno);
        port->node = of_node_get(np);
 
        /* Check if device_type property is set to "pci" or "pci-endpoint".
@@ -823,90 +832,196 @@ static void axxia_probe_pciex_bridge(struct device_node 
*np)
         * as root-complex or as endpoint.
         */
        val = of_get_property(port->node, "device_type", NULL);
-       if (!strcmp(val, "pci-endpoint")) {
-               port->endpoint = 1;
-       } else if (!strcmp(val, "pci")) {
-               port->endpoint = 0;
-       } else {
-               printk(KERN_ERR "PCIE%d: missing or incorrect device_type for 
%s\n",
-                      portno, np->full_name);
-               return;
-       }
-       printk(KERN_ERR "PCIE%d: endpoint = %d\n", portno, port->endpoint);
+       port->endpoint = val && strcmp(val, "pci-endpoint") == 0;
 
-       /* Fetch config space registers address */
+       /* Fetch address range for PCIE config space */
        if (of_address_to_resource(np, 0, &port->cfg_space)) {
-               printk(KERN_ERR "%s: Can't get PCI-E config space !",
-                      np->full_name);
+               pr_err("PCIE%d: No resource for PCIe config space\n", portno);
                return;
        }
-       printk(KERN_INFO
-               "cfg_space start = 0x%012llx, end = 0x%012llx\n",
-               port->cfg_space.start, port->cfg_space.end);
 
-       /* Fetch host bridge internal registers address */
+       /* Fetch address range for host bridge internal registers */
        if (of_address_to_resource(np, 1, &port->utl_regs)) {
-               printk(KERN_ERR "%s: Can't get UTL register base !",
-                      np->full_name);
+               pr_err("PCIE%d: No resource for PCIe registers\n", portno);
                return;
        }
-       printk(KERN_INFO
-               "utl_regs start = 0x%012llx, end = 0x%012llx\n",
-               port->utl_regs.start, port->utl_regs.end);
+
+       if (request_resource(&iomem_resource, &port->utl_regs))
+               return;
+
+       /*
+        * Outbound PCI memory window
+        */
+
+       /* Defaults */
+       port->outbound = pcie_outbound_default[portno];
+       port->outbound.name = port->name;
 
        field = of_get_property(np, "ranges", &rlen);
-       if (field == NULL)
-               printk("not able to get ranges\n");
+       if (field) {
+               pci_space = of_read_number(field + 0, 1);
+               switch ((pci_space >> 24) & 3) {
+               case 0:
+                       pr_err("PCIE%d: Invalid 'ranges'\n", portno);
+                       break;
+               case 1: /* PCI IO Space */
+                       pr_err("PCIE%d: PCI IO not supported\n", portno);
+                       break;
+               case 2: /* PCI MEM 32-bit */
+               case 3: /* PCI MEM 64-bit */
+                       cpu_addr  = of_read_number(field + 3, 2);
+                       size      = of_read_number(field + 5, 2);
+                       port->outbound.start = cpu_addr;
+                       port->outbound.end   = cpu_addr + size - 1;
+                       port->pci_addr = of_read_number(field + 1, 2);
+                       break;
+               }
+       }
 
-       pci_addr = of_read_number(field + 1, 2);
-       printk(KERN_INFO "pci_addr = 0x%012llx\n", pci_addr);
-       port->pci_addr = pci_addr;
+       if (resource_size(&port->outbound) > MAX_OUTBOUND_SIZE) {
+               pr_err("PCIE%d: Outbound window too large (using max %#x)\n",
+                      portno, MAX_OUTBOUND_SIZE);
+               port->outbound.end = (port->outbound.start +
+                                     MAX_OUTBOUND_SIZE - 1);
+       }
+
+       if (request_resource(&iomem_resource, &port->outbound)) {
+               pr_err("PCIE%d: Memory resource request failed\n", portno);
+               return;
+       }
+
+       if (request_resource(&iomem_resource, &port->cfg_space)) {
+               pr_err("PCIE%d: Config space request failed\n", portno);
+               return;
+       }
 
-       printk(KERN_INFO "%s PCIE%d config base = 0x%012llx\n",
-               np->full_name, port->index, port->utl_regs.start);
+       pr_info("PCIE%d: Outbound %#llx..%#llx (CPU) -> %#llx (PCI)\n",
+               portno,
+               port->outbound.start, port->outbound.end,
+               port->pci_addr);
 
-       /* Default 256 MB */
-       port->inbound.start = 0;
-       size = 0x10000000;
-       port->inbound.end = size - 1;
+       /*
+        * Inbound PCI memory window
+        */
+
+       /* Default 4GB */
+       port->inbound.name  = "PCIE DMA";
+       port->inbound.start = 0x00000000;
+       port->inbound.end   = 0xffffffff;
        port->inbound.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
 
        /* Get dma-ranges property */
        field = of_get_property(np, "dma-ranges", &rlen);
-       if (field == NULL) {
-               printk(KERN_INFO "not able to get dma-ranges\n");
-               /* use default */
-               return;
+       if (!field) {
+               pr_info("PCIE%d: No 'dma-ranges' property, using defaults\n",
+                       portno);
+       } else {
+               BUILD_BUG_ON(sizeof(resource_size_t) != sizeof(u64));
+
+               /* Limited to one inbound window for now... */
+               pci_space = of_read_number(field + 0, 1);
+               pci_addr  = of_read_number(field + 1, 2);
+               cpu_addr  = of_read_number(field + 3, pna);
+               size      = of_read_number(field + pna + 3, 2);
+
+               port->inbound.start = cpu_addr;
+               port->inbound.end   = cpu_addr + size - 1;
+               port->pci_bar       = pci_addr;
        }
 
-       /* Walk it */
-       while ((rlen -= num * 4) >= 0) {
-               u64 pci_addr = of_read_number(field + 1, 2);
-               u64 cpu_addr = of_read_number(field + 3, 1);
-               size = of_read_number(field + pna + 3, 2);
-               field += num;
+       pr_info("PCIE%d: Inbound %#llx (PCI) -> %#llx..%#llx (CPU)\n",
+               portno,
+               port->pci_bar,
+               port->inbound.start, port->inbound.end);
 
-               /* We currently only support memory at 0, and pci_addr
-                * within 32 bits space and 1:1 mapping
-                */
-               if (cpu_addr != 0 || pci_addr > 0xffffffff) {
-                       printk(KERN_WARNING
-                              "%s: Ignored unsupported dma range"
-                                       "0x%016llx...0x%016llx -> 0x%016llx\n",
-                               np->full_name, pci_addr,
-                               pci_addr + size - 1, cpu_addr);
+}
+
+/*
+ * Allocate a MSI interrupt number and IRQ (the IRQ is a constant offset from
+ * the MSI index). The kernel IRQs for MSI are in a range above hardware IRQs.
+ *
+ * First call also allocates the 1Kb MSI table and configures the controller.
+ */
+int
+arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+       struct axxia_pciex_port *port = bus_to_port(pdev->bus);
+       struct msi_msg msg;
+       int pos, irq;
+
+       /* Allocate MSI table on demand when first device needs it */
+       if (!port->msi_virt)
+               port->msi_virt = pcie_alloc_msi_table(pdev, port);
+
+       if (!port->msi_virt)
+               return -ENOMEM;
+
+       /* Find available MSI */
+again:
+       pos = find_first_zero_bit(msi_irq_in_use, NUM_MSI_IRQ);
+       /* Offset to get the IRQ */
+       irq = AXXIA_MSI_FIRST + pos;
+       if (irq >= NR_IRQS)
+               return -ENOSYS;
+       if (test_and_set_bit(pos, msi_irq_in_use))
+               goto again;
+
+       /* Initialize IRQ descriptor */
+       dynamic_irq_init(irq);
+       irq_set_msi_desc(irq, desc);
+       /* Use a simple handle for our "SW" MSI IRQs */
+       irq_set_chip_and_handler(irq, &axxia_msi_chip, handle_simple_irq);
+       set_irq_flags(irq, IRQF_VALID);
+
+       /* Configure PCI device with its MSI address */
+       msg.address_hi = 0x0;
+       msg.address_lo = port->msi_pci_addr + 4*pos;
+       msg.data       = irq;
+       write_msi_msg(irq, &msg);
+
+       return 0;
+}
+
+/*
+ * Called by the generic MSI layer to free MSI IRQ.
+ */
+void
+arch_teardown_msi_irq(unsigned int irq)
+{
+       int pos = irq - AXXIA_MSI_FIRST;
+
+       if (0 <= pos && pos < NR_IRQS) {
+               clear_bit(pos, msi_irq_in_use);
+               dynamic_irq_cleanup(irq);
+       }
+}
+
+/**
+ * Initialize PCIe controller(s) found in the device tree.
+ */
+void __init
+axxia_pcie_init(void)
+{
+       struct device_node *np;
+       int num_ports = 0;
+
+       /* allocate memory */
+       axxia_pciex_ports = kzalloc(PCIE_MAX_PORTS *
+                                   sizeof(struct axxia_pciex_port),
+                                   GFP_KERNEL);
+       if (!axxia_pciex_ports) {
+               pr_err("PCIE: No memory\n");
+               return;
+       }
+
+       for_each_compatible_node(np, NULL, "lsi,plb-pciex") {
+               if (!of_device_is_available(np))
                        continue;
-               }
-               /* Use that */
-               port->inbound.start = pci_addr;
-               /* Beware of 32 bits resources */
-               if (sizeof(resource_size_t) == sizeof(u32) &&
-                       (pci_addr + size) > 0x100000000ull) {
-                       port->inbound.end = 0xffffffff;
-               } else
-                       port->inbound.end = port->inbound.start + size - 1;
-               break;
+
+               axxia_probe_pciex_bridge(np);
+               pci_common_init(&axxia_pcie_hw[num_ports]);
+               if (++num_ports == PCIE_MAX_PORTS)
+                       break;
        }
-       printk(KERN_INFO "inbound start = 0x%016llx, end = 0x%016llx\n",\
-               port->inbound.start, port->inbound.end);
 }
+
-- 
1.8.3

_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to