diff mbox

[v6,01/21] irqchip: ARM: GIC: Move some bits of GICv2 to a library-type file

Message ID 1404140510-5382-2-git-send-email-marc.zyngier@arm.com
State Superseded
Headers show

Commit Message

Marc Zyngier June 30, 2014, 3:01 p.m. UTC
A few GICv2 low-level function are actually very useful to GICv3,
and it makes some sense to share them across the two drivers.
They end-up in their own file, with an additional parameter used
to ensure an optional synchronization (unused on GICv2).

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/Makefile         |   2 +-
 drivers/irqchip/irq-gic-common.c | 115 +++++++++++++++++++++++++++++++++++++++
 drivers/irqchip/irq-gic-common.h |  29 ++++++++++
 drivers/irqchip/irq-gic.c        |  59 ++------------------
 4 files changed, 149 insertions(+), 56 deletions(-)
 create mode 100644 drivers/irqchip/irq-gic-common.c
 create mode 100644 drivers/irqchip/irq-gic-common.h

Comments

Jason Cooper July 8, 2014, 10:31 p.m. UTC | #1
Marc,

On Mon, Jun 30, 2014 at 04:01:30PM +0100, Marc Zyngier wrote:
> A few GICv2 low-level function are actually very useful to GICv3,
> and it makes some sense to share them across the two drivers.
> They end-up in their own file, with an additional parameter used
> to ensure an optional synchronization (unused on GICv2).
> 
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Jason Cooper <jason@lakedaemon.net>
> Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  drivers/irqchip/Makefile         |   2 +-
>  drivers/irqchip/irq-gic-common.c | 115 +++++++++++++++++++++++++++++++++++++++
>  drivers/irqchip/irq-gic-common.h |  29 ++++++++++
>  drivers/irqchip/irq-gic.c        |  59 ++------------------
>  4 files changed, 149 insertions(+), 56 deletions(-)
>  create mode 100644 drivers/irqchip/irq-gic-common.c
>  create mode 100644 drivers/irqchip/irq-gic-common.h

I've now applied this and patch #2 to irqchip/gic.  It'll be in -next
tonight, and I'll merge it into /core at some point in the future.
Probably after the other gic changes go on top of this.

At any rate, unless you tell me it's all fouled up, this branch is
stable.  Since I'll be adding more stuff on top, I've tagged this for
you guys to pull:

  git://git.infradead.org/users/jcooper/linux.git  tags/deps-irqchip-gic-3.17

Please wait to send your pull request for changes depending on this
branch until after you see Thomas send Linus the request for irq/core.

thx,

Jason.
Christoffer Dall July 11, 2014, 4:15 p.m. UTC | #2
On Tue, Jul 08, 2014 at 06:31:45PM -0400, Jason Cooper wrote:
> Marc,
> 
> On Mon, Jun 30, 2014 at 04:01:30PM +0100, Marc Zyngier wrote:
> > A few GICv2 low-level function are actually very useful to GICv3,
> > and it makes some sense to share them across the two drivers.
> > They end-up in their own file, with an additional parameter used
> > to ensure an optional synchronization (unused on GICv2).
> > 
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Jason Cooper <jason@lakedaemon.net>
> > Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
> > Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> > ---
> >  drivers/irqchip/Makefile         |   2 +-
> >  drivers/irqchip/irq-gic-common.c | 115 +++++++++++++++++++++++++++++++++++++++
> >  drivers/irqchip/irq-gic-common.h |  29 ++++++++++
> >  drivers/irqchip/irq-gic.c        |  59 ++------------------
> >  4 files changed, 149 insertions(+), 56 deletions(-)
> >  create mode 100644 drivers/irqchip/irq-gic-common.c
> >  create mode 100644 drivers/irqchip/irq-gic-common.h
> 
> I've now applied this and patch #2 to irqchip/gic.  It'll be in -next
> tonight, and I'll merge it into /core at some point in the future.
> Probably after the other gic changes go on top of this.
> 
> At any rate, unless you tell me it's all fouled up, this branch is
> stable.  Since I'll be adding more stuff on top, I've tagged this for
> you guys to pull:
> 
>   git://git.infradead.org/users/jcooper/linux.git  tags/deps-irqchip-gic-3.17
> 
> Please wait to send your pull request for changes depending on this
> branch until after you see Thomas send Linus the request for irq/core.
> 

Thanks, I've pushed

  git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git queue


which will pretty much be the pull request to kvm/next (still need to
test a few bits before moving to next and make it stable to be included
in kvm/next).

Will coordinate with Paolo to make sure commit
021f653791ad17e03f98aaa7fb933816ae16f161 lands in Linus' tree before
sending the KVM pull-request.

