* [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
* Re: [PATCH] irqchip/gic-v3-its: Claim LPI tables inherited across kexec on DT
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
0 siblings, 1 reply; 4+ messages in thread
From: Marc Zyngier @ 2026-10-24 11:39 UTC (permalink / raw)
To: Qianhui Xu; +Cc: Thomas Gleixner, linux-arm-kernel, linux-kernel
On Sat, 24 Oct 2026 08:58:56 +0100,
Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn> wrote:
>
> 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.
But you're missing the point. *nothing* works at all, and this has
nothing to do with the command queue. Everything is dead.
>
> 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
What makes you think that EFI and DT are incompatible? 90% of my
machines are DT based and yet boot with EFI.
> 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.
No. This is way too late, and nothing guarantees that these are not
already used for other purposes by the new kernel. I'm not interested
in something that only has a statistical chance of working. Either it
works always, or it doesn't at all.
The only sane ways to do this is to either use EFI, or to configure
the LPI tables from the bootloader, reserving them at boot time by
sticking the reservation in the DT. They are then preserved along the
whole of the kexec chain. That's what sane platforms do, and this is a
long enough established practice.
Thanks,
M.
--
Jazz isn't dead. It just smells funny.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] irqchip/gic-v3-its: Claim LPI tables inherited across kexec on DT
2026-10-24 11:39 ` Marc Zyngier
@ 2026-10-26 11:41 ` Qianhui Xu
2026-10-26 13:53 ` Marc Zyngier
0 siblings, 1 reply; 4+ messages in thread
From: Qianhui Xu @ 2026-10-26 11:41 UTC (permalink / raw)
To: Marc Zyngier
Cc: Thomas Gleixner, linux-arm-msm, linux-arm-kernel, linux-kernel
Hi Marc,
Understood on all three points, and the series is withdrawn -- I am not
going to resend it in any form.
Just so it is on record that I got the reasoning right this time:
- Inheriting LPI tables is not something the incoming kernel can decide to
fix up after the fact. By the time it runs, it can no longer tell which
of those pages are still the LPI tables and which are ordinary memory it
has already handed out, so any "claim" is a race with a statistical
chance of being correct. That is why it is either configured before the
handoff, or not at all.
- EFI and DT are not alternatives: the reservation has to exist in
whichever description the next kernel is given, EFI memory map or DT
reserved-memory, and EFI booting a DT machine is the normal case.
- Therefore the LPI tables have to be programmed and reserved by the
firmware/bootloader at boot and stay reserved across the whole kexec
chain.
In our case the "bootloader" for a kexec chain is the kexec loader itself,
so the work moves there: add the reservation to the FDT that is handed over
(e.g. grow the blob when there is no space for the memreserve) and have the
loader program the tables, instead of the kernel trying to reclaim them.
Anything that needs LPIs will simply use a full reboot until that exists.
No further review requested -- thanks for stopping this early rather than
after a round of review.
Best regards,
Qianhui
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] irqchip/gic-v3-its: Claim LPI tables inherited across kexec on DT
2026-10-26 11:41 ` Qianhui Xu
@ 2026-10-26 13:53 ` Marc Zyngier
0 siblings, 0 replies; 4+ messages in thread
From: Marc Zyngier @ 2026-10-26 13:53 UTC (permalink / raw)
To: Qianhui Xu; +Cc: Thomas Gleixner, linux-arm-msm, linux-arm-kernel, linux-kernel
On Mon, 26 Oct 2026 11:41:29 +0000,
Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn> wrote:
>
> Hi Marc,
>
> Understood on all three points, and the series is withdrawn -- I am not
> going to resend it in any form.
Thanks.
>
> Just so it is on record that I got the reasoning right this time:
>
> - Inheriting LPI tables is not something the incoming kernel can decide to
> fix up after the fact. By the time it runs, it can no longer tell which
> of those pages are still the LPI tables and which are ordinary memory it
> has already handed out, so any "claim" is a race with a statistical
> chance of being correct. That is why it is either configured before the
> handoff, or not at all.
Indeed. By the time it gets to the GIC driver, the memory used by the
LPI tables could be allocated to other things (page tables, for
example), and memory corruption is very likely.
> - EFI and DT are not alternatives: the reservation has to exist in
> whichever description the next kernel is given, EFI memory map or DT
> reserved-memory, and EFI booting a DT machine is the normal case.
Correct. The EFI reservation is done through Linux-specific EFI tables
that are available irrespective of the platform description method. DT
reserved memory is also usable, but obviously has to be set from the
initial boot point.
> - Therefore the LPI tables have to be programmed and reserved by the
> firmware/bootloader at boot and stay reserved across the whole kexec
> chain.
>
> In our case the "bootloader" for a kexec chain is the kexec loader itself,
> so the work moves there: add the reservation to the FDT that is handed over
> (e.g. grow the blob when there is no space for the memreserve) and have the
> loader program the tables, instead of the kernel trying to reclaim them.
> Anything that needs LPIs will simply use a full reboot until that exists.
If you're using Linux as your first stage bootloader (like petitboot),
then the DT you produce has to have the reservation. If you're using
u-boot without EFI as the bootloader, you can perform the reservation
there.
M.
--
Without deviation from the norm, progress is not possible.
^ 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®