diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-10-23 09:42:30 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-10-23 09:42:30 -0400 |
commit | 34471a9168c8bfd7f0d00989a7b0797ad27d585e (patch) | |
tree | 847af3ec746c6357902cf57c7e12ba55a35eed30 /arch/arm/common | |
parent | cefd3e71efca6f4ef7f06f1fc507771d76072741 (diff) | |
parent | 28af690a284dfcb627bd69d0963db1c0f412cb8c (diff) |
Merge branch 'ppi-irq-core-for-rmk' of git://github.com/mzyngier/arm-platforms into devel-stable
Diffstat (limited to 'arch/arm/common')
-rw-r--r-- | arch/arm/common/gic.c | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 734db99eaee7..016c1aeb847c 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
@@ -29,6 +29,9 @@ | |||
29 | #include <linux/cpu_pm.h> | 29 | #include <linux/cpu_pm.h> |
30 | #include <linux/cpumask.h> | 30 | #include <linux/cpumask.h> |
31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/percpu.h> | ||
34 | #include <linux/slab.h> | ||
32 | 35 | ||
33 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
34 | #include <asm/mach/irq.h> | 37 | #include <asm/mach/irq.h> |
@@ -181,7 +184,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, | |||
181 | return -EINVAL; | 184 | return -EINVAL; |
182 | 185 | ||
183 | mask = 0xff << shift; | 186 | mask = 0xff << shift; |
184 | bit = 1 << (cpu + shift); | 187 | bit = 1 << (cpu_logical_map(cpu) + shift); |
185 | 188 | ||
186 | spin_lock(&irq_controller_lock); | 189 | spin_lock(&irq_controller_lock); |
187 | val = readl_relaxed(reg) & ~mask; | 190 | val = readl_relaxed(reg) & ~mask; |
@@ -260,9 +263,16 @@ static void __init gic_dist_init(struct gic_chip_data *gic, | |||
260 | unsigned int irq_start) | 263 | unsigned int irq_start) |
261 | { | 264 | { |
262 | unsigned int gic_irqs, irq_limit, i; | 265 | unsigned int gic_irqs, irq_limit, i; |
266 | u32 cpumask; | ||
263 | void __iomem *base = gic->dist_base; | 267 | void __iomem *base = gic->dist_base; |
264 | u32 cpumask = 1 << smp_processor_id(); | 268 | u32 cpu = 0; |
269 | u32 nrppis = 0, ppi_base = 0; | ||
265 | 270 | ||
271 | #ifdef CONFIG_SMP | ||
272 | cpu = cpu_logical_map(smp_processor_id()); | ||
273 | #endif | ||
274 | |||
275 | cpumask = 1 << cpu; | ||
266 | cpumask |= cpumask << 8; | 276 | cpumask |= cpumask << 8; |
267 | cpumask |= cpumask << 16; | 277 | cpumask |= cpumask << 16; |
268 | 278 | ||
@@ -280,6 +290,23 @@ static void __init gic_dist_init(struct gic_chip_data *gic, | |||
280 | gic->gic_irqs = gic_irqs; | 290 | gic->gic_irqs = gic_irqs; |
281 | 291 | ||
282 | /* | 292 | /* |
293 | * Nobody would be insane enough to use PPIs on a secondary | ||
294 | * GIC, right? | ||
295 | */ | ||
296 | if (gic == &gic_data[0]) { | ||
297 | nrppis = (32 - irq_start) & 31; | ||
298 | |||
299 | /* The GIC only supports up to 16 PPIs. */ | ||
300 | if (nrppis > 16) | ||
301 | BUG(); | ||
302 | |||
303 | ppi_base = gic->irq_offset + 32 - nrppis; | ||
304 | } | ||
305 | |||
306 | pr_info("Configuring GIC with %d sources (%d PPIs)\n", | ||
307 | gic_irqs, (gic == &gic_data[0]) ? nrppis : 0); | ||
308 | |||
309 | /* | ||
283 | * Set all global interrupts to be level triggered, active low. | 310 | * Set all global interrupts to be level triggered, active low. |
284 | */ | 311 | */ |
285 | for (i = 32; i < gic_irqs; i += 16) | 312 | for (i = 32; i < gic_irqs; i += 16) |
@@ -314,7 +341,17 @@ static void __init gic_dist_init(struct gic_chip_data *gic, | |||
314 | /* | 341 | /* |
315 | * Setup the Linux IRQ subsystem. | 342 | * Setup the Linux IRQ subsystem. |
316 | */ | 343 | */ |
317 | for (i = irq_start; i < irq_limit; i++) { | 344 | for (i = 0; i < nrppis; i++) { |
345 | int ppi = i + ppi_base; | ||
346 | |||
347 | irq_set_percpu_devid(ppi); | ||
348 | irq_set_chip_and_handler(ppi, &gic_chip, | ||
349 | handle_percpu_devid_irq); | ||
350 | irq_set_chip_data(ppi, gic); | ||
351 | set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN); | ||
352 | } | ||
353 | |||
354 | for (i = irq_start + nrppis; i < irq_limit; i++) { | ||
318 | irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq); | 355 | irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq); |
319 | irq_set_chip_data(i, gic); | 356 | irq_set_chip_data(i, gic); |
320 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 357 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); |
@@ -557,20 +594,15 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr) | |||
557 | gic_cpu_init(&gic_data[gic_nr]); | 594 | gic_cpu_init(&gic_data[gic_nr]); |
558 | } | 595 | } |
559 | 596 | ||
560 | void __cpuinit gic_enable_ppi(unsigned int irq) | ||
561 | { | ||
562 | unsigned long flags; | ||
563 | |||
564 | local_irq_save(flags); | ||
565 | irq_set_status_flags(irq, IRQ_NOPROBE); | ||
566 | gic_unmask_irq(irq_get_irq_data(irq)); | ||
567 | local_irq_restore(flags); | ||
568 | } | ||
569 | |||
570 | #ifdef CONFIG_SMP | 597 | #ifdef CONFIG_SMP |
571 | void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) | 598 | void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) |
572 | { | 599 | { |
573 | unsigned long map = *cpus_addr(*mask); | 600 | int cpu; |
601 | unsigned long map = 0; | ||
602 | |||
603 | /* Convert our logical CPU mask into a physical one. */ | ||
604 | for_each_cpu(cpu, mask) | ||
605 | map |= 1 << cpu_logical_map(cpu); | ||
574 | 606 | ||
575 | /* | 607 | /* |
576 | * Ensure that stores to Normal memory are visible to the | 608 | * Ensure that stores to Normal memory are visible to the |