irqchip: arm64: Initial support for GICv3

Backport of patch from Mark Salter's fedorahosted tree.

Signed-off-by: Al Stone <ahs3@redhat.com>

Original patch:

    From 837f86c496d77eeed4455853bb45ca85a1d6e6b9 Mon Sep 17 00:00:00 2001
    From: Marc Zyngier <marc.zyngier@arm.com>
    Date: Mon, 30 Jun 2014 16:01:31 +0100
    Subject: [PATCH 52/87] irqchip: arm64: Initial support for GICv3

    The Generic Interrupt Controller (version 3) offers services that are
    similar to GICv2, with a number of additional features:
    - Affinity routing based on the CPU MPIDR (ARE)
    - System register for the CPU interfaces (SRE)
    - Support for more that 8 CPUs
    - Locality-specific Peripheral Interrupts (LPIs)
    - Interrupt Translation Services (ITS)

    This patch adds preliminary support for GICv3 with ARE and SRE,
    non-secure mode only. It relies on higher exception levels to grant ARE
    and SRE access.

    Support for LPI and ITS will be added at a later time.

    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Jason Cooper <jason@lakedaemon.net>
    Reviewed-by: Zi Shen Lim <zlim@broadcom.com>
    Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
    Reviewed-by: Tirumalesh Chalamarla <tchalamarla@cavium.com>
    Reviewed-by: Yun Wu <wuyun.wu@huawei.com>
    Reviewed-by: Zhen Lei <thunder.leizhen@huawei.com>
    Tested-by: Tirumalesh Chalamarla<tchalamarla@cavium.com>
    Tested-by: Radha Mohan Chintakuntla <rchintakuntla@cavium.com>
    Acked-by: Radha Mohan Chintakuntla <rchintakuntla@cavium.com>
    Acked-by: Catalin Marinas <catalin.marinas@arm.com>
    Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
    ---
     arch/arm64/Kconfig                 |   1 +
     arch/arm64/kernel/head.S           |  18 +
     arch/arm64/kernel/hyp-stub.S       |   1 +
     drivers/irqchip/Kconfig            |   5 +
     drivers/irqchip/Makefile           |   1 +
     drivers/irqchip/irq-gic-v3.c       | 692 +++++++++++++++++++++++++++++++++++++
     include/linux/irqchip/arm-gic-v3.h | 198 +++++++++++
     7 files changed, 916 insertions(+)
     create mode 100644 drivers/irqchip/irq-gic-v3.c
     create mode 100644 include/linux/irqchip/arm-gic-v3.h

    diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
    index 839f48c..690e91c 100644
    --- a/arch/arm64/Kconfig
    +++ b/arch/arm64/Kconfig
    @@ -11,6 +11,7 @@ config ARM64
     	select ARM_AMBA
     	select ARM_ARCH_TIMER
     	select ARM_GIC
    +	select ARM_GIC_V3
     	select BUILDTIME_EXTABLE_SORT
     	select CLONE_BACKWARDS
     	select COMMON_CLK
    diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
    index a2c1195..d1f7b96 100644
    --- a/arch/arm64/kernel/head.S
    +++ b/arch/arm64/kernel/head.S
    @@ -22,6 +22,7 @@

     #include <linux/linkage.h>
     #include <linux/init.h>
    +#include <linux/irqchip/arm-gic-v3.h>

     #include <asm/assembler.h>
     #include <asm/ptrace.h>
    @@ -295,6 +296,23 @@ CPU_LE(	bic	x0, x0, #(3 << 24)	)	// Clear the EE and E0E bits for EL1
     	msr	cnthctl_el2, x0
     	msr	cntvoff_el2, xzr		// Clear virtual offset

    +#ifdef CONFIG_ARM_GIC_V3
    +	/* GICv3 system register access */
    +	mrs	x0, id_aa64pfr0_el1
    +	ubfx	x0, x0, #24, #4
    +	cmp	x0, #1
    +	b.ne	3f
    +
    +	mrs	x0, ICC_SRE_EL2
    +	orr	x0, x0, #ICC_SRE_EL2_SRE	// Set ICC_SRE_EL2.SRE==1
    +	orr	x0, x0, #ICC_SRE_EL2_ENABLE	// Set ICC_SRE_EL2.Enable==1
    +	msr	ICC_SRE_EL2, x0
    +	isb					// Make sure SRE is now set
    +	msr	ICH_HCR_EL2, xzr		// Reset ICC_HCR_EL2 to defaults
    +
    +3:
    +#endif
    +
     	/* Populate ID registers. */
     	mrs	x0, midr_el1
     	mrs	x1, mpidr_el1
    diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
    index 0959611..a272f33 100644
    --- a/arch/arm64/kernel/hyp-stub.S
    +++ b/arch/arm64/kernel/hyp-stub.S
    @@ -19,6 +19,7 @@

     #include <linux/init.h>
     #include <linux/linkage.h>
    +#include <linux/irqchip/arm-gic-v3.h>

     #include <asm/assembler.h>
     #include <asm/ptrace.h>
    diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
    index bbb746e..7f0c2a3 100644
    --- a/drivers/irqchip/Kconfig
    +++ b/drivers/irqchip/Kconfig
    @@ -10,6 +10,11 @@ config ARM_GIC
     config GIC_NON_BANKED
     	bool

    +config ARM_GIC_V3
    +	bool
    +	select IRQ_DOMAIN
    +	select MULTI_IRQ_HANDLER
    +
     config ARM_NVIC
     	bool
     	select IRQ_DOMAIN
    diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
    index 9b9505c..c57e642 100644
    --- a/drivers/irqchip/Makefile
    +++ b/drivers/irqchip/Makefile
    @@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o
     obj-$(CONFIG_ARCH_SUNXI)		+= irq-sunxi-nmi.o
     obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o
     obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
    +obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.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-v3.c b/drivers/irqchip/irq-gic-v3.c
    new file mode 100644
    index 0000000..81519ba
    --- /dev/null
    +++ b/drivers/irqchip/irq-gic-v3.c
    @@ -0,0 +1,692 @@
    +/*
    + * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
    + * Author: Marc Zyngier <marc.zyngier@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, see <http://www.gnu.org/licenses/>.
    + */
    +
    +#include <linux/cpu.h>
    +#include <linux/delay.h>
    +#include <linux/interrupt.h>
    +#include <linux/of.h>
    +#include <linux/of_address.h>
    +#include <linux/of_irq.h>
    +#include <linux/percpu.h>
    +#include <linux/slab.h>
    +
    +#include <linux/irqchip/arm-gic-v3.h>
    +
    +#include <asm/cputype.h>
    +#include <asm/exception.h>
    +#include <asm/smp_plat.h>
    +
    +#include "irq-gic-common.h"
    +#include "irqchip.h"
    +
    +struct gic_chip_data {
    +	void __iomem		*dist_base;
    +	void __iomem		**redist_base;
    +	void __percpu __iomem	**rdist;
    +	struct irq_domain	*domain;
    +	u64			redist_stride;
    +	u32			redist_regions;
    +	unsigned int		irq_nr;
    +};
    +
    +static struct gic_chip_data gic_data __read_mostly;
    +
    +#define gic_data_rdist()		(this_cpu_ptr(gic_data.rdist))
    +#define gic_data_rdist_rd_base()	(*gic_data_rdist())
    +#define gic_data_rdist_sgi_base()	(gic_data_rdist_rd_base() + SZ_64K)
    +
    +/* Our default, arbitrary priority value. Linux only uses one anyway. */
    +#define DEFAULT_PMR_VALUE	0xf0
    +
    +static inline unsigned int gic_irq(struct irq_data *d)
    +{
    +	return d->hwirq;
    +}
    +
    +static inline int gic_irq_in_rdist(struct irq_data *d)
    +{
    +	return gic_irq(d) < 32;
    +}
    +
    +static inline void __iomem *gic_dist_base(struct irq_data *d)
    +{
    +	if (gic_irq_in_rdist(d))	/* SGI+PPI -> SGI_base for this CPU */
    +		return gic_data_rdist_sgi_base();
    +
    +	if (d->hwirq <= 1023)		/* SPI -> dist_base */
    +		return gic_data.dist_base;
    +
    +	if (d->hwirq >= 8192)
    +		BUG();		/* LPI Detected!!! */
    +
    +	return NULL;
    +}
    +
    +static void gic_do_wait_for_rwp(void __iomem *base)
    +{
    +	u32 count = 1000000;	/* 1s! */
    +
    +	while (readl_relaxed(base + GICD_CTLR) & GICD_CTLR_RWP) {
    +		count--;
    +		if (!count) {
    +			pr_err_ratelimited("RWP timeout, gone fishing\n");
    +			return;
    +		}
    +		cpu_relax();
    +		udelay(1);
    +	};
    +}
    +
    +/* Wait for completion of a distributor change */
    +static void gic_dist_wait_for_rwp(void)
    +{
    +	gic_do_wait_for_rwp(gic_data.dist_base);
    +}
    +
    +/* Wait for completion of a redistributor change */
    +static void gic_redist_wait_for_rwp(void)
    +{
    +	gic_do_wait_for_rwp(gic_data_rdist_rd_base());
    +}
    +
    +/* Low level accessors */
    +static u64 gic_read_iar(void)
    +{
    +	u64 irqstat;
    +
    +	asm volatile("mrs %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
    +	return irqstat;
    +}
    +
    +static void gic_write_pmr(u64 val)
    +{
    +	asm volatile("msr " __stringify(ICC_PMR_EL1) ", %0" : : "r" (val));
    +}
    +
    +static void gic_write_ctlr(u64 val)
    +{
    +	asm volatile("msr " __stringify(ICC_CTLR_EL1) ", %0" : : "r" (val));
    +	isb();
    +}
    +
    +static void gic_write_grpen1(u64 val)
    +{
    +	asm volatile("msr " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" (val));
    +	isb();
    +}
    +
    +static void gic_write_sgi1r(u64 val)
    +{
    +	asm volatile("msr " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val));
    +}
    +
    +static void gic_enable_sre(void)
    +{
    +	u64 val;
    +
    +	asm volatile("mrs %0, " __stringify(ICC_SRE_EL1) : "=r" (val));
    +	val |= ICC_SRE_EL1_SRE;
    +	asm volatile("msr " __stringify(ICC_SRE_EL1) ", %0" : : "r" (val));
    +	isb();
    +
    +	/*
    +	 * Need to check that the SRE bit has actually been set. If
    +	 * not, it means that SRE is disabled at EL2. We're going to
    +	 * die painfully, and there is nothing we can do about it.
    +	 *
    +	 * Kindly inform the luser.
    +	 */
    +	asm volatile("mrs %0, " __stringify(ICC_SRE_EL1) : "=r" (val));
    +	if (!(val & ICC_SRE_EL1_SRE))
    +		pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n");
    +}
    +
    +static void gic_enable_redist(void)
    +{
    +	void __iomem *rbase;
    +	u32 count = 1000000;	/* 1s! */
    +	u32 val;
    +
    +	rbase = gic_data_rdist_rd_base();
    +
    +	/* Wake up this CPU redistributor */
    +	val = readl_relaxed(rbase + GICR_WAKER);
    +	val &= ~GICR_WAKER_ProcessorSleep;
    +	writel_relaxed(val, rbase + GICR_WAKER);
    +
    +	while (readl_relaxed(rbase + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) {
    +		count--;
    +		if (!count) {
    +			pr_err_ratelimited("redist didn't wake up...\n");
    +			return;
    +		}
    +		cpu_relax();
    +		udelay(1);
    +	};
    +}
    +
    +/*
    + * Routines to disable, enable, EOI and route interrupts
    + */
    +static void gic_poke_irq(struct irq_data *d, u32 offset)
    +{
    +	u32 mask = 1 << (gic_irq(d) % 32);
    +	void (*rwp_wait)(void);
    +	void __iomem *base;
    +
    +	if (gic_irq_in_rdist(d)) {
    +		base = gic_data_rdist_sgi_base();
    +		rwp_wait = gic_redist_wait_for_rwp;
    +	} else {
    +		base = gic_data.dist_base;
    +		rwp_wait = gic_dist_wait_for_rwp;
    +	}
    +
    +	writel_relaxed(mask, base + offset + (gic_irq(d) / 32) * 4);
    +	rwp_wait();
    +}
    +
    +static int gic_peek_irq(struct irq_data *d, u32 offset)
    +{
    +	u32 mask = 1 << (gic_irq(d) % 32);
    +	void __iomem *base;
    +
    +	if (gic_irq_in_rdist(d))
    +		base = gic_data_rdist_sgi_base();
    +	else
    +		base = gic_data.dist_base;
    +
    +	return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask);
    +}
    +
    +static void gic_mask_irq(struct irq_data *d)
    +{
    +	gic_poke_irq(d, GICD_ICENABLER);
    +}
    +
    +static void gic_unmask_irq(struct irq_data *d)
    +{
    +	gic_poke_irq(d, GICD_ISENABLER);
    +}
    +
    +static void gic_eoi_irq(struct irq_data *d)
    +{
    +	gic_write_eoir(gic_irq(d));
    +}
    +
    +static int gic_set_type(struct irq_data *d, unsigned int type)
    +{
    +	unsigned int irq = gic_irq(d);
    +	void (*rwp_wait)(void);
    +	void __iomem *base;
    +
    +	/* Interrupt configuration for SGIs can't be changed */
    +	if (irq < 16)
    +		return -EINVAL;
    +
    +	if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
    +		return -EINVAL;
    +
    +	if (gic_irq_in_rdist(d)) {
    +		base = gic_data_rdist_sgi_base();
    +		rwp_wait = gic_redist_wait_for_rwp;
    +	} else {
    +		base = gic_data.dist_base;
    +		rwp_wait = gic_dist_wait_for_rwp;
    +	}
    +
    +	gic_configure_irq(irq, type, base, rwp_wait);
    +
    +	return 0;
    +}
    +
    +static u64 gic_mpidr_to_affinity(u64 mpidr)
    +{
    +	u64 aff;
    +
    +	aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
    +	       MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
    +	       MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
    +	       MPIDR_AFFINITY_LEVEL(mpidr, 0));
    +
    +	return aff;
    +}
    +
    +static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
    +{
    +	u64 irqnr;
    +
    +	do {
    +		irqnr = gic_read_iar();
    +
    +		if (likely(irqnr > 15 && irqnr < 1020)) {
    +			u64 irq = irq_find_mapping(gic_data.domain, irqnr);
    +			if (likely(irq)) {
    +				handle_IRQ(irq, regs);
    +				continue;
    +			}
    +
    +			WARN_ONCE(true, "Unexpected SPI received!\n");
    +			gic_write_eoir(irqnr);
    +		}
    +		if (irqnr < 16) {
    +			gic_write_eoir(irqnr);
    +#ifdef CONFIG_SMP
    +			handle_IPI(irqnr, regs);
    +#else
    +			WARN_ONCE(true, "Unexpected SGI received!\n");
    +#endif
    +			continue;
    +		}
    +	} while (irqnr != ICC_IAR1_EL1_SPURIOUS);
    +}
    +
    +static void __init gic_dist_init(void)
    +{
    +	unsigned int i;
    +	u64 affinity;
    +	void __iomem *base = gic_data.dist_base;
    +
    +	/* Disable the distributor */
    +	writel_relaxed(0, base + GICD_CTLR);
    +	gic_dist_wait_for_rwp();
    +
    +	gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
    +
    +	/* Enable distributor with ARE, Group1 */
    +	writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
    +		       base + GICD_CTLR);
    +
    +	/*
    +	 * Set all global interrupts to the boot CPU only. ARE must be
    +	 * enabled.
    +	 */
    +	affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
    +	for (i = 32; i < gic_data.irq_nr; i++)
    +		writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
    +}
    +
    +static int gic_populate_rdist(void)
    +{
    +	u64 mpidr = cpu_logical_map(smp_processor_id());
    +	u64 typer;
    +	u32 aff;
    +	int i;
    +
    +	/*
    +	 * Convert affinity to a 32bit value that can be matched to
    +	 * GICR_TYPER bits [63:32].
    +	 */
    +	aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
    +	       MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
    +	       MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
    +	       MPIDR_AFFINITY_LEVEL(mpidr, 0));
    +
    +	for (i = 0; i < gic_data.redist_regions; i++) {
    +		void __iomem *ptr = gic_data.redist_base[i];
    +		u32 reg;
    +
    +		reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
    +		if (reg != GIC_PIDR2_ARCH_GICv3 &&
    +		    reg != GIC_PIDR2_ARCH_GICv4) { /* We're in trouble... */
    +			pr_warn("No redistributor present @%p\n", ptr);
    +			break;
    +		}
    +
    +		do {
    +			typer = readq_relaxed(ptr + GICR_TYPER);
    +			if ((typer >> 32) == aff) {
    +				gic_data_rdist_rd_base() = ptr;
    +				pr_info("CPU%d: found redistributor %llx @%p\n",
    +					smp_processor_id(),
    +					(unsigned long long)mpidr, ptr);
    +				return 0;
    +			}
    +
    +			if (gic_data.redist_stride) {
    +				ptr += gic_data.redist_stride;
    +			} else {
    +				ptr += SZ_64K * 2; /* Skip RD_base + SGI_base */
    +				if (typer & GICR_TYPER_VLPIS)
    +					ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
    +			}
    +		} while (!(typer & GICR_TYPER_LAST));
    +	}
    +
    +	/* We couldn't even deal with ourselves... */
    +	WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
    +	     smp_processor_id(), (unsigned long long)mpidr);
    +	return -ENODEV;
    +}
    +
    +static void gic_cpu_init(void)
    +{
    +	void __iomem *rbase;
    +
    +	/* Register ourselves with the rest of the world */
    +	if (gic_populate_rdist())
    +		return;
    +
    +	gic_enable_redist();
    +
    +	rbase = gic_data_rdist_sgi_base();
    +
    +	gic_cpu_config(rbase, gic_redist_wait_for_rwp);
    +
    +	/* Enable system registers */
    +	gic_enable_sre();
    +
    +	/* Set priority mask register */
    +	gic_write_pmr(DEFAULT_PMR_VALUE);
    +
    +	/* EOI deactivates interrupt too (mode 0) */
    +	gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
    +
    +	/* ... and let's hit the road... */
    +	gic_write_grpen1(1);
    +}
    +
    +#ifdef CONFIG_SMP
    +static int gic_secondary_init(struct notifier_block *nfb,
    +			      unsigned long action, void *hcpu)
    +{
    +	if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
    +		gic_cpu_init();
    +	return NOTIFY_OK;
    +}
    +
    +/*
    + * Notifier for enabling the GIC CPU interface. Set an arbitrarily high
    + * priority because the GIC needs to be up before the ARM generic timers.
    + */
    +static struct notifier_block gic_cpu_notifier = {
    +	.notifier_call = gic_secondary_init,
    +	.priority = 100,
    +};
    +
    +static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
    +				   u64 cluster_id)
    +{
    +	int cpu = *base_cpu;
    +	u64 mpidr = cpu_logical_map(cpu);
    +	u16 tlist = 0;
    +
    +	while (cpu < nr_cpu_ids) {
    +		/*
    +		 * If we ever get a cluster of more than 16 CPUs, just
    +		 * scream and skip that CPU.
    +		 */
    +		if (WARN_ON((mpidr & 0xff) >= 16))
    +			goto out;
    +
    +		tlist |= 1 << (mpidr & 0xf);
    +
    +		cpu = cpumask_next(cpu, mask);
    +		if (cpu == nr_cpu_ids)
    +			goto out;
    +
    +		mpidr = cpu_logical_map(cpu);
    +
    +		if (cluster_id != (mpidr & ~0xffUL)) {
    +			cpu--;
    +			goto out;
    +		}
    +	}
    +out:
    +	*base_cpu = cpu;
    +	return tlist;
    +}
    +
    +static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
    +{
    +	u64 val;
    +
    +	val = (MPIDR_AFFINITY_LEVEL(cluster_id, 3) << 48	|
    +	       MPIDR_AFFINITY_LEVEL(cluster_id, 2) << 32	|
    +	       irq << 24			    		|
    +	       MPIDR_AFFINITY_LEVEL(cluster_id, 1) << 16	|
    +	       tlist);
    +
    +	pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
    +	gic_write_sgi1r(val);
    +}
    +
    +static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
    +{
    +	int cpu;
    +
    +	if (WARN_ON(irq >= 16))
    +		return;
    +
    +	/*
    +	 * Ensure that stores to Normal memory are visible to the
    +	 * other CPUs before issuing the IPI.
    +	 */
    +	smp_wmb();
    +
    +	for_each_cpu_mask(cpu, *mask) {
    +		u64 cluster_id = cpu_logical_map(cpu) & ~0xffUL;
    +		u16 tlist;
    +
    +		tlist = gic_compute_target_list(&cpu, mask, cluster_id);
    +		gic_send_sgi(cluster_id, tlist, irq);
    +	}
    +
    +	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
    +	isb();
    +}
    +
    +static void gic_smp_init(void)
    +{
    +	set_smp_cross_call(gic_raise_softirq);
    +	register_cpu_notifier(&gic_cpu_notifier);
    +}
    +
    +static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
    +			    bool force)
    +{
    +	unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
    +	void __iomem *reg;
    +	int enabled;
    +	u64 val;
    +
    +	if (gic_irq_in_rdist(d))
    +		return -EINVAL;
    +
    +	/* If interrupt was enabled, disable it first */
    +	enabled = gic_peek_irq(d, GICD_ISENABLER);
    +	if (enabled)
    +		gic_mask_irq(d);
    +
    +	reg = gic_dist_base(d) + GICD_IROUTER + (gic_irq(d) * 8);
    +	val = gic_mpidr_to_affinity(cpu_logical_map(cpu));
    +
    +	writeq_relaxed(val, reg);
    +
    +	/*
    +	 * If the interrupt was enabled, enabled it again. Otherwise,
    +	 * just wait for the distributor to have digested our changes.
    +	 */
    +	if (enabled)
    +		gic_unmask_irq(d);
    +	else
    +		gic_dist_wait_for_rwp();
    +
    +	return IRQ_SET_MASK_OK;
    +}
    +#else
    +#define gic_set_affinity	NULL
    +#define gic_smp_init()		do { } while(0)
    +#endif
    +
    +static struct irq_chip gic_chip = {
    +	.name			= "GICv3",
    +	.irq_mask		= gic_mask_irq,
    +	.irq_unmask		= gic_unmask_irq,
    +	.irq_eoi		= gic_eoi_irq,
    +	.irq_set_type		= gic_set_type,
    +	.irq_set_affinity	= gic_set_affinity,
    +};
    +
    +static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
    +			      irq_hw_number_t hw)
    +{
    +	/* SGIs are private to the core kernel */
    +	if (hw < 16)
    +		return -EPERM;
    +	/* PPIs */
    +	if (hw < 32) {
    +		irq_set_percpu_devid(irq);
    +		irq_set_chip_and_handler(irq, &gic_chip,
    +					 handle_percpu_devid_irq);
    +		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
    +	}
    +	/* SPIs */
    +	if (hw >= 32 && hw < gic_data.irq_nr) {
    +		irq_set_chip_and_handler(irq, &gic_chip,
    +					 handle_fasteoi_irq);
    +		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
    +	}
    +	irq_set_chip_data(irq, d->host_data);
    +	return 0;
    +}
    +
    +static int gic_irq_domain_xlate(struct irq_domain *d,
    +				struct device_node *controller,
    +				const u32 *intspec, unsigned int intsize,
    +				unsigned long *out_hwirq, unsigned int *out_type)
    +{
    +	if (d->of_node != controller)
    +		return -EINVAL;
    +	if (intsize < 3)
    +		return -EINVAL;
    +
    +	switch(intspec[0]) {
    +	case 0:			/* SPI */
    +		*out_hwirq = intspec[1] + 32;
    +		break;
    +	case 1:			/* PPI */
    +		*out_hwirq = intspec[1] + 16;
    +		break;
    +	default:
    +		return -EINVAL;
    +	}
    +
    +	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
    +	return 0;
    +}
    +
    +static const struct irq_domain_ops gic_irq_domain_ops = {
    +	.map = gic_irq_domain_map,
    +	.xlate = gic_irq_domain_xlate,
    +};
    +
    +static int __init gic_of_init(struct device_node *node, struct device_node *parent)
    +{
    +	void __iomem *dist_base;
    +	void __iomem **redist_base;
    +	u64 redist_stride;
    +	u32 redist_regions;
    +	u32 reg;
    +	int gic_irqs;
    +	int err;
    +	int i;
    +
    +	dist_base = of_iomap(node, 0);
    +	if (!dist_base) {
    +		pr_err("%s: unable to map gic dist registers\n",
    +			node->full_name);
    +		return -ENXIO;
    +	}
    +
    +	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
    +	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
    +		pr_err("%s: no distributor detected, giving up\n",
    +			node->full_name);
    +		err = -ENODEV;
    +		goto out_unmap_dist;
    +	}
    +
    +	if (of_property_read_u32(node, "#redistributor-regions", &redist_regions))
    +		redist_regions = 1;
    +
    +	redist_base = kzalloc(sizeof(*redist_base) * redist_regions, GFP_KERNEL);
    +	if (!redist_base) {
    +		err = -ENOMEM;
    +		goto out_unmap_dist;
    +	}
    +
    +	for (i = 0; i < redist_regions; i++) {
    +		redist_base[i] = of_iomap(node, 1 + i);
    +		if (!redist_base[i]) {
    +			pr_err("%s: couldn't map region %d\n",
    +			       node->full_name, i);
    +			err = -ENODEV;
    +			goto out_unmap_rdist;
    +		}
    +	}
    +
    +	if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
    +		redist_stride = 0;
    +
    +	gic_data.dist_base = dist_base;
    +	gic_data.redist_base = redist_base;
    +	gic_data.redist_regions = redist_regions;
    +	gic_data.redist_stride = redist_stride;
    +
    +	/*
    +	 * Find out how many interrupts are supported.
    +	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
    +	 */
    +	gic_irqs = readl_relaxed(gic_data.dist_base + GICD_TYPER) & 0x1f;
    +	gic_irqs = (gic_irqs + 1) * 32;
    +	if (gic_irqs > 1020)
    +		gic_irqs = 1020;
    +	gic_data.irq_nr = gic_irqs;
    +
    +	gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
    +					      &gic_data);
    +	gic_data.rdist = alloc_percpu(typeof(*gic_data.rdist));
    +
    +	if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdist)) {
    +		err = -ENOMEM;
    +		goto out_free;
    +	}
    +
    +	set_handle_irq(gic_handle_irq);
    +
    +	gic_smp_init();
    +	gic_dist_init();
    +	gic_cpu_init();
    +
    +	return 0;
    +
    +out_free:
    +	if (gic_data.domain)
    +		irq_domain_remove(gic_data.domain);
    +	free_percpu(gic_data.rdist);
    +out_unmap_rdist:
    +	for (i = 0; i < redist_regions; i++)
    +		if (redist_base[i])
    +			iounmap(redist_base[i]);
    +	kfree(redist_base);
    +out_unmap_dist:
    +	iounmap(dist_base);
    +	return err;
    +}
    +
    +IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
    diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
    new file mode 100644
    index 0000000..30cb755
    --- /dev/null
    +++ b/include/linux/irqchip/arm-gic-v3.h
    @@ -0,0 +1,198 @@
    +/*
    + * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
    + * Author: Marc Zyngier <marc.zyngier@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, see <http://www.gnu.org/licenses/>.
    + */
    +#ifndef __LINUX_IRQCHIP_ARM_GIC_V3_H
    +#define __LINUX_IRQCHIP_ARM_GIC_V3_H
    +
    +/*
    + * Distributor registers. We assume we're running non-secure, with ARE
    + * being set. Secure-only and non-ARE registers are not described.
    + */
    +#define GICD_CTLR			0x0000
    +#define GICD_TYPER			0x0004
    +#define GICD_IIDR			0x0008
    +#define GICD_STATUSR			0x0010
    +#define GICD_SETSPI_NSR			0x0040
    +#define GICD_CLRSPI_NSR			0x0048
    +#define GICD_SETSPI_SR			0x0050
    +#define GICD_CLRSPI_SR			0x0058
    +#define GICD_SEIR			0x0068
    +#define GICD_ISENABLER			0x0100
    +#define GICD_ICENABLER			0x0180
    +#define GICD_ISPENDR			0x0200
    +#define GICD_ICPENDR			0x0280
    +#define GICD_ISACTIVER			0x0300
    +#define GICD_ICACTIVER			0x0380
    +#define GICD_IPRIORITYR			0x0400
    +#define GICD_ICFGR			0x0C00
    +#define GICD_IROUTER			0x6000
    +#define GICD_PIDR2			0xFFE8
    +
    +#define GICD_CTLR_RWP			(1U << 31)
    +#define GICD_CTLR_ARE_NS		(1U << 4)
    +#define GICD_CTLR_ENABLE_G1A		(1U << 1)
    +#define GICD_CTLR_ENABLE_G1		(1U << 0)
    +
    +#define GICD_IROUTER_SPI_MODE_ONE	(0U << 31)
    +#define GICD_IROUTER_SPI_MODE_ANY	(1U << 31)
    +
    +#define GIC_PIDR2_ARCH_MASK		0xf0
    +#define GIC_PIDR2_ARCH_GICv3		0x30
    +#define GIC_PIDR2_ARCH_GICv4		0x40
    +
    +/*
    + * Re-Distributor registers, offsets from RD_base
    + */
    +#define GICR_CTLR			GICD_CTLR
    +#define GICR_IIDR			0x0004
    +#define GICR_TYPER			0x0008
    +#define GICR_STATUSR			GICD_STATUSR
    +#define GICR_WAKER			0x0014
    +#define GICR_SETLPIR			0x0040
    +#define GICR_CLRLPIR			0x0048
    +#define GICR_SEIR			GICD_SEIR
    +#define GICR_PROPBASER			0x0070
    +#define GICR_PENDBASER			0x0078
    +#define GICR_INVLPIR			0x00A0
    +#define GICR_INVALLR			0x00B0
    +#define GICR_SYNCR			0x00C0
    +#define GICR_MOVLPIR			0x0100
    +#define GICR_MOVALLR			0x0110
    +#define GICR_PIDR2			GICD_PIDR2
    +
    +#define GICR_WAKER_ProcessorSleep	(1U << 1)
    +#define GICR_WAKER_ChildrenAsleep	(1U << 2)
    +
    +/*
    + * Re-Distributor registers, offsets from SGI_base
    + */
    +#define GICR_ISENABLER0			GICD_ISENABLER
    +#define GICR_ICENABLER0			GICD_ICENABLER
    +#define GICR_ISPENDR0			GICD_ISPENDR
    +#define GICR_ICPENDR0			GICD_ICPENDR
    +#define GICR_ISACTIVER0			GICD_ISACTIVER
    +#define GICR_ICACTIVER0			GICD_ICACTIVER
    +#define GICR_IPRIORITYR0		GICD_IPRIORITYR
    +#define GICR_ICFGR0			GICD_ICFGR
    +
    +#define GICR_TYPER_VLPIS		(1U << 1)
    +#define GICR_TYPER_LAST			(1U << 4)
    +
    +/*
    + * CPU interface registers
    + */
    +#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << 1)
    +#define ICC_CTLR_EL1_EOImode_drop	(1U << 1)
    +#define ICC_SRE_EL1_SRE			(1U << 0)
    +
    +/*
    + * Hypervisor interface registers (SRE only)
    + */
    +#define ICH_LR_VIRTUAL_ID_MASK		((1UL << 32) - 1)
    +
    +#define ICH_LR_EOI			(1UL << 41)
    +#define ICH_LR_GROUP			(1UL << 60)
    +#define ICH_LR_STATE			(3UL << 62)
    +#define ICH_LR_PENDING_BIT		(1UL << 62)
    +#define ICH_LR_ACTIVE_BIT		(1UL << 63)
    +
    +#define ICH_MISR_EOI			(1 << 0)
    +#define ICH_MISR_U			(1 << 1)
    +
    +#define ICH_HCR_EN			(1 << 0)
    +#define ICH_HCR_UIE			(1 << 1)
    +
    +#define ICH_VMCR_CTLR_SHIFT		0
    +#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
    +#define ICH_VMCR_BPR1_SHIFT		18
    +#define ICH_VMCR_BPR1_MASK		(7 << ICH_VMCR_BPR1_SHIFT)
    +#define ICH_VMCR_BPR0_SHIFT		21
    +#define ICH_VMCR_BPR0_MASK		(7 << ICH_VMCR_BPR0_SHIFT)
    +#define ICH_VMCR_PMR_SHIFT		24
    +#define ICH_VMCR_PMR_MASK		(0xffUL << ICH_VMCR_PMR_SHIFT)
    +
    +#define ICC_EOIR1_EL1			S3_0_C12_C12_1
    +#define ICC_IAR1_EL1			S3_0_C12_C12_0
    +#define ICC_SGI1R_EL1			S3_0_C12_C11_5
    +#define ICC_PMR_EL1			S3_0_C4_C6_0
    +#define ICC_CTLR_EL1			S3_0_C12_C12_4
    +#define ICC_SRE_EL1			S3_0_C12_C12_5
    +#define ICC_GRPEN1_EL1			S3_0_C12_C12_7
    +
    +#define ICC_IAR1_EL1_SPURIOUS		0x3ff
    +
    +#define ICC_SRE_EL2			S3_4_C12_C9_5
    +
    +#define ICC_SRE_EL2_SRE			(1 << 0)
    +#define ICC_SRE_EL2_ENABLE		(1 << 3)
    +
    +/*
    + * System register definitions
    + */
    +#define ICH_VSEIR_EL2			S3_4_C12_C9_4
    +#define ICH_HCR_EL2			S3_4_C12_C11_0
    +#define ICH_VTR_EL2			S3_4_C12_C11_1
    +#define ICH_MISR_EL2			S3_4_C12_C11_2
    +#define ICH_EISR_EL2			S3_4_C12_C11_3
    +#define ICH_ELSR_EL2			S3_4_C12_C11_5
    +#define ICH_VMCR_EL2			S3_4_C12_C11_7
    +
    +#define __LR0_EL2(x)			S3_4_C12_C12_ ## x
    +#define __LR8_EL2(x)			S3_4_C12_C13_ ## x
    +
    +#define ICH_LR0_EL2			__LR0_EL2(0)
    +#define ICH_LR1_EL2			__LR0_EL2(1)
    +#define ICH_LR2_EL2			__LR0_EL2(2)
    +#define ICH_LR3_EL2			__LR0_EL2(3)
    +#define ICH_LR4_EL2			__LR0_EL2(4)
    +#define ICH_LR5_EL2			__LR0_EL2(5)
    +#define ICH_LR6_EL2			__LR0_EL2(6)
    +#define ICH_LR7_EL2			__LR0_EL2(7)
    +#define ICH_LR8_EL2			__LR8_EL2(0)
    +#define ICH_LR9_EL2			__LR8_EL2(1)
    +#define ICH_LR10_EL2			__LR8_EL2(2)
    +#define ICH_LR11_EL2			__LR8_EL2(3)
    +#define ICH_LR12_EL2			__LR8_EL2(4)
    +#define ICH_LR13_EL2			__LR8_EL2(5)
    +#define ICH_LR14_EL2			__LR8_EL2(6)
    +#define ICH_LR15_EL2			__LR8_EL2(7)
    +
    +#define __AP0Rx_EL2(x)			S3_4_C12_C8_ ## x
    +#define ICH_AP0R0_EL2			__AP0Rx_EL2(0)
    +#define ICH_AP0R1_EL2			__AP0Rx_EL2(1)
    +#define ICH_AP0R2_EL2			__AP0Rx_EL2(2)
    +#define ICH_AP0R3_EL2			__AP0Rx_EL2(3)
    +
    +#define __AP1Rx_EL2(x)			S3_4_C12_C9_ ## x
    +#define ICH_AP1R0_EL2			__AP1Rx_EL2(0)
    +#define ICH_AP1R1_EL2			__AP1Rx_EL2(1)
    +#define ICH_AP1R2_EL2			__AP1Rx_EL2(2)
    +#define ICH_AP1R3_EL2			__AP1Rx_EL2(3)
    +
    +#ifndef __ASSEMBLY__
    +
    +#include <linux/stringify.h>
    +
    +static inline void gic_write_eoir(u64 irq)
    +{
    +	asm volatile("msr " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" (irq));
    +	isb();
    +}
    +
    +#endif
    +
    +#endif
    --
    1.9.3
arm64: boot protocol documentation update for GICv3

Backport of patch from Mark Salter's fedorahosted tree.

Signed-off-by: Al Stone <ahs3@redhat.com>

Original patch:

    From 1447fe9b857dea58d837ee193bef76dfcc631821 Mon Sep 17 00:00:00 2001
    From: Marc Zyngier <marc.zyngier@arm.com>
    Date: Mon, 30 Jun 2014 16:01:33 +0100
    Subject: [PATCH 54/87] arm64: boot protocol documentation update for GICv3

    Linux has some requirements that must be satisfied in order to boot
    on a system built with a GICv3.

    Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
    Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
    ---
     Documentation/arm64/booting.txt | 8 ++++++++
     1 file changed, 8 insertions(+)

    diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
    index 37fc4f6..da1d4bf 100644
    --- a/Documentation/arm64/booting.txt
    +++ b/Documentation/arm64/booting.txt
    @@ -141,6 +141,14 @@ Before jumping into the kernel, the following conditions must be met:
       the kernel image will be entered must be initialised by software at a
       higher exception level to prevent execution in an UNKNOWN state.

    +  For systems with a GICv3 interrupt controller:
    +  - If EL3 is present:
    +    ICC_SRE_EL3.Enable (bit 3) must be initialiased to 0b1.
    +    ICC_SRE_EL3.SRE (bit 0) must be initialised to 0b1.
    +  - If the kernel is entered at EL1:
    +    ICC.SRE_EL2.Enable (bit 3) must be initialised to 0b1
    +    ICC_SRE_EL2.SRE (bit 0) must be initialised to 0b1.
    +
     The requirements described above for CPU mode, caches, MMUs, architected
     timers, coherency and system registers apply to all CPUs.  All CPUs must
     enter the kernel in the same exception level.
    --
    1.9.3
KVM: ARM: vgic: abstract access to the ELRSR bitmap

Backport of patch from Mark Salter's fedorahosted tree.

Signed-off-by: Al Stone <ahs3@redhat.com>

Original patch:

    From 9228fa4d9084bd1f20156f3709ffe5a4e8e11ae4 Mon Sep 17 00:00:00 2001
    From: Marc Zyngier <marc.zyngier@arm.com>
    Date: Mon, 30 Jun 2014 16:01:36 +0100
    Subject: [PATCH 57/87] KVM: ARM: vgic: abstract access to the ELRSR bitmap

    Move the GICH_ELRSR access to its own functions, and add them to
    the vgic_ops structure.

    Acked-by: Catalin Marinas <catalin.marinas@arm.com>
    Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
    Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
    ---
     include/kvm/arm_vgic.h |  2 ++
     virt/kvm/arm/vgic.c    | 43 ++++++++++++++++++++++++++++++++++++++-----
     2 files changed, 40 insertions(+), 5 deletions(-)

    diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
    index 17bbe51..38864f5 100644
    --- a/include/kvm/arm_vgic.h
    +++ b/include/kvm/arm_vgic.h
    @@ -84,6 +84,8 @@ struct vgic_lr {
     struct vgic_ops {
     	struct vgic_lr	(*get_lr)(const struct kvm_vcpu *, int);
     	void	(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr);
    +	void	(*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
    +	u64	(*get_elrsr)(const struct kvm_vcpu *vcpu);
     };

     struct vgic_dist {
    diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
    index 11408fe..b1d646a 100644
    --- a/virt/kvm/arm/vgic.c
    +++ b/virt/kvm/arm/vgic.c
    @@ -1015,9 +1015,29 @@ static void vgic_v2_set_lr(struct kvm_vcpu *vcpu, int lr,
     	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = lr_val;
     }

    +static void vgic_v2_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
    +				  struct vgic_lr lr_desc)
    +{
    +	if (!(lr_desc.state & LR_STATE_MASK))
    +		set_bit(lr, (unsigned long *)vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr);
    +}
    +
    +static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
    +{
    +	u64 val;
    +
    +	val  = vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr[1];
    +	val <<= 32;
    +	val |= vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr[0];
    +
    +	return val;
    +}
    +
     static const struct vgic_ops vgic_ops = {
     	.get_lr			= vgic_v2_get_lr,
     	.set_lr			= vgic_v2_set_lr,
    +	.sync_lr_elrsr		= vgic_v2_sync_lr_elrsr,
    +	.get_elrsr		= vgic_v2_get_elrsr,
     };

     static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
    @@ -1031,6 +1051,17 @@ static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr,
     	vgic_ops.set_lr(vcpu, lr, vlr);
     }

    +static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
    +			       struct vgic_lr vlr)
    +{
    +	vgic_ops.sync_lr_elrsr(vcpu, lr, vlr);
    +}
    +
    +static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
    +{
    +	return vgic_ops.get_elrsr(vcpu);
    +}
    +
     static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
     {
     	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
    @@ -1260,7 +1291,7 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
     			 * Despite being EOIed, the LR may not have
     			 * been marked as empty.
     			 */
    -			set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr);
    +			vgic_sync_lr_elrsr(vcpu, lr, vlr);
     		}
     	}

    @@ -1278,14 +1309,17 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
     {
     	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
     	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
    +	u64 elrsr;
    +	unsigned long *elrsr_ptr;
     	int lr, pending;
     	bool level_pending;

     	level_pending = vgic_process_maintenance(vcpu);
    +	elrsr = vgic_get_elrsr(vcpu);
    +	elrsr_ptr = (unsigned long *)&elrsr;

     	/* Clear mappings for empty LRs */
    -	for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr,
    -			 vgic_cpu->nr_lr) {
    +	for_each_set_bit(lr, elrsr_ptr, vgic_cpu->nr_lr) {
     		struct vgic_lr vlr;

     		if (!test_and_clear_bit(lr, vgic_cpu->lr_used))
    @@ -1298,8 +1332,7 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
     	}

     	/* Check if we still have something up our sleeve... */
    -	pending = find_first_zero_bit((unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr,
    -				      vgic_cpu->nr_lr);
    +	pending = find_first_zero_bit(elrsr_ptr, vgic_cpu->nr_lr);
     	if (level_pending || pending < vgic_cpu->nr_lr)
     		set_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu);
     }
    --
    1.9.3
