Commit 16e3613a authored by Marc Zyngier's avatar Marc Zyngier

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: default avatarMarc Zyngier <maz@kernel.org>
parents 0fcfb00b 835f442f
......@@ -46,6 +46,10 @@
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
#define RD_LOCAL_LPI_ENABLED BIT(0)
#define RD_LOCAL_PENDTABLE_PREALLOCATED BIT(1)
#define RD_LOCAL_MEMRESERVE_DONE BIT(2)
static u32 lpi_id_bits;
/*
......@@ -3044,7 +3048,7 @@ static void its_cpu_init_lpis(void)
phys_addr_t paddr;
u64 val, tmp;
if (gic_data_rdist()->lpi_enabled)
if (gic_data_rdist()->flags & RD_LOCAL_LPI_ENABLED)
return;
val = readl_relaxed(rbase + GICR_CTLR);
......@@ -3063,15 +3067,13 @@ static void its_cpu_init_lpis(void)
paddr &= GENMASK_ULL(51, 16);
WARN_ON(!gic_check_reserved_range(paddr, LPI_PENDBASE_SZ));
its_free_pending_table(gic_data_rdist()->pend_page);
gic_data_rdist()->pend_page = NULL;
gic_data_rdist()->flags |= RD_LOCAL_PENDTABLE_PREALLOCATED;
goto out;
}
pend_page = gic_data_rdist()->pend_page;
paddr = page_to_phys(pend_page);
WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));
/* set PROPBASE */
val = (gic_rdists->prop_table_pa |
......@@ -3158,10 +3160,11 @@ static void its_cpu_init_lpis(void)
/* Make sure the GIC has seen the above */
dsb(sy);
out:
gic_data_rdist()->lpi_enabled = true;
gic_data_rdist()->flags |= RD_LOCAL_LPI_ENABLED;
pr_info("GICv3: CPU%d: using %s LPI pending table @%pa\n",
smp_processor_id(),
gic_data_rdist()->pend_page ? "allocated" : "reserved",
gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED ?
"reserved" : "allocated",
&paddr);
}
......@@ -5138,7 +5141,7 @@ static int redist_disable_lpis(void)
*
* If running with preallocated tables, there is nothing to do.
*/
if (gic_data_rdist()->lpi_enabled ||
if ((gic_data_rdist()->flags & RD_LOCAL_LPI_ENABLED) ||
(gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED))
return 0;
......@@ -5200,6 +5203,51 @@ int its_cpu_init(void)
return 0;
}
static void rdist_memreserve_cpuhp_cleanup_workfn(struct work_struct *work)
{
cpuhp_remove_state_nocalls(gic_rdists->cpuhp_memreserve_state);
gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
}
static DECLARE_WORK(rdist_memreserve_cpuhp_cleanup_work,
rdist_memreserve_cpuhp_cleanup_workfn);
static int its_cpu_memreserve_lpi(unsigned int cpu)
{
struct page *pend_page;
int ret = 0;
/* This gets to run exactly once per CPU */
if (gic_data_rdist()->flags & RD_LOCAL_MEMRESERVE_DONE)
return 0;
pend_page = gic_data_rdist()->pend_page;
if (WARN_ON(!pend_page)) {
ret = -ENOMEM;
goto out;
}
/*
* If the pending table was pre-programmed, free the memory we
* preemptively allocated. Otherwise, reserve that memory for
* later kexecs.
*/
if (gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED) {
its_free_pending_table(pend_page);
gic_data_rdist()->pend_page = NULL;
} else {
phys_addr_t paddr = page_to_phys(pend_page);
WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));
}
out:
/* Last CPU being brought up gets to issue the cleanup */
if (cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
schedule_work(&rdist_memreserve_cpuhp_cleanup_work);
gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE;
return ret;
}
static const struct of_device_id its_device_id[] = {
{ .compatible = "arm,gic-v3-its", },
{},
......@@ -5383,6 +5431,26 @@ static void __init its_acpi_probe(void)
static void __init its_acpi_probe(void) { }
#endif
int __init its_lpi_memreserve_init(void)
{
int state;
if (!efi_enabled(EFI_CONFIG_TABLES))
return 0;
gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
"irqchip/arm/gicv3/memreserve:online",
its_cpu_memreserve_lpi,
NULL);
if (state < 0)
return state;
gic_rdists->cpuhp_memreserve_state = state;
return 0;
}
int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
struct irq_domain *parent_domain)
{
......
......@@ -1802,6 +1802,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
if (gic_dist_supports_lpis()) {
its_init(handle, &gic_data.rdists, gic_data.domain);
its_cpu_init();
its_lpi_memreserve_init();
} else {
if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
gicv2m_init(handle, gic_data.domain);
......
......@@ -615,7 +615,7 @@ struct rdists {
void __iomem *rd_base;
struct page *pend_page;
phys_addr_t phys_base;
bool lpi_enabled;
u64 flags;
cpumask_t *vpe_table_mask;
void *vpe_l1_base;
} __percpu *rdist;
......@@ -624,6 +624,7 @@ struct rdists {
u64 flags;
u32 gicd_typer;
u32 gicd_typer2;
int cpuhp_memreserve_state;
bool has_vlpis;
bool has_rvpeid;
bool has_direct_lpi;
......@@ -632,6 +633,7 @@ struct rdists {
struct irq_domain;
struct fwnode_handle;
int __init its_lpi_memreserve_init(void);
int its_cpu_init(void);
int its_init(struct fwnode_handle *handle, struct rdists *rdists,
struct irq_domain *domain);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment