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

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
Loading
Loading
Loading
Loading
+12 −32
Original line number Diff line number Diff line
@@ -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);
+7 −2
Original line number Diff line number Diff line
@@ -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,
+17 −17
Original line number Diff line number Diff line
@@ -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;
		}
	}