Skip to content

Commit 6b1e065

Browse files
covanamKAGA-KOKO
authored andcommitted
irqchip/sifive-plic: Unmask interrupt in plic_irq_enable()
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 adds the IRQS_ONESHOT flag. But PREEMPT_RT only makes the problem more likely to appear, the bug has been around since commit a1706a1 ("irqchip/sifive-plic: Separate the enable and mask operations"). Fix it by unmasking interrupt in plic_irq_enable(). Fixes: a1706a1 ("irqchip/sifive-plic: Separate the enable and mask operations") Signed-off-by: Nam Cao <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/all/[email protected]
1 parent 1442ee0 commit 6b1e065

File tree

1 file changed

+11
-10
lines changed

1 file changed

+11
-10
lines changed

drivers/irqchip/irq-sifive-plic.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,6 @@ static inline void plic_irq_toggle(const struct cpumask *mask,
126126
}
127127
}
128128

129-
static void plic_irq_enable(struct irq_data *d)
130-
{
131-
plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1);
132-
}
133-
134-
static void plic_irq_disable(struct irq_data *d)
135-
{
136-
plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0);
137-
}
138-
139129
static void plic_irq_unmask(struct irq_data *d)
140130
{
141131
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
@@ -150,6 +140,17 @@ static void plic_irq_mask(struct irq_data *d)
150140
writel(0, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
151141
}
152142

143+
static void plic_irq_enable(struct irq_data *d)
144+
{
145+
plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1);
146+
plic_irq_unmask(d);
147+
}
148+
149+
static void plic_irq_disable(struct irq_data *d)
150+
{
151+
plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0);
152+
}
153+
153154
static void plic_irq_eoi(struct irq_data *d)
154155
{
155156
struct plic_handler *handler = this_cpu_ptr(&plic_handlers);

0 commit comments

Comments
 (0)