* [PATCH] irqchip/sifive-plic: Unmask interrupt in plic_irq_enable()
@ 2024-09-26 15:43 Nam Cao
2024-10-02 14:00 ` Thomas Gleixner
0 siblings, 1 reply; 2+ messages in thread
From: Nam Cao @ 2024-09-26 15:43 UTC (permalink / raw)
To: Thomas Gleixner, Paul Walmsley, Samuel Holland, Marc Zyngier,
linux-kernel, linux-riscv
Cc: Nam Cao, stable
It is possible that an interrupt is disabled and masked at the same time.
When the interrupt is enabled again by enable_irq(), only plic_irq_enable()
is called, not plic_irq_unmask(). The interrupt remains masked and never
raises.
An example where interrupt is both disabled and masked is when
handle_fasteoi_irq() is the handler, and IRQS_ONESHOT is set. The interrupt
handler:
1. Mask the interrupt
2. Handle the interrupt
3. Check if interrupt is still enabled, and unmask it (see
cond_unmask_eoi_irq())
If another task disables the interrupt in the middle of the above steps,
the interrupt will not get unmasked, and will remain masked when it is
enabled in the future.
The problem is occasionally observed when PREEMPT_RT is enabled, because
PREEMPT_RT add the IRQS_ONESHOT flag. But PREEMPT_RT only makes the
problem more likely to appear, the bug has been around since
commit a1706a1c5062 ("irqchip/sifive-plic: Separate the enable and mask
operations").
Fix it by unmasking interrupt in plic_irq_enable().
Fixes: a1706a1c5062 ("irqchip/sifive-plic: Separate the enable and mask operations").
Signed-off-by: Nam Cao <namcao@linutronix.de>
Cc: stable@vger.kernel.org
---
drivers/irqchip/irq-sifive-plic.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index 2f6ef5c495bd..0efbf14ec9fa 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -128,6 +128,9 @@ static inline void plic_irq_toggle(const struct cpumask *mask,
static void plic_irq_enable(struct irq_data *d)
{
+ struct plic_priv *priv = irq_data_get_irq_chip_data(d);
+
+ writel(1, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1);
}
--
2.39.5
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] irqchip/sifive-plic: Unmask interrupt in plic_irq_enable()
2024-09-26 15:43 [PATCH] irqchip/sifive-plic: Unmask interrupt in plic_irq_enable() Nam Cao
@ 2024-10-02 14:00 ` Thomas Gleixner
0 siblings, 0 replies; 2+ messages in thread
From: Thomas Gleixner @ 2024-10-02 14:00 UTC (permalink / raw)
To: Nam Cao, Paul Walmsley, Samuel Holland, Marc Zyngier,
linux-kernel, linux-riscv
Cc: Nam Cao, stable
On Thu, Sep 26 2024 at 17:43, Nam Cao wrote:
> If another task disables the interrupt in the middle of the above steps,
> the interrupt will not get unmasked, and will remain masked when it is
> enabled in the future.
>
> The problem is occasionally observed when PREEMPT_RT is enabled, because
> PREEMPT_RT add the IRQS_ONESHOT flag. But PREEMPT_RT only makes the
> problem more likely to appear, the bug has been around since
> commit a1706a1c5062 ("irqchip/sifive-plic: Separate the enable and mask
> operations").
Correct. It's a general problem independent of RT.
> Fix it by unmasking interrupt in plic_irq_enable().
>
> Fixes: a1706a1c5062 ("irqchip/sifive-plic: Separate the enable and mask operations").
> Signed-off-by: Nam Cao <namcao@linutronix.de>
> Cc: stable@vger.kernel.org
> ---
> drivers/irqchip/irq-sifive-plic.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
> index 2f6ef5c495bd..0efbf14ec9fa 100644
> --- a/drivers/irqchip/irq-sifive-plic.c
> +++ b/drivers/irqchip/irq-sifive-plic.c
> @@ -128,6 +128,9 @@ static inline void plic_irq_toggle(const struct cpumask *mask,
>
> static void plic_irq_enable(struct irq_data *d)
> {
> + struct plic_priv *priv = irq_data_get_irq_chip_data(d);
> +
> + writel(1, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
> plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1);
Can you please move plic_irq_enable() below plic_irq_unmask() and invoke
the latter instead of duplicating the code?
Also usually unmask() is done after enable(), but the ordering probably
does not matter here.
Thanks,
tglx
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-10-02 14:00 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-26 15:43 [PATCH] irqchip/sifive-plic: Unmask interrupt in plic_irq_enable() Nam Cao
2024-10-02 14:00 ` Thomas Gleixner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox