mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] irqchip/gic-v3-its: Claim LPI tables inherited across kexec on DT
@ 2026-10-24  7:58 Qianhui Xu
  2026-10-24 11:39 ` Marc Zyngier
  0 siblings, 1 reply; 4+ messages in thread
From: Qianhui Xu @ 2026-10-24  7:58 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: Marc Zyngier, linux-arm-kernel, linux-kernel, Xu Qianhui

From: Xu Qianhui <xiaqinghuan@mail.ustc.edu.cn>

When a kernel is kexec'd into while LPIs are enabled, the incoming kernel
finds GICR_CTLR.EnableLPIs set and tries to re-initialise the LPI tables
from scratch.  That requires disabling LPIs first, which is not always
possible: on some implementations (e.g. Qualcomm SM8750) the EnableLPIs
bit is RES1 once set, the write to clear it is ignored, and
redist_disable_lpis() returns -EBUSY.  its_cpu_init() then bails out
early, LPIs are never reprogrammed, and every MSI command queued against
the ITS waits for its completion timeout: measured 99 timeouts of about
1.25 s each, pushing /init out from 1.3 s to 126 s.

The tables themselves are still intact and usable, and the driver already
has a path for that (RDIST_FLAGS_RD_TABLES_PREALLOCATED), but it is gated
on the tables being reserved memory.  On an EFI boot the outgoing kernel
records a persistent reservation; on a DT boot nothing does.  Adding a
memreserve entry is not an option either: the flattened DTB handed over by
the bootloader has no space left for a new one (-FDT_ERR_NOSPACE), and
kexec clones that blob when the image is loaded, long before the jump.

So claim the inherited tables in the incoming kernel instead: reserve the
property table while LPIs are being probed (memblock still owns the pages,
well before memblock_free_all()), and the per-CPU pending tables when the
preallocated path is taken.  The preallocated path is then selected
normally and the ITS keeps working across the handoff.

Measured on SM8750, kexec into the same image with a disk root:

  before: 99 x "ITS queue timeout", 8 x "Failed to disable LPIs",
          /init at 126.35 s
  after:   0 x "ITS queue timeout", 0 x "Failed to disable LPIs",
          /init at   1.31 s

Behaviour on a normal cold boot is unchanged: enabled_lpis_allowed() is
only consulted when LPIs are already enabled on entry, and the
preallocated path is only taken when that flag ends up set.

Signed-off-by: Xu Qianhui <xiaqinghuan@mail.ustc.edu.cn>
---
 drivers/irqchip/irq-gic-v3-its.c | 46 +++++++++++++++++++++++++++-----
 1 file changed, 39 insertions(+), 7 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 6f5811aae5..6dcd903e9f 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -2280,7 +2280,7 @@ static void its_free_prop_table(struct page *prop_page)
 	its_free_pages(page_address(prop_page), get_order(LPI_PROPBASE_SZ));
 }
 
-static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size)
+static bool gic_range_is_reserved(phys_addr_t addr, unsigned long size)
 {
 	phys_addr_t start, end, addr_end;
 	u64 i;
@@ -2300,13 +2300,27 @@ static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size)
 			return true;
 	}
 
-	/* Not found, not a good sign... */
-	pr_warn("GICv3: Expected reserved range [%pa:%pa], not found\n",
-		&addr, &addr_end);
-	add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
 	return false;
 }
 
+/*
+ * LPIs are already enabled but the tables we were handed are not reserved
+ * memory.  On a DT boot there is no EFI persistent reservation and the
+ * flattened DTB has no room left for a memreserve entry, so the kernel we came
+ * from (kexec) had no way to hand them over as reserved.  Starting from scratch
+ * is not an option either: PROPBASER/PENDBASER may only be reprogrammed with
+ * LPIs disabled, and on some implementations the EnableLPIs bit reads as RES1
+ * once set.  So keep the inherited tables and claim them before memblock hands
+ * the pages over to the buddy allocator.
+ */
+static bool gic_claim_inherited_lpi_table(phys_addr_t addr, unsigned long size)
+{
+	if (gic_range_is_reserved(addr, size))
+		return true;
+
+	return !memblock_reserve(addr, size);
+}
+
 static int gic_reserve_range(phys_addr_t addr, unsigned long size)
 {
 	if (efi_enabled(EFI_CONFIG_TABLES))
@@ -3067,7 +3081,15 @@ static bool enabled_lpis_allowed(void)
 	val = gicr_read_propbaser(gic_data_rdist_rd_base() + GICR_PROPBASER);
 	addr = val & GENMASK_ULL(51, 12);
 
-	return gic_check_reserved_range(addr, LPI_PROPBASE_SZ);
+	if (!gic_claim_inherited_lpi_table(addr, LPI_PROPBASE_SZ)) {
+		pr_warn("GICv3: inherited LPI property table @%pa is neither reserved nor claimable\n",
+			&addr);
+		add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
+		return false;
+	}
+
+	pr_info_once("GICv3: claiming inherited LPI property table @%pa\n", &addr);
+	return true;
 }
 
 static int __init allocate_lpi_tables(void)
@@ -3175,7 +3197,17 @@ static void its_cpu_init_lpis(void)
 		paddr = gicr_read_pendbaser(rbase + GICR_PENDBASER);
 		paddr &= GENMASK_ULL(51, 16);
 
-		WARN_ON(!gic_check_reserved_range(paddr, LPI_PENDBASE_SZ));
+		/*
+		 * Same as the property table: keep the inherited pending table
+		 * rather than handing the ITS a range the allocator may reuse.
+		 */
+		if (!gic_claim_inherited_lpi_table(paddr, LPI_PENDBASE_SZ)) {
+			pr_warn_once("GICv3: inherited LPI pending table @%pa is neither reserved nor claimable\n",
+				     &paddr);
+			add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
+		} else {
+			pr_info_once("GICv3: claiming inherited LPI pending tables\n");
+		}
 		gic_data_rdist()->flags |= RD_LOCAL_PENDTABLE_PREALLOCATED;
 
 		goto out;
-- 
2.53.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-26 13:53 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-24  7:58 [PATCH] irqchip/gic-v3-its: Claim LPI tables inherited across kexec on DT Qianhui Xu
2026-10-24 11:39 ` Marc Zyngier
2026-10-26 11:41   ` Qianhui Xu
2026-10-26 13:53     ` Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®