aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2013-01-30 18:49:57 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2013-02-08 05:17:22 -0500
commit2bb3135166abcd59979cfcdd3696ba840b6b9d45 (patch)
tree3ba104b4cf88a22f1a7e7facdb113a4664192e6d /arch
parent949db153b6466c6f7cad5a427ecea94985927311 (diff)
ARM: GIC: fix GIC cpumask initialization
Punit Agrawal reports: > I was trying to boot 3.8-rc5 on Realview EB 11MPCore using > realview-smp_defconfig as a starting point but the kernel failed to > progress past the log below (config attached). > > Pawel suggested I try reverting 384a290283f - "ARM: gic: use a private > mapping for CPU target interfaces" that you've authored. With this > commit reverted the kernel boots. > > I am not quite sure why the commit breaks 11MPCore but Pawel (cc'd) > might be able to shed light on that. Some early GIC implementations return zero for the first distributor CPU routing register. This means we can't rely on that telling us which CPU interface we're connected to. We know that these platforms implement PPIs for IRQs 29-31 - but we shouldn't assume that these will always be populated. So, instead, scan for a non-zero CPU routing register in the first 32 IRQs and use that as our CPU mask. Reported-by: Punit Agrawal <punit.agrawal@arm.com> Reviewed-by: Nicolas Pitre <nico@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/common/gic.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 36ae03a3f5d1..87dfa9026c5b 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -351,6 +351,25 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
351 irq_set_chained_handler(irq, gic_handle_cascade_irq); 351 irq_set_chained_handler(irq, gic_handle_cascade_irq);
352} 352}
353 353
354static u8 gic_get_cpumask(struct gic_chip_data *gic)
355{
356 void __iomem *base = gic_data_dist_base(gic);
357 u32 mask, i;
358
359 for (i = mask = 0; i < 32; i += 4) {
360 mask = readl_relaxed(base + GIC_DIST_TARGET + i);
361 mask |= mask >> 16;
362 mask |= mask >> 8;
363 if (mask)
364 break;
365 }
366
367 if (!mask)
368 pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
369
370 return mask;
371}
372
354static void __init gic_dist_init(struct gic_chip_data *gic) 373static void __init gic_dist_init(struct gic_chip_data *gic)
355{ 374{
356 unsigned int i; 375 unsigned int i;
@@ -369,7 +388,9 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
369 /* 388 /*
370 * Set all global interrupts to this CPU only. 389 * Set all global interrupts to this CPU only.
371 */ 390 */
372 cpumask = readl_relaxed(base + GIC_DIST_TARGET + 0); 391 cpumask = gic_get_cpumask(gic);
392 cpumask |= cpumask << 8;
393 cpumask |= cpumask << 16;
373 for (i = 32; i < gic_irqs; i += 4) 394 for (i = 32; i < gic_irqs; i += 4)
374 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); 395 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
375 396
@@ -400,7 +421,7 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
400 * Get what the GIC says our CPU mask is. 421 * Get what the GIC says our CPU mask is.
401 */ 422 */
402 BUG_ON(cpu >= NR_GIC_CPU_IF); 423 BUG_ON(cpu >= NR_GIC_CPU_IF);
403 cpu_mask = readl_relaxed(dist_base + GIC_DIST_TARGET + 0); 424 cpu_mask = gic_get_cpumask(gic);
404 gic_cpu_map[cpu] = cpu_mask; 425 gic_cpu_map[cpu] = cpu_mask;
405 426
406 /* 427 /*