diff options
Diffstat (limited to 'arch/arm/common/gic.c')
-rw-r--r-- | arch/arm/common/gic.c | 164 |
1 files changed, 141 insertions, 23 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 0e6ae470c94f..a1feb6b4f9f5 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
@@ -40,13 +40,36 @@ | |||
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | 41 | ||
42 | #include <asm/irq.h> | 42 | #include <asm/irq.h> |
43 | #include <asm/exception.h> | ||
43 | #include <asm/mach/irq.h> | 44 | #include <asm/mach/irq.h> |
44 | #include <asm/hardware/gic.h> | 45 | #include <asm/hardware/gic.h> |
45 | 46 | ||
46 | static DEFINE_RAW_SPINLOCK(irq_controller_lock); | 47 | union gic_base { |
48 | void __iomem *common_base; | ||
49 | void __percpu __iomem **percpu_base; | ||
50 | }; | ||
47 | 51 | ||
48 | /* Address of GIC 0 CPU interface */ | 52 | struct gic_chip_data { |
49 | void __iomem *gic_cpu_base_addr __read_mostly; | 53 | unsigned int irq_offset; |
54 | union gic_base dist_base; | ||
55 | union gic_base cpu_base; | ||
56 | #ifdef CONFIG_CPU_PM | ||
57 | u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; | ||
58 | u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; | ||
59 | u32 saved_spi_target[DIV_ROUND_UP(1020, 4)]; | ||
60 | u32 __percpu *saved_ppi_enable; | ||
61 | u32 __percpu *saved_ppi_conf; | ||
62 | #endif | ||
63 | #ifdef CONFIG_IRQ_DOMAIN | ||
64 | struct irq_domain domain; | ||
65 | #endif | ||
66 | unsigned int gic_irqs; | ||
67 | #ifdef CONFIG_GIC_NON_BANKED | ||
68 | void __iomem *(*get_base)(union gic_base *); | ||
69 | #endif | ||
70 | }; | ||
71 | |||
72 | static DEFINE_RAW_SPINLOCK(irq_controller_lock); | ||
50 | 73 | ||
51 | /* | 74 | /* |
52 | * Supported arch specific GIC irq extension. | 75 | * Supported arch specific GIC irq extension. |
@@ -67,16 +90,48 @@ struct irq_chip gic_arch_extn = { | |||
67 | 90 | ||
68 | static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly; | 91 | static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly; |
69 | 92 | ||
93 | #ifdef CONFIG_GIC_NON_BANKED | ||
94 | static void __iomem *gic_get_percpu_base(union gic_base *base) | ||
95 | { | ||
96 | return *__this_cpu_ptr(base->percpu_base); | ||
97 | } | ||
98 | |||
99 | static void __iomem *gic_get_common_base(union gic_base *base) | ||
100 | { | ||
101 | return base->common_base; | ||
102 | } | ||
103 | |||
104 | static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data) | ||
105 | { | ||
106 | return data->get_base(&data->dist_base); | ||
107 | } | ||
108 | |||
109 | static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data) | ||
110 | { | ||
111 | return data->get_base(&data->cpu_base); | ||
112 | } | ||
113 | |||
114 | static inline void gic_set_base_accessor(struct gic_chip_data *data, | ||
115 | void __iomem *(*f)(union gic_base *)) | ||
116 | { | ||
117 | data->get_base = f; | ||
118 | } | ||
119 | #else | ||
120 | #define gic_data_dist_base(d) ((d)->dist_base.common_base) | ||
121 | #define gic_data_cpu_base(d) ((d)->cpu_base.common_base) | ||
122 | #define gic_set_base_accessor(d,f) | ||
123 | #endif | ||
124 | |||
70 | static inline void __iomem *gic_dist_base(struct irq_data *d) | 125 | static inline void __iomem *gic_dist_base(struct irq_data *d) |
71 | { | 126 | { |
72 | struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); | 127 | struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); |
73 | return gic_data->dist_base; | 128 | return gic_data_dist_base(gic_data); |
74 | } | 129 | } |
75 | 130 | ||
76 | static inline void __iomem *gic_cpu_base(struct irq_data *d) | 131 | static inline void __iomem *gic_cpu_base(struct irq_data *d) |
77 | { | 132 | { |
78 | struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); | 133 | struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); |
79 | return gic_data->cpu_base; | 134 | return gic_data_cpu_base(gic_data); |
80 | } | 135 | } |
81 | 136 | ||
82 | static inline unsigned int gic_irq(struct irq_data *d) | 137 | static inline unsigned int gic_irq(struct irq_data *d) |
@@ -215,6 +270,32 @@ static int gic_set_wake(struct irq_data *d, unsigned int on) | |||
215 | #define gic_set_wake NULL | 270 | #define gic_set_wake NULL |
216 | #endif | 271 | #endif |
217 | 272 | ||
273 | asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) | ||
274 | { | ||
275 | u32 irqstat, irqnr; | ||
276 | struct gic_chip_data *gic = &gic_data[0]; | ||
277 | void __iomem *cpu_base = gic_data_cpu_base(gic); | ||
278 | |||
279 | do { | ||
280 | irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); | ||
281 | irqnr = irqstat & ~0x1c00; | ||
282 | |||
283 | if (likely(irqnr > 15 && irqnr < 1021)) { | ||
284 | irqnr = irq_domain_to_irq(&gic->domain, irqnr); | ||
285 | handle_IRQ(irqnr, regs); | ||
286 | continue; | ||
287 | } | ||
288 | if (irqnr < 16) { | ||
289 | writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); | ||
290 | #ifdef CONFIG_SMP | ||
291 | handle_IPI(irqnr, regs); | ||
292 | #endif | ||
293 | continue; | ||
294 | } | ||
295 | break; | ||
296 | } while (1); | ||
297 | } | ||
298 | |||
218 | static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) | 299 | static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) |
219 | { | 300 | { |
220 | struct gic_chip_data *chip_data = irq_get_handler_data(irq); | 301 | struct gic_chip_data *chip_data = irq_get_handler_data(irq); |
@@ -225,7 +306,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) | |||
225 | chained_irq_enter(chip, desc); | 306 | chained_irq_enter(chip, desc); |
226 | 307 | ||
227 | raw_spin_lock(&irq_controller_lock); | 308 | raw_spin_lock(&irq_controller_lock); |
228 | status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK); | 309 | status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK); |
229 | raw_spin_unlock(&irq_controller_lock); | 310 | raw_spin_unlock(&irq_controller_lock); |
230 | 311 | ||
231 | gic_irq = (status & 0x3ff); | 312 | gic_irq = (status & 0x3ff); |
@@ -270,7 +351,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic) | |||
270 | u32 cpumask; | 351 | u32 cpumask; |
271 | unsigned int gic_irqs = gic->gic_irqs; | 352 | unsigned int gic_irqs = gic->gic_irqs; |
272 | struct irq_domain *domain = &gic->domain; | 353 | struct irq_domain *domain = &gic->domain; |
273 | void __iomem *base = gic->dist_base; | 354 | void __iomem *base = gic_data_dist_base(gic); |
274 | u32 cpu = 0; | 355 | u32 cpu = 0; |
275 | 356 | ||
276 | #ifdef CONFIG_SMP | 357 | #ifdef CONFIG_SMP |
@@ -330,8 +411,8 @@ static void __init gic_dist_init(struct gic_chip_data *gic) | |||
330 | 411 | ||
331 | static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) | 412 | static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) |
332 | { | 413 | { |
333 | void __iomem *dist_base = gic->dist_base; | 414 | void __iomem *dist_base = gic_data_dist_base(gic); |
334 | void __iomem *base = gic->cpu_base; | 415 | void __iomem *base = gic_data_cpu_base(gic); |
335 | int i; | 416 | int i; |
336 | 417 | ||
337 | /* | 418 | /* |
@@ -368,7 +449,7 @@ static void gic_dist_save(unsigned int gic_nr) | |||
368 | BUG(); | 449 | BUG(); |
369 | 450 | ||
370 | gic_irqs = gic_data[gic_nr].gic_irqs; | 451 | gic_irqs = gic_data[gic_nr].gic_irqs; |
371 | dist_base = gic_data[gic_nr].dist_base; | 452 | dist_base = gic_data_dist_base(&gic_data[gic_nr]); |
372 | 453 | ||
373 | if (!dist_base) | 454 | if (!dist_base) |
374 | return; | 455 | return; |
@@ -403,7 +484,7 @@ static void gic_dist_restore(unsigned int gic_nr) | |||
403 | BUG(); | 484 | BUG(); |
404 | 485 | ||
405 | gic_irqs = gic_data[gic_nr].gic_irqs; | 486 | gic_irqs = gic_data[gic_nr].gic_irqs; |
406 | dist_base = gic_data[gic_nr].dist_base; | 487 | dist_base = gic_data_dist_base(&gic_data[gic_nr]); |
407 | 488 | ||
408 | if (!dist_base) | 489 | if (!dist_base) |
409 | return; | 490 | return; |
@@ -439,8 +520,8 @@ static void gic_cpu_save(unsigned int gic_nr) | |||
439 | if (gic_nr >= MAX_GIC_NR) | 520 | if (gic_nr >= MAX_GIC_NR) |
440 | BUG(); | 521 | BUG(); |
441 | 522 | ||
442 | dist_base = gic_data[gic_nr].dist_base; | 523 | dist_base = gic_data_dist_base(&gic_data[gic_nr]); |
443 | cpu_base = gic_data[gic_nr].cpu_base; | 524 | cpu_base = gic_data_cpu_base(&gic_data[gic_nr]); |
444 | 525 | ||
445 | if (!dist_base || !cpu_base) | 526 | if (!dist_base || !cpu_base) |
446 | return; | 527 | return; |
@@ -465,8 +546,8 @@ static void gic_cpu_restore(unsigned int gic_nr) | |||
465 | if (gic_nr >= MAX_GIC_NR) | 546 | if (gic_nr >= MAX_GIC_NR) |
466 | BUG(); | 547 | BUG(); |
467 | 548 | ||
468 | dist_base = gic_data[gic_nr].dist_base; | 549 | dist_base = gic_data_dist_base(&gic_data[gic_nr]); |
469 | cpu_base = gic_data[gic_nr].cpu_base; | 550 | cpu_base = gic_data_cpu_base(&gic_data[gic_nr]); |
470 | 551 | ||
471 | if (!dist_base || !cpu_base) | 552 | if (!dist_base || !cpu_base) |
472 | return; | 553 | return; |
@@ -491,6 +572,11 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) | |||
491 | int i; | 572 | int i; |
492 | 573 | ||
493 | for (i = 0; i < MAX_GIC_NR; i++) { | 574 | for (i = 0; i < MAX_GIC_NR; i++) { |
575 | #ifdef CONFIG_GIC_NON_BANKED | ||
576 | /* Skip over unused GICs */ | ||
577 | if (!gic_data[i].get_base) | ||
578 | continue; | ||
579 | #endif | ||
494 | switch (cmd) { | 580 | switch (cmd) { |
495 | case CPU_PM_ENTER: | 581 | case CPU_PM_ENTER: |
496 | gic_cpu_save(i); | 582 | gic_cpu_save(i); |
@@ -563,8 +649,9 @@ const struct irq_domain_ops gic_irq_domain_ops = { | |||
563 | #endif | 649 | #endif |
564 | }; | 650 | }; |
565 | 651 | ||
566 | void __init gic_init(unsigned int gic_nr, int irq_start, | 652 | void __init gic_init_bases(unsigned int gic_nr, int irq_start, |
567 | void __iomem *dist_base, void __iomem *cpu_base) | 653 | void __iomem *dist_base, void __iomem *cpu_base, |
654 | u32 percpu_offset) | ||
568 | { | 655 | { |
569 | struct gic_chip_data *gic; | 656 | struct gic_chip_data *gic; |
570 | struct irq_domain *domain; | 657 | struct irq_domain *domain; |
@@ -574,15 +661,42 @@ void __init gic_init(unsigned int gic_nr, int irq_start, | |||
574 | 661 | ||
575 | gic = &gic_data[gic_nr]; | 662 | gic = &gic_data[gic_nr]; |
576 | domain = &gic->domain; | 663 | domain = &gic->domain; |
577 | gic->dist_base = dist_base; | 664 | #ifdef CONFIG_GIC_NON_BANKED |
578 | gic->cpu_base = cpu_base; | 665 | if (percpu_offset) { /* Frankein-GIC without banked registers... */ |
666 | unsigned int cpu; | ||
667 | |||
668 | gic->dist_base.percpu_base = alloc_percpu(void __iomem *); | ||
669 | gic->cpu_base.percpu_base = alloc_percpu(void __iomem *); | ||
670 | if (WARN_ON(!gic->dist_base.percpu_base || | ||
671 | !gic->cpu_base.percpu_base)) { | ||
672 | free_percpu(gic->dist_base.percpu_base); | ||
673 | free_percpu(gic->cpu_base.percpu_base); | ||
674 | return; | ||
675 | } | ||
676 | |||
677 | for_each_possible_cpu(cpu) { | ||
678 | unsigned long offset = percpu_offset * cpu_logical_map(cpu); | ||
679 | *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset; | ||
680 | *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset; | ||
681 | } | ||
682 | |||
683 | gic_set_base_accessor(gic, gic_get_percpu_base); | ||
684 | } else | ||
685 | #endif | ||
686 | { /* Normal, sane GIC... */ | ||
687 | WARN(percpu_offset, | ||
688 | "GIC_NON_BANKED not enabled, ignoring %08x offset!", | ||
689 | percpu_offset); | ||
690 | gic->dist_base.common_base = dist_base; | ||
691 | gic->cpu_base.common_base = cpu_base; | ||
692 | gic_set_base_accessor(gic, gic_get_common_base); | ||
693 | } | ||
579 | 694 | ||
580 | /* | 695 | /* |
581 | * For primary GICs, skip over SGIs. | 696 | * For primary GICs, skip over SGIs. |
582 | * For secondary GICs, skip over PPIs, too. | 697 | * For secondary GICs, skip over PPIs, too. |
583 | */ | 698 | */ |
584 | if (gic_nr == 0) { | 699 | if (gic_nr == 0) { |
585 | gic_cpu_base_addr = cpu_base; | ||
586 | domain->hwirq_base = 16; | 700 | domain->hwirq_base = 16; |
587 | if (irq_start > 0) | 701 | if (irq_start > 0) |
588 | irq_start = (irq_start & ~31) + 16; | 702 | irq_start = (irq_start & ~31) + 16; |
@@ -593,7 +707,7 @@ void __init gic_init(unsigned int gic_nr, int irq_start, | |||
593 | * Find out how many interrupts are supported. | 707 | * Find out how many interrupts are supported. |
594 | * The GIC only supports up to 1020 interrupt sources. | 708 | * The GIC only supports up to 1020 interrupt sources. |
595 | */ | 709 | */ |
596 | gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; | 710 | gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f; |
597 | gic_irqs = (gic_irqs + 1) * 32; | 711 | gic_irqs = (gic_irqs + 1) * 32; |
598 | if (gic_irqs > 1020) | 712 | if (gic_irqs > 1020) |
599 | gic_irqs = 1020; | 713 | gic_irqs = 1020; |
@@ -641,7 +755,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) | |||
641 | dsb(); | 755 | dsb(); |
642 | 756 | ||
643 | /* this always happens on GIC0 */ | 757 | /* this always happens on GIC0 */ |
644 | writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); | 758 | writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); |
645 | } | 759 | } |
646 | #endif | 760 | #endif |
647 | 761 | ||
@@ -652,6 +766,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) | |||
652 | { | 766 | { |
653 | void __iomem *cpu_base; | 767 | void __iomem *cpu_base; |
654 | void __iomem *dist_base; | 768 | void __iomem *dist_base; |
769 | u32 percpu_offset; | ||
655 | int irq; | 770 | int irq; |
656 | struct irq_domain *domain = &gic_data[gic_cnt].domain; | 771 | struct irq_domain *domain = &gic_data[gic_cnt].domain; |
657 | 772 | ||
@@ -664,9 +779,12 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) | |||
664 | cpu_base = of_iomap(node, 1); | 779 | cpu_base = of_iomap(node, 1); |
665 | WARN(!cpu_base, "unable to map gic cpu registers\n"); | 780 | WARN(!cpu_base, "unable to map gic cpu registers\n"); |
666 | 781 | ||
782 | if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) | ||
783 | percpu_offset = 0; | ||
784 | |||
667 | domain->of_node = of_node_get(node); | 785 | domain->of_node = of_node_get(node); |
668 | 786 | ||
669 | gic_init(gic_cnt, -1, dist_base, cpu_base); | 787 | gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset); |
670 | 788 | ||
671 | if (parent) { | 789 | if (parent) { |
672 | irq = irq_of_parse_and_map(node, 0); | 790 | irq = irq_of_parse_and_map(node, 0); |