diff options
Diffstat (limited to 'arch/arm/common')
-rw-r--r-- | arch/arm/common/gic.c | 75 |
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 | ||
36 | static DEFINE_SPINLOCK(irq_controller_lock); | 40 | static 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 | ||
265 | static 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 | |||
279 | static 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 | |||
286 | static struct irqaction *ppi_irqaction; | ||
287 | |||
258 | static void __init gic_dist_init(struct gic_chip_data *gic, | 288 | static 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); |