- Fix possible hang in machine_kexec_mask_interrupts(),

which incorrectly assumes that irq_set_irqchip_state()
    will always be able to complete in a kexec crash path,
    triggered on RK3399 embedded boards (Igor Velkov)
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmrd3X4RHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1gDkQ//Z+vr/rkvqst2EpYPjnygPBvjB/TsVO6d
 FoMUEm+3X8ss9EueryDaHfK52yj7JoPZeot/0Ff38FX9Tu+1kXsmbj07tRMMbk0n
 lcX6z0bfIuFcPiFfZZzraZR7oX0J1tOLkl2BsZzjpw02FPJcOqpPPYhJNMIaRKD6
 nR54X1sgOw5LP9UBX4OCCGF0+rxLxOeFsMt6mytv3Q7HZjWvVRKK2UK8g3GHn579
 AYPli910m+BgHQUbpEy1PHzsxGmoBiO/0jk2h5q15snlXZMnKaLr30GWnU3qzJIf
 T/Z33ouzP+plcPWA8K9GI7XE2Q+TpbtRbUejSqQor57HbAANEm517vnB3tS1Gjca
 tZPo2fvAWpU6BlEDWS+R/03Djt/M5hSB8CGd8ArhPZTCSSgdcGNkoz7rThn6aj9D
 awZBIfi/byLW8i8/m/x0a7IBMCKWCInSmgh87sfUSQTx3V46wS+4V3bMFitYUThv
 prCeIA987cqYWrnbtFGzqTSISKaHaW52iZndU6/Q+vW5a5zfv6vFty3u1qWnCs5o
 XvbRa4fRCLexY5S4+1jVjfhwXxcPpPDiR2WApVQWIls22ieidpMdWEPpTvWwCF7L
 hXQv5Pa+KKgBpeEsZC2wPNJ8Ht2thgF5SWFyLFKTwg/fvEKniSJGks4vICeMLUJ2
 6vbldnXh3Uo=
 =vGaL
 -----END PGP SIGNATURE-----

Merge tag 'irq-urgent-2026-10-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull kexec / irq fix from Ingo Molnar:

 - Fix possible hang in machine_kexec_mask_interrupts(),
   which incorrectly assumes that irq_set_irqchip_state()
   will always be able to complete in a kexec crash path,
   triggered on RK3399 embedded boards (Igor Velkov)

* tag 'irq-urgent-2026-10-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  genirq/kexec: Do not take the bus lock of an interrupt chip on the crash path
This commit is contained in:
Linus Torvalds 2026-10-25 17:51:25 -10:00
commit 2b19759b46
3 changed files with 26 additions and 20 deletions

View File

@ -83,6 +83,7 @@ enum {
#include "settings.h"
extern int __irq_set_trigger(struct irq_desc *desc, unsigned long flags);
extern int __irq_set_irqchip_state(struct irq_desc *desc, enum irqchip_irq_state which, bool val);
extern void __disable_irq(struct irq_desc *desc);
extern void __enable_irq(struct irq_desc *desc);

View File

@ -25,7 +25,7 @@ void machine_kexec_mask_interrupts(void)
* First try to remove the active state from an interrupt which is forwarded
* to a VM. If the interrupt is not forwarded, try to EOI the interrupt.
*/
check_eoi = irq_set_irqchip_state(i, IRQCHIP_STATE_ACTIVE, false);
check_eoi = __irq_set_irqchip_state(desc, IRQCHIP_STATE_ACTIVE, false);
}
if (check_eoi && chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data))

View File

@ -2748,6 +2748,28 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool *
}
EXPORT_SYMBOL_GPL(irq_get_irqchip_state);
int __irq_set_irqchip_state(struct irq_desc *desc, enum irqchip_irq_state which, bool val)
{
struct irq_data *data = irq_desc_get_irq_data(desc);
struct irq_chip *chip;
do {
chip = irq_data_get_irq_chip(data);
if (WARN_ON_ONCE(!chip))
return -ENODEV;
if (chip->irq_set_irqchip_state)
break;
data = irqd_get_parent_data(data);
} while (data);
if (data)
return chip->irq_set_irqchip_state(data, which, val);
return -EINVAL;
}
/**
* irq_set_irqchip_state - set the state of a forwarded interrupt.
* @irq: Interrupt line that is forwarded to a VM
@ -2762,25 +2784,8 @@ EXPORT_SYMBOL_GPL(irq_get_irqchip_state);
*/
int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool val)
{
scoped_irqdesc_get_and_buslock(irq, 0) {
struct irq_data *data = irq_desc_get_irq_data(scoped_irqdesc);
struct irq_chip *chip;
do {
chip = irq_data_get_irq_chip(data);
if (WARN_ON_ONCE(!chip))
return -ENODEV;
if (chip->irq_set_irqchip_state)
break;
data = irqd_get_parent_data(data);
} while (data);
if (data)
return chip->irq_set_irqchip_state(data, which, val);
}
scoped_irqdesc_get_and_buslock(irq, 0)
return __irq_set_irqchip_state(scoped_irqdesc, which, val);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(irq_set_irqchip_state);