| From 3688b0db5c331f4ec3fa5eb9f670a4b04f530700 Mon Sep 17 00:00:00 2001 |
| From: Grygorii Strashko <grygorii.strashko@ti.com> |
| Date: Wed, 8 Apr 2020 22:15:32 +0300 |
| Subject: irqchip/ti-sci-inta: Fix processing of masked irqs |
| |
| From: Grygorii Strashko <grygorii.strashko@ti.com> |
| |
| commit 3688b0db5c331f4ec3fa5eb9f670a4b04f530700 upstream. |
| |
| The ti_sci_inta_irq_handler() does not take into account INTA IRQs state |
| (masked/unmasked) as it uses INTA_STATUS_CLEAR_j register to get INTA IRQs |
| status, which provides raw status value. |
| This causes hard IRQ handlers to be called or threaded handlers to be |
| scheduled many times even if corresponding INTA IRQ is masked. |
| Above, first of all, affects the LEVEL interrupts processing and causes |
| unexpected behavior up the system stack or crash. |
| |
| Fix it by using the Interrupt Masked Status INTA_STATUSM_j register which |
| provides masked INTA IRQs status. |
| |
| Fixes: 9f1463b86c13 ("irqchip/ti-sci-inta: Add support for Interrupt Aggregator driver") |
| Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> |
| Signed-off-by: Marc Zyngier <maz@kernel.org> |
| Reviewed-by: Lokesh Vutla <lokeshvutla@ti.com> |
| Link: https://lore.kernel.org/r/20200408191532.31252-1-grygorii.strashko@ti.com |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/irqchip/irq-ti-sci-inta.c | 3 ++- |
| 1 file changed, 2 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/irqchip/irq-ti-sci-inta.c |
| +++ b/drivers/irqchip/irq-ti-sci-inta.c |
| @@ -37,6 +37,7 @@ |
| #define VINT_ENABLE_SET_OFFSET 0x0 |
| #define VINT_ENABLE_CLR_OFFSET 0x8 |
| #define VINT_STATUS_OFFSET 0x18 |
| +#define VINT_STATUS_MASKED_OFFSET 0x20 |
| |
| /** |
| * struct ti_sci_inta_event_desc - Description of an event coming to |
| @@ -116,7 +117,7 @@ static void ti_sci_inta_irq_handler(stru |
| chained_irq_enter(irq_desc_get_chip(desc), desc); |
| |
| val = readq_relaxed(inta->base + vint_desc->vint_id * 0x1000 + |
| - VINT_STATUS_OFFSET); |
| + VINT_STATUS_MASKED_OFFSET); |
| |
| for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT) { |
| virq = irq_find_mapping(domain, vint_desc->events[bit].hwirq); |