summaryrefslogtreecommitdiff
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorJiaxun Yang <jiaxun.yang@flygoat.com>2020-03-25 11:54:55 +0800
committerThomas Bogendoerfer <tsbogend@alpha.franken.de>2020-03-25 10:56:00 +0100
commitbe09ef09e290e1c8bd361e431d3659e13e65094c (patch)
treef2a684ee425d50e46449990d653129b2dd29fa3b /drivers/irqchip
parentdbb152267908c4b2c3639492a94b6838821bc195 (diff)
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>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/irq-loongson-liointc.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c
index 18de2c09ece4..63b61474a0cc 100644
--- a/drivers/irqchip/irq-loongson-liointc.c
+++ b/drivers/irqchip/irq-loongson-liointc.c
@@ -32,6 +32,8 @@
#define LIOINTC_SHIFT_INTx 4
+#define LIOINTC_ERRATA_IRQ 10
+
struct liointc_handler_data {
struct liointc_priv *priv;
u32 parent_int_map;
@@ -41,6 +43,7 @@ struct liointc_priv {
struct irq_chip_generic *gc;
struct liointc_handler_data handler[LIOINTC_NUM_PARENT];
u8 map_cache[LIOINTC_CHIP_IRQ];
+ bool has_lpc_irq_errata;
};
static void liointc_chained_handle_irq(struct irq_desc *desc)
@@ -54,8 +57,15 @@ static void liointc_chained_handle_irq(struct irq_desc *desc)
pending = readl(gc->reg_base + LIOINTC_REG_INTC_STATUS);
- if (!pending)
- spurious_interrupt();
+ if (!pending) {
+ /* Always blame LPC IRQ if we have that bug */
+ if (handler->priv->has_lpc_irq_errata &&
+ (handler->parent_int_map & ~gc->mask_cache &
+ BIT(LIOINTC_ERRATA_IRQ)))
+ pending = BIT(LIOINTC_ERRATA_IRQ);
+ else
+ spurious_interrupt();
+ }
while (pending) {
int bit = __ffs(pending);