aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-11-11 23:10:30 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-11-12 15:15:29 +0000
commit9395f6ea3c61d80ccc7a13668d27afbb8d9436ba (patch)
treeffef5df8f35a9a194a43b0f81f070eb68dbffff4
parente56c010f0d08bbecd05074eded7805d555da29b6 (diff)
ARM: GIC: don't disable software generated interrupts
Software generated interrupts (SGI) are used for IPIs by the kernel. While previous revisions of the GIC hardware were specified not to implement enable bits for SGIs, more recent hardware is now permitted to implement these bits in a per-CPU banked register. The priority registers for the PPI and SGIs are also per-CPU banked registers, so ensure that these are also appropriately initialized. Reported-by: Scott Valentine <svalentine@concentris-systems.com> Acked-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/common/gic.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index ada6359160e..772f95f1aec 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -251,15 +251,16 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
/*
- * Set priority on all interrupts.
+ * Set priority on all global interrupts.
*/
- for (i = 0; i < max_irq; i += 4)
+ for (i = 32; i < max_irq; i += 4)
writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
/*
- * Disable all interrupts.
+ * Disable all interrupts. Leave the PPI and SGIs alone
+ * as these enables are banked registers.
*/
- for (i = 0; i < max_irq; i += 32)
+ for (i = 32; i < max_irq; i += 32)
writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
/*
@@ -277,11 +278,30 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
{
+ void __iomem *dist_base;
+ int i;
+
if (gic_nr >= MAX_GIC_NR)
BUG();
+ dist_base = gic_data[gic_nr].dist_base;
+ BUG_ON(!dist_base);
+
gic_data[gic_nr].cpu_base = base;
+ /*
+ * Deal with the banked PPI and SGI interrupts - disable all
+ * PPI interrupts, ensure all SGI interrupts are enabled.
+ */
+ writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
+ writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
+
+ /*
+ * Set priority on PPI and SGI interrupts
+ */
+ for (i = 0; i < 32; i += 4)
+ writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+
writel(0xf0, base + GIC_CPU_PRIMASK);
writel(1, base + GIC_CPU_CTRL);
}