Thanks,
-Christoffer
Paolo Bonzini July 11, 2014, 8:47 p.m. UTC | #3
Il 11/07/2014 18:15, Christoffer Dall ha scritto:
> Thanks, I've pushed
>
>   git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git queue
>
>
> which will pretty much be the pull request to kvm/next (still need to
> test a few bits before moving to next and make it stable to be included
> in kvm/next).
>
> Will coordinate with Paolo to make sure commit
> 021f653791ad17e03f98aaa7fb933816ae16f161 lands in Linus' tree before
> sending the KVM pull-request.

So I'll send out the KVM changes early when the merge window open, and 
then pull from you and send the result to Linus in a second request.  Ok?

Paolo
Christoffer Dall July 11, 2014, 9:41 p.m. UTC | #4
On 11 July 2014 22:47, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 11/07/2014 18:15, Christoffer Dall ha scritto:
>
>> Thanks, I've pushed
>>
>>   git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git queue
>>
>>
>> which will pretty much be the pull request to kvm/next (still need to
>> test a few bits before moving to next and make it stable to be included
>> in kvm/next).
>>
>> Will coordinate with Paolo to make sure commit
>> 021f653791ad17e03f98aaa7fb933816ae16f161 lands in Linus' tree before
>> sending the KVM pull-request.
>
>
> So I'll send out the KVM changes early when the merge window open, and then
> pull from you and send the result to Linus in a second request.  Ok?
>
That's fine, I guess the only downside on my end would be a slight
delay in getting the patches into kvm/next, but I don't even think
anyone is eager waiting to update qemu headers or anything like that.
So as long as the second pull request (with my changes) comes after
the patches mentioned above land in Linus tree, I think we're all
good.

If anyone feels like taking a quick peek at the queue branch in the
kvmarm tree to ensure I'm not messing this up, it would be
appreciated.

Thanks,
-Christoffer
diff mbox

Patch

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 62a13e5..9b9505c 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -15,7 +15,7 @@  obj-$(CONFIG_ORION_IRQCHIP)		+= irq-orion.o
 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
+obj-$(CONFIG_ARM_GIC)			+= irq-gic.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-common.c b/drivers/irqchip/irq-gic-common.c
new file mode 100644
index 0000000..60ac704
--- /dev/null
+++ b/drivers/irqchip/irq-gic-common.c
@@ -0,0 +1,115 @@ 
+/*
+ * Copyright (C) 2002 ARM Limited, All Rights Reserved.
+ *
+ * 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/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include "irq-gic-common.h"
+
+void gic_configure_irq(unsigned int irq, unsigned int type,
+		       void __iomem *base, void (*sync_access)(void))
+{
+	u32 enablemask = 1 << (irq % 32);
+	u32 enableoff = (irq / 32) * 4;
+	u32 confmask = 0x2 << ((irq % 16) * 2);
+	u32 confoff = (irq / 16) * 4;
+	bool enabled = false;
+	u32 val;
+
+	/*
+	 * Read current configuration register, and insert the config
+	 * for "irq", depending on "type".
+	 */
+	val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
+	if (type == IRQ_TYPE_LEVEL_HIGH)
+		val &= ~confmask;
+	else if (type == IRQ_TYPE_EDGE_RISING)
+		val |= confmask;
+
+	/*
+	 * As recommended by the spec, disable the interrupt before changing
+	 * the configuration
+	 */
+	if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
+		writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
+		if (sync_access)
+			sync_access();
+		enabled = true;
+	}
+
+	/*
+	 * Write back the new configuration, and possibly re-enable
+	 * the interrupt.
+	 */
+	writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
+
+	if (enabled)
+		writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
+
+	if (sync_access)
+		sync_access();
+}
+
+void __init gic_dist_config(void __iomem *base, int gic_irqs,
+			    void (*sync_access)(void))
+{
+	unsigned int i;
+
+	/*
+	 * Set all global interrupts to be level triggered, active low.
+	 */
+	for (i = 32; i < gic_irqs; i += 16)
+		writel_relaxed(0, base + GIC_DIST_CONFIG + i / 4);
+
+	/*
+	 * Set priority on all global interrupts.
+	 */
+	for (i = 32; i < gic_irqs; i += 4)
+		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i);
+
+	/*
+	 * Disable all interrupts.  Leave the PPI and SGIs alone
+	 * as they are enabled by redistributor registers.
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i / 8);
+
+	if (sync_access)
+		sync_access();
+}
+
+void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
+{
+	int i;
+
+	/*
+	 * Deal with the banked PPI and SGI interrupts - disable all
+	 * PPI interrupts, ensure all SGI interrupts are enabled.
+	 */
+	writel_relaxed(0xffff0000, base + GIC_DIST_ENABLE_CLEAR);
+	writel_relaxed(0x0000ffff, base + GIC_DIST_ENABLE_SET);
+
+	/*
+	 * Set priority on PPI and SGI interrupts
+	 */
+	for (i = 0; i < 32; i += 4)
+		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
+
+	if (sync_access)
+		sync_access();
+}
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
new file mode 100644
index 0000000..b41f024
--- /dev/null
+++ b/drivers/irqchip/irq-gic-common.h
@@ -0,0 +1,29 @@ 
+/*
+ * Copyright (C) 2002 ARM Limited, All Rights Reserved.
+ *
+ * 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 _IRQ_GIC_COMMON_H
+#define _IRQ_GIC_COMMON_H
+
+#include <linux/of.h>
+#include <linux/irqdomain.h>
+
+void gic_configure_irq(unsigned int irq, unsigned int type,
+                       void __iomem *base, void (*sync_access)(void));
+void gic_dist_config(void __iomem *base, int gic_irqs,
+		     void (*sync_access)(void));
+void gic_cpu_config(void __iomem *base, void (*sync_access)(void));
+
+#endif /* _IRQ_GIC_COMMON_H */
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 7e11c9d..508b815 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -46,6 +46,7 @@ 
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
 