KVM: ARM: vgic: abstract EISR bitmap access

Backport of patch from Mark Salter's fedorahosted tree.

Signed-off-by: Al Stone <ahs3@redhat.com>

Original patch:

    From 57783b78c865cf011996f5532602c4cb73addccf Mon Sep 17 00:00:00 2001
    From: Marc Zyngier <marc.zyngier@arm.com>
    Date: Mon, 30 Jun 2014 16:01:37 +0100
    Subject: [PATCH 58/87] KVM: ARM: vgic: abstract EISR bitmap access

    Move the GICH_EISR access to its own function.

    Acked-by: Catalin Marinas <catalin.marinas@arm.com>
    Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
    Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
    ---
     include/kvm/arm_vgic.h |  1 +
     virt/kvm/arm/vgic.c    | 22 ++++++++++++++++++++--
     2 files changed, 21 insertions(+), 2 deletions(-)

    diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
    index 38864f5..ccb9b59 100644
    --- a/include/kvm/arm_vgic.h
    +++ b/include/kvm/arm_vgic.h
    @@ -86,6 +86,7 @@ struct vgic_ops {
     	void	(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr);
     	void	(*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
     	u64	(*get_elrsr)(const struct kvm_vcpu *vcpu);
    +	u64	(*get_eisr)(const struct kvm_vcpu *vcpu);
     };

     struct vgic_dist {
    diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
    index b1d646a..61a6347 100644
    --- a/virt/kvm/arm/vgic.c
    +++ b/virt/kvm/arm/vgic.c
    @@ -1033,11 +1033,23 @@ static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
     	return val;
     }

    +static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
    +{
    +	u64 val;
    +
    +	val  = vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr[1];
    +	val <<= 32;
    +	val |= vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr[0];
    +
    +	return val;
    +}
    +
     static const struct vgic_ops vgic_ops = {
     	.get_lr			= vgic_v2_get_lr,
     	.set_lr			= vgic_v2_set_lr,
     	.sync_lr_elrsr		= vgic_v2_sync_lr_elrsr,
     	.get_elrsr		= vgic_v2_get_elrsr,
    +	.get_eisr		= vgic_v2_get_eisr,
     };

     static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
    @@ -1062,6 +1074,11 @@ static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
     	return vgic_ops.get_elrsr(vcpu);
     }

    +static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
    +{
    +	return vgic_ops.get_eisr(vcpu);
    +}
    +
     static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
     {
     	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
    @@ -1268,10 +1285,11 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
     		 * Some level interrupts have been EOIed. Clear their
     		 * active bit.
     		 */
    +		u64 eisr = vgic_get_eisr(vcpu);
    +		unsigned long *eisr_ptr = (unsigned long *)&eisr;
     		int lr;

    -		for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_eisr,
    -				 vgic_cpu->nr_lr) {
    +		for_each_set_bit(lr, eisr_ptr, vgic_cpu->nr_lr) {
     			struct vgic_lr vlr = vgic_get_lr(vcpu, lr);

     			vgic_irq_clear_active(vcpu, vlr.irq);
    --
    1.9.3
arm64: KVM: vgic: add GICv3 world switch

Backport of patch from Mark Salter's fedorahosted tree.

Signed-off-by: Al Stone <ahs3@redhat.com>

Original patch:

    From 7c4fc8c1caecd5224c8aa57d206495eb25f49c5f Mon Sep 17 00:00:00 2001
    From: Marc Zyngier <marc.zyngier@arm.com>
    Date: Mon, 30 Jun 2014 16:01:49 +0100
    Subject: [PATCH 70/87] arm64: KVM: vgic: add GICv3 world switch

    Introduce the GICv3 world switch code used to save/restore the
    GICv3 context.

    Acked-by: Catalin Marinas <catalin.marinas@arm.com>
    Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
    Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
    ---
     arch/arm64/include/asm/kvm_asm.h |   2 +
     arch/arm64/kernel/asm-offsets.c  |   8 ++
     arch/arm64/kvm/vgic-v3-switch.S  | 238 +++++++++++++++++++++++++++++++++++++++
     3 files changed, 248 insertions(+)

    diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
    index ed4987b..a28c35b 100644
    --- a/arch/arm64/include/asm/kvm_asm.h
    +++ b/arch/arm64/include/asm/kvm_asm.h
    @@ -110,6 +110,8 @@ extern u64 __vgic_v3_get_ich_vtr_el2(void);

     extern char __save_vgic_v2_state[];
     extern char __restore_vgic_v2_state[];
    +extern char __save_vgic_v3_state[];
    +extern char __restore_vgic_v3_state[];

     #endif

    diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
    index dafc415..e74654c 100644
    --- a/arch/arm64/kernel/asm-offsets.c
    +++ b/arch/arm64/kernel/asm-offsets.c
    @@ -139,6 +139,14 @@ int main(void)
       DEFINE(VGIC_V2_CPU_ELRSR,	offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
       DEFINE(VGIC_V2_CPU_APR,	offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
       DEFINE(VGIC_V2_CPU_LR,	offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
    +  DEFINE(VGIC_V3_CPU_HCR,	offsetof(struct vgic_cpu, vgic_v3.vgic_hcr));
    +  DEFINE(VGIC_V3_CPU_VMCR,	offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr));
    +  DEFINE(VGIC_V3_CPU_MISR,	offsetof(struct vgic_cpu, vgic_v3.vgic_misr));
    +  DEFINE(VGIC_V3_CPU_EISR,	offsetof(struct vgic_cpu, vgic_v3.vgic_eisr));
    +  DEFINE(VGIC_V3_CPU_ELRSR,	offsetof(struct vgic_cpu, vgic_v3.vgic_elrsr));
    +  DEFINE(VGIC_V3_CPU_AP0R,	offsetof(struct vgic_cpu, vgic_v3.vgic_ap0r));
    +  DEFINE(VGIC_V3_CPU_AP1R,	offsetof(struct vgic_cpu, vgic_v3.vgic_ap1r));
    +  DEFINE(VGIC_V3_CPU_LR,	offsetof(struct vgic_cpu, vgic_v3.vgic_lr));
       DEFINE(VGIC_CPU_NR_LR,	offsetof(struct vgic_cpu, nr_lr));
       DEFINE(KVM_VTTBR,		offsetof(struct kvm, arch.vttbr));
       DEFINE(KVM_VGIC_VCTRL,	offsetof(struct kvm, arch.vgic.vctrl_base));
    diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S
    index 9fbf273..21e68f6 100644
    --- a/arch/arm64/kvm/vgic-v3-switch.S
    +++ b/arch/arm64/kvm/vgic-v3-switch.S
    @@ -18,9 +18,247 @@
     #include <linux/linkage.h>
     #include <linux/irqchip/arm-gic-v3.h>

    +#include <asm/assembler.h>
    +#include <asm/memory.h>
    +#include <asm/asm-offsets.h>
    +#include <asm/kvm.h>
    +#include <asm/kvm_asm.h>
    +#include <asm/kvm_arm.h>
    +
     	.text
     	.pushsection	.hyp.text, "ax"

    +/*
    + * We store LRs in reverse order to let the CPU deal with streaming
    + * access. Use this macro to make it look saner...
    + */
    +#define LR_OFFSET(n)	(VGIC_V3_CPU_LR + (15 - n) * 8)
    +
    +/*
    + * Save the VGIC CPU state into memory
    + * x0: Register pointing to VCPU struct
    + * Do not corrupt x1!!!
    + */
    +.macro	save_vgic_v3_state
    +	// Compute the address of struct vgic_cpu
    +	add	x3, x0, #VCPU_VGIC_CPU
    +
    +	// Make sure stores to the GIC via the memory mapped interface
    +	// are now visible to the system register interface
    +	dsb	st
    +
    +	// Save all interesting registers
    +	mrs	x4, ICH_HCR_EL2
    +	mrs	x5, ICH_VMCR_EL2
    +	mrs	x6, ICH_MISR_EL2
    +	mrs	x7, ICH_EISR_EL2
    +	mrs	x8, ICH_ELSR_EL2
    +
    +	str	w4, [x3, #VGIC_V3_CPU_HCR]
    +	str	w5, [x3, #VGIC_V3_CPU_VMCR]
    +	str	w6, [x3, #VGIC_V3_CPU_MISR]
    +	str	w7, [x3, #VGIC_V3_CPU_EISR]
    +	str	w8, [x3, #VGIC_V3_CPU_ELRSR]
    +
    +	msr	ICH_HCR_EL2, xzr
    +
    +	mrs	x21, ICH_VTR_EL2
    +	mvn	w22, w21
    +	ubfiz	w23, w22, 2, 4	// w23 = (15 - ListRegs) * 4
    +
    +	adr	x24, 1f
    +	add	x24, x24, x23
    +	br	x24
    +
    +1:
    +	mrs	x20, ICH_LR15_EL2
    +	mrs	x19, ICH_LR14_EL2
    +	mrs	x18, ICH_LR13_EL2
    +	mrs	x17, ICH_LR12_EL2
    +	mrs	x16, ICH_LR11_EL2
    +	mrs	x15, ICH_LR10_EL2
    +	mrs	x14, ICH_LR9_EL2
    +	mrs	x13, ICH_LR8_EL2
    +	mrs	x12, ICH_LR7_EL2
    +	mrs	x11, ICH_LR6_EL2
    +	mrs	x10, ICH_LR5_EL2
    +	mrs	x9, ICH_LR4_EL2
    +	mrs	x8, ICH_LR3_EL2
    +	mrs	x7, ICH_LR2_EL2
    +	mrs	x6, ICH_LR1_EL2
    +	mrs	x5, ICH_LR0_EL2
    +
    +	adr	x24, 1f
    +	add	x24, x24, x23
    +	br	x24
    +
    +1:
    +	str	x20, [x3, #LR_OFFSET(15)]
    +	str	x19, [x3, #LR_OFFSET(14)]
    +	str	x18, [x3, #LR_OFFSET(13)]
    +	str	x17, [x3, #LR_OFFSET(12)]
    +	str	x16, [x3, #LR_OFFSET(11)]
    +	str	x15, [x3, #LR_OFFSET(10)]
    +	str	x14, [x3, #LR_OFFSET(9)]
    +	str	x13, [x3, #LR_OFFSET(8)]
    +	str	x12, [x3, #LR_OFFSET(7)]
    +	str	x11, [x3, #LR_OFFSET(6)]
    +	str	x10, [x3, #LR_OFFSET(5)]
    +	str	x9, [x3, #LR_OFFSET(4)]
    +	str	x8, [x3, #LR_OFFSET(3)]
    +	str	x7, [x3, #LR_OFFSET(2)]
    +	str	x6, [x3, #LR_OFFSET(1)]
    +	str	x5, [x3, #LR_OFFSET(0)]
    +
    +	tbnz	w21, #29, 6f	// 6 bits
    +	tbz	w21, #30, 5f	// 5 bits
    +				// 7 bits
    +	mrs	x20, ICH_AP0R3_EL2
    +	str	w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
    +	mrs	x19, ICH_AP0R2_EL2
    +	str	w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
    +6:	mrs	x18, ICH_AP0R1_EL2
    +	str	w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
    +5:	mrs	x17, ICH_AP0R0_EL2
    +	str	w17, [x3, #VGIC_V3_CPU_AP0R]
    +
    +	tbnz	w21, #29, 6f	// 6 bits
    +	tbz	w21, #30, 5f	// 5 bits
    +				// 7 bits
    +	mrs	x20, ICH_AP1R3_EL2
    +	str	w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
    +	mrs	x19, ICH_AP1R2_EL2
    +	str	w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
    +6:	mrs	x18, ICH_AP1R1_EL2
    +	str	w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
    +5:	mrs	x17, ICH_AP1R0_EL2
    +	str	w17, [x3, #VGIC_V3_CPU_AP1R]
    +
    +	// Restore SRE_EL1 access and re-enable SRE at EL1.
    +	mrs	x5, ICC_SRE_EL2
    +	orr	x5, x5, #ICC_SRE_EL2_ENABLE
    +	msr	ICC_SRE_EL2, x5
    +	isb
    +	mov	x5, #1
    +	msr	ICC_SRE_EL1, x5
    +.endm
    +
    +/*
    + * Restore the VGIC CPU state from memory
    + * x0: Register pointing to VCPU struct
    + */
    +.macro	restore_vgic_v3_state
    +	// Disable SRE_EL1 access. Necessary, otherwise
    +	// ICH_VMCR_EL2.VFIQEn becomes one, and FIQ happens...
    +	msr	ICC_SRE_EL1, xzr
    +	isb
    +
    +	// Compute the address of struct vgic_cpu
    +	add	x3, x0, #VCPU_VGIC_CPU
    +
    +	// Restore all interesting registers
    +	ldr	w4, [x3, #VGIC_V3_CPU_HCR]
    +	ldr	w5, [x3, #VGIC_V3_CPU_VMCR]
    +
    +	msr	ICH_HCR_EL2, x4
    +	msr	ICH_VMCR_EL2, x5
    +
    +	mrs	x21, ICH_VTR_EL2
    +
    +	tbnz	w21, #29, 6f	// 6 bits
    +	tbz	w21, #30, 5f	// 5 bits
    +				// 7 bits
    +	ldr	w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
    +	msr	ICH_AP1R3_EL2, x20
    +	ldr	w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
    +	msr	ICH_AP1R2_EL2, x19
    +6:	ldr	w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
    +	msr	ICH_AP1R1_EL2, x18
    +5:	ldr	w17, [x3, #VGIC_V3_CPU_AP1R]
    +	msr	ICH_AP1R0_EL2, x17
    +
    +	tbnz	w21, #29, 6f	// 6 bits
    +	tbz	w21, #30, 5f	// 5 bits
    +				// 7 bits
    +	ldr	w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
    +	msr	ICH_AP0R3_EL2, x20
    +	ldr	w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
    +	msr	ICH_AP0R2_EL2, x19
    +6:	ldr	w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
    +	msr	ICH_AP0R1_EL2, x18
    +5:	ldr	w17, [x3, #VGIC_V3_CPU_AP0R]
    +	msr	ICH_AP0R0_EL2, x17
    +
    +	and	w22, w21, #0xf
    +	mvn	w22, w21
    +	ubfiz	w23, w22, 2, 4	// w23 = (15 - ListRegs) * 4
    +
    +	adr	x24, 1f
    +	add	x24, x24, x23
    +	br	x24
    +
    +1:
    +	ldr	x20, [x3, #LR_OFFSET(15)]
    +	ldr	x19, [x3, #LR_OFFSET(14)]
    +	ldr	x18, [x3, #LR_OFFSET(13)]
    +	ldr	x17, [x3, #LR_OFFSET(12)]
    +	ldr	x16, [x3, #LR_OFFSET(11)]
    +	ldr	x15, [x3, #LR_OFFSET(10)]
    +	ldr	x14, [x3, #LR_OFFSET(9)]
    +	ldr	x13, [x3, #LR_OFFSET(8)]
    +	ldr	x12, [x3, #LR_OFFSET(7)]
    +	ldr	x11, [x3, #LR_OFFSET(6)]
    +	ldr	x10, [x3, #LR_OFFSET(5)]
    +	ldr	x9, [x3, #LR_OFFSET(4)]
    +	ldr	x8, [x3, #LR_OFFSET(3)]
    +	ldr	x7, [x3, #LR_OFFSET(2)]
    +	ldr	x6, [x3, #LR_OFFSET(1)]
    +	ldr	x5, [x3, #LR_OFFSET(0)]
    +
    +	adr	x24, 1f
    +	add	x24, x24, x23
    +	br	x24
    +
    +1:
    +	msr	ICH_LR15_EL2, x20
    +	msr	ICH_LR14_EL2, x19
    +	msr	ICH_LR13_EL2, x18
    +	msr	ICH_LR12_EL2, x17
    +	msr	ICH_LR11_EL2, x16
    +	msr	ICH_LR10_EL2, x15
    +	msr	ICH_LR9_EL2,  x14
    +	msr	ICH_LR8_EL2,  x13
    +	msr	ICH_LR7_EL2,  x12
    +	msr	ICH_LR6_EL2,  x11
    +	msr	ICH_LR5_EL2,  x10
    +	msr	ICH_LR4_EL2,   x9
    +	msr	ICH_LR3_EL2,   x8
    +	msr	ICH_LR2_EL2,   x7
    +	msr	ICH_LR1_EL2,   x6
    +	msr	ICH_LR0_EL2,   x5
    +
    +	// Ensure that the above will have reached the
    +	// (re)distributors. This ensure the guest will read
    +	// the correct values from the memory-mapped interface.
    +	isb
    +	dsb	sy
    +
    +	// Prevent the guest from touching the GIC system registers
    +	mrs	x5, ICC_SRE_EL2
    +	and	x5, x5, #~ICC_SRE_EL2_ENABLE
    +	msr	ICC_SRE_EL2, x5
    +.endm
    +
    +ENTRY(__save_vgic_v3_state)
    +	save_vgic_v3_state
    +	ret
    +ENDPROC(__save_vgic_v3_state)
    +
    +ENTRY(__restore_vgic_v3_state)
    +	restore_vgic_v3_state
    +	ret
    +ENDPROC(__restore_vgic_v3_state)
    +
     ENTRY(__vgic_v3_get_ich_vtr_el2)
     	mrs	x0, ICH_VTR_EL2
     	ret
    --
    1.9.3
Fix ioport_map() for !CONFIG_GENERIC_IOMAP cases.

The inline version of ioport_map() that gets used when !CONFIG_GENERIC_IOMAP
is wrong. It returns a mapped (i.e. virtual) address that can start from
zero and completely ignores the PCI_IOBASE and IO_SPACE_LIMIT that most
architectures that use !CONFIG_GENERIC_MAP define.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Tanmay Inamdar <tinamdar@apm.com>
pci: Export find_pci_host_bridge() function.

This is a useful function and we should make it visible outside the
generic PCI code. Export it as a GPL symbol.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Tested-by: Tanmay Inamdar <tinamdar@apm.com>
pci: Introduce pci_register_io_range() helper function.

Some architectures do not have a simple view of the PCI I/O space
and instead use a range of CPU addresses that map to bus addresses. For
some architectures these ranges will be expressed by OF bindings
in a device tree file.

Introduce a pci_register_io_range() helper function with a generic
implementation that can be used by such architectures to keep track
of the I/O ranges described by the PCI bindings. If the PCI_IOBASE
macro is not defined that signals lack of support for PCI and we
return an error.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
pci: OF: Fix the conversion of IO ranges into IO resources.

The ranges property for a host bridge controller in DT describes
the mapping between the PCI bus address and the CPU physical address.
The resources framework however expects that the IO resources start
at a pseudo "port" address 0 (zero) and have a maximum size of IO_SPACE_LIMIT.
The conversion from pci ranges to resources failed to take that into account.

In the process move the function into drivers/of/address.c as it now
depends on pci_address_to_pio() code and make it return an error message.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Tested-by: Tanmay Inamdar <tinamdar@apm.com>
pci: Create pci_host_bridge before its associated bus in pci_create_root_bus.

Before commit 7b5436635800 the pci_host_bridge was created before the root bus.
As that commit has added a needless dependency on the bus for pci_alloc_host_bridge()
the creation order has been changed for no good reason. Revert the order of
creation as we are going to depend on the pci_host_bridge structure to retrieve the
domain number of the root bus.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Acked-by: Grant Likely <grant.likely@linaro.org>
Tested-by: Tanmay Inamdar <tinamdar@apm.com>
pci: Introduce a domain number for pci_host_bridge.

Make it easier to discover the domain number of a bus by storing
the number in pci_host_bridge for the root bus. Several architectures
have their own way of storing this information, so it makes sense
to try to unify the code. While at this, add a new function that
creates a root bus in a given domain and make pci_create_root_bus()
a wrapper around this function.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Tested-by: Tanmay Inamdar <tinamdar@apm.com>
pci: of: Parse and map the IRQ when adding the PCI device.

Enhance the default implementation of pcibios_add_device() to
parse and map the IRQ of the device if a DT binding is available.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
pci: Add support for creating a generic host_bridge from device tree

Several platforms use a rather generic version of parsing
the device tree to find the host bridge ranges. Move the common code
into the generic PCI code and use it to create a pci_host_bridge
structure that can be used by arch code.

Based on early attempts by Andrew Murray to unify the code.
Used powerpc and microblaze PCI code as starting point.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Tested-by: Tanmay Inamdar <tinamdar@apm.com>
pci: Remap I/O bus resources into CPU space with pci_remap_iospace()

Introduce a default implementation for remapping PCI bus I/O resources
onto the CPU address space. Architectures with special needs may
provide their own version, but most should be able to use this one.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
arm64: Add architectural support for PCI

Backport of patch from Mark Salter's fedorahosted tree.

Signed-off-by: Al Stone <ahs3@redhat.com>

Original patch:

    From ec8b3890befa17cc1f1157609d124b5d3f021b39 Mon Sep 17 00:00:00 2001
    From: Liviu Dudau <Liviu.Dudau@arm.com>
    Date: Tue, 1 Jul 2014 19:44:00 +0100
    Subject: [PATCH 81/87] arm64: Add architectural support for PCI

    Use the generic host bridge functions to provide support for
    PCI Express on arm64.

    Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
    ---
     arch/arm64/Kconfig            | 19 ++++++++++++++++-
     arch/arm64/include/asm/Kbuild |  1 +
     arch/arm64/include/asm/io.h   |  3 ++-
     arch/arm64/include/asm/pci.h  | 49 +++++++++++++++++++++++++++++++++++++++++++
     arch/arm64/kernel/Makefile    |  1 +
     arch/arm64/kernel/pci.c       | 38 +++++++++++++++++++++++++++++++++
     6 files changed, 109 insertions(+), 2 deletions(-)
     create mode 100644 arch/arm64/include/asm/pci.h
     create mode 100644 arch/arm64/kernel/pci.c

    diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
    index 690e91c..23871dd 100644
    --- a/arch/arm64/Kconfig
    +++ b/arch/arm64/Kconfig
    @@ -77,7 +77,7 @@ config MMU
     	def_bool y

     config NO_IOPORT_MAP
    -	def_bool y
    +	def_bool y if !PCI

     config STACKTRACE_SUPPORT
     	def_bool y
    @@ -152,6 +152,23 @@ menu "Bus support"
     config ARM_AMBA
     	bool

    +config PCI
    +	bool "PCI support"
    +	help
    +	  This feature enables support for PCIe bus system. If you say Y
    +	  here, the kernel will include drivers and infrastructure code
    +	  to support PCIe bus devices.
    +
    +config PCI_DOMAINS
    +	def_bool PCI
    +
    +config PCI_SYSCALL
    +	def_bool PCI
    +
    +source "drivers/pci/Kconfig"
    +source "drivers/pci/pcie/Kconfig"
    +source "drivers/pci/hotplug/Kconfig"
    +
     endmenu

     menu "Kernel Features"
    diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
    index 0b3fcf8..07cb417 100644
    --- a/arch/arm64/include/asm/Kbuild
    +++ b/arch/arm64/include/asm/Kbuild
    @@ -29,6 +29,7 @@ generic-y += mman.h
     generic-y += msgbuf.h
     generic-y += mutex.h
     generic-y += pci.h
    +generic-y += pci-bridge.h
     generic-y += poll.h
     generic-y += preempt.h
     generic-y += resource.h
    diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
    index e0ecdcf..dc34039 100644
    --- a/arch/arm64/include/asm/io.h
    +++ b/arch/arm64/include/asm/io.h
    @@ -121,7 +121,8 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
     /*
      *  I/O port access primitives.
      */
    -#define IO_SPACE_LIMIT		0xffff
    +#define arch_has_dev_port()	(1)
    +#define IO_SPACE_LIMIT		0x1ffffff
     #define PCI_IOBASE		((void __iomem *)(MODULES_VADDR - SZ_32M))

     static inline u8 inb(unsigned long addr)
    diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
    new file mode 100644
    index 0000000..3f7856e
    --- /dev/null
    +++ b/arch/arm64/include/asm/pci.h
    @@ -0,0 +1,49 @@
    +#ifndef __ASM_PCI_H
    +#define __ASM_PCI_H
    +#ifdef __KERNEL__
    +
    +#include <linux/types.h>
    +#include <linux/slab.h>
    +#include <linux/dma-mapping.h>
    +
    +#include <asm/io.h>
    +#include <asm-generic/pci-bridge.h>
    +#include <asm-generic/pci-dma-compat.h>
    +
    +#define PCIBIOS_MIN_IO		0x1000
    +#define PCIBIOS_MIN_MEM		0
    +
    +struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);
    +
    +/*
    + * Set to 1 if the kernel should re-assign all PCI bus numbers
    + */
    +#define pcibios_assign_all_busses() \
    +	(pci_has_flag(PCI_REASSIGN_ALL_BUS))
    +
    +/*
    + * PCI address space differs from physical memory address space
    + */
    +#define PCI_DMA_BUS_IS_PHYS	(0)
    +
    +extern int isa_dma_bridge_buggy;
    +
    +#ifdef CONFIG_PCI
    +static inline int pci_domain_nr(struct pci_bus *bus)
    +{
    +	struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
    +
    +	if (bridge)
    +		return bridge->domain_nr;
    +
    +	return 0;
    +}
    +
    +static inline int pci_proc_domain(struct pci_bus *bus)
    +{
    +	return 1;
    +}
    +#endif  /* CONFIG_PCI */
    +
    +#endif  /* __KERNEL__ */
    +#endif  /* __ASM_PCI_H */
    diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
    index cdaedad..36b117a 100644
    --- a/arch/arm64/kernel/Makefile
    +++ b/arch/arm64/kernel/Makefile
    @@ -29,6 +29,7 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
     arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
     arm64-obj-$(CONFIG_KGDB)		+= kgdb.o
     arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o
    +arm64-obj-$(CONFIG_PCI)			+= pci.o

     obj-y					+= $(arm64-obj-y) vdso/
     obj-m					+= $(arm64-obj-m)
    diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
    new file mode 100644
    index 0000000..955d6d1
    --- /dev/null
    +++ b/arch/arm64/kernel/pci.c
    @@ -0,0 +1,38 @@
    +/*
    + * Code borrowed from powerpc/kernel/pci-common.c
    + *
    + * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
    + * Copyright (C) 2014 ARM Ltd.
    + *
    + * 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.
    + *
    + */
    +
    +#include <linux/init.h>
    +#include <linux/io.h>
    +#include <linux/kernel.h>
    +#include <linux/mm.h>
    +#include <linux/of_pci.h>
    +#include <linux/of_platform.h>
    +#include <linux/slab.h>
    +
    +#include <asm/pci-bridge.h>
    +
    +/*
    + * Called after each bus is probed, but before its children are examined
    + */
    +void pcibios_fixup_bus(struct pci_bus *bus)
    +{
    +	/* nothing to do, expected to be removed in the future */
    +}
    +
    +/*
    + * We don't have to worry about legacy ISA devices, so nothing to do here
    + */
    +resource_size_t pcibios_align_resource(void *data, const struct resource *res,
    +				resource_size_t size, resource_size_t align)
    +{
    +	return res->start;
    +}
    --
    1.9.3
pci: APM X-Gene PCIe controller driver

This patch adds the AppliedMicro X-Gene SOC PCIe controller driver.
X-Gene PCIe controller supports maximum up to 8 lanes and GEN3 speed.
X-Gene SOC supports maximum 5 PCIe ports.

Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
arm64: dts: APM X-Gene PCIe device tree nodes

This patch adds the device tree nodes for APM X-Gene PCIe controller and
PCIe clock interface. Since X-Gene SOC supports maximum 5 ports, 5 dts
nodes are added.

Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
dt-bindings: pci: xgene pcie device tree bindings

This patch adds the bindings for X-Gene PCIe driver. The driver resides
under 'drivers/pci/host/pci-xgene.c' file.

Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
MAINTAINERS: entry for APM X-Gene PCIe host driver

Add entry for AppliedMicro X-Gene PCIe host driver.

Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
pci/xgene: use pci_remap_iospace() instead of pci_ioremap_io()

Signed-off-by: Mark Salter <msalter@redhat.com>