Commit 6863c838 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'irq-core-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq core updates from Thomas Gleixner:
 "Updates for the interrupt core and treewide cleanups:

   - Rework of the Per Processor Interrupt (PPI) management on ARM[64]

     PPI support was built under the assumption that the systems are
     homogenous so that the same CPU local device types are connected to
     them. That's unfortunately wishful thinking and created horrible
     workarounds.

     This rework provides affinity management for PPIs so that they can
     be individually configured in the firmware tables and mops up the
     related drivers all over the place.

   - Prevent CPUSET/isolation changes to arbitrarily affine interrupt
     threads to random CPUs, which ignores user or driver settings.

   - Plug a harmless race in the interrupt affinity proc interface,
     which allows to see a half updated mask

   - Adjust the priority of secondary interrupt threads on RT, so that
     the combination of primary and secondary thread emulates the
     hardware interrupt plus thread scenario. Having them at the same
     priority can cause starvation issues in some drivers"

* tag 'irq-core-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (33 commits)
  genirq: Remove cpumask availability check on kthread affinity setting
  genirq: Fix interrupt threads affinity vs. cpuset isolated partitions
  genirq: Prevent early spurious wake-ups of interrupt threads
  genirq: Use raw_spinlock_irq() in irq_set_affinity_notifier()
  genirq/manage: Reduce priority of forced secondary interrupt handler
  genirq/proc: Fix race in show_irq_affinity()
  genirq: Fix percpu_devid irq affinity documentation
  perf: arm_pmu: Kill last use of per-CPU cpu_armpmu pointer
  irqdomain: Kill of_node_to_fwnode() helper
  genirq: Kill irq_{g,s}et_percpu_devid_partition()
  irqchip: Kill irq-partition-percpu
  irqchip/apple-aic: Drop support for custom PMU irq partitions
  irqchip/gic-v3: Drop support for custom PPI partitions
  coresight: trbe: Request specific affinities for per CPU interrupts
  perf: arm_spe_pmu: Request specific affinities for per CPU interrupts
  perf: arm_pmu: Request specific affinities for per CPU NMIs/interrupts
  genirq: Add request_percpu_irq_affinity() helper
  genirq: Allow per-cpu interrupt sharing for non-overlapping affinities
  genirq: Update request_percpu_nmi() to take an affinity
  genirq: Add affinity to percpu_devid interrupt requests
  ...
parents 312f5b18 3de5e46e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1094,7 +1094,7 @@ static void ipi_setup_sgi(int ipi)
	irq = ipi_irq_base + ipi;

	if (ipi_should_be_nmi(ipi)) {
		err = request_percpu_nmi(irq, ipi_handler, "IPI", &irq_stat);
		err = request_percpu_nmi(irq, ipi_handler, "IPI", NULL, &irq_stat);
		WARN(err, "Could not request IRQ %d as NMI, err=%d\n", irq, err);
	} else {
		err = request_percpu_irq(irq, ipi_handler, "IPI", &irq_stat);
+19 −0
Original line number Diff line number Diff line
@@ -300,6 +300,25 @@ int acpi_irq_get(acpi_handle handle, unsigned int index, struct resource *res)
}
EXPORT_SYMBOL_GPL(acpi_irq_get);

const struct cpumask *acpi_irq_get_affinity(acpi_handle handle,
					    unsigned int index)
{
	struct irq_fwspec_info info;
	struct irq_fwspec fwspec;
	unsigned long flags;

	if (acpi_irq_parse_one(handle, index, &fwspec, &flags))
		return NULL;

	if (irq_populate_fwspec_info(&fwspec, &info))
		return NULL;

	if (!(info.flags & IRQ_FWSPEC_INFO_AFFINITY_VALID))
		return NULL;

	return info.affinity;
}

/**
 * acpi_set_irq_model - Setup the GSI irqdomain information
 * @model: the value assigned to acpi_irq_model
+56 −15
Original line number Diff line number Diff line
@@ -150,25 +150,37 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,
EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
#endif /* CONFIG_HAS_IOMEM */

static const struct cpumask *get_irq_affinity(struct platform_device *dev,
					      unsigned int num)
{
	const struct cpumask *mask = NULL;
#ifndef CONFIG_SPARC
	struct fwnode_handle *fwnode = dev_fwnode(&dev->dev);

	if (is_of_node(fwnode))
		mask = of_irq_get_affinity(to_of_node(fwnode), num);
	else if (is_acpi_device_node(fwnode))
		mask = acpi_irq_get_affinity(ACPI_HANDLE_FWNODE(fwnode), num);
#endif

	return mask ?: cpu_possible_mask;
}

