fixup_irqs() re-injects a pending interrupt on its new target CPU by looking at the outermost domain chip and invoking its irq_retrigger() callback directly. When the outermost chip does not implement irq_retrigger(), the pending interrupt is silently dropped, which can lead to lost interrupts on CPU hot-unplug.
Keep calling the outermost chip's irq_retrigger() when it is present, but fall back to irq_chip_retrigger_hierarchy() otherwise, which walks up the interrupt hierarchy until it finds a chip that implements irq_retrigger(). While at it, use a scoped guard for desc->lock. VECTOR_RETRIGGERED is now set only when the retrigger succeeds instead of unconditionally, which is harmless today since apic_retrigger_irq() always returns 1. Suggested-by: Thomas Gleixner <[email protected]> Reviewed-by: Shradha Gupta <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Reviewed-by: Michael Kelley <[email protected]> Signed-off-by: Naman Jain <[email protected]> --- arch/x86/kernel/irq.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 30122f0b3af96..e0163f7ac7368 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -470,6 +470,7 @@ void fixup_irqs(void) struct irq_desc *desc; struct irq_data *data; struct irq_chip *chip; + int ret; irq_migrate_all_off_this_cpu(); @@ -490,21 +491,23 @@ void fixup_irqs(void) * nothing else will touch it. */ for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { - if (IS_ERR_OR_NULL(__this_cpu_read(vector_irq[vector]))) + desc = __this_cpu_read(vector_irq[vector]); + + if (IS_ERR_OR_NULL(desc)) continue; if (is_vector_pending(vector)) { - desc = __this_cpu_read(vector_irq[vector]); - - raw_spin_lock(&desc->lock); + guard(raw_spinlock)(&desc->lock); data = irq_desc_get_irq_data(desc); chip = irq_data_get_irq_chip(data); - if (chip->irq_retrigger) { - chip->irq_retrigger(data); + if (chip->irq_retrigger) + ret = chip->irq_retrigger(data); + else + ret = irq_chip_retrigger_hierarchy(data); + if (ret) __this_cpu_write(vector_irq[vector], VECTOR_RETRIGGERED); - } - raw_spin_unlock(&desc->lock); } + if (__this_cpu_read(vector_irq[vector]) != VECTOR_RETRIGGERED) __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); } -- 2.43.0
