Skip to content

Commit c733ebb

Browse files
author
Marc Zyngier
committed
irqchip/gic-v3-its: Reset each ITS's BASERn register before probe
A recent bug report outlined that the way GICv4.1 is handled across kexec is pretty bad. We can end-up in a situation where ITSs share memory (this is the case when SVPET==1) and reprogram the base registers, creating a situation where ITSs that are part of a given affinity group see different pointers. Which is illegal. Boo. In order to restore some sanity, reset the BASERn registers to 0 *before* probing any ITS. Although this isn't optimised at all, this is only a once-per-boot cost, which shouldn't show up on anyone's radar. Cc: Jay Chen <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Reviewed-by: Lorenzo Pieralisi <[email protected]> Link: https://lore.kernel.org/r/20211216190315.GA14220@lpieralisi Link: https://lore.kernel.org/r/[email protected]
1 parent 16436f7 commit c733ebb

File tree

1 file changed

+99
-21
lines changed

1 file changed

+99
-21
lines changed

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

Lines changed: 99 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4856,6 +4856,38 @@ static struct syscore_ops its_syscore_ops = {
48564856
.resume = its_restore_enable,
48574857
};
48584858

4859+
static void __init __iomem *its_map_one(struct resource *res, int *err)
4860+
{
4861+
void __iomem *its_base;
4862+
u32 val;
4863+
4864+
its_base = ioremap(res->start, SZ_64K);
4865+
if (!its_base) {
4866+
pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
4867+
*err = -ENOMEM;
4868+
return NULL;
4869+
}
4870+
4871+
val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
4872+
if (val != 0x30 && val != 0x40) {
4873+
pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
4874+
*err = -ENODEV;
4875+
goto out_unmap;
4876+
}
4877+
4878+
*err = its_force_quiescent(its_base);
4879+
if (*err) {
4880+
pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
4881+
goto out_unmap;
4882+
}
4883+
4884+
return its_base;
4885+
4886+
out_unmap:
4887+
iounmap(its_base);
4888+
return NULL;
4889+
}
4890+
48594891
static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
48604892
{
48614893
struct irq_domain *inner_domain;
@@ -4963,29 +4995,14 @@ static int __init its_probe_one(struct resource *res,
49634995
{
49644996
struct its_node *its;
49654997
void __iomem *its_base;
4966-
u32 val, ctlr;
49674998
u64 baser, tmp, typer;
49684999
struct page *page;
5000+
u32 ctlr;
49695001
int err;
49705002

4971-
its_base = ioremap(res->start, SZ_64K);
4972-
if (!its_base) {
4973-
pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
4974-
return -ENOMEM;
4975-
}
4976-
4977-
val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
4978-
if (val != 0x30 && val != 0x40) {
4979-
pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
4980-
err = -ENODEV;
4981-
goto out_unmap;
4982-
}
4983-
4984-
err = its_force_quiescent(its_base);
4985-
if (err) {
4986-
pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
4987-
goto out_unmap;
4988-
}
5003+
its_base = its_map_one(res, &err);
5004+
if (!its_base)
5005+
return err;
49895006

49905007
pr_info("ITS %pR\n", res);
49915008

@@ -5249,6 +5266,23 @@ static int its_cpu_memreserve_lpi(unsigned int cpu)
52495266
return ret;
52505267
}
52515268

5269+
/* Mark all the BASER registers as invalid before they get reprogrammed */
5270+
static int __init its_reset_one(struct resource *res)
5271+
{
5272+
void __iomem *its_base;
5273+
int err, i;
5274+
5275+
its_base = its_map_one(res, &err);
5276+
if (!its_base)
5277+
return err;
5278+
5279+
for (i = 0; i < GITS_BASER_NR_REGS; i++)
5280+
gits_write_baser(0, its_base + GITS_BASER + (i << 3));
5281+
5282+
iounmap(its_base);
5283+
return 0;
5284+
}
5285+
52525286
static const struct of_device_id its_device_id[] = {
52535287
{ .compatible = "arm,gic-v3-its", },
52545288
{},
@@ -5259,6 +5293,26 @@ static int __init its_of_probe(struct device_node *node)
52595293
struct device_node *np;
52605294
struct resource res;
52615295

5296+
/*
5297+
* Make sure *all* the ITS are reset before we probe any, as
5298+
* they may be sharing memory. If any of the ITS fails to
5299+
* reset, don't even try to go any further, as this could
5300+
* result in something even worse.
5301+
*/
5302+
for (np = of_find_matching_node(node, its_device_id); np;
5303+
np = of_find_matching_node(np, its_device_id)) {
5304+
int err;
5305+
5306+
if (!of_device_is_available(np) ||
5307+
!of_property_read_bool(np, "msi-controller") ||
5308+
of_address_to_resource(np, 0, &res))
5309+
continue;
5310+
5311+
err = its_reset_one(&res);
5312+
if (err)
5313+
return err;
5314+
}
5315+
52625316
for (np = of_find_matching_node(node, its_device_id); np;
52635317
np = of_find_matching_node(np, its_device_id)) {
52645318
if (!of_device_is_available(np))
@@ -5421,11 +5475,35 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
54215475
return err;
54225476
}
54235477

5478+
static int __init its_acpi_reset(union acpi_subtable_headers *header,
5479+
const unsigned long end)
5480+
{
5481+
struct acpi_madt_generic_translator *its_entry;
5482+
struct resource res;
5483+
5484+
its_entry = (struct acpi_madt_generic_translator *)header;
5485+
res = (struct resource) {
5486+
.start = its_entry->base_address,
5487+
.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1,
5488+
.flags = IORESOURCE_MEM,
5489+
};
5490+
5491+
return its_reset_one(&res);
5492+
}
5493+
54245494
static void __init its_acpi_probe(void)
54255495
{
54265496
acpi_table_parse_srat_its();
5427-
acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
5428-
gic_acpi_parse_madt_its, 0);
5497+
/*
5498+
* Make sure *all* the ITS are reset before we probe any, as
5499+
* they may be sharing memory. If any of the ITS fails to
5500+
* reset, don't even try to go any further, as this could
5501+
* result in something even worse.
5502+
*/
5503+
if (acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
5504+
its_acpi_reset, 0) > 0)
5505+
acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
5506+
gic_acpi_parse_madt_its, 0);
54295507
acpi_its_srat_maps_free();
54305508
}
54315509
#else

0 commit comments

Comments
 (0)