aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorAndrew Bresticker <abrestic@chromium.org>2014-09-18 17:47:27 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-11-24 01:44:56 -0500
commite9de688dac6534e72d000e9069be2f929a6087be (patch)
treee1dd1dbbe4727982177d90a7cd161703a0d7dd16 /drivers/irqchip
parent4a6a3ea392306b04fc687d4314efba562121cc9a (diff)
irqchip: mips-gic: Support local interrupts
The MIPS GIC supports 7 local interrupts, 2 of which are the GIC local watchdog and count/compare timer. The remainder are CPU interrupts which may optionally be re-routed through the GIC. GIC hardware IRQs 0-6 are now used for local interrupts while hardware IRQs 7+ are used for external (shared) interrupts. Note that the 5 CPU interrupts may not be re-routable through the GIC. In that case mapping will fail and the vectors reported in C0_IntCtl should be used instead. gic_get_c0_compare_int() and gic_get_c0_perfcount_int() will return the correct IRQ number to use for the C0 timer and perfcounter interrupts based on the routability of those interrupts through the GIC. A separate irq_chip, with callbacks that mask/unmask the local interrupt on all CPUs, is used for the C0 timer and performance counter interrupts since all other platforms do not use the percpu IRQ API for those interrupts. Malta, SEAD-3, and the GIC clockevent driver have been updated to use local interrupts and the R4K clockevent driver has been updated to poll for C0 timer interrupts through the GIC when the GIC is present. Signed-off-by: Andrew Bresticker <abrestic@chromium.org> Acked-by: Jason Cooper <jason@lakedaemon.net> Reviewed-by: Qais Yousef <qais.yousef@imgtec.com> Tested-by: Qais Yousef <qais.yousef@imgtec.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jeffrey Deans <jeffrey.deans@imgtec.com> Cc: Markos Chandras <markos.chandras@imgtec.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: Jonas Gorski <jogo@openwrt.org> Cc: John Crispin <blogic@openwrt.org> Cc: David Daney <ddaney.cavm@gmail.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7819/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/irq-mips-gic.c291
1 files changed, 223 insertions, 68 deletions
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];
44static DEFINE_SPINLOCK(gic_lock); 44static DEFINE_SPINLOCK(gic_lock);
45static struct irq_domain *gic_irq_domain; 45static struct irq_domain *gic_irq_domain;
46static int gic_shared_intrs; 46static int gic_shared_intrs;
47static int gic_vpes;
47static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; 48static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
48 49
49static void __gic_irq_dispatch(void); 50static void __gic_irq_dispatch(void);
@@ -96,12 +97,35 @@ cycle_t gic_read_compare(void)
96} 97}
97#endif 98#endif
98 99
100static 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
99unsigned int gic_get_timer_pending(void) 124unsigned 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
122static 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
169unsigned int gic_compare_int(void) 146unsigned 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
157int 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
165int 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
180void gic_get_int_mask(unsigned long *dst, const unsigned long *src) 177void 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
218static void gic_mask_irq(struct irq_data *d) 215static 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
223static void gic_unmask_irq(struct irq_data *d) 220static 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
228static void gic_ack_irq(struct irq_data *d) 225static 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
235static int gic_set_type(struct irq_data *d, unsigned int type) 232static 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)
291static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, 288static 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
339static 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
351static 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
358static 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
365static 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
371static 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
385static 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
399static 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
342static void __gic_irq_dispatch(void) 405static 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 = {
397static __init void gic_ipi_init_one(unsigned int intr, int cpu, 467static __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
433static void __init gic_basic_init(int numvpes) 504static 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
449static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, 529static 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
595static 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
615static 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
468static struct irq_domain_ops gic_irq_domain_ops = { 623static 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}