aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2011-07-20 11:24:14 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2011-10-23 08:32:29 -0400
commit292b293ceef2eda1f96f0c90b96e954d7bdabd1c (patch)
tree931da77e74e1aee404ffb61f8ffe2f6acb73f80c /arch/arm/common
parent88b6fc8c57055590d8e9538f6faa85483db8c366 (diff)
ARM: gic: consolidate PPI handling
PPI handling is a bit of an odd beast. It uses its own low level handling code and is hardwired to the local timers (hence lacking a registration interface). Instead, switch the low handling to the normal SPI handling code. PPIs are handled by the handle_percpu_devid_irq flow. This also allows the removal of some duplicated code. Cc: Kukjin Kim <kgene.kim@samsung.com> Cc: David Brown <davidb@codeaurora.org> Cc: Bryan Huntsman <bryanh@codeaurora.org> Cc: Tony Lindgren <tony@atomide.com> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Magnus Damm <magnus.damm@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Acked-by: David Brown <davidb@codeaurora.org> Tested-by: David Brown <davidb@codeaurora.org> Tested-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm/common')
-rw-r--r--arch/arm/common/gic.c75
1 files changed, 74 insertions, 1 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 666b278e56d7..bbea0168779b 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -28,10 +28,14 @@
28#include <linux/smp.h> 28#include <linux/smp.h>
29#include <linux/cpumask.h> 29#include <linux/cpumask.h>
30#include <linux/io.h> 30#include <linux/io.h>
31#include <linux/interrupt.h>
32#include <linux/percpu.h>
33#include <linux/slab.h>
31 34
32#include <asm/irq.h> 35#include <asm/irq.h>
33#include <asm/mach/irq.h> 36#include <asm/mach/irq.h>
34#include <asm/hardware/gic.h> 37#include <asm/hardware/gic.h>
38#include <asm/localtimer.h>
35 39
36static DEFINE_SPINLOCK(irq_controller_lock); 40static DEFINE_SPINLOCK(irq_controller_lock);
37 41
@@ -255,6 +259,32 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
255 irq_set_chained_handler(irq, gic_handle_cascade_irq); 259 irq_set_chained_handler(irq, gic_handle_cascade_irq);
256} 260}
257 261
262#ifdef CONFIG_LOCAL_TIMERS
263#define gic_ppi_handler percpu_timer_handler
264#else
265static irqreturn_t gic_ppi_handler(int irq, void *dev_id)
266{
267 return IRQ_NONE;
268}
269#endif
270
271#define PPI_IRQACT(nr) \
272 { \
273 .handler = gic_ppi_handler, \
274 .flags = IRQF_PERCPU | IRQF_TIMER, \
275 .irq = nr, \
276 .name = "PPI-" # nr, \
277 }
278
279static struct irqaction ppi_irqaction_template[16] __initdata = {
280 PPI_IRQACT(0), PPI_IRQACT(1), PPI_IRQACT(2), PPI_IRQACT(3),
281 PPI_IRQACT(4), PPI_IRQACT(5), PPI_IRQACT(6), PPI_IRQACT(7),
282 PPI_IRQACT(8), PPI_IRQACT(9), PPI_IRQACT(10), PPI_IRQACT(11),
283 PPI_IRQACT(12), PPI_IRQACT(13), PPI_IRQACT(14), PPI_IRQACT(15),
284};
285
286static struct irqaction *ppi_irqaction;
287
258static void __init gic_dist_init(struct gic_chip_data *gic, 288static void __init gic_dist_init(struct gic_chip_data *gic,
259 unsigned int irq_start) 289 unsigned int irq_start)
260{ 290{
@@ -262,6 +292,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
262 u32 cpumask; 292 u32 cpumask;
263 void __iomem *base = gic->dist_base; 293 void __iomem *base = gic->dist_base;
264 u32 cpu = 0; 294 u32 cpu = 0;
295 u32 nrppis = 0, ppi_base = 0;
265 296
266#ifdef CONFIG_SMP 297#ifdef CONFIG_SMP
267 cpu = cpu_logical_map(smp_processor_id()); 298 cpu = cpu_logical_map(smp_processor_id());
@@ -283,6 +314,33 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
283 gic_irqs = 1020; 314 gic_irqs = 1020;
284 315
285 /* 316 /*
317 * Nobody would be insane enough to use PPIs on a secondary
318 * GIC, right?
319 */
320 if (gic == &gic_data[0]) {
321 nrppis = (32 - irq_start) & 31;
322
323 /* The GIC only supports up to 16 PPIs. */
324 if (nrppis > 16)
325 BUG();
326
327 ppi_base = gic->irq_offset + 32 - nrppis;
328
329 ppi_irqaction = kmemdup(&ppi_irqaction_template[16 - nrppis],
330 sizeof(*ppi_irqaction) * nrppis,
331 GFP_KERNEL);
332
333 if (nrppis && !ppi_irqaction) {
334 pr_err("GIC: Can't allocate PPI memory");
335 nrppis = 0;
336 ppi_base = 0;
337 }
338 }
339
340 pr_info("Configuring GIC with %d sources (%d PPIs)\n",
341 gic_irqs, (gic == &gic_data[0]) ? nrppis : 0);
342
343 /*
286 * Set all global interrupts to be level triggered, active low. 344 * Set all global interrupts to be level triggered, active low.
287 */ 345 */
288 for (i = 32; i < gic_irqs; i += 16) 346 for (i = 32; i < gic_irqs; i += 16)
@@ -317,7 +375,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
317 /* 375 /*
318 * Setup the Linux IRQ subsystem. 376 * Setup the Linux IRQ subsystem.
319 */ 377 */
320 for (i = irq_start; i < irq_limit; i++) { 378 for (i = 0; i < nrppis; i++) {
379 int ppi = i + ppi_base;
380 int err;
381
382 irq_set_percpu_devid(ppi);
383 irq_set_chip_and_handler(ppi, &gic_chip,
384 handle_percpu_devid_irq);
385 irq_set_chip_data(ppi, gic);
386 set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN);
387
388 err = setup_percpu_irq(ppi, &ppi_irqaction[i]);
389 if (err)
390 pr_err("GIC: can't setup PPI%d (%d)\n", ppi, err);
391 }
392
393 for (i = irq_start + nrppis; i < irq_limit; i++) {
321 irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq); 394 irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
322 irq_set_chip_data(i, gic); 395 irq_set_chip_data(i, gic);
323 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 396 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);