diff options
-rw-r--r-- | arch/mips/include/asm/gic.h | 29 | ||||
-rw-r--r-- | arch/mips/include/asm/mips-boards/maltaint.h | 4 | ||||
-rw-r--r-- | arch/mips/include/asm/mips-boards/sead3int.h | 10 | ||||
-rw-r--r-- | arch/mips/kernel/cevt-gic.c | 15 | ||||
-rw-r--r-- | arch/mips/kernel/cevt-r4k.c | 2 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-int.c | 6 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-time.c | 13 | ||||
-rw-r--r-- | arch/mips/mti-sead3/sead3-time.c | 34 | ||||
-rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 291 |
9 files changed, 279 insertions, 125 deletions
diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index f2453958cbe5..6b996105c4fe 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h | |||
@@ -209,6 +209,7 @@ | |||
209 | #define GIC_VPE_WD_MAP_OFS 0x0040 | 209 | #define GIC_VPE_WD_MAP_OFS 0x0040 |
210 | #define GIC_VPE_COMPARE_MAP_OFS 0x0044 | 210 | #define GIC_VPE_COMPARE_MAP_OFS 0x0044 |
211 | #define GIC_VPE_TIMER_MAP_OFS 0x0048 | 211 | #define GIC_VPE_TIMER_MAP_OFS 0x0048 |
212 | #define GIC_VPE_FDC_MAP_OFS 0x004c | ||
212 | #define GIC_VPE_PERFCTR_MAP_OFS 0x0050 | 213 | #define GIC_VPE_PERFCTR_MAP_OFS 0x0050 |
213 | #define GIC_VPE_SWINT0_MAP_OFS 0x0054 | 214 | #define GIC_VPE_SWINT0_MAP_OFS 0x0054 |
214 | #define GIC_VPE_SWINT1_MAP_OFS 0x0058 | 215 | #define GIC_VPE_SWINT1_MAP_OFS 0x0058 |
@@ -262,6 +263,10 @@ | |||
262 | #define GIC_MAP_MSK (MSK(6) << GIC_MAP_SHF) | 263 | #define GIC_MAP_MSK (MSK(6) << GIC_MAP_SHF) |
263 | 264 | ||
264 | /* GIC_VPE_CTL Masks */ | 265 | /* GIC_VPE_CTL Masks */ |
266 | #define GIC_VPE_CTL_FDC_RTBL_SHF 4 | ||
267 | #define GIC_VPE_CTL_FDC_RTBL_MSK (MSK(1) << GIC_VPE_CTL_FDC_RTBL_SHF) | ||
268 | #define GIC_VPE_CTL_SWINT_RTBL_SHF 3 | ||
269 | #define GIC_VPE_CTL_SWINT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_SWINT_RTBL_SHF) | ||
265 | #define GIC_VPE_CTL_PERFCNT_RTBL_SHF 2 | 270 | #define GIC_VPE_CTL_PERFCNT_RTBL_SHF 2 |
266 | #define GIC_VPE_CTL_PERFCNT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF) | 271 | #define GIC_VPE_CTL_PERFCNT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF) |
267 | #define GIC_VPE_CTL_TIMER_RTBL_SHF 1 | 272 | #define GIC_VPE_CTL_TIMER_RTBL_SHF 1 |
@@ -329,16 +334,30 @@ | |||
329 | /* Add 2 to convert GIC CPU pin to core interrupt */ | 334 | /* Add 2 to convert GIC CPU pin to core interrupt */ |
330 | #define GIC_CPU_PIN_OFFSET 2 | 335 | #define GIC_CPU_PIN_OFFSET 2 |
331 | 336 | ||
332 | /* Local GIC interrupts. */ | ||
333 | #define GIC_INT_TMR (GIC_CPU_INT5) | ||
334 | #define GIC_INT_PERFCTR (GIC_CPU_INT5) | ||
335 | |||
336 | /* Add 2 to convert non-EIC hardware interrupt to EIC vector number. */ | 337 | /* Add 2 to convert non-EIC hardware interrupt to EIC vector number. */ |
337 | #define GIC_CPU_TO_VEC_OFFSET (2) | 338 | #define GIC_CPU_TO_VEC_OFFSET (2) |
338 | 339 | ||
339 | /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */ | 340 | /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */ |
340 | #define GIC_PIN_TO_VEC_OFFSET (1) | 341 | #define GIC_PIN_TO_VEC_OFFSET (1) |
341 | 342 | ||
343 | /* Local GIC interrupts. */ | ||
344 | #define GIC_LOCAL_INT_WD 0 /* GIC watchdog */ | ||
345 | #define GIC_LOCAL_INT_COMPARE 1 /* GIC count and compare timer */ | ||
346 | #define GIC_LOCAL_INT_TIMER 2 /* CPU timer interrupt */ | ||
347 | #define GIC_LOCAL_INT_PERFCTR 3 /* CPU performance counter */ | ||
348 | #define GIC_LOCAL_INT_SWINT0 4 /* CPU software interrupt 0 */ | ||
349 | #define GIC_LOCAL_INT_SWINT1 5 /* CPU software interrupt 1 */ | ||
350 | #define GIC_LOCAL_INT_FDC 6 /* CPU fast debug channel */ | ||
351 | #define GIC_NUM_LOCAL_INTRS 7 | ||
352 | |||
353 | /* Convert between local/shared IRQ number and GIC HW IRQ number. */ | ||
354 | #define GIC_LOCAL_HWIRQ_BASE 0 | ||
355 | #define GIC_LOCAL_TO_HWIRQ(x) (GIC_LOCAL_HWIRQ_BASE + (x)) | ||
356 | #define GIC_HWIRQ_TO_LOCAL(x) ((x) - GIC_LOCAL_HWIRQ_BASE) | ||
357 | #define GIC_SHARED_HWIRQ_BASE GIC_NUM_LOCAL_INTRS | ||
358 | #define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x)) | ||
359 | #define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE) | ||
360 | |||
342 | #include <linux/clocksource.h> | 361 | #include <linux/clocksource.h> |
343 | #include <linux/irq.h> | 362 | #include <linux/irq.h> |
344 | 363 | ||
@@ -363,4 +382,6 @@ extern void gic_bind_eic_interrupt(int irq, int set); | |||
363 | extern unsigned int gic_get_timer_pending(void); | 382 | extern unsigned int gic_get_timer_pending(void); |
364 | extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src); | 383 | extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src); |
365 | extern unsigned int gic_get_int(void); | 384 | extern unsigned int gic_get_int(void); |
385 | extern int gic_get_c0_compare_int(void); | ||
386 | extern int gic_get_c0_perfcount_int(void); | ||
366 | #endif /* _ASM_GICREGS_H */ | 387 | #endif /* _ASM_GICREGS_H */ |
diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h index bdd6f392f160..38b06a027437 100644 --- a/arch/mips/include/asm/mips-boards/maltaint.h +++ b/arch/mips/include/asm/mips-boards/maltaint.h | |||
@@ -10,6 +10,8 @@ | |||
10 | #ifndef _MIPS_MALTAINT_H | 10 | #ifndef _MIPS_MALTAINT_H |
11 | #define _MIPS_MALTAINT_H | 11 | #define _MIPS_MALTAINT_H |
12 | 12 | ||
13 | #include <asm/gic.h> | ||
14 | |||
13 | /* | 15 | /* |
14 | * Interrupts 0..15 are used for Malta ISA compatible interrupts | 16 | * Interrupts 0..15 are used for Malta ISA compatible interrupts |
15 | */ | 17 | */ |
@@ -61,6 +63,6 @@ | |||
61 | #define MSC01E_INT_CPUCTR 11 | 63 | #define MSC01E_INT_CPUCTR 11 |
62 | 64 | ||
63 | /* GIC external interrupts */ | 65 | /* GIC external interrupts */ |
64 | #define GIC_INT_I8259A 3 | 66 | #define GIC_INT_I8259A GIC_SHARED_TO_HWIRQ(3) |
65 | 67 | ||
66 | #endif /* !(_MIPS_MALTAINT_H) */ | 68 | #endif /* !(_MIPS_MALTAINT_H) */ |
diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h index a2e0095440fe..59d6c32c7595 100644 --- a/arch/mips/include/asm/mips-boards/sead3int.h +++ b/arch/mips/include/asm/mips-boards/sead3int.h | |||
@@ -10,6 +10,8 @@ | |||
10 | #ifndef _MIPS_SEAD3INT_H | 10 | #ifndef _MIPS_SEAD3INT_H |
11 | #define _MIPS_SEAD3INT_H | 11 | #define _MIPS_SEAD3INT_H |
12 | 12 | ||
13 | #include <asm/gic.h> | ||
14 | |||
13 | /* SEAD-3 GIC address space definitions. */ | 15 | /* SEAD-3 GIC address space definitions. */ |
14 | #define GIC_BASE_ADDR 0x1b1c0000 | 16 | #define GIC_BASE_ADDR 0x1b1c0000 |
15 | #define GIC_ADDRSPACE_SZ (128 * 1024) | 17 | #define GIC_ADDRSPACE_SZ (128 * 1024) |
@@ -22,9 +24,9 @@ | |||
22 | #define CPU_INT_NET 6 | 24 | #define CPU_INT_NET 6 |
23 | 25 | ||
24 | /* GIC interrupt offsets */ | 26 | /* GIC interrupt offsets */ |
25 | #define GIC_INT_NET 0 | 27 | #define GIC_INT_NET GIC_SHARED_TO_HWIRQ(0) |
26 | #define GIC_INT_UART1 2 | 28 | #define GIC_INT_UART1 GIC_SHARED_TO_HWIRQ(2) |
27 | #define GIC_INT_UART0 3 | 29 | #define GIC_INT_UART0 GIC_SHARED_TO_HWIRQ(3) |
28 | #define GIC_INT_EHCI 5 | 30 | #define GIC_INT_EHCI GIC_SHARED_TO_HWIRQ(5) |
29 | 31 | ||
30 | #endif /* !(_MIPS_SEAD3INT_H) */ | 32 | #endif /* !(_MIPS_SEAD3INT_H) */ |
diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c index a90bd4c81c7d..4f9262ab04f9 100644 --- a/arch/mips/kernel/cevt-gic.c +++ b/arch/mips/kernel/cevt-gic.c | |||
@@ -68,7 +68,7 @@ int gic_clockevent_init(void) | |||
68 | if (!cpu_has_counter || !gic_frequency) | 68 | if (!cpu_has_counter || !gic_frequency) |
69 | return -ENXIO; | 69 | return -ENXIO; |
70 | 70 | ||
71 | irq = MIPS_GIC_IRQ_BASE; | 71 | irq = MIPS_GIC_IRQ_BASE + GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); |
72 | 72 | ||
73 | cd = &per_cpu(gic_clockevent_device, cpu); | 73 | cd = &per_cpu(gic_clockevent_device, cpu); |
74 | 74 | ||
@@ -91,16 +91,13 @@ int gic_clockevent_init(void) | |||
91 | 91 | ||
92 | clockevents_register_device(cd); | 92 | clockevents_register_device(cd); |
93 | 93 | ||
94 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), | 94 | if (!gic_timer_irq_installed) { |
95 | GIC_MAP_TO_PIN_MSK | gic_cpu_pin); | 95 | setup_percpu_irq(irq, &gic_compare_irqaction); |
96 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK); | 96 | gic_timer_irq_installed = 1; |
97 | } | ||
97 | 98 | ||
98 | if (gic_timer_irq_installed) | 99 | enable_percpu_irq(irq, IRQ_TYPE_NONE); |
99 | return 0; | ||
100 | 100 | ||
101 | gic_timer_irq_installed = 1; | ||
102 | 101 | ||
103 | setup_irq(irq, &gic_compare_irqaction); | ||
104 | irq_set_handler(irq, handle_percpu_irq); | ||
105 | return 0; | 102 | return 0; |
106 | } | 103 | } |
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 5b8f8e32b47d..fd0ef8d851cc 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c | |||
@@ -86,7 +86,7 @@ void mips_event_handler(struct clock_event_device *dev) | |||
86 | static int c0_compare_int_pending(void) | 86 | static int c0_compare_int_pending(void) |
87 | { | 87 | { |
88 | #ifdef CONFIG_MIPS_GIC | 88 | #ifdef CONFIG_MIPS_GIC |
89 | if (cpu_has_veic) | 89 | if (gic_present) |
90 | return gic_get_timer_pending(); | 90 | return gic_get_timer_pending(); |
91 | #endif | 91 | #endif |
92 | return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP); | 92 | return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP); |
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index 3b3bc1d9ebf9..c6b35482505d 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c | |||
@@ -273,11 +273,7 @@ asmlinkage void plat_irq_dispatch(void) | |||
273 | 273 | ||
274 | irq = irq_ffs(pending); | 274 | irq = irq_ffs(pending); |
275 | 275 | ||
276 | /* HACK: GIC doesn't properly dispatch local interrupts yet */ | 276 | do_IRQ(MIPS_CPU_IRQ_BASE + irq); |
277 | if (gic_present && irq == MIPSCPU_INT_GIC && gic_compare_int()) | ||
278 | do_IRQ(MIPS_GIC_IRQ_BASE); | ||
279 | else | ||
280 | do_IRQ(MIPS_CPU_IRQ_BASE + irq); | ||
281 | } | 277 | } |
282 | 278 | ||
283 | #ifdef CONFIG_MIPS_MT_SMP | 279 | #ifdef CONFIG_MIPS_MT_SMP |
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 17cfc8a379a6..f6ca8ea4d992 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c | |||
@@ -126,9 +126,9 @@ int get_c0_perfcount_int(void) | |||
126 | if (cpu_has_veic) { | 126 | if (cpu_has_veic) { |
127 | set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); | 127 | set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); |
128 | mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; | 128 | mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; |
129 | } else if (gic_present) { | ||
130 | mips_cpu_perf_irq = gic_get_c0_perfcount_int(); | ||
129 | } else if (cp0_perfcount_irq >= 0) { | 131 | } else if (cp0_perfcount_irq >= 0) { |
130 | if (cpu_has_vint) | ||
131 | set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); | ||
132 | mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; | 132 | mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; |
133 | } else { | 133 | } else { |
134 | mips_cpu_perf_irq = -1; | 134 | mips_cpu_perf_irq = -1; |
@@ -139,15 +139,12 @@ int get_c0_perfcount_int(void) | |||
139 | 139 | ||
140 | unsigned int get_c0_compare_int(void) | 140 | unsigned int get_c0_compare_int(void) |
141 | { | 141 | { |
142 | #ifdef MSC01E_INT_BASE | ||
143 | if (cpu_has_veic) { | 142 | if (cpu_has_veic) { |
144 | set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch); | 143 | set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch); |
145 | mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; | 144 | mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; |
146 | } else | 145 | } else if (gic_present) { |
147 | #endif | 146 | mips_cpu_timer_irq = gic_get_c0_compare_int(); |
148 | { | 147 | } else { |
149 | if (cpu_has_vint) | ||
150 | set_vi_handler(cp0_compare_irq, mips_timer_dispatch); | ||
151 | mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; | 148 | mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; |
152 | } | 149 | } |
153 | 150 | ||
diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c index f090c5177719..fd40de352c57 100644 --- a/arch/mips/mti-sead3/sead3-time.c +++ b/arch/mips/mti-sead3/sead3-time.c | |||
@@ -8,24 +8,12 @@ | |||
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | 9 | ||
10 | #include <asm/cpu.h> | 10 | #include <asm/cpu.h> |
11 | #include <asm/gic.h> | ||
11 | #include <asm/setup.h> | 12 | #include <asm/setup.h> |
12 | #include <asm/time.h> | 13 | #include <asm/time.h> |
13 | #include <asm/irq.h> | 14 | #include <asm/irq.h> |
14 | #include <asm/mips-boards/generic.h> | 15 | #include <asm/mips-boards/generic.h> |
15 | 16 | ||
16 | static int mips_cpu_timer_irq; | ||
17 | static int mips_cpu_perf_irq; | ||
18 | |||
19 | static void mips_timer_dispatch(void) | ||
20 | { | ||
21 | do_IRQ(mips_cpu_timer_irq); | ||
22 | } | ||
23 | |||
24 | static void mips_perf_dispatch(void) | ||
25 | { | ||
26 | do_IRQ(mips_cpu_perf_irq); | ||
27 | } | ||
28 | |||
29 | static void __iomem *status_reg = (void __iomem *)0xbf000410; | 17 | static void __iomem *status_reg = (void __iomem *)0xbf000410; |
30 | 18 | ||
31 | /* | 19 | /* |
@@ -83,22 +71,18 @@ void read_persistent_clock(struct timespec *ts) | |||
83 | 71 | ||
84 | int get_c0_perfcount_int(void) | 72 | int get_c0_perfcount_int(void) |
85 | { | 73 | { |
86 | if (cp0_perfcount_irq >= 0) { | 74 | if (gic_present) |
87 | if (cpu_has_vint) | 75 | return gic_get_c0_compare_int(); |
88 | set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); | 76 | if (cp0_perfcount_irq >= 0) |
89 | mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; | 77 | return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; |
90 | } else { | 78 | return -1; |
91 | mips_cpu_perf_irq = -1; | ||
92 | } | ||
93 | return mips_cpu_perf_irq; | ||
94 | } | 79 | } |
95 | 80 | ||
96 | unsigned int get_c0_compare_int(void) | 81 | unsigned int get_c0_compare_int(void) |
97 | { | 82 | { |
98 | if (cpu_has_vint) | 83 | if (gic_present) |
99 | set_vi_handler(cp0_compare_irq, mips_timer_dispatch); | 84 | return gic_get_c0_compare_int(); |
100 | mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; | 85 | return MIPS_CPU_IRQ_BASE + cp0_compare_irq; |
101 | return mips_cpu_timer_irq; | ||
102 | } | 86 | } |
103 | 87 | ||
104 | void __init plat_time_init(void) | 88 | void __init plat_time_init(void) |
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 64d7d571df62..d4f631ec7338 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c | |||
@@ -44,6 +44,7 @@ static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; | |||
44 | static DEFINE_SPINLOCK(gic_lock); | 44 | static DEFINE_SPINLOCK(gic_lock); |
45 | static struct irq_domain *gic_irq_domain; | 45 | static struct irq_domain *gic_irq_domain; |
46 | static int gic_shared_intrs; | 46 | static int gic_shared_intrs; |
47 | static int gic_vpes; | ||
47 | static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; | 48 | static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; |
48 | 49 | ||
49 | static void __gic_irq_dispatch(void); | 50 | static void __gic_irq_dispatch(void); |
@@ -96,12 +97,35 @@ cycle_t gic_read_compare(void) | |||
96 | } | 97 | } |
97 | #endif | 98 | #endif |
98 | 99 | ||
100 | static bool gic_local_irq_is_routable(int intr) | ||
101 | { | ||
102 | u32 vpe_ctl; | ||
103 | |||
104 | /* All local interrupts are routable in EIC mode. */ | ||
105 | if (cpu_has_veic) | ||
106 | return true; | ||
107 | |||
108 | GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_CTL), vpe_ctl); | ||
109 | switch (intr) { | ||
110 | case GIC_LOCAL_INT_TIMER: | ||
111 | return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK; | ||
112 | case GIC_LOCAL_INT_PERFCTR: | ||
113 | return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK; | ||
114 | case GIC_LOCAL_INT_FDC: | ||
115 | return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK; | ||
116 | case GIC_LOCAL_INT_SWINT0: | ||
117 | case GIC_LOCAL_INT_SWINT1: | ||
118 | return vpe_ctl & GIC_VPE_CTL_SWINT_RTBL_MSK; | ||
119 | default: | ||
120 | return true; | ||
121 | } | ||
122 | } | ||
123 | |||
99 | unsigned int gic_get_timer_pending(void) | 124 | unsigned int gic_get_timer_pending(void) |
100 | { | 125 | { |
101 | unsigned int vpe_pending; | 126 | unsigned int vpe_pending; |
102 | 127 | ||
103 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0); | 128 | GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), vpe_pending); |
104 | GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending); | ||
105 | return vpe_pending & GIC_VPE_PEND_TIMER_MSK; | 129 | return vpe_pending & GIC_VPE_PEND_TIMER_MSK; |
106 | } | 130 | } |
107 | 131 | ||
@@ -119,53 +143,6 @@ void gic_send_ipi(unsigned int intr) | |||
119 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); | 143 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); |
120 | } | 144 | } |
121 | 145 | ||
122 | static void __init vpe_local_setup(unsigned int numvpes) | ||
123 | { | ||
124 | unsigned long timer_intr = GIC_INT_TMR; | ||
125 | unsigned long perf_intr = GIC_INT_PERFCTR; | ||
126 | unsigned int vpe_ctl; | ||
127 | int i; | ||
128 | |||
129 | if (cpu_has_veic) { | ||
130 | /* | ||
131 | * GIC timer interrupt -> CPU HW Int X (vector X+2) -> | ||
132 | * map to pin X+2-1 (since GIC adds 1) | ||
133 | */ | ||
134 | timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); | ||
135 | /* | ||
136 | * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) -> | ||
137 | * map to pin X+2-1 (since GIC adds 1) | ||
138 | */ | ||
139 | perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Setup the default performance counter timer interrupts | ||
144 | * for all VPEs | ||
145 | */ | ||
146 | for (i = 0; i < numvpes; i++) { | ||
147 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | ||
148 | |||
149 | /* Are Interrupts locally routable? */ | ||
150 | GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); | ||
151 | if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) | ||
152 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), | ||
153 | GIC_MAP_TO_PIN_MSK | timer_intr); | ||
154 | if (cpu_has_veic) { | ||
155 | set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET, | ||
156 | __gic_irq_dispatch); | ||
157 | } | ||
158 | |||
159 | if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) | ||
160 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), | ||
161 | GIC_MAP_TO_PIN_MSK | perf_intr); | ||
162 | if (cpu_has_veic) { | ||
163 | set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, | ||
164 | __gic_irq_dispatch); | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | unsigned int gic_compare_int(void) | 146 | unsigned int gic_compare_int(void) |
170 | { | 147 | { |
171 | unsigned int pending; | 148 | unsigned int pending; |
@@ -177,6 +154,26 @@ unsigned int gic_compare_int(void) | |||
177 | return 0; | 154 | return 0; |
178 | } | 155 | } |
179 | 156 | ||
157 | int gic_get_c0_compare_int(void) | ||
158 | { | ||
159 | if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) | ||
160 | return MIPS_CPU_IRQ_BASE + cp0_compare_irq; | ||
161 | return irq_create_mapping(gic_irq_domain, | ||
162 | GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER)); | ||
163 | } | ||
164 | |||
165 | int gic_get_c0_perfcount_int(void) | ||
166 | { | ||
167 | if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) { | ||
168 | /* Is the erformance counter shared with the timer? */ | ||
169 | if (cp0_perfcount_irq < 0) | ||
170 | return -1; | ||
171 | return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; | ||
172 | } | ||
173 | return irq_create_mapping(gic_irq_domain, | ||
174 | GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR)); | ||
175 | } | ||
176 | |||
180 | void gic_get_int_mask(unsigned long *dst, const unsigned long *src) | 177 | void gic_get_int_mask(unsigned long *dst, const unsigned long *src) |
181 | { | 178 | { |
182 | unsigned int i; | 179 | unsigned int i; |
@@ -217,24 +214,24 @@ unsigned int gic_get_int(void) | |||
217 | 214 | ||
218 | static void gic_mask_irq(struct irq_data *d) | 215 | static void gic_mask_irq(struct irq_data *d) |
219 | { | 216 | { |
220 | GIC_CLR_INTR_MASK(d->hwirq); | 217 | GIC_CLR_INTR_MASK(GIC_HWIRQ_TO_SHARED(d->hwirq)); |
221 | } | 218 | } |
222 | 219 | ||
223 | static void gic_unmask_irq(struct irq_data *d) | 220 | static void gic_unmask_irq(struct irq_data *d) |
224 | { | 221 | { |
225 | GIC_SET_INTR_MASK(d->hwirq); | 222 | GIC_SET_INTR_MASK(GIC_HWIRQ_TO_SHARED(d->hwirq)); |
226 | } | 223 | } |
227 | 224 | ||
228 | static void gic_ack_irq(struct irq_data *d) | 225 | static void gic_ack_irq(struct irq_data *d) |
229 | { | 226 | { |
230 | unsigned int irq = d->hwirq; | 227 | unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); |
231 | 228 | ||
232 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); | 229 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); |
233 | } | 230 | } |
234 | 231 | ||
235 | static int gic_set_type(struct irq_data *d, unsigned int type) | 232 | static int gic_set_type(struct irq_data *d, unsigned int type) |
236 | { | 233 | { |
237 | unsigned int irq = d->hwirq; | 234 | unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); |
238 | unsigned long flags; | 235 | unsigned long flags; |
239 | bool is_edge; | 236 | bool is_edge; |
240 | 237 | ||
@@ -291,7 +288,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) | |||
291 | static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, | 288 | static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, |
292 | bool force) | 289 | bool force) |
293 | { | 290 | { |
294 | unsigned int irq = d->hwirq; | 291 | unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); |
295 | cpumask_t tmp = CPU_MASK_NONE; | 292 | cpumask_t tmp = CPU_MASK_NONE; |
296 | unsigned long flags; | 293 | unsigned long flags; |
297 | int i; | 294 | int i; |
@@ -339,12 +336,85 @@ static struct irq_chip gic_edge_irq_controller = { | |||
339 | #endif | 336 | #endif |
340 | }; | 337 | }; |
341 | 338 | ||
339 | static unsigned int gic_get_local_int(void) | ||
340 | { | ||
341 | unsigned long pending, masked; | ||
342 | |||
343 | GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending); | ||
344 | GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_MASK), masked); | ||
345 | |||
346 | bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); | ||
347 | |||
348 | return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS); | ||
349 | } | ||
350 | |||
351 | static void gic_mask_local_irq(struct irq_data *d) | ||
352 | { | ||
353 | int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); | ||
354 | |||
355 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); | ||
356 | } | ||
357 | |||
358 | static void gic_unmask_local_irq(struct irq_data *d) | ||
359 | { | ||
360 | int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); | ||
361 | |||
362 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); | ||
363 | } | ||
364 | |||
365 | static struct irq_chip gic_local_irq_controller = { | ||
366 | .name = "MIPS GIC Local", | ||
367 | .irq_mask = gic_mask_local_irq, | ||
368 | .irq_unmask = gic_unmask_local_irq, | ||
369 | }; | ||
370 | |||
371 | static void gic_mask_local_irq_all_vpes(struct irq_data *d) | ||
372 | { | ||
373 | int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); | ||
374 | int i; | ||
375 | unsigned long flags; | ||
376 | |||
377 | spin_lock_irqsave(&gic_lock, flags); | ||
378 | for (i = 0; i < gic_vpes; i++) { | ||
379 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | ||
380 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); | ||
381 | } | ||
382 | spin_unlock_irqrestore(&gic_lock, flags); | ||
383 | } | ||
384 | |||
385 | static void gic_unmask_local_irq_all_vpes(struct irq_data *d) | ||
386 | { | ||
387 | int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); | ||
388 | int i; | ||
389 | unsigned long flags; | ||
390 | |||
391 | spin_lock_irqsave(&gic_lock, flags); | ||
392 | for (i = 0; i < gic_vpes; i++) { | ||
393 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | ||
394 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); | ||
395 | } | ||
396 | spin_unlock_irqrestore(&gic_lock, flags); | ||
397 | } | ||
398 | |||
399 | static struct irq_chip gic_all_vpes_local_irq_controller = { | ||
400 | .name = "MIPS GIC Local", | ||
401 | .irq_mask = gic_mask_local_irq_all_vpes, | ||
402 | .irq_unmask = gic_unmask_local_irq_all_vpes, | ||
403 | }; | ||
404 | |||
342 | static void __gic_irq_dispatch(void) | 405 | static void __gic_irq_dispatch(void) |
343 | { | 406 | { |
344 | unsigned int intr, virq; | 407 | unsigned int intr, virq; |
345 | 408 | ||
409 | while ((intr = gic_get_local_int()) != GIC_NUM_LOCAL_INTRS) { | ||
410 | virq = irq_linear_revmap(gic_irq_domain, | ||
411 | GIC_LOCAL_TO_HWIRQ(intr)); | ||
412 | do_IRQ(virq); | ||
413 | } | ||
414 | |||
346 | while ((intr = gic_get_int()) != gic_shared_intrs) { | 415 | while ((intr = gic_get_int()) != gic_shared_intrs) { |
347 | virq = irq_linear_revmap(gic_irq_domain, intr); | 416 | virq = irq_linear_revmap(gic_irq_domain, |
417 | GIC_SHARED_TO_HWIRQ(intr)); | ||
348 | do_IRQ(virq); | 418 | do_IRQ(virq); |
349 | } | 419 | } |
350 | } | 420 | } |
@@ -397,7 +467,8 @@ static struct irqaction irq_call = { | |||
397 | static __init void gic_ipi_init_one(unsigned int intr, int cpu, | 467 | static __init void gic_ipi_init_one(unsigned int intr, int cpu, |
398 | struct irqaction *action) | 468 | struct irqaction *action) |
399 | { | 469 | { |
400 | int virq = irq_create_mapping(gic_irq_domain, intr); | 470 | int virq = irq_create_mapping(gic_irq_domain, |
471 | GIC_SHARED_TO_HWIRQ(intr)); | ||
401 | int i; | 472 | int i; |
402 | 473 | ||
403 | GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); | 474 | GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); |
@@ -430,7 +501,7 @@ static inline void gic_ipi_init(void) | |||
430 | } | 501 | } |
431 | #endif | 502 | #endif |
432 | 503 | ||
433 | static void __init gic_basic_init(int numvpes) | 504 | static void __init gic_basic_init(void) |
434 | { | 505 | { |
435 | unsigned int i; | 506 | unsigned int i; |
436 | 507 | ||
@@ -443,28 +514,112 @@ static void __init gic_basic_init(int numvpes) | |||
443 | GIC_CLR_INTR_MASK(i); | 514 | GIC_CLR_INTR_MASK(i); |
444 | } | 515 | } |
445 | 516 | ||
446 | vpe_local_setup(numvpes); | 517 | for (i = 0; i < gic_vpes; i++) { |
518 | unsigned int j; | ||
519 | |||
520 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | ||
521 | for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { | ||
522 | if (!gic_local_irq_is_routable(j)) | ||
523 | continue; | ||
524 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); | ||
525 | } | ||
526 | } | ||
447 | } | 527 | } |
448 | 528 | ||
449 | static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, | 529 | static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, |
450 | irq_hw_number_t hw) | 530 | irq_hw_number_t hw) |
451 | { | 531 | { |
532 | int intr = GIC_HWIRQ_TO_LOCAL(hw); | ||
533 | int ret = 0; | ||
534 | int i; | ||
535 | unsigned long flags; | ||
536 | |||
537 | if (!gic_local_irq_is_routable(intr)) | ||
538 | return -EPERM; | ||
539 | |||
540 | /* | ||
541 | * HACK: These are all really percpu interrupts, but the rest | ||
542 | * of the MIPS kernel code does not use the percpu IRQ API for | ||
543 | * the CP0 timer and performance counter interrupts. | ||
544 | */ | ||
545 | if (intr != GIC_LOCAL_INT_TIMER && intr != GIC_LOCAL_INT_PERFCTR) { | ||
546 | irq_set_chip_and_handler(virq, | ||
547 | &gic_local_irq_controller, | ||
548 | handle_percpu_devid_irq); | ||
549 | irq_set_percpu_devid(virq); | ||
550 | } else { | ||
551 | irq_set_chip_and_handler(virq, | ||
552 | &gic_all_vpes_local_irq_controller, | ||
553 | handle_percpu_irq); | ||
554 | } | ||
555 | |||
556 | spin_lock_irqsave(&gic_lock, flags); | ||
557 | for (i = 0; i < gic_vpes; i++) { | ||
558 | u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin; | ||
559 | |||
560 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | ||
561 | |||
562 | switch (intr) { | ||
563 | case GIC_LOCAL_INT_WD: | ||
564 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); | ||
565 | break; | ||
566 | case GIC_LOCAL_INT_COMPARE: | ||
567 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val); | ||
568 | break; | ||
569 | case GIC_LOCAL_INT_TIMER: | ||
570 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val); | ||
571 | break; | ||
572 | case GIC_LOCAL_INT_PERFCTR: | ||
573 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val); | ||
574 | break; | ||
575 | case GIC_LOCAL_INT_SWINT0: | ||
576 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val); | ||
577 | break; | ||
578 | case GIC_LOCAL_INT_SWINT1: | ||
579 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val); | ||
580 | break; | ||
581 | case GIC_LOCAL_INT_FDC: | ||
582 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); | ||
583 | break; | ||
584 | default: | ||
585 | pr_err("Invalid local IRQ %d\n", intr); | ||
586 | ret = -EINVAL; | ||
587 | break; | ||
588 | } | ||
589 | } | ||
590 | spin_unlock_irqrestore(&gic_lock, flags); | ||
591 | |||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, | ||
596 | irq_hw_number_t hw) | ||
597 | { | ||
598 | int intr = GIC_HWIRQ_TO_SHARED(hw); | ||
452 | unsigned long flags; | 599 | unsigned long flags; |
453 | 600 | ||
454 | irq_set_chip_and_handler(virq, &gic_level_irq_controller, | 601 | irq_set_chip_and_handler(virq, &gic_level_irq_controller, |
455 | handle_level_irq); | 602 | handle_level_irq); |
456 | 603 | ||
457 | spin_lock_irqsave(&gic_lock, flags); | 604 | spin_lock_irqsave(&gic_lock, flags); |
458 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)), | 605 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), |
459 | GIC_MAP_TO_PIN_MSK | gic_cpu_pin); | 606 | GIC_MAP_TO_PIN_MSK | gic_cpu_pin); |
460 | /* Map to VPE 0 by default */ | 607 | /* Map to VPE 0 by default */ |
461 | GIC_SH_MAP_TO_VPE_SMASK(hw, 0); | 608 | GIC_SH_MAP_TO_VPE_SMASK(intr, 0); |
462 | set_bit(hw, pcpu_masks[0].pcpu_mask); | 609 | set_bit(intr, pcpu_masks[0].pcpu_mask); |
463 | spin_unlock_irqrestore(&gic_lock, flags); | 610 | spin_unlock_irqrestore(&gic_lock, flags); |
464 | 611 | ||
465 | return 0; | 612 | return 0; |
466 | } | 613 | } |
467 | 614 | ||
615 | static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, | ||
616 | irq_hw_number_t hw) | ||
617 | { | ||
618 | if (GIC_HWIRQ_TO_LOCAL(hw) < GIC_NUM_LOCAL_INTRS) | ||
619 | return gic_local_irq_domain_map(d, virq, hw); | ||
620 | return gic_shared_irq_domain_map(d, virq, hw); | ||
621 | } | ||
622 | |||
468 | static struct irq_domain_ops gic_irq_domain_ops = { | 623 | static struct irq_domain_ops gic_irq_domain_ops = { |
469 | .map = gic_irq_domain_map, | 624 | .map = gic_irq_domain_map, |
470 | .xlate = irq_domain_xlate_twocell, | 625 | .xlate = irq_domain_xlate_twocell, |
@@ -475,7 +630,6 @@ void __init gic_init(unsigned long gic_base_addr, | |||
475 | unsigned int irqbase) | 630 | unsigned int irqbase) |
476 | { | 631 | { |
477 | unsigned int gicconfig; | 632 | unsigned int gicconfig; |
478 | int numvpes, numintrs; | ||
479 | 633 | ||
480 | _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, | 634 | _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, |
481 | gic_addrspace_size); | 635 | gic_addrspace_size); |
@@ -485,9 +639,9 @@ void __init gic_init(unsigned long gic_base_addr, | |||
485 | GIC_SH_CONFIG_NUMINTRS_SHF; | 639 | GIC_SH_CONFIG_NUMINTRS_SHF; |
486 | gic_shared_intrs = ((gic_shared_intrs + 1) * 8); | 640 | gic_shared_intrs = ((gic_shared_intrs + 1) * 8); |
487 | 641 | ||
488 | numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> | 642 | gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> |
489 | GIC_SH_CONFIG_NUMVPES_SHF; | 643 | GIC_SH_CONFIG_NUMVPES_SHF; |
490 | numvpes = numvpes + 1; | 644 | gic_vpes = gic_vpes + 1; |
491 | 645 | ||
492 | if (cpu_has_veic) { | 646 | if (cpu_has_veic) { |
493 | /* Always use vector 1 in EIC mode */ | 647 | /* Always use vector 1 in EIC mode */ |
@@ -500,12 +654,13 @@ void __init gic_init(unsigned long gic_base_addr, | |||
500 | gic_irq_dispatch); | 654 | gic_irq_dispatch); |
501 | } | 655 | } |
502 | 656 | ||
503 | gic_irq_domain = irq_domain_add_simple(NULL, gic_shared_intrs, irqbase, | 657 | gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_LOCAL_INTRS + |
658 | gic_shared_intrs, irqbase, | ||
504 | &gic_irq_domain_ops, NULL); | 659 | &gic_irq_domain_ops, NULL); |
505 | if (!gic_irq_domain) | 660 | if (!gic_irq_domain) |
506 | panic("Failed to add GIC IRQ domain"); | 661 | panic("Failed to add GIC IRQ domain"); |
507 | 662 | ||
508 | gic_basic_init(numvpes); | 663 | gic_basic_init(); |
509 | 664 | ||
510 | gic_ipi_init(); | 665 | gic_ipi_init(); |
511 | } | 666 | } |