Commit c5fe9de7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'irq_urgent_for_v5.17_rc2_p2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq fixes from Borislav Petkov:

 - Drop an unused private data field in the AIC driver

 - Various fixes to the realtek-rtl driver

 - Make the GICv3 ITS driver compile again in !SMP configurations

 - Force reset of the GICv3 ITSs at probe time to avoid issues during kexec

 - Yet another kfree/bitmap_free conversion

 - Various DT updates (Renesas, SiFive)

* tag 'irq_urgent_for_v5.17_rc2_p2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  dt-bindings: interrupt-controller: sifive,plic: Group interrupt tuples
  dt-bindings: interrupt-controller: sifive,plic: Fix number of interrupts
  dt-bindings: irqchip: renesas-irqc: Add R-Car V3U support
  irqchip/gic-v3-its: Reset each ITS's BASERn register before probe
  irqchip/gic-v3-its: Fix build for !SMP
  irqchip/loongson-pch-ms: Use bitmap_free() to free bitmap
  irqchip/realtek-rtl: Service all pending interrupts
  irqchip/realtek-rtl: Fix off-by-one in routing
  irqchip/realtek-rtl: Map control data to virq
  irqchip/apple-aic: Drop unused ipi_hwirq field
parents 27a96c4f 243d3080
...@@ -36,6 +36,7 @@ properties: ...@@ -36,6 +36,7 @@ properties:
- renesas,intc-ex-r8a77980 # R-Car V3H - renesas,intc-ex-r8a77980 # R-Car V3H
- renesas,intc-ex-r8a77990 # R-Car E3 - renesas,intc-ex-r8a77990 # R-Car E3
- renesas,intc-ex-r8a77995 # R-Car D3 - renesas,intc-ex-r8a77995 # R-Car D3
- renesas,intc-ex-r8a779a0 # R-Car V3U
- const: renesas,irqc - const: renesas,irqc
'#interrupt-cells': '#interrupt-cells':
......
...@@ -62,6 +62,7 @@ properties: ...@@ -62,6 +62,7 @@ properties:
interrupts-extended: interrupts-extended:
minItems: 1 minItems: 1
maxItems: 15872
description: description:
Specifies which contexts are connected to the PLIC, with "-1" specifying Specifies which contexts are connected to the PLIC, with "-1" specifying
that a context is not present. Each node pointed to should be a that a context is not present. Each node pointed to should be a
...@@ -90,12 +91,11 @@ examples: ...@@ -90,12 +91,11 @@ examples:
#interrupt-cells = <1>; #interrupt-cells = <1>;
compatible = "sifive,fu540-c000-plic", "sifive,plic-1.0.0"; compatible = "sifive,fu540-c000-plic", "sifive,plic-1.0.0";
interrupt-controller; interrupt-controller;
interrupts-extended = < interrupts-extended = <&cpu0_intc 11>,
&cpu0_intc 11 <&cpu1_intc 11>, <&cpu1_intc 9>,
&cpu1_intc 11 &cpu1_intc 9 <&cpu2_intc 11>, <&cpu2_intc 9>,
&cpu2_intc 11 &cpu2_intc 9 <&cpu3_intc 11>, <&cpu3_intc 9>,
&cpu3_intc 11 &cpu3_intc 9 <&cpu4_intc 11>, <&cpu4_intc 9>;
&cpu4_intc 11 &cpu4_intc 9>;
reg = <0xc000000 0x4000000>; reg = <0xc000000 0x4000000>;
riscv,ndev = <10>; riscv,ndev = <10>;
}; };
...@@ -178,7 +178,6 @@ struct aic_irq_chip { ...@@ -178,7 +178,6 @@ struct aic_irq_chip {
struct irq_domain *hw_domain; struct irq_domain *hw_domain;
struct irq_domain *ipi_domain; struct irq_domain *ipi_domain;
int nr_hw; int nr_hw;
int ipi_hwirq;
}; };
static DEFINE_PER_CPU(uint32_t, aic_fiq_unmasked); static DEFINE_PER_CPU(uint32_t, aic_fiq_unmasked);
......
...@@ -4856,6 +4856,38 @@ static struct syscore_ops its_syscore_ops = { ...@@ -4856,6 +4856,38 @@ static struct syscore_ops its_syscore_ops = {
.resume = its_restore_enable, .resume = its_restore_enable,
}; };
static void __init __iomem *its_map_one(struct resource *res, int *err)
{
void __iomem *its_base;
u32 val;
its_base = ioremap(res->start, SZ_64K);
if (!its_base) {
pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
*err = -ENOMEM;
return NULL;
}
val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
if (val != 0x30 && val != 0x40) {
pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
*err = -ENODEV;
goto out_unmap;
}
*err = its_force_quiescent(its_base);
if (*err) {
pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
goto out_unmap;
}
return its_base;
out_unmap:
iounmap(its_base);
return NULL;
}
static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
{ {
struct irq_domain *inner_domain; struct irq_domain *inner_domain;
...@@ -4963,29 +4995,14 @@ static int __init its_probe_one(struct resource *res, ...@@ -4963,29 +4995,14 @@ static int __init its_probe_one(struct resource *res,
{ {
struct its_node *its; struct its_node *its;
void __iomem *its_base; void __iomem *its_base;
u32 val, ctlr;
u64 baser, tmp, typer; u64 baser, tmp, typer;
struct page *page; struct page *page;
u32 ctlr;
int err; int err;
its_base = ioremap(res->start, SZ_64K); its_base = its_map_one(res, &err);
if (!its_base) { if (!its_base)
pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start); return err;
return -ENOMEM;
}
val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
if (val != 0x30 && val != 0x40) {
pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
err = -ENODEV;
goto out_unmap;
}
err = its_force_quiescent(its_base);
if (err) {
pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
goto out_unmap;
}
pr_info("ITS %pR\n", res); pr_info("ITS %pR\n", res);
...@@ -5241,13 +5258,31 @@ static int its_cpu_memreserve_lpi(unsigned int cpu) ...@@ -5241,13 +5258,31 @@ static int its_cpu_memreserve_lpi(unsigned int cpu)
out: out:
/* Last CPU being brought up gets to issue the cleanup */ /* Last CPU being brought up gets to issue the cleanup */
if (cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask)) if (!IS_ENABLED(CONFIG_SMP) ||
cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
schedule_work(&rdist_memreserve_cpuhp_cleanup_work); schedule_work(&rdist_memreserve_cpuhp_cleanup_work);
gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE; gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE;
return ret; return ret;
} }
/* Mark all the BASER registers as invalid before they get reprogrammed */
static int __init its_reset_one(struct resource *res)
{
void __iomem *its_base;
int err, i;
its_base = its_map_one(res, &err);
if (!its_base)
return err;
for (i = 0; i < GITS_BASER_NR_REGS; i++)
gits_write_baser(0, its_base + GITS_BASER + (i << 3));
iounmap(its_base);
return 0;
}
static const struct of_device_id its_device_id[] = { static const struct of_device_id its_device_id[] = {
{ .compatible = "arm,gic-v3-its", }, { .compatible = "arm,gic-v3-its", },
{}, {},
...@@ -5258,6 +5293,26 @@ static int __init its_of_probe(struct device_node *node) ...@@ -5258,6 +5293,26 @@ static int __init its_of_probe(struct device_node *node)
struct device_node *np; struct device_node *np;
struct resource res; struct resource res;
/*
* Make sure *all* the ITS are reset before we probe any, as
* they may be sharing memory. If any of the ITS fails to
* reset, don't even try to go any further, as this could
* result in something even worse.
*/
for (np = of_find_matching_node(node, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
int err;
if (!of_device_is_available(np) ||
!of_property_read_bool(np, "msi-controller") ||
of_address_to_resource(np, 0, &res))
continue;
err = its_reset_one(&res);
if (err)
return err;
}
for (np = of_find_matching_node(node, its_device_id); np; for (np = of_find_matching_node(node, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) { np = of_find_matching_node(np, its_device_id)) {
if (!of_device_is_available(np)) if (!of_device_is_available(np))
...@@ -5420,9 +5475,33 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, ...@@ -5420,9 +5475,33 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
return err; return err;
} }
static int __init its_acpi_reset(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_madt_generic_translator *its_entry;
struct resource res;
its_entry = (struct acpi_madt_generic_translator *)header;
res = (struct resource) {
.start = its_entry->base_address,
.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1,
.flags = IORESOURCE_MEM,
};
return its_reset_one(&res);
}
static void __init its_acpi_probe(void) static void __init its_acpi_probe(void)
{ {
acpi_table_parse_srat_its(); acpi_table_parse_srat_its();
/*
* Make sure *all* the ITS are reset before we probe any, as
* they may be sharing memory. If any of the ITS fails to
* reset, don't even try to go any further, as this could
* result in something even worse.
*/
if (acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
its_acpi_reset, 0) > 0)
acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR, acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
gic_acpi_parse_madt_its, 0); gic_acpi_parse_madt_its, 0);
acpi_its_srat_maps_free(); acpi_its_srat_maps_free();
......
...@@ -241,7 +241,7 @@ static int pch_msi_init(struct device_node *node, ...@@ -241,7 +241,7 @@ static int pch_msi_init(struct device_node *node,
return 0; return 0;
err_map: err_map:
kfree(priv->msi_map); bitmap_free(priv->msi_map);
err_priv: err_priv:
kfree(priv); kfree(priv);
return ret; return ret;
......
...@@ -62,7 +62,7 @@ static struct irq_chip realtek_ictl_irq = { ...@@ -62,7 +62,7 @@ static struct irq_chip realtek_ictl_irq = {
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{ {
irq_set_chip_and_handler(hw, &realtek_ictl_irq, handle_level_irq); irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
return 0; return 0;
} }
...@@ -76,16 +76,20 @@ static void realtek_irq_dispatch(struct irq_desc *desc) ...@@ -76,16 +76,20 @@ static void realtek_irq_dispatch(struct irq_desc *desc)
{ {
struct irq_chip *chip = irq_desc_get_chip(desc); struct irq_chip *chip = irq_desc_get_chip(desc);
struct irq_domain *domain; struct irq_domain *domain;
unsigned int pending; unsigned long pending;
unsigned int soc_int;
chained_irq_enter(chip, desc); chained_irq_enter(chip, desc);
pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR)); pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR));
if (unlikely(!pending)) { if (unlikely(!pending)) {
spurious_interrupt(); spurious_interrupt();
goto out; goto out;
} }
domain = irq_desc_get_handler_data(desc); domain = irq_desc_get_handler_data(desc);
generic_handle_domain_irq(domain, __ffs(pending)); for_each_set_bit(soc_int, &pending, 32)
generic_handle_domain_irq(domain, soc_int);
out: out:
chained_irq_exit(chip, desc); chained_irq_exit(chip, desc);
...@@ -95,7 +99,8 @@ static void realtek_irq_dispatch(struct irq_desc *desc) ...@@ -95,7 +99,8 @@ static void realtek_irq_dispatch(struct irq_desc *desc)
* SoC interrupts are cascaded to MIPS CPU interrupts according to the * SoC interrupts are cascaded to MIPS CPU interrupts according to the
* interrupt-map in the device tree. Each SoC interrupt gets 4 bits for * interrupt-map in the device tree. Each SoC interrupt gets 4 bits for
* the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts * the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts
* thus go into 4 IRRs. * thus go into 4 IRRs. A routing value of '0' means the interrupt is left
* disconnected. Routing values {1..15} connect to output lines {0..14}.
*/ */
static int __init map_interrupts(struct device_node *node, struct irq_domain *domain) static int __init map_interrupts(struct device_node *node, struct irq_domain *domain)
{ {
...@@ -134,7 +139,7 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do ...@@ -134,7 +139,7 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do
of_node_put(cpu_ictl); of_node_put(cpu_ictl);
cpu_int = be32_to_cpup(imap + 2); cpu_int = be32_to_cpup(imap + 2);
if (cpu_int > 7) if (cpu_int > 7 || cpu_int < 2)
return -EINVAL; return -EINVAL;
if (!(mips_irqs_set & BIT(cpu_int))) { if (!(mips_irqs_set & BIT(cpu_int))) {
...@@ -143,7 +148,8 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do ...@@ -143,7 +148,8 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do
mips_irqs_set |= BIT(cpu_int); mips_irqs_set |= BIT(cpu_int);
} }
regs[(soc_int * 4) / 32] |= cpu_int << (soc_int * 4) % 32; /* Use routing values (1..6) for CPU interrupts (2..7) */
regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32;
imap += 3; imap += 3;
} }
......
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