Commit 36714d69 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'irq-urgent-2024-06-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq fixes from Ingo Molnar:

 - Fix possible memory leak the riscv-intc irqchip driver load failures

 - Fix boot crash in the sifive-plic irqchip driver caused by recently
   changed boot initialization order

 - Fix race condition in the gic-v3-its irqchip driver

* tag 'irq-urgent-2024-06-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  irqchip/gic-v3-its: Fix potential race condition in its_vlpi_prop_update()
  irqchip/sifive-plic: Chain to parent IRQ after handlers are ready
  irqchip/riscv-intc: Prevent memory leak when riscv_intc_init_common() fails
parents 7cedb020 b97e8a2f
......@@ -1846,28 +1846,22 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
{
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
u32 event = its_get_event_id(d);
int ret = 0;
if (!info->map)
return -EINVAL;
raw_spin_lock(&its_dev->event_map.vlpi_lock);
if (!its_dev->event_map.vm) {
struct its_vlpi_map *maps;
maps = kcalloc(its_dev->event_map.nr_lpis, sizeof(*maps),
GFP_ATOMIC);
if (!maps) {
ret = -ENOMEM;
goto out;
}
if (!maps)
return -ENOMEM;
its_dev->event_map.vm = info->map->vm;
its_dev->event_map.vlpi_maps = maps;
} else if (its_dev->event_map.vm != info->map->vm) {
ret = -EINVAL;
goto out;
return -EINVAL;
}
/* Get our private copy of the mapping information */
......@@ -1899,46 +1893,32 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
its_dev->event_map.nr_vlpis++;
}
out:
raw_spin_unlock(&its_dev->event_map.vlpi_lock);
return ret;
return 0;
}
static int its_vlpi_get(struct irq_data *d, struct its_cmd_info *info)
{
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
struct its_vlpi_map *map;
int ret = 0;
raw_spin_lock(&its_dev->event_map.vlpi_lock);
map = get_vlpi_map(d);
if (!its_dev->event_map.vm || !map) {
ret = -EINVAL;
goto out;
}
if (!its_dev->event_map.vm || !map)
return -EINVAL;
/* Copy our mapping information to the incoming request */
*info->map = *map;
out:
raw_spin_unlock(&its_dev->event_map.vlpi_lock);
return ret;
return 0;
}
static int its_vlpi_unmap(struct irq_data *d)
{
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
u32 event = its_get_event_id(d);
int ret = 0;
raw_spin_lock(&its_dev->event_map.vlpi_lock);
if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d)) {
ret = -EINVAL;
goto out;
}
if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d))
return -EINVAL;
/* Drop the virtual mapping */
its_send_discard(its_dev, event);
......@@ -1962,9 +1942,7 @@ static int its_vlpi_unmap(struct irq_data *d)
kfree(its_dev->event_map.vlpi_maps);
}
out:
raw_spin_unlock(&its_dev->event_map.vlpi_lock);
return ret;
return 0;
}
static int its_vlpi_prop_update(struct irq_data *d, struct its_cmd_info *info)
......@@ -1992,6 +1970,8 @@ static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
if (!is_v4(its_dev->its))
return -EINVAL;
guard(raw_spinlock_irq)(&its_dev->event_map.vlpi_lock);
/* Unmap request? */
if (!info)
return its_vlpi_unmap(d);
......
......@@ -253,8 +253,9 @@ IRQCHIP_DECLARE(andes, "andestech,cpu-intc", riscv_intc_init);
static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
const unsigned long end)
{
struct fwnode_handle *fn;
struct acpi_madt_rintc *rintc;
struct fwnode_handle *fn;
int rc;
rintc = (struct acpi_madt_rintc *)header;
......@@ -273,7 +274,11 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
return -ENOMEM;
}
return riscv_intc_init_common(fn, &riscv_intc_chip);
rc = riscv_intc_init_common(fn, &riscv_intc_chip);
if (rc)
irq_domain_free_fwnode(fn);
return rc;
}
IRQCHIP_ACPI_DECLARE(riscv_intc, ACPI_MADT_TYPE_RINTC, NULL,
......
......@@ -85,7 +85,7 @@ struct plic_handler {
struct plic_priv *priv;
};
static int plic_parent_irq __ro_after_init;
static bool plic_cpuhp_setup_done __ro_after_init;
static bool plic_global_setup_done __ro_after_init;
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
static int plic_irq_set_type(struct irq_data *d, unsigned int type);
......@@ -487,10 +487,8 @@ static int plic_probe(struct platform_device *pdev)
unsigned long plic_quirks = 0;
struct plic_handler *handler;
u32 nr_irqs, parent_hwirq;
struct irq_domain *domain;
struct plic_priv *priv;
irq_hw_number_t hwirq;
bool cpuhp_setup;
if (is_of_node(dev->fwnode)) {
const struct of_device_id *id;
......@@ -549,14 +547,6 @@ static int plic_probe(struct platform_device *pdev)
continue;
}
/* Find parent domain and register chained handler */
domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY);
if (!plic_parent_irq && domain) {
plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT);
if (plic_parent_irq)
irq_set_chained_handler(plic_parent_irq, plic_handle_irq);
}
/*
* When running in M-mode we need to ignore the S-mode handler.
* Here we assume it always comes later, but that might be a
......@@ -597,25 +587,35 @@ static int plic_probe(struct platform_device *pdev)
goto fail_cleanup_contexts;
/*
* We can have multiple PLIC instances so setup cpuhp state
* We can have multiple PLIC instances so setup global state
* and register syscore operations only once after context
* handlers of all online CPUs are initialized.
*/
if (!plic_cpuhp_setup_done) {
cpuhp_setup = true;
if (!plic_global_setup_done) {
struct irq_domain *domain;
bool global_setup = true;
for_each_online_cpu(cpu) {
handler = per_cpu_ptr(&plic_handlers, cpu);
if (!handler->present) {
cpuhp_setup = false;
global_setup = false;
break;
}
}
if (cpuhp_setup) {
if (global_setup) {
/* Find parent domain and register chained handler */
domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY);
if (domain)
plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT);
if (plic_parent_irq)
irq_set_chained_handler(plic_parent_irq, plic_handle_irq);
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
"irqchip/sifive/plic:starting",
plic_starting_cpu, plic_dying_cpu);
register_syscore_ops(&plic_irq_syscore_ops);
plic_cpuhp_setup_done = true;
plic_global_setup_done = true;
}
}
......
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