From: Thomas Gleixner <tglx@kernel.org>
To: Sasha Levin <sashal@kernel.org>, iav@iav.lv
Cc: stable@vger.kernel.org
Subject: [PATCH 6.12.y] genirq/kexec: Do not take the bus lock of an interrupt chip on the crash path
Date: Sun, 08 Nov 2026 14:13:57 +0100 [thread overview]
Message-ID: <87a4njwjmy.ffs@fw13> (raw)
In-Reply-To: <20261107052534-failed-6.12-717862eac6ef@kernel.org>
From: Igor Velkov <iav@iav.lv>
commit 717862eac6eff0eea8ac30a0c0de0bed84922aab upstream.
machine_kexec_mask_interrupts() calls irq_set_irqchip_state() for every
started interrupt. That function takes the bus lock of the chip and
desc->lock, and syncs the chip when it drops them. On the crash path
interrupts are off and the other CPUs are stopped, so a chip whose bus
transfer is completed by an interrupt never returns from the sync.
On RK3399 boards with an RK808 PMIC the RTC alarm interrupt belongs to
the regmap-irq chip of the RK808, which sits on I2C. rk808_irq_chip sets
init_ack_masked, so regmap_irq_sync_unlock() writes the ack register on
every unlock, and the I2C controller needs its own interrupt to finish
the transfer. A panic with a crash kernel loaded prints
SMP: stopping secondary CPUs
and then nothing until the watchdog resets the board.
machine_kexec_mask_interrupts() takes neither lock for the other
operations on the descriptor. Move the search for the chip that
implements irq_set_irqchip_state() into __irq_set_irqchip_state(), which
takes no locks, and call it from machine_kexec_mask_interrupts().
Fixes: 78fd584cdec0 ("arm64: kdump: implement machine_crash_shutdown()")
Suggested-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Igor Velkov <iav@iav.lv>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261015-kexec-irq-bus-lock-v2-1-2af15f0757b6@iav.lv
---
kernel/irq/internals.h | 1 +
kernel/irq/kexec.c | 2 +-
kernel/irq/manage.c | 49 +++++++++++++++++++++++++------------------------
3 files changed, 27 insertions(+), 25 deletions(-)
---
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -75,6 +75,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);
--- a/kernel/irq/kexec.c
+++ b/kernel/irq/kexec.c
@@ -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))
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -2854,6 +2854,28 @@ int irq_get_irqchip_state(unsigned int i
}
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
@@ -2870,36 +2892,15 @@ int irq_set_irqchip_state(unsigned int i
bool val)
{
struct irq_desc *desc;
- struct irq_data *data;
- struct irq_chip *chip;
unsigned long flags;
- int err = -EINVAL;
+ int err;
desc = irq_get_desc_buslock(irq, &flags, 0);
if (!desc)
- return err;
-
- data = irq_desc_get_irq_data(desc);
-
- do {
- chip = irq_data_get_irq_chip(data);
- if (WARN_ON_ONCE(!chip)) {
- err = -ENODEV;
- goto out_unlock;
- }
- if (chip->irq_set_irqchip_state)
- break;
-#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
- data = data->parent_data;
-#else
- data = NULL;
-#endif
- } while (data);
+ return -EINVAL;
- if (data)
- err = chip->irq_set_irqchip_state(data, which, val);
+ err = __irq_set_irqchip_state(desc, which, val);
-out_unlock:
irq_put_desc_busunlock(desc, flags);
return err;
}
prev parent reply other threads:[~2026-11-08 13:14 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 10:25 FAILED: patch "[PATCH] genirq/kexec: Do not take the bus lock of an interrupt chip on the crash path" failed to apply to 6.12-stable tree Sasha Levin
2026-11-08 13:13 ` Thomas Gleixner [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87a4njwjmy.ffs@fw13 \
--to=tglx@kernel.org \
--cc=iav@iav.lv \
--cc=sashal@kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.