+#include "irq-gic-common.h"
 #include "irqchip.h"
 
 union gic_base {
@@ -188,12 +189,6 @@  static int gic_set_type(struct irq_data *d, unsigned int type)
 {
 	void __iomem *base = gic_dist_base(d);
 	unsigned int gicirq = gic_irq(d);
-	u32 enablemask = 1 << (gicirq % 32);
-	u32 enableoff = (gicirq / 32) * 4;
-	u32 confmask = 0x2 << ((gicirq % 16) * 2);
-	u32 confoff = (gicirq / 16) * 4;
-	bool enabled = false;
-	u32 val;
 
 	/* Interrupt configuration for SGIs can't be changed */
 	if (gicirq < 16)
@@ -207,25 +202,7 @@  static int gic_set_type(struct irq_data *d, unsigned int type)
 	if (gic_arch_extn.irq_set_type)
 		gic_arch_extn.irq_set_type(d, type);
 
-	val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
-	if (type == IRQ_TYPE_LEVEL_HIGH)
-		val &= ~confmask;
-	else if (type == IRQ_TYPE_EDGE_RISING)
-		val |= confmask;
-
-	/*
-	 * As recommended by the spec, disable the interrupt before changing
-	 * the configuration
-	 */
-	if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
-		writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
-		enabled = true;
-	}
-
-	writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
-
-	if (enabled)
-		writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
+	gic_configure_irq(gicirq, type, base, NULL);
 
 	raw_spin_unlock(&irq_controller_lock);
 
@@ -387,12 +364,6 @@  static void __init gic_dist_init(struct gic_chip_data *gic)
 	writel_relaxed(0, base + GIC_DIST_CTRL);
 
 	/*
-	 * Set all global interrupts to be level triggered, active low.
-	 */
-	for (i = 32; i < gic_irqs; i += 16)
-		writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
-
-	/*
 	 * Set all global interrupts to this CPU only.
 	 */
 	cpumask = gic_get_cpumask(gic);
@@ -401,18 +372,7 @@  static void __init gic_dist_init(struct gic_chip_data *gic)
 	for (i = 32; i < gic_irqs; i += 4)
 		writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
 
-	/*
-	 * Set priority on all global interrupts.
-	 */
-	for (i = 32; i < gic_irqs; i += 4)
-		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
-
-	/*
-	 * Disable all interrupts.  Leave the PPI and SGIs alone
-	 * as these enables are banked registers.
-	 */
-	for (i = 32; i < gic_irqs; i += 32)
-		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+	gic_dist_config(base, gic_irqs, NULL);
 
 	writel_relaxed(1, base + GIC_DIST_CTRL);
 }
@@ -439,18 +399,7 @@  static void gic_cpu_init(struct gic_chip_data *gic)
 		if (i != cpu)
 			gic_cpu_map[i] &= ~cpu_mask;
 
-	/*
-	 * Deal with the banked PPI and SGI interrupts - disable all
-	 * PPI interrupts, ensure all SGI interrupts are enabled.
-	 */
-	writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
-	writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
-
-	/*
-	 * Set priority on PPI and SGI interrupts
-	 */
-	for (i = 0; i < 32; i += 4)
-		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+	gic_cpu_config(dist_base, NULL);
 
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	writel_relaxed(1, base + GIC_CPU_CTRL);