/**
 * platform_get_irq_optional - get an optional IRQ for a device
 * platform_get_irq_affinity - get an optional IRQ and its affinity for a device
 * @dev:	platform device
 * @num: IRQ number index
 * @num:	interrupt number index
 * @affinity:	optional cpumask pointer to get the affinity of a per-cpu interrupt
 *
 * Gets an IRQ for a platform device. Device drivers should check the return
 * value for errors so as to not pass a negative integer value to the
 * request_irq() APIs. This is the same as platform_get_irq(), except that it
 * does not print an error message if an IRQ can not be obtained.
 *
 * For example::
 * Gets an interupt for a platform device. Device drivers should check the
 * return value for errors so as to not pass a negative integer value to
 * the request_irq() APIs. Optional affinity information is provided in the
 * affinity pointer if available, and NULL otherwise.
 *
 *		int irq = platform_get_irq_optional(pdev, 0);
 *		if (irq < 0)
 *			return irq;
 *
 * Return: non-zero IRQ number on success, negative error number on failure.
 * Return: non-zero interrupt number on success, negative error number on failure.
 */
int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
int platform_get_irq_affinity(struct platform_device *dev, unsigned int num,
			      const struct cpumask **affinity)
{
	int ret;
#ifdef CONFIG_SPARC
@@ -236,8 +248,37 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
out:
	if (WARN(!ret, "0 is an invalid IRQ number\n"))
		return -EINVAL;

	if (ret > 0 && affinity)
		*affinity = get_irq_affinity(dev, num);

	return ret;
}
EXPORT_SYMBOL_GPL(platform_get_irq_affinity);

/**
 * platform_get_irq_optional - get an optional interrupt for a device
 * @dev:	platform device
 * @num:	interrupt number index
 *
 * Gets an interrupt for a platform device. Device drivers should check the
 * return value for errors so as to not pass a negative integer value to
 * the request_irq() APIs. This is the same as platform_get_irq(), except
 * that it does not print an error message if an interrupt can not be
 * obtained.
 *
 * For example::
 *
 *		int irq = platform_get_irq_optional(pdev, 0);
 *		if (irq < 0)
 *			return irq;
 *
 * Return: non-zero interrupt number on success, negative error number on failure.
 */
int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
{
	return platform_get_irq_affinity(dev, num, NULL);
}
EXPORT_SYMBOL_GPL(platform_get_irq_optional);

/**
+5 −4
Original line number Diff line number Diff line
@@ -1474,9 +1474,10 @@ static void arm_trbe_remove_cpuhp(struct trbe_drvdata *drvdata)
static int arm_trbe_probe_irq(struct platform_device *pdev,
			      struct trbe_drvdata *drvdata)
{
	const struct cpumask *affinity;
	int ret;

	drvdata->irq = platform_get_irq(pdev, 0);
	drvdata->irq = platform_get_irq_affinity(pdev, 0, &affinity);
	if (drvdata->irq < 0) {
		pr_err("IRQ not found for the platform device\n");
		return drvdata->irq;
@@ -1487,14 +1488,14 @@ static int arm_trbe_probe_irq(struct platform_device *pdev,
		return -EINVAL;
	}

	if (irq_get_percpu_devid_partition(drvdata->irq, &drvdata->supported_cpus))
		return -EINVAL;
	cpumask_copy(&drvdata->supported_cpus, affinity);

	drvdata->handle = alloc_percpu(struct perf_output_handle *);
	if (!drvdata->handle)
		return -ENOMEM;

	ret = request_percpu_irq(drvdata->irq, arm_trbe_irq_handler, DRVNAME, drvdata->handle);
	ret = request_percpu_irq_affinity(drvdata->irq, arm_trbe_irq_handler, DRVNAME,
					  affinity, drvdata->handle);
	if (ret) {
		free_percpu(drvdata->handle);
		return ret;
+0 −4
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ config GIC_NON_BANKED
config ARM_GIC_V3
	bool
	select IRQ_DOMAIN_HIERARCHY
	select PARTITION_PERCPU
	select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
	select HAVE_ARM_SMCCC_DISCOVERY
	select IRQ_MSI_IOMMU
@@ -451,9 +450,6 @@ config LS_SCFG_MSI
	depends on PCI_MSI
	select IRQ_MSI_LIB

config PARTITION_PERCPU
	bool

config STM32MP_EXTI
	tristate "STM32MP extended interrupts and event controller"
	depends on (ARCH_STM32 && !ARM_SINGLE_ARMV7M) || COMPILE_TEST
Loading