IRQCHIP: mips-gic: Avoid rerouting timer IRQs for smp-cmp
Commite9de688dac
("irqchip: mips-gic: Support local interrupts") changed the GIC irqchip driver so that all local interrupts were routed to the same CPU pin used for external interrupts. Unfortunately this causes a regression when smp-cmp is used. The CPUs are started by the bootloader and put in a timer based waiting poll loop, but when their timer interrupts are rerouted to a different IRQ pin which is not unmasked they never wake up. Since smp-cmp support is deprecated and everybody who was using it should be switching to smp-cps which brings up the secondary CPUs without bootloader assistance, I've gone for the simple fix which can be easily removed once smp-cmp is removed, rather than a fully generic fix. In __gic_init() the local GIC_VPE_TIMER_MAP register is read to find the boot-time routing of the local timer interrupt, and a chained handler is added to that CPU pin as well as the normal one. Signed-off-by: James Hogan <james.hogan@imgtec.com> Fixes:e9de688dac
("irqchip: mips-gic: Support local interrupts") Cc: Andrew Bresticker <abrestic@chromium.org> Cc: Qais Yousef <qais.yousef@imgtec.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: Jason Cooper <jason@lakedaemon.net> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-mips@linux-mips.org Reviewed-by: Andrew Bresticker <abrestic@chromium.org> Patchwork: https://patchwork.linux-mips.org/patch/9081/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
c2d9f17757
commit
1b6af71a8f
|
@ -37,6 +37,7 @@ static struct irq_domain *gic_irq_domain;
|
||||||
static int gic_shared_intrs;
|
static int gic_shared_intrs;
|
||||||
static int gic_vpes;
|
static int gic_vpes;
|
||||||
static unsigned int gic_cpu_pin;
|
static unsigned int gic_cpu_pin;
|
||||||
|
static unsigned int timer_cpu_pin;
|
||||||
static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
|
static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
|
||||||
|
|
||||||
static void __gic_irq_dispatch(void);
|
static void __gic_irq_dispatch(void);
|
||||||
|
@ -616,6 +617,8 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||||
gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val);
|
gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val);
|
||||||
break;
|
break;
|
||||||
case GIC_LOCAL_INT_TIMER:
|
case GIC_LOCAL_INT_TIMER:
|
||||||
|
/* CONFIG_MIPS_CMP workaround (see __gic_init) */
|
||||||
|
val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin;
|
||||||
gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val);
|
gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val);
|
||||||
break;
|
break;
|
||||||
case GIC_LOCAL_INT_PERFCTR:
|
case GIC_LOCAL_INT_PERFCTR:
|
||||||
|
@ -713,12 +716,36 @@ static void __init __gic_init(unsigned long gic_base_addr,
|
||||||
if (cpu_has_veic) {
|
if (cpu_has_veic) {
|
||||||
/* Always use vector 1 in EIC mode */
|
/* Always use vector 1 in EIC mode */
|
||||||
gic_cpu_pin = 0;
|
gic_cpu_pin = 0;
|
||||||
|
timer_cpu_pin = gic_cpu_pin;
|
||||||
set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
|
set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
|
||||||
__gic_irq_dispatch);
|
__gic_irq_dispatch);
|
||||||
} else {
|
} else {
|
||||||
gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
|
gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
|
||||||
irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
|
irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
|
||||||
gic_irq_dispatch);
|
gic_irq_dispatch);
|
||||||
|
/*
|
||||||
|
* With the CMP implementation of SMP (deprecated), other CPUs
|
||||||
|
* are started by the bootloader and put into a timer based
|
||||||
|
* waiting poll loop. We must not re-route those CPU's local
|
||||||
|
* timer interrupts as the wait instruction will never finish,
|
||||||
|
* so just handle whatever CPU interrupt it is routed to by
|
||||||
|
* default.
|
||||||
|
*
|
||||||
|
* This workaround should be removed when CMP support is
|
||||||
|
* dropped.
|
||||||
|
*/
|
||||||
|
if (IS_ENABLED(CONFIG_MIPS_CMP) &&
|
||||||
|
gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) {
|
||||||
|
timer_cpu_pin = gic_read(GIC_REG(VPE_LOCAL,
|
||||||
|
GIC_VPE_TIMER_MAP)) &
|
||||||
|
GIC_MAP_MSK;
|
||||||
|
irq_set_chained_handler(MIPS_CPU_IRQ_BASE +
|
||||||
|
GIC_CPU_PIN_OFFSET +
|
||||||
|
timer_cpu_pin,
|
||||||
|
gic_irq_dispatch);
|
||||||
|
} else {
|
||||||
|
timer_cpu_pin = gic_cpu_pin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS +
|
gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS +
|
||||||
|
|
Loading…
Reference in New Issue