mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 22:51:35 +00:00
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_vpes;
|
||||
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 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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
case GIC_LOCAL_INT_PERFCTR:
|
||||
@ -713,12 +716,36 @@ static void __init __gic_init(unsigned long gic_base_addr,
|
||||
if (cpu_has_veic) {
|
||||
/* Always use vector 1 in EIC mode */
|
||||
gic_cpu_pin = 0;
|
||||
timer_cpu_pin = gic_cpu_pin;
|
||||
set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
|
||||
__gic_irq_dispatch);
|
||||
} else {
|
||||
gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
|
||||
irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
|
||||
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 +
|
||||
|
Loading…
Reference in New Issue
Block a user