Skip to content

Commit e579076

Browse files
qiuguorui1Marc Zyngier
authored andcommitted
irqchip/stm32-exti: Avoid losing interrupts due to clearing pending bits by mistake
In the current code, when the eoi callback of the exti clears the pending bit of the current interrupt, it will first read the values of fpr and rpr, then logically OR the corresponding bit of the interrupt number, and finally write back to fpr and rpr. We found through experiments that if two exti interrupts, we call them int1/int2, arrive almost at the same time. in our scenario, the time difference is 30 microseconds, assuming int1 is triggered first. there will be an extreme scenario: both int's pending bit are set to 1, the irq handle of int1 is executed first, and eoi handle is then executed, at this moment, all pending bits are cleared, but the int 2 has not finally been reported to the cpu yet, which eventually lost int2. According to stm32's TRM description about rpr and fpr: Writing a 1 to this bit will trigger a rising edge event on event x, Writing 0 has no effect. Therefore, when clearing the pending bit, we only need to clear the pending bit of the irq. Fixes: 927abfc ("irqchip/stm32: Add stm32mp1 support with hierarchy domain") Signed-off-by: qiuguorui1 <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Cc: [email protected] # v4.18+ Link: https://lore.kernel.org/r/[email protected]
1 parent a150dac commit e579076

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

drivers/irqchip/irq-stm32-exti.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,16 @@ static void stm32_irq_ack(struct irq_data *d)
416416
irq_gc_unlock(gc);
417417
}
418418

419+
/* directly set the target bit without reading first. */
420+
static inline void stm32_exti_write_bit(struct irq_data *d, u32 reg)
421+
{
422+
struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
423+
void __iomem *base = chip_data->host_data->base;
424+
u32 val = BIT(d->hwirq % IRQS_PER_BANK);
425+
426+
writel_relaxed(val, base + reg);
427+
}
428+
419429
static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg)
420430
{
421431
struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
@@ -449,9 +459,9 @@ static void stm32_exti_h_eoi(struct irq_data *d)
449459

450460
raw_spin_lock(&chip_data->rlock);
451461

452-
stm32_exti_set_bit(d, stm32_bank->rpr_ofst);
462+
stm32_exti_write_bit(d, stm32_bank->rpr_ofst);
453463
if (stm32_bank->fpr_ofst != UNDEF_REG)
454-
stm32_exti_set_bit(d, stm32_bank->fpr_ofst);
464+
stm32_exti_write_bit(d, stm32_bank->fpr_ofst);
455465

456466
raw_spin_unlock(&chip_data->rlock);
457467

0 commit comments

Comments
 (0)