Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip: loongson-liointc: Workaround LPC IRQ Errata

The 1.0 version of that controller has a bug that status bit
of LPC IRQ sometimes doesn't get set correctly.

So we can always blame LPC IRQ when spurious interrupt happens
at the parent interrupt line which LPC IRQ supposed to route
to.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Co-developed-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>

authored by

Jiaxun Yang and committed by
Thomas Bogendoerfer
be09ef09 dbb15226

+12 -2
+12 -2
drivers/irqchip/irq-loongson-liointc.c
··· 32 32 33 33 #define LIOINTC_SHIFT_INTx 4 34 34 35 + #define LIOINTC_ERRATA_IRQ 10 36 + 35 37 struct liointc_handler_data { 36 38 struct liointc_priv *priv; 37 39 u32 parent_int_map; ··· 43 41 struct irq_chip_generic *gc; 44 42 struct liointc_handler_data handler[LIOINTC_NUM_PARENT]; 45 43 u8 map_cache[LIOINTC_CHIP_IRQ]; 44 + bool has_lpc_irq_errata; 46 45 }; 47 46 48 47 static void liointc_chained_handle_irq(struct irq_desc *desc) ··· 57 54 58 55 pending = readl(gc->reg_base + LIOINTC_REG_INTC_STATUS); 59 56 60 - if (!pending) 61 - spurious_interrupt(); 57 + if (!pending) { 58 + /* Always blame LPC IRQ if we have that bug */ 59 + if (handler->priv->has_lpc_irq_errata && 60 + (handler->parent_int_map & ~gc->mask_cache & 61 + BIT(LIOINTC_ERRATA_IRQ))) 62 + pending = BIT(LIOINTC_ERRATA_IRQ); 63 + else 64 + spurious_interrupt(); 65 + } 62 66 63 67 while (pending) { 64 68 int bit = __ffs(pending);