[RFC 2/8] irqchip: gic: Provide support for interrupt grouping
Daniel Thompson
daniel.thompson at linaro.org
Wed May 14 08:58:39 PDT 2014
GICv2+ implementions that do not implement security extensions (and
devices that boot in secure mode by default) allow the interrupt group
registers (used for FIQ/IRQ selection) to be accessed from kernel code.
However the current gic support does not initialize the controller to
make interrupt grouping effective.
The registers involved are RAZ/WI when unimplemented or protected by
security policy then it should be safe to set up the grouping
unconditionally.
Tested on a (self-written) qemu GICv2 model (written from ARM spec) and
an STiH416 (ARM Cortex A9).
Signed-off-by: Daniel Thompson <daniel.thompson at linaro.org>
Acked-by: Dirk Behme <dirk.behme at de.bosch.com>
---
drivers/irqchip/irq-gic.c | 35 ++++++++++++++++++++++++++++++-----
include/linux/irqchip/arm-gic.h | 3 +++
2 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 57d165e..aa8efe4 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
/*
+ * Set all global interrupts to be group 1.
+ *
+ * If grouping is not available (not implemented or prohibited by
+ * security mode) these registers a read-as-zero/write-ignored.
+ */
+ for (i = 32; i < gic_irqs; i += 32)
+ writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+ /*
* 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);
- writel_relaxed(1, base + GIC_DIST_CTRL);
+ /*
+ * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+ * bit 1 ignored)
+ */
+ writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+ GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);
}
static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +466,16 @@ static void gic_cpu_init(struct gic_chip_data *gic)
for (i = 0; i < 32; i += 4)
writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+ /*
+ * Set all PPI and SGI interrupts to be group 1.
+ *
+ * If grouping is not available (not implemented or prohibited by
+ * security mode) these registers are read-as-zero/write-ignored.
+ */
+ writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
- writel_relaxed(1, base + GIC_CPU_CTRL);
+ writel_relaxed(0x1f, base + GIC_CPU_CTRL);
}
void gic_cpu_if_down(void)
@@ -537,7 +559,9 @@ static void gic_dist_restore(unsigned int gic_nr)
writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
dist_base + GIC_DIST_ENABLE_SET + i * 4);
- writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+ writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+ GIC_DIST_CTRL_ENABLE_GRP1_BIT,
+ dist_base + GIC_DIST_CTRL);
}
static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +618,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
- writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+ writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
}
static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
@@ -670,7 +694,8 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
dmb(ishst);
/* this always happens on GIC0 */
- writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+ writel_relaxed(map << 16 | irq | 0x8000,
+ gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0..919502f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -37,6 +37,9 @@
#define GIC_DIST_SGI_PENDING_CLEAR 0xf10
#define GIC_DIST_SGI_PENDING_SET 0xf20
+#define GIC_DIST_CTRL_ENABLE_GRP0_BIT (1 << 0)
+#define GIC_DIST_CTRL_ENABLE_GRP1_BIT (1 << 1)
+
#define GICH_HCR 0x0
#define GICH_VTR 0x4
#define GICH_VMCR 0x8
--
1.9.0
More information about the linux-arm-kernel
mailing list