Add (fixed) GICv2m driver from PDSW pci64 branch
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 466497d..e9bbe99 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -53,6 +53,8 @@
                 bool "Versatile Express gem5 model"
                 select MIGHT_HAVE_PCI
                 select PCI
+                select ARM_GIC_MSI
+                select ARCH_SUPPORTS_MSI
                 select NEED_MACH_IO_H
                 select NEED_MACH_MEMORY_H
                 help
diff --git a/arch/arm/mach-vexpress/include/mach/irqs.h b/arch/arm/mach-vexpress/include/mach/irqs.h
index f8f7f78..7e157e9 100644
--- a/arch/arm/mach-vexpress/include/mach/irqs.h
+++ b/arch/arm/mach-vexpress/include/mach/irqs.h
@@ -2,5 +2,5 @@
 #define IRQ_LOCALWDOG		30
 
 #ifndef CONFIG_SPARSE_IRQ
-#define NR_IRQS	256
+#define NR_IRQS	512
 #endif
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 516d8a7..fe7dd2d 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -9,6 +9,7 @@
 	select ARM_AMBA
 	select ARM_ARCH_TIMER
 	select ARM_GIC
+	select ARM_GIC_MSI
 	select BUILDTIME_EXTABLE_SORT
 	select CLONE_BACKWARDS
 	select COMMON_CLK
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 61ffdca..5b43df1 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -7,6 +7,9 @@
 	select IRQ_DOMAIN
 	select MULTI_IRQ_HANDLER
 
+config ARM_GIC_MSI
+	bool
+
 config GIC_NON_BANKED
 	bool
 
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 5194afb..dea3f7d 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -14,6 +14,7 @@
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o
 obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o
 obj-$(CONFIG_ARM_GIC)			+= irq-gic.o
+obj-$(CONFIG_ARM_GIC_MSI)		+= irq-gic-msi.o
 obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
 obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
 obj-$(CONFIG_IMGPDC_IRQ)		+= irq-imgpdc.o
