diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2025-07-18 20:54:08 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2025-07-22 14:30:42 +0200 |
commit | 4e879dedd571128ed5aa4d5989ec0a1938804d20 (patch) | |
tree | 25c58a2f2eb882c29d12438fc80b5a81bfe7bece /kernel/irq/chip.c | |
parent | 46958a7bac2d32fda43fd7cd1858aa414640fbd1 (diff) |
genirq: Move irq_wait_for_poll() to call site
Move it to the call site so that the waiting for the INPROGRESS flag can be
reused by an upcoming mitigation for a potential live lock in the edge type
handler.
No functional change.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Liangyan <liangyan.peng@bytedance.com>
Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
Link: https://lore.kernel.org/all/20250718185311.948555026@linutronix.de
Diffstat (limited to 'kernel/irq/chip.c')
-rw-r--r-- | kernel/irq/chip.c | 33 |
1 files changed, 24 insertions, 9 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 5bb26fc5368b..290244ca28dd 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -457,11 +457,21 @@ void unmask_threaded_irq(struct irq_desc *desc) unmask_irq(desc); } -static bool irq_check_poll(struct irq_desc *desc) -{ - if (!(desc->istate & IRQS_POLL_INPROGRESS)) - return false; - return irq_wait_for_poll(desc); +/* Busy wait until INPROGRESS is cleared */ +static bool irq_wait_on_inprogress(struct irq_desc *desc) +{ + if (IS_ENABLED(CONFIG_SMP)) { + do { + raw_spin_unlock(&desc->lock); + while (irqd_irq_inprogress(&desc->irq_data)) + cpu_relax(); + raw_spin_lock(&desc->lock); + } while (irqd_irq_inprogress(&desc->irq_data)); + + /* Might have been disabled in meantime */ + return !irqd_irq_disabled(&desc->irq_data) && desc->action; + } + return false; } static bool irq_can_handle_pm(struct irq_desc *desc) @@ -481,10 +491,15 @@ static bool irq_can_handle_pm(struct irq_desc *desc) if (irq_pm_check_wakeup(desc)) return false; - /* - * Handle a potential concurrent poll on a different core. - */ - return irq_check_poll(desc); + /* Check whether the interrupt is polled on another CPU */ + if (unlikely(desc->istate & IRQS_POLL_INPROGRESS)) { + if (WARN_ONCE(irq_poll_cpu == smp_processor_id(), + "irq poll in progress on cpu %d for irq %d\n", + smp_processor_id(), desc->irq_data.irq)) + return false; + return irq_wait_on_inprogress(desc); + } + return false; } static inline bool irq_can_handle_actions(struct irq_desc *desc) |