Skip to content

Commit 16e3613

Browse files
author
Marc Zyngier
committed
Merge branch irq/its-kexec-rt into irq/irqchip-next
* irq/its-kexec-rt: : . : Series from Valentin Schneider, aiming at fixing the issues : the ITS driver has with PREEMPT_RT whilst trying to reserve : memory at early boot to support kexec. : . irqchip/gic-v3-its: Limit memreserve cpuhp state lifetime irqchip/gic-v3-its: Postpone LPI pending table freeing and memreserve irqchip/gic-v3-its: Give the percpu rdist struct its own flags field Signed-off-by: Marc Zyngier <[email protected]>
2 parents 0fcfb00 + 835f442 commit 16e3613

File tree

3 files changed

+79
-8
lines changed

3 files changed

+79
-8
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
4747
#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
4848

49+
#define RD_LOCAL_LPI_ENABLED BIT(0)
50+
#define RD_LOCAL_PENDTABLE_PREALLOCATED BIT(1)
51+
#define RD_LOCAL_MEMRESERVE_DONE BIT(2)
52+
4953
static u32 lpi_id_bits;
5054

5155
/*
@@ -3044,7 +3048,7 @@ static void its_cpu_init_lpis(void)
30443048
phys_addr_t paddr;
30453049
u64 val, tmp;
30463050

3047-
if (gic_data_rdist()->lpi_enabled)
3051+
if (gic_data_rdist()->flags & RD_LOCAL_LPI_ENABLED)
30483052
return;
30493053

30503054
val = readl_relaxed(rbase + GICR_CTLR);
@@ -3063,15 +3067,13 @@ static void its_cpu_init_lpis(void)
30633067
paddr &= GENMASK_ULL(51, 16);
30643068

30653069
WARN_ON(!gic_check_reserved_range(paddr, LPI_PENDBASE_SZ));
3066-
its_free_pending_table(gic_data_rdist()->pend_page);
3067-
gic_data_rdist()->pend_page = NULL;
3070+
gic_data_rdist()->flags |= RD_LOCAL_PENDTABLE_PREALLOCATED;
30683071

30693072
goto out;
30703073
}
30713074

30723075
pend_page = gic_data_rdist()->pend_page;
30733076
paddr = page_to_phys(pend_page);
3074-
WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));
30753077

30763078
/* set PROPBASE */
30773079
val = (gic_rdists->prop_table_pa |
@@ -3158,10 +3160,11 @@ static void its_cpu_init_lpis(void)
31583160
/* Make sure the GIC has seen the above */
31593161
dsb(sy);
31603162
out:
3161-
gic_data_rdist()->lpi_enabled = true;
3163+
gic_data_rdist()->flags |= RD_LOCAL_LPI_ENABLED;
31623164
pr_info("GICv3: CPU%d: using %s LPI pending table @%pa\n",
31633165
smp_processor_id(),
3164-
gic_data_rdist()->pend_page ? "allocated" : "reserved",
3166+
gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED ?
3167+
"reserved" : "allocated",
31653168
&paddr);
31663169
}
31673170

@@ -5138,7 +5141,7 @@ static int redist_disable_lpis(void)
51385141
*
51395142
* If running with preallocated tables, there is nothing to do.
51405143
*/
5141-
if (gic_data_rdist()->lpi_enabled ||
5144+
if ((gic_data_rdist()->flags & RD_LOCAL_LPI_ENABLED) ||
51425145
(gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED))
51435146
return 0;
51445147

@@ -5200,6 +5203,51 @@ int its_cpu_init(void)
52005203
return 0;
52015204
}
52025205

5206+
static void rdist_memreserve_cpuhp_cleanup_workfn(struct work_struct *work)
5207+
{
5208+
cpuhp_remove_state_nocalls(gic_rdists->cpuhp_memreserve_state);
5209+
gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
5210+
}
5211+
5212+
static DECLARE_WORK(rdist_memreserve_cpuhp_cleanup_work,
5213+
rdist_memreserve_cpuhp_cleanup_workfn);
5214+
5215+
static int its_cpu_memreserve_lpi(unsigned int cpu)
5216+
{
5217+
struct page *pend_page;
5218+
int ret = 0;
5219+
5220+
/* This gets to run exactly once per CPU */
5221+
if (gic_data_rdist()->flags & RD_LOCAL_MEMRESERVE_DONE)
5222+
return 0;
5223+
5224+
pend_page = gic_data_rdist()->pend_page;
5225+
if (WARN_ON(!pend_page)) {
5226+
ret = -ENOMEM;
5227+
goto out;
5228+
}
5229+
/*
5230+
* If the pending table was pre-programmed, free the memory we
5231+
* preemptively allocated. Otherwise, reserve that memory for
5232+
* later kexecs.
5233+
*/
5234+
if (gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED) {
5235+
its_free_pending_table(pend_page);
5236+
gic_data_rdist()->pend_page = NULL;
5237+
} else {
5238+
phys_addr_t paddr = page_to_phys(pend_page);
5239+
WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));
5240+
}
5241+
5242+
out:
5243+
/* Last CPU being brought up gets to issue the cleanup */
5244+
if (cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
5245+
schedule_work(&rdist_memreserve_cpuhp_cleanup_work);
5246+
5247+
gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE;
5248+
return ret;
5249+
}
5250+
52035251
static const struct of_device_id its_device_id[] = {
52045252
{ .compatible = "arm,gic-v3-its", },
52055253
{},
@@ -5383,6 +5431,26 @@ static void __init its_acpi_probe(void)
53835431
static void __init its_acpi_probe(void) { }
53845432
#endif
53855433

5434+
int __init its_lpi_memreserve_init(void)
5435+
{
5436+
int state;
5437+
5438+
if (!efi_enabled(EFI_CONFIG_TABLES))
5439+
return 0;
5440+
5441+
gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
5442+
state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
5443+
"irqchip/arm/gicv3/memreserve:online",
5444+
its_cpu_memreserve_lpi,
5445+
NULL);
5446+
if (state < 0)
5447+
return state;
5448+
5449+
gic_rdists->cpuhp_memreserve_state = state;
5450+
5451+
return 0;
5452+
}
5453+
53865454
int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
53875455
struct irq_domain *parent_domain)
53885456
{

drivers/irqchip/irq-gic-v3.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
18021802
if (gic_dist_supports_lpis()) {
18031803
its_init(handle, &gic_data.rdists, gic_data.domain);
18041804
its_cpu_init();
1805+
its_lpi_memreserve_init();
18051806
} else {
18061807
if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
18071808
gicv2m_init(handle, gic_data.domain);

include/linux/irqchip/arm-gic-v3.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ struct rdists {
615615
void __iomem *rd_base;
616616
struct page *pend_page;
617617
phys_addr_t phys_base;
618-
bool lpi_enabled;
618+
u64 flags;
619619
cpumask_t *vpe_table_mask;
620620
void *vpe_l1_base;
621621
} __percpu *rdist;
@@ -624,6 +624,7 @@ struct rdists {
624624
u64 flags;
625625
u32 gicd_typer;
626626
u32 gicd_typer2;
627+
int cpuhp_memreserve_state;
627628
bool has_vlpis;
628629
bool has_rvpeid;
629630
bool has_direct_lpi;
@@ -632,6 +633,7 @@ struct rdists {
632633

633634
struct irq_domain;
634635
struct fwnode_handle;
636+
int __init its_lpi_memreserve_init(void);
635637
int its_cpu_init(void);
636638
int its_init(struct fwnode_handle *handle, struct rdists *rdists,
637639
struct irq_domain *domain);

0 commit comments

Comments
 (0)