diff --git a/drivers/irqchip/irq-gic-msi.c b/drivers/irqchip/irq-gic-msi.c
new file mode 100644
index 0000000..406bf33
--- /dev/null
+++ b/drivers/irqchip/irq-gic-msi.c
@@ -0,0 +1,283 @@
+/*
+ * GIC MSI Extensions Driver.
+ *
+ * This driver provides support for up to 1 MSI per pci_dev. The functionality
+ * is provided by an MSI widget which provides an MSI capture register which
+ * fires SPIs. This driver hooks into the standard MSI arch callbacks and maps
+ * MSI vectors to SPI interrupts.
+ *
+ * Copyright (C) 2012-2013 ARM Ltd.
+ * Author: Andrew Murray <andrew.murray@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/arm-gic-msi.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#define DEVICE_NAME "gic-msi"
+
+#ifdef CONFIG_PCI_MSI
+
+/* The kernel only supports a single MSI controller, thus our driver is limited
+   to a single instance */
+static struct gic_msi_data *gd;
+
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+	int virt, vector;
+	struct msi_msg msg;
+	struct gic_msi_frame *frame;
+
+	if (WARN(!gd, DEVICE_NAME ": No MSI handler"))
+		return 1;
+
+	/* Look in all the frames to find an available MSI vector/SPI */
+	list_for_each_entry(frame, &gd->frames, list) {
+again:
+		vector = find_first_zero_bit(frame->msi_irq_in_use,
+				frame->nr_msi);
+		if (vector >= frame->nr_msi)
+			continue;
+
+		if (test_and_set_bit(vector, frame->msi_irq_in_use))
+			goto again;
+
+		virt = vector + frame->start_spi;
+
+		irq_set_msi_desc(virt, desc);
+		irq_set_irq_type(virt, IRQ_TYPE_EDGE_RISING);
+
+#ifdef CONFIG_64BIT
+		msg.address_hi = (phys_addr_t)frame->base_p >> 32;
+#endif
+		msg.address_lo = (phys_addr_t)frame->base_p + GIC_MSI_SETSPI_NSR;
+		msg.data = virt;
+
+		write_msi_msg(virt, &msg);
+
+		return 0;
+	}
+
+	/* No free MSIs */
+	WARN_ON(DEVICE_NAME ": Unable to assign another MSI");
+	return 1;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+	struct gic_msi_frame *frame;
+	int hwirq;
+
+	if (WARN(!gd, DEVICE_NAME ": No MSI handler"))
+		return;
+
+	list_for_each_entry(frame, &gd->frames, list) {
+		hwirq = irq - frame->start_spi;
+		if (hwirq < frame->nr_msi) {
+			clear_bit(hwirq, frame->msi_irq_in_use);
+			return;
+		}
+	}
+}
+static int gic_msi_init_frame(struct resource *res)
+{
+	struct gic_msi_frame *frame;
+	int err, x;
+
+	frame = kzalloc(sizeof(struct gic_msi_frame), GFP_KERNEL);
+	if (WARN(!frame, DEVICE_NAME ": Unable to allocate memory"))
+		return -ENOMEM;
+
+	frame->base_p = res->start;
+	frame->base_sz = resource_size(res);
+
+	if (!request_mem_region(res->start, resource_size(res), DEVICE_NAME)) {
+		pr_err(DEVICE_NAME
+			": Failed to request config registers resource\n");
+		err = -EBUSY;
+		goto err_request_mem;
+	}
+
+	frame->base_p= res->start;
+	frame->base_sz= resource_size(res);
+	frame->base = ioremap(res->start, resource_size(res));
+	if (!frame->base) {
+		pr_err(DEVICE_NAME
+			": Failed to map configuration registers resource\n");
+		err = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	x = readl(frame->base + GIC_MSI_TYPER);
+	frame->start_spi = (x & GIC_MSI_TYPER_START_MASK)
+				>> GIC_MSI_TYPER_START_SHIFT;
+	frame->nr_msi = x & GIC_MSI_TYPER_NR_MASK;
+
+	list_add_tail(&frame->list, &gd->frames);
+
+	return 0;
+
+err_ioremap:
+	iounmap(frame->base);
+
+err_request_mem:
+	kfree(frame);
+
+	return err;
+}
+
+static int gic_msi_remove_frames(void)
+{
+	struct gic_msi_frame *frame, *tmp;
+
+	list_for_each_entry_safe(frame, tmp, &gd->frames, list) {
+		iounmap(frame->base);
+		release_mem_region(frame->base_p, frame->base_sz);
+		list_del(&frame->list);
+		kfree(frame);
+	}
+	return 0;
+}
+
+static int gic_msi_get_virt_offset(struct device_node *np, int *virt_offset)
+{
+	struct device_node *p;
+	struct irq_domain *domain;
+	unsigned int type, spec[3] = { 0, 0, 0 };
+	irq_hw_number_t hwirq;
+	int err;
+
+	p = of_irq_find_parent(np);
+	if (WARN(!p, DEVICE_NAME ": Unable to find interrupt parent"))
+		return -EINVAL;
+
+	domain = irq_find_host(p);
+	if (WARN(!domain, DEVICE_NAME
+			": Unable to find interrupt parent domain"))
+		goto err;
+
+	if (WARN(!domain->ops->xlate, DEVICE_NAME
+		": Unable to translate interrupt parent domain"))
+		goto err;
+
+	err = domain->ops->xlate(domain, p, spec, sizeof(spec) / sizeof(int),
+					&hwirq, &type);
+	if (err) {
+		pr_err(DEVICE_NAME
+			": Unable to translate interrupt parent domain\n");
+		goto err;
+
+	}
+
+	*virt_offset = irq_create_mapping(domain, hwirq);
+
+	of_node_put(p);
+	return 0;
+
+err:
+	of_node_put(p);
+	return -EINVAL;
+}
+
+static int gic_msi_probe(struct platform_device *pdev)
+{
+	int err, x = 0;
+	struct device_node *np;
+	struct resource res;
+
+	np = pdev->dev.of_node;
+
+	if (WARN(gd, DEVICE_NAME ": MSI handler already installed"))
+		return -EEXIST;
+
+	if (WARN(!np, DEVICE_NAME ": No device tree node"))
+		return -EINVAL;
+
+	gd = kzalloc(sizeof(struct gic_msi_data), GFP_KERNEL);
+	if (WARN(!gd, DEVICE_NAME ": Unable to allocate memory"))
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&gd->frames);
+
+	err = gic_msi_get_virt_offset(np, &gd->virt_offset);
+	if (err) {
+		pr_err(DEVICE_NAME
+			": Unable to get virtual offset\n");
+		goto err_init_frame;
+	}
+
+	/* Iterate through each frame identified in the DT */
+	while (!(err = of_address_to_resource(np, x++, &res))) {
+		err = gic_msi_init_frame(&res);
+		if (err)
+			goto err_init_frame;
+
+		break;
+	}
+
+	return 0;
+err_init_frame:
+	gic_msi_remove_frames();
+
+	kfree(gd);
+	gd = NULL;
+
+	return -EINVAL;
+}
+
+/**
+ * Remove is a bad idea. We cannot easily tell PCIe devices to stop
+ * sending MSI's they've been allocated. In any case remove is unlikely
+ * to be used.
+ */
+static int gic_msi_remove(struct platform_device *pdev)
+{
+	gic_msi_remove_frames();
+
+	kfree(gd);
+	gd = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id gic_msi_ids[] = {
+	{ .compatible = "arm,gic-msi", },
+};
+
+static struct platform_driver gic_msi_driver = {
+	.probe  = gic_msi_probe,
+	.remove = gic_msi_remove,
+	.driver = {
+		.name = DEVICE_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = gic_msi_ids,
+	},
+};
+
+static int __init gic_msi_init(void)
+{
+	return platform_driver_register(&gic_msi_driver);
+}
+
+subsys_initcall(gic_msi_init);
+#endif
diff --git a/include/linux/irqchip/arm-gic-msi.h b/include/linux/irqchip/arm-gic-msi.h
new file mode 100644
index 0000000..6235a78
--- /dev/null
+++ b/include/linux/irqchip/arm-gic-msi.h
@@ -0,0 +1,56 @@
+/*
+ * include/linux/irqchip/arm-gic-msi.h
+ *
+ * This driver provides support for up to 1 MSI per pci_dev. The functionality
+ * is provided by an MSI widget which provides an MSI capture register which
+ * fires SPIs. This driver hooks into the standard MSI arch callbacks and maps
+ * MSI vectors to SPI interrupts.
+ *
+ * Copyright (C) 2012-2013 ARM Ltd.
+ * Author: Andrew Murray <andrew.murray@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ */
+#ifndef __LINUX_IRQCHIP_ARM_GIC_MSI_H
+#define __LINUX_IRQCHIP_ARM_GIC_MSI_H
+
+/*
+ * The hardware provides its functionality through multiple frames, each
+ * frame contains an MSI capture register and maps to a specific range of
+ * SPIs. The maximum number of SPIs per frame is 1024
+ */
+#define GIC_MSI_MAX_FRAME		1024
+
+#define GIC_MSI_TYPER			0x8
+#define GIC_MSI_SETSPI_NSR		0x40
+#define GIC_MSI_TYPER_NR_MASK		0x3ff
+#define GIC_MSI_TYPER_START_MASK	0x3ff0000
+#define GIC_MSI_TYPER_START_SHIFT	16
+
+struct gic_msi_frame {
+	void __iomem *base;
+	resource_size_t base_p;
+	resource_size_t base_sz;
+	int start_spi;
+	int nr_msi;
+	struct list_head list;
+	DECLARE_BITMAP(msi_irq_in_use, GIC_MSI_MAX_FRAME);
+};
+
+struct gic_msi_data {
+	struct list_head frames;
+	int virt_offset;
+};
+
+#endif