aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/irqchip/irq-mips-gic.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 2b0468e3df6a..56b96c63dc4b 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -37,6 +37,7 @@ static struct irq_domain *gic_irq_domain;
37static int gic_shared_intrs; 37static int gic_shared_intrs;
38static int gic_vpes; 38static int gic_vpes;
39static unsigned int gic_cpu_pin; 39static unsigned int gic_cpu_pin;
40static unsigned int timer_cpu_pin;
40static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; 41static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
41 42
42static void __gic_irq_dispatch(void); 43static void __gic_irq_dispatch(void);
@@ -616,6 +617,8 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
616 gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val); 617 gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val);
617 break; 618 break;
618 case GIC_LOCAL_INT_TIMER: 619 case GIC_LOCAL_INT_TIMER:
620 /* CONFIG_MIPS_CMP workaround (see __gic_init) */
621 val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin;
619 gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val); 622 gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val);
620 break; 623 break;
621 case GIC_LOCAL_INT_PERFCTR: 624 case GIC_LOCAL_INT_PERFCTR:
@@ -713,12 +716,36 @@ static void __init __gic_init(unsigned long gic_base_addr,
713 if (cpu_has_veic) { 716 if (cpu_has_veic) {
714 /* Always use vector 1 in EIC mode */ 717 /* Always use vector 1 in EIC mode */
715 gic_cpu_pin = 0; 718 gic_cpu_pin = 0;
719 timer_cpu_pin = gic_cpu_pin;
716 set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET, 720 set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
717 __gic_irq_dispatch); 721 __gic_irq_dispatch);
718 } else { 722 } else {
719 gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET; 723 gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
720 irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec, 724 irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
721 gic_irq_dispatch); 725 gic_irq_dispatch);
726 /*
727 * With the CMP implementation of SMP (deprecated), other CPUs
728 * are started by the bootloader and put into a timer based
729 * waiting poll loop. We must not re-route those CPU's local
730 * timer interrupts as the wait instruction will never finish,
731 * so just handle whatever CPU interrupt it is routed to by
732 * default.
733 *
734 * This workaround should be removed when CMP support is
735 * dropped.
736 */
737 if (IS_ENABLED(CONFIG_MIPS_CMP) &&
738 gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) {
739 timer_cpu_pin = gic_read(GIC_REG(VPE_LOCAL,
740 GIC_VPE_TIMER_MAP)) &
741 GIC_MAP_MSK;
742 irq_set_chained_handler(MIPS_CPU_IRQ_BASE +
743 GIC_CPU_PIN_OFFSET +
744 timer_cpu_pin,
745 gic_irq_dispatch);
746 } else {
747 timer_cpu_pin = gic_cpu_pin;
748 }
722 } 749 }
723 750
724 gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + 751 gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS +