aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common/gic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/common/gic.c')
-rw-r--r--arch/arm/common/gic.c218
1 files changed, 207 insertions, 11 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 4ddd0a6ac7f..05cd423c575 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -29,6 +29,7 @@
29#include <linux/cpumask.h> 29#include <linux/cpumask.h>
30#include <linux/io.h> 30#include <linux/io.h>
31 31
32#include <asm/cpu_pm.h>
32#include <asm/irq.h> 33#include <asm/irq.h>
33#include <asm/mach/irq.h> 34#include <asm/mach/irq.h>
34#include <asm/hardware/gic.h> 35#include <asm/hardware/gic.h>
@@ -38,12 +39,6 @@ static DEFINE_SPINLOCK(irq_controller_lock);
38/* Address of GIC 0 CPU interface */ 39/* Address of GIC 0 CPU interface */
39void __iomem *gic_cpu_base_addr __read_mostly; 40void __iomem *gic_cpu_base_addr __read_mostly;
40 41
41struct gic_chip_data {
42 unsigned int irq_offset;
43 void __iomem *dist_base;
44 void __iomem *cpu_base;
45};
46
47/* 42/*
48 * Supported arch specific GIC irq extension. 43 * Supported arch specific GIC irq extension.
49 * Default make them NULL. 44 * Default make them NULL.
@@ -179,22 +174,32 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
179{ 174{
180 void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); 175 void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
181 unsigned int shift = (d->irq % 4) * 8; 176 unsigned int shift = (d->irq % 4) * 8;
182 unsigned int cpu = cpumask_first(mask_val); 177 unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
183 u32 val, mask, bit; 178 u32 val, mask, bit;
179#ifdef CONFIG_GIC_SET_MULTIPLE_CPUS
180 struct irq_desc *desc = irq_to_desc(d->irq);
181#endif
184 182
185 if (cpu >= 8) 183 if (cpu >= 8 || cpu >= nr_cpu_ids)
186 return -EINVAL; 184 return -EINVAL;
187 185
188 mask = 0xff << shift; 186 mask = 0xff << shift;
189 bit = 1 << (cpu + shift); 187 bit = 1 << (cpu + shift);
190 188
191 spin_lock(&irq_controller_lock); 189 spin_lock(&irq_controller_lock);
192 d->node = cpu;
193 val = readl_relaxed(reg) & ~mask; 190 val = readl_relaxed(reg) & ~mask;
194 writel_relaxed(val | bit, reg); 191 val |= bit;
192#ifdef CONFIG_GIC_SET_MULTIPLE_CPUS
193 if (desc && desc->affinity_hint) {
194 struct cpumask mask_hint;
195 if (cpumask_and(&mask_hint, desc->affinity_hint, mask_val))
196 val |= (*cpumask_bits(&mask_hint) << shift) & mask;
197 }
198#endif
199 writel_relaxed(val, reg);
195 spin_unlock(&irq_controller_lock); 200 spin_unlock(&irq_controller_lock);
196 201
197 return 0; 202 return IRQ_SET_MASK_OK;
198} 203}
199#endif 204#endif
200 205
@@ -283,6 +288,8 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
283 if (gic_irqs > 1020) 288 if (gic_irqs > 1020)
284 gic_irqs = 1020; 289 gic_irqs = 1020;
285 290
291 gic->gic_irqs = gic_irqs;
292
286 /* 293 /*
287 * Set all global interrupts to be level triggered, active low. 294 * Set all global interrupts to be level triggered, active low.
288 */ 295 */
@@ -350,6 +357,180 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
350 writel_relaxed(1, base + GIC_CPU_CTRL); 357 writel_relaxed(1, base + GIC_CPU_CTRL);
351} 358}
352 359
360/*
361 * Saves the GIC distributor registers during suspend or idle. Must be called
362 * with interrupts disabled but before powering down the GIC. After calling
363 * this function, no interrupts will be delivered by the GIC, and another
364 * platform-specific wakeup source must be enabled.
365 */
366static void gic_dist_save(unsigned int gic_nr)
367{
368 unsigned int gic_irqs;
369 void __iomem *dist_base;
370 int i;
371
372 if (gic_nr >= MAX_GIC_NR)
373 BUG();
374
375 gic_irqs = gic_data[gic_nr].gic_irqs;
376 dist_base = gic_data[gic_nr].dist_base;
377
378 if (!dist_base)
379 return;
380
381 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
382 gic_data[gic_nr].saved_spi_conf[i] =
383 readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
384
385 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
386 gic_data[gic_nr].saved_spi_pri[i] =
387 readl_relaxed(dist_base + GIC_DIST_PRI + i * 4);
388
389 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
390 gic_data[gic_nr].saved_spi_target[i] =
391 readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
392
393 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
394 gic_data[gic_nr].saved_spi_enable[i] =
395 readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
396
397 writel_relaxed(0, dist_base + GIC_DIST_CTRL);
398}
399
400/*
401 * Restores the GIC distributor registers during resume or when coming out of
402 * idle. Must be called before enabling interrupts. If a level interrupt
403 * that occured while the GIC was suspended is still present, it will be
404 * handled normally, but any edge interrupts that occured will not be seen by
405 * the GIC and need to be handled by the platform-specific wakeup source.
406 */
407static void gic_dist_restore(unsigned int gic_nr)
408{
409 unsigned int gic_irqs;
410 unsigned int i;
411 void __iomem *dist_base;
412
413 if (gic_nr >= MAX_GIC_NR)
414 BUG();
415
416 gic_irqs = gic_data[gic_nr].gic_irqs;
417 dist_base = gic_data[gic_nr].dist_base;
418
419 if (!dist_base)
420 return;
421
422 writel_relaxed(0, dist_base + GIC_DIST_CTRL);
423
424 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
425 writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
426 dist_base + GIC_DIST_CONFIG + i * 4);
427
428 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
429 writel_relaxed(gic_data[gic_nr].saved_spi_pri[i],
430 dist_base + GIC_DIST_PRI + i * 4);
431
432 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
433 writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
434 dist_base + GIC_DIST_TARGET + i * 4);
435
436 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
437 writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
438 dist_base + GIC_DIST_ENABLE_SET + i * 4);
439
440 writel_relaxed(1, dist_base + GIC_DIST_CTRL);
441}
442
443static void gic_cpu_save(unsigned int gic_nr)
444{
445 int i;
446 u32 *ptr;
447 void __iomem *dist_base;
448 void __iomem *cpu_base;
449
450 if (gic_nr >= MAX_GIC_NR)
451 BUG();
452
453 dist_base = gic_data[gic_nr].dist_base;
454 cpu_base = gic_data[gic_nr].cpu_base;
455
456 if (!dist_base || !cpu_base)
457 return;
458
459 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
460 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
461 ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
462
463 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
464 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
465 ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
466
467 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_pri);
468 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
469 ptr[i] = readl_relaxed(dist_base + GIC_DIST_PRI + i * 4);
470}
471
472static void gic_cpu_restore(unsigned int gic_nr)
473{
474 int i;
475 u32 *ptr;
476 void __iomem *dist_base;
477 void __iomem *cpu_base;
478
479 if (gic_nr >= MAX_GIC_NR)
480 BUG();
481
482 dist_base = gic_data[gic_nr].dist_base;
483 cpu_base = gic_data[gic_nr].cpu_base;
484
485 if (!dist_base || !cpu_base)
486 return;
487
488 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
489 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
490 writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
491
492 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
493 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
494 writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
495
496 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_pri);
497 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
498 writel_relaxed(ptr[i], dist_base + GIC_DIST_PRI + i * 4);
499
500 writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
501 writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
502}
503
504static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
505{
506 int i;
507
508 for (i = 0; i < MAX_GIC_NR; i++) {
509 switch (cmd) {
510 case CPU_PM_ENTER:
511 gic_cpu_save(i);
512 break;
513 case CPU_PM_ENTER_FAILED:
514 case CPU_PM_EXIT:
515 gic_cpu_restore(i);
516 break;
517 case CPU_COMPLEX_PM_ENTER:
518 gic_dist_save(i);
519 break;
520 case CPU_COMPLEX_PM_ENTER_FAILED:
521 case CPU_COMPLEX_PM_EXIT:
522 gic_dist_restore(i);
523 break;
524 }
525 }
526
527 return NOTIFY_OK;
528}
529
530static struct notifier_block gic_notifier_block = {
531 .notifier_call = gic_notifier,
532};
533
353void __init gic_init(unsigned int gic_nr, unsigned int irq_start, 534void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
354 void __iomem *dist_base, void __iomem *cpu_base) 535 void __iomem *dist_base, void __iomem *cpu_base)
355{ 536{
@@ -365,8 +546,23 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
365 if (gic_nr == 0) 546 if (gic_nr == 0)
366 gic_cpu_base_addr = cpu_base; 547 gic_cpu_base_addr = cpu_base;
367 548
549 gic_chip.flags |= gic_arch_extn.flags;
368 gic_dist_init(gic, irq_start); 550 gic_dist_init(gic, irq_start);
369 gic_cpu_init(gic); 551 gic_cpu_init(gic);
552
553 gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
554 sizeof(u32));
555 BUG_ON(!gic->saved_ppi_enable);
556
557 gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
558 sizeof(u32));
559 BUG_ON(!gic->saved_ppi_conf);
560
561 gic->saved_ppi_pri = __alloc_percpu(DIV_ROUND_UP(32, 4) * 4,
562 sizeof(u32));
563 BUG_ON(!gic->saved_ppi_pri);
564
565 cpu_pm_register_notifier(&gic_notifier_block);
370} 566}
371 567
372void __cpuinit gic_secondary_init(unsigned int gic_nr) 568void __cpuinit gic_secondary_init(unsigned int gic_nr)