aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2011-11-12 11:09:49 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2011-11-15 13:13:03 -0500
commitdb0d4db22a78d31c59087f7057b8f1612fecc35d (patch)
treee2d84ee2c816d4bef066806863a3937792a08581 /arch/arm
parentcfcfc9eca2bcbd26a8e206baeb005b055dbf8e37 (diff)
ARM: gic: allow GIC to support non-banked setups
The GIC support code is heavily using the fact that hardware implementations are exposing banked registers. Unfortunately, it looks like at least one GIC implementation (EXYNOS) offers both the distributor and the CPU interfaces at different addresses, depending on the CPU. This problem is solved by allowing the distributor and CPU interface addresses to be per-cpu variables for the platforms that require it. The EXYNOS code is updated not to mess with the GIC internals while handling interrupts, and struct gic_chip_data is back to being private. The DT binding for the gic is updated to allow an optional "cpu-offset" value, which is used to compute the various base addresses. Finally, a new config option (GIC_NON_BANKED) is used to control this feature, so the overhead is only present on kernels compiled with support for EXYNOS. Tested on Origen (EXYNOS4) and Panda (OMAP4). Cc: Kukjin Kim <kgene.kim@samsung.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/common/Kconfig3
-rw-r--r--arch/arm/common/gic.c133
-rw-r--r--arch/arm/include/asm/hardware/gic.h24
-rw-r--r--arch/arm/mach-exynos/cpu.c16
-rw-r--r--arch/arm/mach-exynos/platsmp.c28
-rw-r--r--arch/arm/plat-s5p/Kconfig1
6 files changed, 128 insertions, 77 deletions
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 74df9ca2be3..a3beda1213d 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -2,6 +2,9 @@ config ARM_GIC
2 select IRQ_DOMAIN 2 select IRQ_DOMAIN
3 bool 3 bool
4 4
5config GIC_NON_BANKED
6 bool
7
5config ARM_VIC 8config ARM_VIC
6 bool 9 bool
7 10
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 0e6ae470c94..43cb6f1a7cf 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -43,6 +43,31 @@
43#include <asm/mach/irq.h> 43#include <asm/mach/irq.h>
44#include <asm/hardware/gic.h> 44#include <asm/hardware/gic.h>
45 45
46union gic_base {
47 void __iomem *common_base;
48 void __percpu __iomem **percpu_base;
49};
50
51struct gic_chip_data {
52 unsigned int irq_offset;
53 union gic_base dist_base;
54 union gic_base cpu_base;
55#ifdef CONFIG_CPU_PM
56 u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
57 u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
58 u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
59 u32 __percpu *saved_ppi_enable;
60 u32 __percpu *saved_ppi_conf;
61#endif
62#ifdef CONFIG_IRQ_DOMAIN
63 struct irq_domain domain;
64#endif
65 unsigned int gic_irqs;
66#ifdef CONFIG_GIC_NON_BANKED
67 void __iomem *(*get_base)(union gic_base *);
68#endif
69};
70
46static DEFINE_RAW_SPINLOCK(irq_controller_lock); 71static DEFINE_RAW_SPINLOCK(irq_controller_lock);
47 72
48/* Address of GIC 0 CPU interface */ 73/* Address of GIC 0 CPU interface */
@@ -67,16 +92,48 @@ struct irq_chip gic_arch_extn = {
67 92
68static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly; 93static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
69 94
95#ifdef CONFIG_GIC_NON_BANKED
96static void __iomem *gic_get_percpu_base(union gic_base *base)
97{
98 return *__this_cpu_ptr(base->percpu_base);
99}
100
101static void __iomem *gic_get_common_base(union gic_base *base)
102{
103 return base->common_base;
104}
105
106static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
107{
108 return data->get_base(&data->dist_base);
109}
110
111static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
112{
113 return data->get_base(&data->cpu_base);
114}
115
116static inline void gic_set_base_accessor(struct gic_chip_data *data,
117 void __iomem *(*f)(union gic_base *))
118{
119 data->get_base = f;
120}
121#else
122#define gic_data_dist_base(d) ((d)->dist_base.common_base)
123#define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
124#define gic_set_base_accessor(d,f)
125#endif
126
70static inline void __iomem *gic_dist_base(struct irq_data *d) 127static inline void __iomem *gic_dist_base(struct irq_data *d)
71{ 128{
72 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); 129 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
73 return gic_data->dist_base; 130 return gic_data_dist_base(gic_data);
74} 131}
75 132
76static inline void __iomem *gic_cpu_base(struct irq_data *d) 133static inline void __iomem *gic_cpu_base(struct irq_data *d)
77{ 134{
78 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); 135 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
79 return gic_data->cpu_base; 136 return gic_data_cpu_base(gic_data);
80} 137}
81 138
82static inline unsigned int gic_irq(struct irq_data *d) 139static inline unsigned int gic_irq(struct irq_data *d)
@@ -225,7 +282,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
225 chained_irq_enter(chip, desc); 282 chained_irq_enter(chip, desc);
226 283
227 raw_spin_lock(&irq_controller_lock); 284 raw_spin_lock(&irq_controller_lock);
228 status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK); 285 status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
229 raw_spin_unlock(&irq_controller_lock); 286 raw_spin_unlock(&irq_controller_lock);
230 287
231 gic_irq = (status & 0x3ff); 288 gic_irq = (status & 0x3ff);
@@ -270,7 +327,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
270 u32 cpumask; 327 u32 cpumask;
271 unsigned int gic_irqs = gic->gic_irqs; 328 unsigned int gic_irqs = gic->gic_irqs;
272 struct irq_domain *domain = &gic->domain; 329 struct irq_domain *domain = &gic->domain;
273 void __iomem *base = gic->dist_base; 330 void __iomem *base = gic_data_dist_base(gic);
274 u32 cpu = 0; 331 u32 cpu = 0;
275 332
276#ifdef CONFIG_SMP 333#ifdef CONFIG_SMP
@@ -330,8 +387,8 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
330 387
331static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) 388static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
332{ 389{
333 void __iomem *dist_base = gic->dist_base; 390 void __iomem *dist_base = gic_data_dist_base(gic);
334 void __iomem *base = gic->cpu_base; 391 void __iomem *base = gic_data_cpu_base(gic);
335 int i; 392 int i;
336 393
337 /* 394 /*
@@ -368,7 +425,7 @@ static void gic_dist_save(unsigned int gic_nr)
368 BUG(); 425 BUG();
369 426
370 gic_irqs = gic_data[gic_nr].gic_irqs; 427 gic_irqs = gic_data[gic_nr].gic_irqs;
371 dist_base = gic_data[gic_nr].dist_base; 428 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
372 429
373 if (!dist_base) 430 if (!dist_base)
374 return; 431 return;
@@ -403,7 +460,7 @@ static void gic_dist_restore(unsigned int gic_nr)
403 BUG(); 460 BUG();
404 461
405 gic_irqs = gic_data[gic_nr].gic_irqs; 462 gic_irqs = gic_data[gic_nr].gic_irqs;
406 dist_base = gic_data[gic_nr].dist_base; 463 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
407 464
408 if (!dist_base) 465 if (!dist_base)
409 return; 466 return;
@@ -439,8 +496,8 @@ static void gic_cpu_save(unsigned int gic_nr)
439 if (gic_nr >= MAX_GIC_NR) 496 if (gic_nr >= MAX_GIC_NR)
440 BUG(); 497 BUG();
441 498
442 dist_base = gic_data[gic_nr].dist_base; 499 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
443 cpu_base = gic_data[gic_nr].cpu_base; 500 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
444 501
445 if (!dist_base || !cpu_base) 502 if (!dist_base || !cpu_base)
446 return; 503 return;
@@ -465,8 +522,8 @@ static void gic_cpu_restore(unsigned int gic_nr)
465 if (gic_nr >= MAX_GIC_NR) 522 if (gic_nr >= MAX_GIC_NR)
466 BUG(); 523 BUG();
467 524
468 dist_base = gic_data[gic_nr].dist_base; 525 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
469 cpu_base = gic_data[gic_nr].cpu_base; 526 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
470 527
471 if (!dist_base || !cpu_base) 528 if (!dist_base || !cpu_base)
472 return; 529 return;
@@ -491,6 +548,11 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
491 int i; 548 int i;
492 549
493 for (i = 0; i < MAX_GIC_NR; i++) { 550 for (i = 0; i < MAX_GIC_NR; i++) {
551#ifdef CONFIG_GIC_NON_BANKED
552 /* Skip over unused GICs */
553 if (!gic_data[i].get_base)
554 continue;
555#endif
494 switch (cmd) { 556 switch (cmd) {
495 case CPU_PM_ENTER: 557 case CPU_PM_ENTER:
496 gic_cpu_save(i); 558 gic_cpu_save(i);
@@ -563,8 +625,9 @@ const struct irq_domain_ops gic_irq_domain_ops = {
563#endif 625#endif
564}; 626};
565 627
566void __init gic_init(unsigned int gic_nr, int irq_start, 628void __init gic_init_bases(unsigned int gic_nr, int irq_start,
567 void __iomem *dist_base, void __iomem *cpu_base) 629 void __iomem *dist_base, void __iomem *cpu_base,
630 u32 percpu_offset)
568{ 631{
569 struct gic_chip_data *gic; 632 struct gic_chip_data *gic;
570 struct irq_domain *domain; 633 struct irq_domain *domain;
@@ -574,8 +637,36 @@ void __init gic_init(unsigned int gic_nr, int irq_start,
574 637
575 gic = &gic_data[gic_nr]; 638 gic = &gic_data[gic_nr];
576 domain = &gic->domain; 639 domain = &gic->domain;
577 gic->dist_base = dist_base; 640#ifdef CONFIG_GIC_NON_BANKED
578 gic->cpu_base = cpu_base; 641 if (percpu_offset) { /* Frankein-GIC without banked registers... */
642 unsigned int cpu;
643
644 gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
645 gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
646 if (WARN_ON(!gic->dist_base.percpu_base ||
647 !gic->cpu_base.percpu_base)) {
648 free_percpu(gic->dist_base.percpu_base);
649 free_percpu(gic->cpu_base.percpu_base);
650 return;
651 }
652
653 for_each_possible_cpu(cpu) {
654 unsigned long offset = percpu_offset * cpu_logical_map(cpu);
655 *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
656 *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
657 }
658
659 gic_set_base_accessor(gic, gic_get_percpu_base);
660 } else
661#endif
662 { /* Normal, sane GIC... */
663 WARN(percpu_offset,
664 "GIC_NON_BANKED not enabled, ignoring %08x offset!",
665 percpu_offset);
666 gic->dist_base.common_base = dist_base;
667 gic->cpu_base.common_base = cpu_base;
668 gic_set_base_accessor(gic, gic_get_common_base);
669 }
579 670
580 /* 671 /*
581 * For primary GICs, skip over SGIs. 672 * For primary GICs, skip over SGIs.
@@ -593,7 +684,7 @@ void __init gic_init(unsigned int gic_nr, int irq_start,
593 * Find out how many interrupts are supported. 684 * Find out how many interrupts are supported.
594 * The GIC only supports up to 1020 interrupt sources. 685 * The GIC only supports up to 1020 interrupt sources.
595 */ 686 */
596 gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; 687 gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
597 gic_irqs = (gic_irqs + 1) * 32; 688 gic_irqs = (gic_irqs + 1) * 32;
598 if (gic_irqs > 1020) 689 if (gic_irqs > 1020)
599 gic_irqs = 1020; 690 gic_irqs = 1020;
@@ -641,7 +732,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
641 dsb(); 732 dsb();
642 733
643 /* this always happens on GIC0 */ 734 /* this always happens on GIC0 */
644 writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); 735 writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
645} 736}
646#endif 737#endif
647 738
@@ -652,6 +743,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
652{ 743{
653 void __iomem *cpu_base; 744 void __iomem *cpu_base;
654 void __iomem *dist_base; 745 void __iomem *dist_base;
746 u32 percpu_offset;
655 int irq; 747 int irq;
656 struct irq_domain *domain = &gic_data[gic_cnt].domain; 748 struct irq_domain *domain = &gic_data[gic_cnt].domain;
657 749
@@ -664,9 +756,12 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
664 cpu_base = of_iomap(node, 1); 756 cpu_base = of_iomap(node, 1);
665 WARN(!cpu_base, "unable to map gic cpu registers\n"); 757 WARN(!cpu_base, "unable to map gic cpu registers\n");
666 758
759 if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
760 percpu_offset = 0;
761
667 domain->of_node = of_node_get(node); 762 domain->of_node = of_node_get(node);
668 763
669 gic_init(gic_cnt, -1, dist_base, cpu_base); 764 gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
670 765
671 if (parent) { 766 if (parent) {
672 irq = irq_of_parse_and_map(node, 0); 767 irq = irq_of_parse_and_map(node, 0);
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 3e91f22046f..2721d90625e 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -39,27 +39,19 @@ struct device_node;
39extern void __iomem *gic_cpu_base_addr; 39extern void __iomem *gic_cpu_base_addr;
40extern struct irq_chip gic_arch_extn; 40extern struct irq_chip gic_arch_extn;
41 41
42void gic_init(unsigned int, int, void __iomem *, void __iomem *); 42void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
43 u32 offset);
43int gic_of_init(struct device_node *node, struct device_node *parent); 44int gic_of_init(struct device_node *node, struct device_node *parent);
44void gic_secondary_init(unsigned int); 45void gic_secondary_init(unsigned int);
45void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); 46void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
46void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); 47void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
47 48
48struct gic_chip_data { 49static inline void gic_init(unsigned int nr, int start,
49 void __iomem *dist_base; 50 void __iomem *dist , void __iomem *cpu)
50 void __iomem *cpu_base; 51{
51#ifdef CONFIG_CPU_PM 52 gic_init_bases(nr, start, dist, cpu, 0);
52 u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; 53}
53 u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; 54
54 u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
55 u32 __percpu *saved_ppi_enable;
56 u32 __percpu *saved_ppi_conf;
57#endif
58#ifdef CONFIG_IRQ_DOMAIN
59 struct irq_domain domain;
60#endif
61 unsigned int gic_irqs;
62};
63#endif 55#endif
64 56
65#endif 57#endif
diff --git a/arch/arm/mach-exynos/cpu.c b/arch/arm/mach-exynos/cpu.c
index 90ec247f3b3..e92e464bdbb 100644
--- a/arch/arm/mach-exynos/cpu.c
+++ b/arch/arm/mach-exynos/cpu.c
@@ -207,27 +207,13 @@ void __init exynos4_init_clocks(int xtal)
207 exynos4_setup_clocks(); 207 exynos4_setup_clocks();
208} 208}
209 209
210static void exynos4_gic_irq_fix_base(struct irq_data *d)
211{
212 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
213
214 gic_data->cpu_base = S5P_VA_GIC_CPU +
215 (gic_bank_offset * smp_processor_id());
216
217 gic_data->dist_base = S5P_VA_GIC_DIST +
218 (gic_bank_offset * smp_processor_id());
219}
220
221void __init exynos4_init_irq(void) 210void __init exynos4_init_irq(void)
222{ 211{
223 int irq; 212 int irq;
224 213
225 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; 214 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
226 215
227 gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU); 216 gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset);
228 gic_arch_extn.irq_eoi = exynos4_gic_irq_fix_base;
229 gic_arch_extn.irq_unmask = exynos4_gic_irq_fix_base;
230 gic_arch_extn.irq_mask = exynos4_gic_irq_fix_base;
231 217
232 for (irq = 0; irq < MAX_COMBINER_NR; irq++) { 218 for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
233 219
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 69ffb2fb387..60bc45e3e70 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -32,7 +32,6 @@
32 32
33#include <plat/cpu.h> 33#include <plat/cpu.h>
34 34
35extern unsigned int gic_bank_offset;
36extern void exynos4_secondary_startup(void); 35extern void exynos4_secondary_startup(void);
37 36
38#define CPU1_BOOT_REG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ 37#define CPU1_BOOT_REG (samsung_rev() == EXYNOS4210_REV_1_1 ? \
@@ -65,31 +64,6 @@ static void __iomem *scu_base_addr(void)
65 64
66static DEFINE_SPINLOCK(boot_lock); 65static DEFINE_SPINLOCK(boot_lock);
67 66
68static void __cpuinit exynos4_gic_secondary_init(void)
69{
70 void __iomem *dist_base = S5P_VA_GIC_DIST +
71 (gic_bank_offset * smp_processor_id());
72 void __iomem *cpu_base = S5P_VA_GIC_CPU +
73 (gic_bank_offset * smp_processor_id());
74 int i;
75
76 /*
77 * Deal with the banked PPI and SGI interrupts - disable all
78 * PPI interrupts, ensure all SGI interrupts are enabled.
79 */
80 __raw_writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
81 __raw_writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
82
83 /*
84 * Set priority on PPI and SGI interrupts
85 */
86 for (i = 0; i < 32; i += 4)
87 __raw_writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
88
89 __raw_writel(0xf0, cpu_base + GIC_CPU_PRIMASK);
90 __raw_writel(1, cpu_base + GIC_CPU_CTRL);
91}
92
93void __cpuinit platform_secondary_init(unsigned int cpu) 67void __cpuinit platform_secondary_init(unsigned int cpu)
94{ 68{
95 /* 69 /*
@@ -97,7 +71,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
97 * core (e.g. timer irq), then they will not have been enabled 71 * core (e.g. timer irq), then they will not have been enabled
98 * for us: do so 72 * for us: do so
99 */ 73 */
100 exynos4_gic_secondary_init(); 74 gic_secondary_init(0);
101 75
102 /* 76 /*
103 * let the primary processor know we're out of the 77 * let the primary processor know we're out of the
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 9b9968fa869..8167ce66188 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -11,6 +11,7 @@ config PLAT_S5P
11 default y 11 default y
12 select ARM_VIC if !ARCH_EXYNOS4 12 select ARM_VIC if !ARCH_EXYNOS4
13 select ARM_GIC if ARCH_EXYNOS4 13 select ARM_GIC if ARCH_EXYNOS4
14 select GIC_NON_BANKED if ARCH_EXYNOS4
14 select NO_IOPORT 15 select NO_IOPORT
15 select ARCH_REQUIRE_GPIOLIB 16 select ARCH_REQUIRE_GPIOLIB
16 select S3C_GPIO_TRACK 17 select S3C_GPIO_TRACK