genirq: Add support for percpu_devid IRQ affinity
Subsystems (12)
Marc Zyngier
maintainerv2 cover genirq: Add support for percpu_devid IRQ affinity
This is the second version of this series, originally posted at [1], which aims at allowing percpu_devid interrupt requests on the basis of an affinity mask. See the original submission for the details of why this is a desirable outcome.
From v1, we have a number of changes, both functional and cosmetic, but the fundamentals are pretty much the same (change log below), with an even more appealing diffstat.
Thanks to Will, Thomas and Raphael for their constructive review comments.
FWIW, I've pushed a branch at [2].
* From v1 [1]:
- Fixed NMI handling by getting rid of the NMI-specific flow handler, which was pretty useless anyway (Will)
- As a result, killed a metric buttload worth of GICv3 code
- Moved irq_fwspec out of irq_fwspec_info, and passed it as a parameter to irq_get_fwspec_info(), renamed from irq_get_info(), and applied some generous sanitisation of the structure (Thomas)
- Dropped the rather useless fwspec validity flag (Thomas)
- Rejigged the PMU per-CPU handling to better deal with the DT/ACPI differences, and drop some now useless patches (Will)
- Plenty of cosmetic rework (Raphael, Thomas)
[1] https://lore.kernel.org/r/[email protected]
[2] git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git irq/ppi-affinity
Marc Zyngier (24):
irqdomain: Add firmware info reporting interface
ACPI: irq: Add IRQ affinity reporting interface
of/irq: Add IRQ affinity reporting interface
platform: Add firmware-agnostic irq and affinity retrieval interface irqchip/gic-v3: Add FW info retrieval support irqchip/apple-aic: Add FW info retrieval support
coresight: trbe: Convert to new IRQ affinity retrieval API
perf: arm_pmu: Convert to new IRQ affinity retrieval API
perf: arm_spe_pmu: Convert to new IRQ affinity retrieval API irqchip/gic-v3: Switch high priority PPIs over to
handle_percpu_devid_irq()
genirq: Kill handle_percpu_devid_fasteoi_nmi()
genirq: Merge irqaction::{dev_id,percpu_dev_id}
genirq: Factor-in percpu irqaction creation
genirq: Add affinity to percpu_devid interrupt requests
genirq: Update request_percpu_nmi() to take an affinity
genirq: Allow per-cpu interrupt sharing for non-overlapping affinities
genirq: Add request_percpu_irq_affinity() helper
perf: arm_spe_pmu: Request specific affinities for percpu IRQ
coresight: trbe: Request specific affinities for percpu IRQ irqchip/gic-v3: Drop support for custom PPI partitions irqchip/apple-aic: Drop support for custom PMU irq partitions
irqchip: Kill irq-partition-percpu
genirq: Kill irq_{g,s}et_percpu_devid_partition()
perf: arm_pmu: Kill last use of per-CPU cpu_armpmu pointer
Will Deacon (1):
perf: arm_pmu: Request specific affinities for percpu NMI/IRQ
arch/arm64/kernel/smp.c | 2 +- drivers/acpi/irq.c | 19 ++ drivers/base/platform.c | 60 ++++- drivers/hwtracing/coresight/coresight-trbe.c | 9 +- drivers/irqchip/Kconfig | 4 - drivers/irqchip/Makefile | 1 - drivers/irqchip/irq-apple-aic.c | 56 +++-- drivers/irqchip/irq-gic-v3.c | 224 +++++------------ drivers/irqchip/irq-partition-percpu.c | 241 ------------------- drivers/of/irq.c | 20 ++ drivers/perf/arm_pmu.c | 50 ++-- drivers/perf/arm_pmu_acpi.c | 2 +- drivers/perf/arm_pmu_platform.c | 20 +- drivers/perf/arm_pmuv3.c | 2 +- drivers/perf/arm_spe_pmu.c | 13 +- include/linux/acpi.h | 7 + include/linux/interrupt.h | 24 +- include/linux/irq.h | 5 - include/linux/irqchip/irq-partition-percpu.h | 53 ---- include/linux/irqdesc.h | 1 - include/linux/irqdomain.h | 28 +++ include/linux/of_irq.h | 7 + include/linux/perf/arm_pmu.h | 6 +- include/linux/platform_device.h | 2 + kernel/irq/chip.c | 36 +-- kernel/irq/irqdesc.c | 24 +- kernel/irq/irqdomain.c | 32 ++- kernel/irq/manage.c | 124 +++++++--- 28 files changed, 423 insertions(+), 649 deletions(-) delete mode 100644 drivers/irqchip/irq-partition-percpu.c delete mode 100644 include/linux/irqchip/irq-partition-percpu.h
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 1/25 irqdomain: Add firmware info reporting interface
Allow an irqdomain callback to report firmware-provided information that is otherwise not available in a generic way. This is reported using a new data structure (struct irq_fwspec_info).
This callback is optional and the only information that can be reported currently is the affinity of an interrupt. However, the containing structure is designed to be extensible, allowing other potentially relevant information to be reported in the future.
--- include/linux/irqdomain.h | 28 ++++++++++++++++++++++++++++ kernel/irq/irqdomain.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 5 deletions(-)
include/linux/irqdomain.h +28 -0
@@ -44,6 +44,24 @@ struct irq_fwspec {u32 param[IRQ_DOMAIN_IRQ_SPEC_PARAMS ]; }; +/** +* struct irq_fwspec_info - firmware provided IRQ information structure +* +* @fwspec: Firmware-specific interrupt specifier +* @cpumask: Affinity mask for this interrupt +* @flags: Information validity flags +* +* This structure reports firmware-specific information about an +* interrupt. The only significant information is the affinity of a +* per-CPU interrupt, but this is designed to be extended as required. +*/ +struct irq_fwspec_info { +unsigned long flags; +const struct cpumask *affinity; +}; + +#define IRQ_FWSPEC_INFO_AFFINITY_VALID BIT(0) +/* Conversion function from of_phandle_args fields to fwspec */ void of_phandle_args_to_fwspec (struct device_node *np,const u32 *args,unsigned int count,struct irq_fwspec *fwspec);
@@ -69,6 +87,9 @@ void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,* @translate: Given @fwspec, decode the hardware irq number (@out_hwirq) and * linux irq type value (@out_type). This is a generalised @xlate * (over struct irq_fwspec) and is preferred if provided. +* @get_fwspec_info: +* Given @fwspec, report additional firmware-provided information in +* @info. Optional. * @debug_show: For domains to show specific data for an interrupt in debugfs. * * Functions below are provided by the driver and called whenever a new mapping
@@ -96,6 +117,7 @@ struct irq_domain_ops {void (*deactivate)(struct irq_domain *d,struct irq_data *irq_data);int (*translate)(struct irq_domain *d,struct irq_fwspec *fwspec,unsigned long *out_hwirq,unsigned int *out_type); +int (*get_fwspec_info)(struct irq_fwspec *fwspec,struct irq_fwspec_info *info);#endif #ifdef CONFIG_GENERIC_IRQ_DEBUGFS void (*debug_show)(struct seq_file *m, struct irq_domain *d,
@@ -602,6 +624,8 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain, unsigned int irq_basint irq_domain_disconnect_hierarchy (struct irq_domain *domain,unsigned int virq); +int irq_populate_fwspec_info (struct irq_fwspec *fwspec,struct irq_fwspec_info *info); +static inline bool irq_domain_is_hierarchy (struct irq_domain *domain) {return domain->flags &IRQ_DOMAIN_FLAG_HIERARCHY ;
@@ -685,6 +709,10 @@ static inline bool irq_domain_is_msi_device(struct irq_domain *domain) return false; } +static inline int irq_populate_fwspec_info (struct irq_fwspec *fwspec,struct irq_fwspec_info *info) +{ +return -EINVAL ; +}#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ #ifdef CONFIG_GENERIC_MSI_IRQ
kernel/irq/irqdomain.c +27 -5
@@ -867,13 +867,9 @@ void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args, }EXPORT_SYMBOL_GPL (of_phandle_args_to_fwspec); -unsigned int irq_create_fwspec_mapping (struct irq_fwspec *fwspec) +static struct irq_domain *fwspec_to_domain (struct irq_fwspec *fwspec) {struct irq_domain *domain; -struct irq_data *irq_data; -irq_hw_number_t hwirq; -unsigned int type =IRQ_TYPE_NONE ; -int virq;if (fwspec->fwnode) { domain =irq_find_matching_fwspec (fwspec,DOMAIN_BUS_WIRED );
@@ -883,6 +879,32 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) domain = irq_default_domain; } +return domain; +} + +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +int irq_populate_fwspec_info (struct irq_fwspec *fwspec,struct irq_fwspec_info *info) +{ +struct irq_domain *domain =fwspec_to_domain (fwspec); + +memset (info,0 ,sizeof (*info)); + +if (!domain || !domain->ops->get_fwspec_info) +return 0 ; + +return domain->ops->get_fwspec_info (fwspec, info); +} +#endif + +unsigned int irq_create_fwspec_mapping (struct irq_fwspec *fwspec) +{ +unsigned int type =IRQ_TYPE_NONE ; +struct irq_domain *domain; +struct irq_data *irq_data; +irq_hw_number_t hwirq; +int virq; + + domain =fwspec_to_domain (fwspec);if (!domain) {pr_warn ("no irq domain found for %s !\n" ,of_node_full_name (to_of_node (fwspec->fwnode)));
Signature · 1 line
2.39.2
Re: [PATCH v2 01/25] irqdomain: Add firmware info reporting interface
Quoted 10 lines · On Mon, 15 Sep 2025 09:56:38 +0100 Marc Zyngier <[email protected]> wrote:
Allow an irqdomain callback to report firmware-provided information that is otherwise not available in a generic way. This is reported using a new data structure (struct
irq_fwspec_info).This callback is optional and the only information that can be reported currently is the affinity of an interrupt. However, the containing structure is designed to be extensible, allowing other potentially relevant information to be reported in the future.
Signed-off-by Marc Zyngier <[email protected]>
Hi Marc,
Quoted 10 lines
--- include/linux/irqdomain.h | 28 ++++++++++++++++++++++++++++ kernel/irq/irqdomain.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 5 deletions(-)include/linux/irqdomain.h +0
-0
include/linux/irqdomain.h struct irq_fwspec { · line 50
Quoted 7 lines
include/linux/irqdomain.h +4
-0@@ -44,6 +44,24 @@ struct irq_fwspec {u32 param[IRQ_DOMAIN_IRQ_SPEC_PARAMS ]; }; +/** +* struct irq_fwspec_info - firmware provided IRQ information structure +* +* @fwspec: Firmware-specific interrupt specifier
Not aligning with what is in the structure that I can see.
Quoted 11 lines
include/linux/irqdomain.h +11
-0+* @cpumask: Affinity mask for this interrupt +* @flags: Information validity flags +* +* This structure reports firmware-specific information about an +* interrupt. The only significant information is the affinity of a +* per-CPU interrupt, but this is designed to be extended as required. +*/ +struct irq_fwspec_info { +unsigned long flags; +const struct cpumask *affinity; +};
Marc Zyngier
maintainerRe: [PATCH v2 01/25] irqdomain: Add firmware info reporting interface
Quoted 29 lines · Jonathan Cameron
Quoted 10 lines · On Mon, 15 Sep 2025 09:56:38 +0100 Marc Zyngier <[email protected]> wrote:
Allow an irqdomain callback to report firmware-provided information that is otherwise not available in a generic way. This is reported using a new data structure (struct
irq_fwspec_info).This callback is optional and the only information that can be reported currently is the affinity of an interrupt. However, the containing structure is designed to be extensible, allowing other potentially relevant information to be reported in the future.
Signed-off-by Marc Zyngier <[email protected]>Hi Marc,
Quoted 13 lines
--- include/linux/irqdomain.h | 28 ++++++++++++++++++++++++++++ kernel/irq/irqdomain.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 5 deletions(-)include/linux/irqdomain.h +0
-0@@ -44,6 +44,24 @@ struct irq_fwspec {u32 param[IRQ_DOMAIN_IRQ_SPEC_PARAMS ]; };
Quoted 6 lines
include/linux/irqdomain.h struct irq_fwspec { · line 50
Quoted 4 lines
include/linux/irqdomain.h +4
-0+/** +* struct irq_fwspec_info - firmware provided IRQ information structure +* +* @fwspec: Firmware-specific interrupt specifier Not aligning with what is in the structure that I can see.
Ah crap, I missed that one. I'll stash another fix for the next version.
Thanks,
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerPATCH v2 2/25 ACPI: irq: Add IRQ affinity reporting interface
In reply to Marc ZyngierPlug the irq_populate_fwspec_info() helper into the ACPI layer to offer an IRQ affinity reporting function. This is currently only supported for the CONFIG_ACPI_GENERIC_GSI configurations, but could later be extended to legacy architectures if necessary.
--- drivers/acpi/irq.c | 19 +++++++++++++++++++ include/linux/acpi.h | 7 +++++++ 2 files changed, 26 insertions(+)
drivers/acpi/irq.c +19 -0
@@ -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
include/linux/acpi.h +7 -0
@@ -1509,12 +1509,19 @@ static inline int acpi_parse_spcr(bool enable_earlycon, bool enable_console)#if IS_ENABLED (CONFIG_ACPI_GENERIC_GSI )int acpi_irq_get (acpi_handle handle,unsigned int index,struct resource *res); +const struct cpumask *acpi_irq_get_affinity (acpi_handle handle, +unsigned int index);#else static inline int acpi_irq_get (acpi_handle handle,unsigned int index,struct resource *res) {return -EINVAL ; } +static inline const struct cpumask *acpi_irq_get_affinity (acpi_handle handle, +unsigned int index) +{ +return NULL ; +}#endif #ifdef CONFIG_ACPI_LPIT
Signature · 1 line
2.39.2
Re: [PATCH v2 02/25] ACPI: irq: Add IRQ affinity reporting interface
Quoted 7 lines · Marc Zyngier
Plug the
irq_populate_fwspec_info()helper into the ACPI layer to offer an IRQ affinity reporting function. This is currently only supported for theCONFIG_ACPI_GENERIC_GSIconfigurations, but could later be extended to legacy architectures if necessary.Signed-off-by Marc Zyngier <[email protected]>
Quoted 62 lines
--- drivers/acpi/irq.c | 19 +++++++++++++++++++ include/linux/acpi.h | 7 +++++++ 2 files changed, 26 insertions(+)drivers/acpi/irq.c +19
-0@@ -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 include/linux/acpi.h +7
-1@@ -1509,12 +1509,19 @@ static inline int acpi_parse_spcr(bool enable_earlycon, bool enable_console)#if IS_ENABLED (CONFIG_ACPI_GENERIC_GSI )int acpi_irq_get (acpi_handle handle,unsigned int index,struct resource *res); +const struct cpumask *acpi_irq_get_affinity (acpi_handle handle, +unsigned int index);#else static inline int acpi_irq_get (acpi_handle handle,unsigned int index,struct resource *res) {return -EINVAL ; } +static inline const struct cpumask *acpi_irq_get_affinity (acpi_handle handle, +unsigned int index) +{ +return NULL ; +}#endif #ifdef CONFIG_ACPI_LPIT --2.39.2
Marc Zyngier
maintainerPATCH v2 3/25 of/irq: Add IRQ affinity reporting interface
In reply to Marc ZyngierPlug the irq_populate_fwspec_info() helper into the OF layer to offer an IRQ affinity reporting function.
--- drivers/of/irq.c | 20 ++++++++++++++++++++ include/linux/of_irq.h | 7 +++++++ 2 files changed, 27 insertions(+)
drivers/of/irq.c +20 -0
@@ -479,6 +479,26 @@ int of_irq_get(struct device_node *dev, int index) }EXPORT_SYMBOL_GPL (of_irq_get); +const struct cpumask *of_irq_get_affinity (struct device_node *dev,int index) +{ +struct of_phandle_args oirq; +struct irq_fwspec_info info; +struct irq_fwspec fwspec; +int rc; + + rc =of_irq_parse_one (dev, index, &oirq); +if (rc) +return NULL ; + +of_phandle_args_to_fwspec (oirq.np, oirq.args, oirq.args_count, + &fwspec); + +if (!irq_populate_fwspec_info (&fwspec, &info)) +return info.affinity; + +return NULL ; +} +/** * of_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number * @dev: pointer to device tree node
include/linux/of_irq.h +7 -0
@@ -43,6 +43,8 @@ extern int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq);extern int of_irq_count (struct device_node *dev);extern int of_irq_get (struct device_node *dev,int index); +extern const struct cpumask *of_irq_get_affinity (struct device_node *dev, +int index);extern int of_irq_get_byname (struct device_node *dev,const char *name);extern int of_irq_to_resource_table (struct device_node *dev,struct resource *res,int nr_irqs);
@@ -77,6 +79,11 @@ static inline int of_irq_get_byname(struct device_node *dev, const char *name) {return 0 ; } +static inline const struct cpumask *of_irq_get_affinity (struct device_node *dev, +int index) +{ +return NULL ; +}static inline int of_irq_to_resource_table (struct device_node *dev,struct resource *res,int nr_irqs) {
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 4/25 platform: Add firmware-agnostic irq and affinity retrieval interface
In reply to Marc ZyngierExpand platform_get_irq_optional() to also return an affinity if available, renaming it to platform_get_irq_affinity() in the process.
platform_get_irq_optional() is preserved with its current semantics by calling into the new helper with a NULL affinity pointer.
--- drivers/base/platform.c | 60 +++++++++++++++++++++++++++------ include/linux/platform_device.h | 2 ++ 2 files changed, 52 insertions(+), 10 deletions(-)
drivers/base/platform.c +50 -10
@@ -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 affnity for a device * @dev: platform device * @num: IRQ number index +* @affinity: optional cpumask pointer to get the affinity of a per-cpu IRQ * * 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:: -* -* int irq = platform_get_irq_optional(pdev, 0); -* if (irq < 0) -* return irq; +* request_irq() APIs. Optional affinity information is provided in the +* affinity pointer if available, and NULL otherwise. * * Return: non-zero IRQ 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,36 @@ 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 IRQ for a device +* @dev: platform device +* @num: IRQ number index +* +* 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:: +* +* 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. +*/ +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);/**
include/linux/platform_device.h +2 -0
@@ -102,6 +102,8 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,extern int platform_get_irq (struct platform_device *,unsigned int );extern int platform_get_irq_optional (struct platform_device *,unsigned int ); +extern int platform_get_irq_affinity (struct platform_device *,unsigned int , +const struct cpumask **);extern int platform_irq_count (struct platform_device *); extern int devm_platform_get_irqs_affinity(struct platform_device *dev, struct irq_affinity *affd,
Signature · 1 line
2.39.2
Re: [PATCH v2 04/25] platform: Add firmware-agnostic irq and affinity retrieval interface
Quoted 17 lines · On Mon, 15 Sep 2025 09:56:41 +0100 Marc Zyngier <[email protected]> wrote:
Expand
platform_get_irq_optional()to also return an affinity if available, renaming it toplatform_get_irq_affinity()in the process.
platform_get_irq_optional()is preserved with its current semantics by calling into the new helper with a NULL affinity pointer.Signed-off-by Marc Zyngier <[email protected]>--- drivers/base/platform.c | 60 +++++++++++++++++++++++++++------ include/linux/platform_device.h | 2 ++ 2 files changed, 52 insertions(+), 10 deletions(-)drivers/base/platform.c +0
-0
drivers/base/platform.c devm_platform_ioremap_resource_byname(struct platform_device *pdev, · line 170
Quoted 4 lines
drivers/base/platform.c +1
-1/** -* platform_get_irq_optional - get an optional IRQ for a device +* platform_get_irq_affinity - get an optional IRQ and its affnity for a device
affinity
Quoted 19 lines
* @dev: platform device
* @num: IRQ number index
+ * @affinity: optional cpumask pointer to get the affinity of a per-cpu IRQ *include/linux/platform_device.h +2
-0@@ -102,6 +102,8 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,extern int platform_get_irq (struct platform_device *,unsigned int );extern int platform_get_irq_optional (struct platform_device *,unsigned int ); +extern int platform_get_irq_affinity (struct platform_device *,unsigned int , +const struct cpumask **);extern int platform_irq_count (struct platform_device *); extern int devm_platform_get_irqs_affinity(struct platform_device *dev, struct irq_affinity *affd,
Marc Zyngier
maintainerPATCH v2 5/25 irqchip/gic-v3: Add FW info retrieval support
In reply to Marc ZyngierPlug the new .get_info() callback into the GICv3 core driver, using some of the existing PPI affinity handling infrastructure.
--- drivers/irqchip/irq-gic-v3.c | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
drivers/irqchip/irq-gic-v3.c +53 -0
@@ -69,6 +69,8 @@ struct gic_chip_data {bool has_rss;unsigned int ppi_nr;struct partition_desc **ppi_descs; +struct partition_affinity *parts; +unsigned int nr_parts; };#define T241_CHIPS_MAX 4
@@ -1796,11 +1798,58 @@ static int gic_irq_domain_select(struct irq_domain *d,return d ==partition_get_domain (gic_data.ppi_descs[ppi_idx]); } +static int gic_irq_get_fwspec_info (struct irq_fwspec *fwspec,struct irq_fwspec_info *info) +{ +const struct cpumask *mask =NULL ; + + info->flags =0 ; + info->affinity =NULL ; + +/* ACPI is not capable of describing PPI affinity -- yet */ +if (!is_of_node (fwspec->fwnode)) +return 0 ; + +/* If the specifier provides an affinity, use it */ +if (fwspec->param_count ==4 && fwspec->param[3 ]) { +struct fwnode_handle *fw; + +switch (fwspec->param[0 ]) { +case 1 :/* PPI */ +case 3 :/* EPPI */ +break ; +default : +return 0 ; + } + + fw =of_node_to_fwnode (of_find_node_by_phandle (fwspec->param[3 ])); +if (!fw) +return -ENOENT ; + +for (int i =0 ; i < gic_data.nr_parts; i++) { +if (gic_data.parts[i].partition_id == fw) { + mask = &gic_data.parts[i].mask; +break ; + } + } + +if (!mask) +return -ENOENT ; + }else { + mask = cpu_possible_mask; + } + + info->affinity = mask; + info->flags =IRQ_FWSPEC_INFO_AFFINITY_VALID ; + +return 0 ; +} +static const struct irq_domain_ops gic_irq_domain_ops = { .translate = gic_irq_domain_translate, .alloc = gic_irq_domain_alloc, .free = gic_irq_domain_free, .select = gic_irq_domain_select, + .get_fwspec_info = gic_irq_get_fwspec_info, }; static int partition_domain_translate(struct irq_domain *d,
@@ -1839,6 +1888,7 @@ static int partition_domain_translate(struct irq_domain *d,static const struct irq_domain_ops partition_domain_ops = { .translate = partition_domain_translate, .select = gic_irq_domain_select, + .get_fwspec_info = gic_irq_get_fwspec_info, };static bool gic_enable_quirk_msm8996 (void *data)
@@ -2231,6 +2281,9 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) part_idx++; } + gic_data.parts = parts; + gic_data.nr_parts = nr_parts; +for (i =0 ; i < gic_data.ppi_nr; i++) {unsigned int irq;struct partition_desc *desc;
Signature · 1 line
2.39.2
Re: [PATCH v2 05/25] irqchip/gic-v3: Add FW info retrieval support
Quoted 4 lines · On Mon, 15 Sep 2025 09:56:42 +0100 Marc Zyngier <[email protected]> wrote:
Plug the new .get_info() callback into the GICv3 core driver, using some of the existing PPI affinity handling infrastructure.
Signed-off-by Marc Zyngier <[email protected]>
Hi Marc,
Yet another trivial comment. It's one of those days it seems :)
Quoted 35 lines
--- drivers/irqchip/irq-gic-v3.c | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)drivers/irqchip/irq-gic-v3.c +16
-0@@ -69,6 +69,8 @@ struct gic_chip_data {bool has_rss;unsigned int ppi_nr;struct partition_desc **ppi_descs; +struct partition_affinity *parts; +unsigned int nr_parts; };#define T241_CHIPS_MAX 4@@ -1796,11 +1798,58 @@ static int gic_irq_domain_select(struct irq_domain *d,return d ==partition_get_domain (gic_data.ppi_descs[ppi_idx]); } +static int gic_irq_get_fwspec_info (struct irq_fwspec *fwspec,struct irq_fwspec_info *info) +{ +const struct cpumask *mask =NULL ; + + info->flags =0 ; + info->affinity =NULL ; + +/* ACPI is not capable of describing PPI affinity -- yet */ +if (!is_of_node (fwspec->fwnode)) +return 0 ; + +/* If the specifier provides an affinity, use it */ +if (fwspec->param_count ==4 && fwspec->param[3 ]) { +struct fwnode_handle *fw;
drivers/irqchip/irq-gic-v3.c static int gic_irq_domain_select(struct irq_domain *d, · line 1824
Quoted 10 lines
drivers/irqchip/irq-gic-v3.c +10
-0+ +switch (fwspec->param[0 ]) { +case 1 :/* PPI */ +case 3 :/* EPPI */ +break ; +default : +return 0 ; + } + + fw =of_node_to_fwnode (of_find_node_by_phandle (fwspec->param[3 ]));
of_node_to_fwnode() has a note that says it'll be removed in the merge window. It was enough of an oddity I wondered why it existed.
Of course it did say it would be removed in the previous merge window and wasn't... Probably want of_fwnode_handle()
Quoted 20 lines
drivers/irqchip/irq-gic-v3.c +20
-0+if (!fw) +return -ENOENT ; + +for (int i =0 ; i < gic_data.nr_parts; i++) { +if (gic_data.parts[i].partition_id == fw) { + mask = &gic_data.parts[i].mask; +break ; + } + } + +if (!mask) +return -ENOENT ; + }else { + mask = cpu_possible_mask; + } + + info->affinity = mask; + info->flags =IRQ_FWSPEC_INFO_AFFINITY_VALID ; + +return 0 ;
Marc Zyngier
maintainerRe: [PATCH v2 05/25] irqchip/gic-v3: Add FW info retrieval support
Quoted 11 lines · Jonathan Cameron
Quoted 4 lines · On Mon, 15 Sep 2025 09:56:42 +0100 Marc Zyngier <[email protected]> wrote:
Plug the new .get_info() callback into the GICv3 core driver, using some of the existing PPI affinity handling infrastructure.
Signed-off-by Marc Zyngier <[email protected]>Hi Marc,
Yet another trivial comment. It's one of those days it seems :)
No worries, your trivial comments are far more interesting than some of the emails I'm otherwise getting.. ;-)
Quoted 41 lines
Quoted 41 lines
--- drivers/irqchip/irq-gic-v3.c | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)drivers/irqchip/irq-gic-v3.c +21
-0@@ -69,6 +69,8 @@ struct gic_chip_data {bool has_rss;unsigned int ppi_nr;struct partition_desc **ppi_descs; +struct partition_affinity *parts; +unsigned int nr_parts; };#define T241_CHIPS_MAX 4@@ -1796,11 +1798,58 @@ static int gic_irq_domain_select(struct irq_domain *d,return d ==partition_get_domain (gic_data.ppi_descs[ppi_idx]); } +static int gic_irq_get_fwspec_info (struct irq_fwspec *fwspec,struct irq_fwspec_info *info) +{ +const struct cpumask *mask =NULL ; + + info->flags =0 ; + info->affinity =NULL ; + +/* ACPI is not capable of describing PPI affinity -- yet */ +if (!is_of_node (fwspec->fwnode)) +return 0 ; + +/* If the specifier provides an affinity, use it */ +if (fwspec->param_count ==4 && fwspec->param[3 ]) { +struct fwnode_handle *fw; + +switch (fwspec->param[0 ]) { +case 1 :/* PPI */ +case 3 :/* EPPI */ +break ;
Quoted 8 lines
drivers/irqchip/irq-gic-v3.c static int gic_irq_domain_select(struct irq_domain *d, · line 1824
Quoted 5 lines
drivers/irqchip/irq-gic-v3.c +5
-0+default : +return 0 ; + } + + fw =of_node_to_fwnode (of_find_node_by_phandle (fwspec->param[3 ]));
of_node_to_fwnode()has a note that says it'll be removed in the merge window. It was enough of an oddity I wondered why it existed.
Cargo culted, obviously. And yet another sign that I've been sitting on these patches for way too long...
Quoted 2 lines
Of course it did say it would be removed in the previous merge window and wasn't... Probably want
of_fwnode_handle()
Thanks for the hint, I'll add that to v3.
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerPATCH v2 6/25 irqchip/apple-aic: Add FW info retrieval support
In reply to Marc ZyngierPlug the new .get_info() callback into the Apple AIC driver, using some of the existing FIQ affinity handling infrastructure.
--- drivers/irqchip/irq-apple-aic.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
drivers/irqchip/irq-apple-aic.c +28 -0
@@ -651,6 +651,33 @@ static int aic_irq_domain_map(struct irq_domain *id, unsigned int irq,return 0 ; } +static int aic_irq_get_fwspec_info (struct irq_fwspec *fwspec,struct irq_fwspec_info *info) +{ +const struct cpumask *mask; +u32 intid; + + info->flags =0 ; + info->affinity =NULL ; + +if (fwspec->param[0 ] !=AIC_FIQ ) +return 0 ; + +if (fwspec->param_count ==3 ) + intid = fwspec->param[1 ]; +else + intid = fwspec->param[2 ]; + +if (aic_irqc->fiq_aff[intid]) + mask = &aic_irqc->fiq_aff[intid]->aff; +else + mask = cpu_possible_mask; + + info->affinity = mask; + info->flags =IRQ_FWSPEC_INFO_AFFINITY_VALID ; + +return 0 ; +} + static int aic_irq_domain_translate(struct irq_domain *id, struct irq_fwspec *fwspec, unsigned long *hwirq,
@@ -753,6 +780,7 @@ static const struct irq_domain_ops aic_irq_domain_ops = { .translate = aic_irq_domain_translate, .alloc = aic_irq_domain_alloc, .free = aic_irq_domain_free, + .get_fwspec_info = aic_irq_get_fwspec_info, };/*
Signature · 1 line
2.39.2
Re: [PATCH v2 06/25] irqchip/apple-aic: Add FW info retrieval support
Quoted 5 lines · Marc Zyngier
Plug the new .get_info() callback into the Apple AIC driver, using some of the existing FIQ affinity handling infrastructure.
Signed-off-by Marc Zyngier <[email protected]>---
Best,
Sven
Marc Zyngier
maintainerPATCH v2 7/25 coresight: trbe: Convert to new IRQ affinity retrieval API
In reply to Marc ZyngierNow that the relevant interrupt controllers are equipped with a callback returning the affinity of per-CPU interrupts, switch the TRBE driver over to this new method.
--- drivers/hwtracing/coresight/coresight-trbe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/hwtracing/coresight/coresight-trbe.c +3 -3
@@ -1472,9 +1472,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;
@@ -1485,8 +1486,7 @@ 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)
Signature · 1 line
2.39.2
Re: [PATCH v2 07/25] coresight: trbe: Convert to new IRQ affinity retrieval API
Quoted 5 lines · Marc Zyngier
Now that the relevant interrupt controllers are equipped with a callback returning the affinity of per-CPU interrupts, switch the TRBE driver over to this new method.
Signed-off-by Marc Zyngier <[email protected]>
Assuming this goes via irqchip tree,
Quoted 30 lines
--- drivers/hwtracing/coresight/coresight-trbe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)drivers/hwtracing/coresight/coresight-trbe.c +3
-3@@ -1472,9 +1472,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;@@ -1485,8 +1486,7 @@ 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)
Marc Zyngier
maintainerPATCH v2 8/25 perf: arm_pmu: Convert to new IRQ affinity retrieval API
In reply to Marc ZyngierNow that the relevant interrupt controllers are equipped with a callback returning the affinity of per-CPU interrupts, switch the OF side of the ARM PMU driver over to this new method.
--- drivers/perf/arm_pmu_platform.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
drivers/perf/arm_pmu_platform.c +9 -7
@@ -42,14 +42,13 @@ static int probe_current_pmu(struct arm_pmu *pmu,return ret; } -static int pmu_parse_percpu_irq (struct arm_pmu *pmu,int irq) +static int pmu_parse_percpu_irq (struct arm_pmu *pmu,int irq, +const struct cpumask *affinity) { -int cpu, ret;struct pmu_hw_events __percpu *hw_events = pmu->hw_events; +int cpu; - ret =irq_get_percpu_devid_partition (irq, &pmu->supported_cpus); -if (ret) -return ret; +cpumask_copy (&pmu->supported_cpus, affinity);for_each_cpu (cpu, &pmu->supported_cpus)per_cpu (hw_events->irq, cpu) = irq;
@@ -115,9 +114,12 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) }if (num_irqs ==1 ) { -int irq =platform_get_irq (pdev,0 ); +const struct cpumask *affinity; +int irq; + + irq =platform_get_irq_affinity (pdev,0 , &affinity);if ((irq >0 ) &&irq_is_percpu_devid (irq)) -return pmu_parse_percpu_irq (pmu, irq); +return pmu_parse_percpu_irq (pmu, irq, affinity); }if (nr_cpu_ids !=1 && !pmu_has_irq_affinity (dev->of_node))
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 9/25 perf: arm_spe_pmu: Convert to new IRQ affinity retrieval API
In reply to Marc ZyngierNow that the relevant interrupt controllers are equipped with a callback returning the affinity of per-CPU interrupts, switch the ARM SPE driver over to this new method.
--- drivers/perf/arm_spe_pmu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/perf/arm_spe_pmu.c +4 -5
@@ -1211,8 +1211,10 @@ static void arm_spe_pmu_dev_teardown(struct arm_spe_pmu *spe_pmu)static int arm_spe_pmu_irq_probe (struct arm_spe_pmu *spe_pmu) {struct platform_device *pdev = spe_pmu->pdev; -int irq =platform_get_irq (pdev,0 ); +const struct cpumask *affinity; +int irq; + irq =platform_get_irq_affinity (pdev,0 , &affinity);if (irq <0 )return -ENXIO ;
@@ -1221,10 +1223,7 @@ static int arm_spe_pmu_irq_probe(struct arm_spe_pmu *spe_pmu)return -EINVAL ; } -if (irq_get_percpu_devid_partition (irq, &spe_pmu->supported_cpus)) { -dev_err (&pdev->dev,"failed to get PPI partition (%d)\n" , irq); -return -EINVAL ; - } +cpumask_copy (&spe_pmu->supported_cpus, affinity); spe_pmu->irq = irq;return 0 ;
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 10/25 irqchip/gic-v3: Switch high priority PPIs over to handle_percpu_devid_irq()
In reply to Marc ZyngierIt so appears that handle_percpu_devid_irq() is extremely similar to handle_percpu_devid_fasteoi_nmi(), and that the differences do no justify the horrid machinery we have in the GICv3 driver to handle the flow handler switch.
Let's stick with the standard flow handler, even for NMIs.
--- drivers/irqchip/irq-gic-v3.c | 54 ++---------------------------------- 1 file changed, 2 insertions(+), 52 deletions(-)
drivers/irqchip/irq-gic-v3.c +2 -52
@@ -230,9 +230,6 @@ static void __init gic_prio_init(void) !cpus_have_group0); } -/* rdist_nmi_refs[n] == number of cpus having the rdist interrupt n set as NMI */ -static refcount_t *rdist_nmi_refs; -static struct gic_kvm_info gic_v3_kvm_info__initdata ; static DEFINE_PER_CPU(bool, has_rss);
@@ -608,24 +605,6 @@ static u32 __gic_get_ppi_index(irq_hw_number_t hwirq) } } -static u32 __gic_get_rdist_index (irq_hw_number_t hwirq) -{ -switch (__get_intid_range (hwirq)) { -case SGI_RANGE : -case PPI_RANGE : -return hwirq; -case EPPI_RANGE : -return hwirq -EPPI_BASE_INTID +32 ; -default : -unreachable (); - } -} - -static u32 gic_get_rdist_index (struct irq_data *d) -{ -return __gic_get_rdist_index (d->hwirq); -} -static int gic_irq_nmi_setup (struct irq_data *d) {struct irq_desc *desc =irq_to_desc (d->irq);
@@ -646,20 +625,8 @@ static int gic_irq_nmi_setup(struct irq_data *d)return -EINVAL ;/* desc lock should already be held */ -if (gic_irq_in_rdist (d)) { -u32 idx =gic_get_rdist_index (d); - -/* -* Setting up a percpu interrupt as NMI, only switch handler -* for first NMI -*/ -if (!refcount_inc_not_zero (&rdist_nmi_refs[idx])) { -refcount_set (&rdist_nmi_refs[idx],1 ); - desc->handle_irq = handle_percpu_devid_fasteoi_nmi; - } - }else { +if (!gic_irq_in_rdist (d)) desc->handle_irq = handle_fasteoi_nmi; - }gic_irq_set_prio (d, dist_prio_nmi);
@@ -686,15 +653,8 @@ static void gic_irq_nmi_teardown(struct irq_data *d)return ;/* desc lock should already be held */ -if (gic_irq_in_rdist (d)) { -u32 idx =gic_get_rdist_index (d); - -/* Tearing down NMI, only switch handler for last NMI */ -if (refcount_dec_and_test (&rdist_nmi_refs[idx])) - desc->handle_irq = handle_percpu_devid_irq; - }else { +if (!gic_irq_in_rdist (d)) desc->handle_irq = handle_fasteoi_irq; - }gic_irq_set_prio (d, dist_prio_irq); }
@@ -2079,19 +2039,9 @@ static const struct gic_quirk gic_quirks[] = {static void gic_enable_nmi_support (void ) { -int i; -if (!gic_prio_masking_enabled () || nmi_support_forbidden)return ; - rdist_nmi_refs =kcalloc (gic_data.ppi_nr +SGI_NR , -sizeof (*rdist_nmi_refs),GFP_KERNEL ); -if (!rdist_nmi_refs) -return ; - -for (i =0 ; i < gic_data.ppi_nr +SGI_NR ; i++) -refcount_set (&rdist_nmi_refs[i],0 ); -pr_info ("Pseudo-NMIs enabled using %s ICC_PMR_EL1 synchronisation\n" ,gic_has_relaxed_pmr_sync () ?"relaxed" :"forced" );
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 11/25 genirq: Kill handle_percpu_devid_fasteoi_nmi()
In reply to Marc ZyngierThere is no in-tree user of this flow handler anymore, so simply remove it.
--- include/linux/irq.h | 1 - kernel/irq/chip.c | 28 ++-------------------------- 2 files changed, 2 insertions(+), 27 deletions(-)
include/linux/irq.h +0 -1
@@ -655,7 +655,6 @@ extern void handle_bad_irq(struct irq_desc *desc);extern void handle_nested_irq (unsigned int irq);extern void handle_fasteoi_nmi (struct irq_desc *desc); -extern void handle_percpu_devid_fasteoi_nmi (struct irq_desc *desc);extern int irq_chip_compose_msi_msg (struct irq_data *data,struct msi_msg *msg);extern int irq_chip_pm_get (struct irq_data *data);
kernel/irq/chip.c +2 -26
@@ -892,7 +892,8 @@ void handle_percpu_irq(struct irq_desc *desc)* * action->percpu_dev_id is a pointer to percpu variables which * contain the real device id for the cpu on which this handler is -* called +* called. This is also used for per-CPU NMIs, so special care is +* required. */ void handle_percpu_devid_irq (struct irq_desc *desc) {
@@ -929,31 +930,6 @@ void handle_percpu_devid_irq(struct irq_desc *desc) chip->irq_eoi (&desc->irq_data); } -/** -* handle_percpu_devid_fasteoi_nmi - Per CPU local NMI handler with per cpu -* dev ids -* @desc: the interrupt description structure for this irq -* -* Similar to handle_fasteoi_nmi, but handling the dev_id cookie -* as a percpu pointer. -*/ -void handle_percpu_devid_fasteoi_nmi (struct irq_desc *desc) -{ -struct irq_chip *chip =irq_desc_get_chip (desc); -struct irqaction *action = desc->action; -unsigned int irq =irq_desc_get_irq (desc); -irqreturn_t res; - -__kstat_incr_irqs_this_cpu (desc); - -trace_irq_handler_entry (irq, action); - res = action->handler (irq,raw_cpu_ptr (action->percpu_dev_id)); -trace_irq_handler_exit (irq, action, res); - -if (chip->irq_eoi) - chip->irq_eoi (&desc->irq_data); -} -static void __irq_do_set_handler (struct irq_desc *desc,irq_flow_handler_t handle,int is_chained,const char *name)
Signature · 1 line
2.39.2
Re: [PATCH v2 11/25] genirq: Kill handle_percpu_devid_fasteoi_nmi()
Quoted 12 lines · On Mon, 15 Sep 2025 09:56:48 +0100 Marc Zyngier <[email protected]> wrote:
There is no in-tree user of this flow handler anymore, so simply remove it.
Suggested-by Will Deacon <[email protected]>Signed-off-by Marc Zyngier <[email protected]>---
kernel/irq/chip.c +0
-0
kernel/irq/chip.c void handle_percpu_irq(struct irq_desc *desc) · line 896
Quoted 6 lines
kernel/irq/chip.c +2
-1@@ -892,7 +892,8 @@ void handle_percpu_irq(struct irq_desc *desc)* * action->percpu_dev_id is a pointer to percpu variables which * contain the real device id for the cpu on which this handler is -* called +* called. This is also used for per-CPU NMIs, so special care is +* required.
Probably belongs in previous patch as not really related to removing the unused code, but meh.
Quoted 1 line
kernel/irq/chip.c +0
-0*/
Marc Zyngier
maintainerRe: [PATCH v2 11/25] genirq: Kill handle_percpu_devid_fasteoi_nmi()
Quoted 11 lines · Jonathan Cameron
Quoted 6 lines · On Mon, 15 Sep 2025 09:56:48 +0100 Marc Zyngier <[email protected]> wrote:
There is no in-tree user of this flow handler anymore, so simply remove it.
Suggested-by Will Deacon <[email protected]>Signed-off-by Marc Zyngier <[email protected]>---
Quoted 14 lines
kernel/irq/chip.c void handle_percpu_irq(struct irq_desc *desc) · line 896
Quoted 11 lines
kernel/irq/chip.c +2
-1@@ -892,7 +892,8 @@ void handle_percpu_irq(struct irq_desc *desc)* * action->percpu_dev_id is a pointer to percpu variables which * contain the real device id for the cpu on which this handler is -* called +* called. This is also used for per-CPU NMIs, so special care is +* required. Probably belongs in previous patch as not really related to removing the unused code, but meh.
Actually, I think I'll simply drop this comment. It really doesn't bring much to the table.
Thanks,
M.
Signature · 1 line
Jazz isn't dead. It just smells funny.
Marc Zyngier
maintainerPATCH v2 12/25 genirq: Merge irqaction::{dev_id,percpu_dev_id}
In reply to Marc ZyngierWhen irqaction::percpu_dev_id was introduced, it was hoped that it could be part of an anonymous union with dev_id, as the two fields are mutually exclusive.
However, toolchains used at the time were often showing terrible support for anonymous unions, breaking the build on a number of architectures. It was therefore decided to keep the two fields separate and address this down the line.
14 years later, the compiler dark age is over, and there is universal support for anonymous unions. Let's get a whole pointer back that can immediately be spent on something else.
--- include/linux/interrupt.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
include/linux/interrupt.h +4 -2
@@ -121,8 +121,10 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);*/ struct irqaction {irq_handler_t handler; -void *dev_id; -void __percpu *percpu_dev_id; +union { +void *dev_id; +void __percpu *percpu_dev_id; + };struct irqaction *next;irq_handler_t thread_fn;struct task_struct *thread;
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 13/25 genirq: Factor-in percpu irqaction creation
In reply to Marc ZyngierMove the code creating a per-cpu irqaction into its own helper, so that future changes to this code can be kept localised.
At the same time, fix the documentation which appears to say the wrong thing when it comes to interrupts being automatically enabled (percpu_devid interrupts never are).
--- kernel/irq/manage.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-)
kernel/irq/manage.c +24 -16
@@ -2442,6 +2442,24 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)return retval; } +static +struct irqaction *create_percpu_irqaction (irq_handler_t handler,unsigned long flags, +const char *devname,void __percpu *dev_id) +{ +struct irqaction *action; + + action =kzalloc (sizeof (struct irqaction ),GFP_KERNEL ); +if (!action) +return NULL ; + + action->handler = handler; + action->flags = flags |IRQF_PERCPU |IRQF_NO_SUSPEND ; + action->name = devname; + action->percpu_dev_id = dev_id; + +return action; +} +/** * __request_percpu_irq - allocate a percpu interrupt line * @irq: Interrupt line to allocate
@@ -2450,9 +2468,9 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)* @devname: An ascii name for the claiming device * @dev_id: A percpu cookie passed back to the handler function * -* This call allocates interrupt resources and enables the interrupt on the -* local CPU. If the interrupt is supposed to be enabled on other CPUs, it -* has to be done on each CPU using enable_percpu_irq(). +* This call allocates interrupt resources, but doesn't enable the interrupt +* on any CPU, as all percpu-devid interrupts are flagged with IRQ_NOAUTOEN. +* It has to be done on each CPU using enable_percpu_irq(). * * @dev_id must be globally unique. It is a per-cpu variable, and * the handler gets called with the interrupted CPU's instance of
@@ -2477,15 +2495,10 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler,if (flags && flags !=IRQF_TIMER )return -EINVAL ; - action =kzalloc (sizeof (struct irqaction ),GFP_KERNEL ); + action =create_percpu_irqaction (handler, flags, devname, dev_id);if (!action)return -ENOMEM ; - action->handler = handler; - action->flags = flags |IRQF_PERCPU |IRQF_NO_SUSPEND ; - action->name = devname; - action->percpu_dev_id = dev_id; - retval =irq_chip_pm_get (&desc->irq_data);if (retval <0 ) {kfree (action);
@@ -2546,16 +2559,11 @@ int request_percpu_nmi(unsigned int irq, irq_handler_t handler,if (irq_is_nmi (desc))return -EINVAL ; - action =kzalloc (sizeof (struct irqaction ),GFP_KERNEL ); + action =create_percpu_irqaction (handler,IRQF_NO_THREAD |IRQF_NOBALANCING , + name, dev_id);if (!action)return -ENOMEM ; - action->handler = handler; - action->flags =IRQF_PERCPU |IRQF_NO_SUSPEND |IRQF_NO_THREAD - |IRQF_NOBALANCING ; - action->name = name; - action->percpu_dev_id = dev_id; - retval =irq_chip_pm_get (&desc->irq_data);if (retval <0 ) goto err_out;
Signature · 1 line
2.39.2
Re: [PATCH v2 13/25] genirq: Factor-in percpu irqaction creation
Quoted 8 lines · On Mon, 15 Sep 2025 09:56:50 +0100 Marc Zyngier <[email protected]> wrote:
Move the code creating a per-cpu irqaction into its own helper, so that future changes to this code can be kept localised.
At the same time, fix the documentation which appears to say the wrong thing when it comes to interrupts being automatically enabled (
percpu_devidinterrupts never are).Signed-off-by Marc Zyngier <[email protected]>
Marc Zyngier
maintainerPATCH v2 14/25 genirq: Add affinity to percpu_devid interrupt requests
In reply to Marc ZyngierAdd an affinity field to both the irqaction structure and the interrupt request primitives. Nothing is making use of it yet, and the only value used it NULL, which is used as a shorthand for cpu_possible_mask.
This will shortly get used with actual affinities.
--- include/linux/interrupt.h | 5 +++-- kernel/irq/manage.c | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-)
include/linux/interrupt.h +3 -2
@@ -125,6 +125,7 @@ struct irqaction {void *dev_id;void __percpu *percpu_dev_id; }; +const struct cpumask *affinity;struct irqaction *next;irq_handler_t thread_fn;struct task_struct *thread;
@@ -181,7 +182,7 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler,extern int __must_check __request_percpu_irq (unsigned int irq,irq_handler_t handler,unsigned long flags,const char *devname, -void __percpu *percpu_dev_id); +const cpumask_t *affinity,void __percpu *percpu_dev_id); extern int __must_check request_nmi(unsigned int irq, irq_handler_t handler, unsigned long flags,
@@ -192,7 +193,7 @@ request_percpu_irq(unsigned int irq, irq_handler_t handler, const char *devname, void __percpu *percpu_dev_id) { return __request_percpu_irq(irq, handler, 0, -devname ,percpu_dev_id ); +devname ,NULL ,percpu_dev_id ); } extern int __must_check
kernel/irq/manage.c +10 -4
@@ -2444,10 +2444,14 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)static struct irqaction *create_percpu_irqaction (irq_handler_t handler,unsigned long flags, -const char *devname,void __percpu *dev_id) +const char *devname,const cpumask_t *affinity, +void __percpu *dev_id) {struct irqaction *action; +if (!affinity) + affinity = cpu_possible_mask; + action =kzalloc (sizeof (struct irqaction ),GFP_KERNEL );if (!action)return NULL ;
@@ -2456,6 +2460,7 @@ struct irqaction *create_percpu_irqaction(irq_handler_t handler, unsigned long f action->flags = flags |IRQF_PERCPU |IRQF_NO_SUSPEND ; action->name = devname; action->percpu_dev_id = dev_id; + action->affinity = affinity;return action; }
@@ -2466,6 +2471,7 @@ struct irqaction *create_percpu_irqaction(irq_handler_t handler, unsigned long f* @handler: Function to be called when the IRQ occurs. * @flags: Interrupt type flags (IRQF_TIMER only) * @devname: An ascii name for the claiming device +* @affinity: A cpumask describing the target CPUs for this interrupt * @dev_id: A percpu cookie passed back to the handler function * * This call allocates interrupt resources, but doesn't enable the interrupt
@@ -2478,7 +2484,7 @@ struct irqaction *create_percpu_irqaction(irq_handler_t handler, unsigned long f*/ int __request_percpu_irq (unsigned int irq,irq_handler_t handler,unsigned long flags,const char *devname, -void __percpu *dev_id) +const cpumask_t *affinity,void __percpu *dev_id) {struct irqaction *action;struct irq_desc *desc;
@@ -2495,7 +2501,7 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler,if (flags && flags !=IRQF_TIMER )return -EINVAL ; - action =create_percpu_irqaction (handler, flags, devname, dev_id); + action =create_percpu_irqaction (handler, flags, devname, affinity, dev_id);if (!action)return -ENOMEM ;
@@ -2560,7 +2566,7 @@ int request_percpu_nmi(unsigned int irq, irq_handler_t handler,return -EINVAL ; action =create_percpu_irqaction (handler,IRQF_NO_THREAD |IRQF_NOBALANCING , - name, dev_id); + name,NULL , dev_id);if (!action)return -ENOMEM ;
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 15/25 genirq: Update request_percpu_nmi() to take an affinity
In reply to Marc ZyngierContinue spreading the notion of affinity to the percpu interrupt request code by updating the call sites that use request_percpu_nmi() (all two of them) to take an affinity pointer. This pointer is firmly NULL for now.
--- arch/arm64/kernel/smp.c | 2 +- drivers/perf/arm_pmu.c | 4 +++- include/linux/interrupt.h | 4 ++-- kernel/irq/manage.c | 11 +++++++---- 4 files changed, 13 insertions(+), 8 deletions(-)
arch/arm64/kernel/smp.c +1 -1
@@ -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);
drivers/perf/arm_pmu.c +3 -1
@@ -659,7 +659,9 @@ int armpmu_request_irq(int irq, int cpu) irq_ops = &pmunmi_ops; } }else if (armpmu_count_irq_users (irq) ==0 ) { - err =request_percpu_nmi (irq, handler,"arm-pmu" , &cpu_armpmu); + err =request_percpu_nmi (irq, handler,"arm-pmu" , +NULL , + &cpu_armpmu);/* If cannot get an NMI, get a normal interrupt */ if (err) {
include/linux/interrupt.h +2 -2
@@ -197,8 +197,8 @@ request_percpu_irq(unsigned int irq, irq_handler_t handler, }extern int __must_check -request_percpu_nmi (unsigned int irq,irq_handler_t handler, -const char *devname,void __percpu *dev); +request_percpu_nmi (unsigned int irq,irq_handler_t handler,const char *devname, +const struct cpumask *affinity,void __percpu *dev_id);extern const void *free_irq (unsigned int ,void *);extern void free_percpu_irq (unsigned int ,void __percpu *);
kernel/irq/manage.c +7 -4
@@ -2527,6 +2527,7 @@ EXPORT_SYMBOL_GPL(__request_percpu_irq);* @irq: Interrupt line to allocate * @handler: Function to be called when the IRQ occurs. * @name: An ascii name for the claiming device +* @affinity: A cpumask describing the target CPUs for this interrupt * @dev_id: A percpu cookie passed back to the handler function * * This call allocates interrupt resources for a per CPU NMI. Per CPU NMIs
@@ -2544,7 +2545,8 @@ EXPORT_SYMBOL_GPL(__request_percpu_irq);* will fail returning a negative value. */ int request_percpu_nmi (unsigned int irq,irq_handler_t handler, -const char *name,void __percpu *dev_id) +const char *name, +const struct cpumask *affinity,void __percpu *dev_id) {struct irqaction *action;struct irq_desc *desc;
@@ -2561,12 +2563,13 @@ int request_percpu_nmi(unsigned int irq, irq_handler_t handler, !irq_supports_nmi(desc))return -EINVAL ; -/* The line cannot already be NMI */ -if (irq_is_nmi (desc)) +/* The line cannot be NMI already if the new request covers all CPUs */ +if (irq_is_nmi (desc) && + (!affinity ||cpumask_equal (affinity, cpu_possible_mask)))return -EINVAL ; action =create_percpu_irqaction (handler,IRQF_NO_THREAD |IRQF_NOBALANCING , - name,NULL , dev_id); + name, affinity, dev_id);if (!action)return -ENOMEM ;
Signature · 1 line
2.39.2
Re: [PATCH v2 15/25] genirq: Update request_percpu_nmi() to take an affinity
Quoted 6 lines · On Mon, 15 Sep 2025 09:56:52 +0100 Marc Zyngier <[email protected]> wrote:
Continue spreading the notion of affinity to the percpu interrupt request code by updating the call sites that use
request_percpu_nmi()(all two of them) to take an affinity pointer. This pointer is firmly NULL for now.Signed-off-by Marc Zyngier <[email protected]>
A few fussy reviewer comments inline.
Quoted 25 lines
--- arch/arm64/kernel/smp.c | 2 +- drivers/perf/arm_pmu.c | 4 +++- include/linux/interrupt.h | 4 ++-- kernel/irq/manage.c | 11 +++++++---- 4 files changed, 13 insertions(+), 8 deletions(-)arch/arm64/kernel/smp.c +1
-1@@ -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);drivers/perf/arm_pmu.c +0
-0
drivers/perf/arm_pmu.c int armpmu_request_irq(int irq, int cpu) · line 663
Quoted 6 lines
drivers/perf/arm_pmu.c +2
-1@@ -659,7 +659,9 @@ int armpmu_request_irq(int irq, int cpu) irq_ops = &pmunmi_ops; } }else if (armpmu_count_irq_users (irq) ==0 ) { - err =request_percpu_nmi (irq, handler,"arm-pmu" , &cpu_armpmu); + err = request_percpu_nmi(irq, handler, "arm-pmu", + NULL,
I was assuming this odd formatting was to help reduce churn in a later patch, but nope this whole block get replaced in patch 18. So might as well move NULL up a line an have a cleaner intermediate state.
Quoted 9 lines
drivers/perf/arm_pmu.c +1
-0+ &cpu_armpmu);/* If cannot get an NMI, get a normal interrupt */ if (err) {include/linux/interrupt.h +0
-0
include/linux/interrupt.h request_percpu_irq(unsigned int irq, irq_handler_t handler, · line 200
Quoted 6 lines
include/linux/interrupt.h +1
-2@@ -197,8 +197,8 @@ request_percpu_irq(unsigned int irq, irq_handler_t handler, } extern int __must_check -request_percpu_nmi (unsigned int irq,irq_handler_t handler, -const char *devname,void __percpu *dev); +request_percpu_nmi(unsigned int irq, irq_handler_t handler, const char *devname,
Odd inconsistency in parameter naming devname/name
Perhaps worth tidying that up whilst here. I only noticed because of the wrap comment below.
Quoted 17 lines
include/linux/interrupt.h +1
-0+ const struct cpumask *affinity, void __percpu *dev_id);extern const void *free_irq (unsigned int ,void *);extern void free_percpu_irq (unsigned int ,void __percpu *);kernel/irq/manage.c +1
-0@@ -2527,6 +2527,7 @@ EXPORT_SYMBOL_GPL(__request_percpu_irq);* @irq: Interrupt line to allocate * @handler: Function to be called when the IRQ occurs. * @name: An ascii name for the claiming device +* @affinity: A cpumask describing the target CPUs for this interrupt * @dev_id: A percpu cookie passed back to the handler function * * This call allocates interrupt resources for a per CPU NMI. Per CPU NMIs
kernel/irq/manage.c EXPORT_SYMBOL_GPL(__request_percpu_irq); · line 2549
Quoted 6 lines
kernel/irq/manage.c +2
-1@@ -2544,7 +2545,8 @@ EXPORT_SYMBOL_GPL(__request_percpu_irq);* will fail returning a negative value. */ int request_percpu_nmi (unsigned int irq,irq_handler_t handler, -const char *name,void __percpu *dev_id) +const char *name, +const struct cpumask *affinity,void __percpu *dev_id)
This seems like an odd wrap and I can't immediately see it making more sense in later patches.
Quoted 3 lines
kernel/irq/manage.c +0
-0{
Marc Zyngier
maintainerPATCH v2 16/25 genirq: Allow per-cpu interrupt sharing for non-overlapping affinities
In reply to Marc ZyngierInterrupt sharing for percpu-devid interrupts is forbidden, and for good reasons. These are interrupts generated *from* a CPU and handled by itself (timer, for example). Nobody in their right mind would put two devices on the same pin (and if they have, they get to keep the pieces...).
But this also prevents more benign cases, where devices are connected to groups of CPUs, and for which the affinities are not overlapping. Effectively, the only thing they share is the interrupt number, and nothing else.
Let's tweak the definition of IRQF_SHARED applied to percpu_devid interrupts to allow this particular case. This results in extra validation at the point of the interrupt being setup and freed, as well as a tiny bit of extra complexity for interrupts at handling time (to pick the correct irqaction).
--- kernel/irq/chip.c | 8 ++++-- kernel/irq/manage.c | 67 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 61 insertions(+), 14 deletions(-)
kernel/irq/chip.c +6 -2
@@ -898,8 +898,9 @@ void handle_percpu_irq(struct irq_desc *desc)void handle_percpu_devid_irq (struct irq_desc *desc) {struct irq_chip *chip =irq_desc_get_chip (desc); -struct irqaction *action = desc->action;unsigned int irq =irq_desc_get_irq (desc); +unsigned int cpu =smp_processor_id (); +struct irqaction *action;irqreturn_t res;/*
@@ -911,12 +912,15 @@ void handle_percpu_devid_irq(struct irq_desc *desc)if (chip->irq_ack) chip->irq_ack (&desc->irq_data); +for (action = desc->action; action; action = action->next) +if (cpumask_test_cpu (cpu, action->affinity)) +break ; +if (likely (action)) {trace_irq_handler_entry (irq, action); res = action->handler (irq,raw_cpu_ptr (action->percpu_dev_id));trace_irq_handler_exit (irq, action, res); }else { -unsigned int cpu =smp_processor_id ();bool enabled =cpumask_test_cpu (cpu, desc->percpu_enabled);if (enabled)
kernel/irq/manage.c +55 -12
127 lines not on this page · raw message
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 17/25 genirq: Add request_percpu_irq_affinity() helper
In reply to Marc ZyngierWhile it would be nice to simply make request_percpu_irq() take an affinity mask, the churn is likely to be on the irritating side given that most drivers do not give a damn about affinities.
So take the more innocuous path to provide a helper that parallels request_percpu_irq(), with an affinity as a bonus argument.
Yes, request_percpu_irq_affinity() is a bit of a mouthful.
--- include/linux/interrupt.h | 9 +++++++++ 1 file changed, 9 insertions(+)
include/linux/interrupt.h +9 -0
@@ -196,6 +196,15 @@ request_percpu_irq(unsigned int irq, irq_handler_t handler, devname, NULL, percpu_dev_id); } +static inline int __must_check +request_percpu_irq_affinity (unsigned int irq,irq_handler_t handler, +const char *devname,const cpumask_t *affinity, +void __percpu *percpu_dev_id) +{ +return __request_percpu_irq (irq, handler,0 , + devname, affinity, percpu_dev_id); +} +extern int __must_check request_percpu_nmi (unsigned int irq,irq_handler_t handler,const char *devname,const struct cpumask *affinity,void __percpu *dev_id);
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 18/25 perf: arm_pmu: Request specific affinities for percpu NMI/IRQ
In reply to Marc ZyngierFrom: Will Deacon <[email protected]>
Let the PMU driver request both NMI and normal IRQs with an affinity mask matching the PMU affinity.
--- drivers/perf/arm_pmu.c | 47 +++++++++++++++++++-------------- drivers/perf/arm_pmu_acpi.c | 2 +- drivers/perf/arm_pmu_platform.c | 4 +-- include/linux/perf/arm_pmu.h | 4 +-- 4 files changed, 32 insertions(+), 25 deletions(-)
drivers/perf/arm_pmu.c +27 -20
@@ -26,7 +26,8 @@#include <asm/irq_regs.h> -static int armpmu_count_irq_users (const int irq); +static int armpmu_count_irq_users (const struct cpumask *affinity, +const int irq);struct pmu_irq_ops {void (*enable_pmuirq)(unsigned int irq);
@@ -64,7 +65,9 @@ static void armpmu_enable_percpu_pmuirq(unsigned int irq)static void armpmu_free_percpu_pmuirq (unsigned int irq,int cpu,void __percpu *devid) { -if (armpmu_count_irq_users (irq) ==1 ) +struct arm_pmu *armpmu = *per_cpu_ptr ((void *__percpu *)devid, cpu); + +if (armpmu_count_irq_users (&armpmu->supported_cpus, irq) ==1 )free_percpu_irq (irq, devid); }
@@ -89,7 +92,9 @@ static void armpmu_disable_percpu_pmunmi(unsigned int irq)static void armpmu_free_percpu_pmunmi (unsigned int irq,int cpu,void __percpu *devid) { -if (armpmu_count_irq_users (irq) ==1 ) +struct arm_pmu *armpmu = *per_cpu_ptr ((void *__percpu *)devid, cpu); + +if (armpmu_count_irq_users (&armpmu->supported_cpus, irq) ==1 )free_percpu_nmi (irq, devid); }
@@ -580,11 +585,11 @@ static const struct attribute_group armpmu_common_attr_group = { .attrs = armpmu_common_attrs, }; -static int armpmu_count_irq_users (const int irq) +static int armpmu_count_irq_users (const struct cpumask *affinity,const int irq) {int cpu, count =0 ; -for_each_possible_cpu (cpu) { +for_each_cpu (cpu, affinity) {if (per_cpu (cpu_irq, cpu) == irq) count++; }
@@ -592,12 +597,13 @@ static int armpmu_count_irq_users(const int irq)return count; } -static const struct pmu_irq_ops *armpmu_find_irq_ops (int irq) +static const struct pmu_irq_ops * +armpmu_find_irq_ops (const struct cpumask *affinity,int irq) {const struct pmu_irq_ops *ops =NULL ;int cpu; -for_each_possible_cpu (cpu) { +for_each_cpu (cpu, affinity) {if (per_cpu (cpu_irq, cpu) != irq)continue ;
@@ -609,22 +615,25 @@ static const struct pmu_irq_ops *armpmu_find_irq_ops(int irq)return ops; } -void armpmu_free_irq (int irq,int cpu) +void armpmu_free_irq (struct arm_pmu *__percpu *armpmu,int irq,int cpu) {if (per_cpu (cpu_irq, cpu) ==0 )return ;if (WARN_ON (irq !=per_cpu (cpu_irq, cpu)))return ; -per_cpu (cpu_irq_ops, cpu)->free_pmuirq (irq, cpu, &cpu_armpmu); +per_cpu (cpu_irq_ops, cpu)->free_pmuirq (irq, cpu, armpmu);per_cpu (cpu_irq, cpu) =0 ;per_cpu (cpu_irq_ops, cpu) =NULL ; } -int armpmu_request_irq (int irq,int cpu) +int armpmu_request_irq (struct arm_pmu *__percpu *pcpu_armpmu,int irq,int cpu) {int err =0 ; +struct arm_pmu **armpmu =per_cpu_ptr (pcpu_armpmu, cpu); +const struct cpumask *affinity = *armpmu ? &(*armpmu)->supported_cpus : + cpu_possible_mask;/* ACPI */ const irq_handler_t handler = armpmu_dispatch_irq;const struct pmu_irq_ops *irq_ops;
@@ -646,27 +655,25 @@ int armpmu_request_irq(int irq, int cpu)IRQF_NOBALANCING |IRQF_NO_AUTOEN |IRQF_NO_THREAD ; - err =request_nmi (irq, handler, irq_flags,"arm-pmu" , -per_cpu_ptr (&cpu_armpmu, cpu)); + err =request_nmi (irq, handler, irq_flags,"arm-pmu" , armpmu);/* If cannot get an NMI, get a normal interrupt */ if (err) { err =request_irq (irq, handler, irq_flags,"arm-pmu" , -per_cpu_ptr (&cpu_armpmu, cpu)); + armpmu); irq_ops = &pmuirq_ops; }else { has_nmi = true; irq_ops = &pmunmi_ops; } - }else if (armpmu_count_irq_users (irq) ==0 ) { - err =request_percpu_nmi (irq, handler,"arm-pmu" , -NULL , - &cpu_armpmu); + }else if (armpmu_count_irq_users (affinity, irq) ==0 ) { + err =request_percpu_nmi (irq, handler,"arm-pmu" , affinity, + pcpu_armpmu);/* If cannot get an NMI, get a normal interrupt */ if (err) { - err =request_percpu_irq (irq, handler,"arm-pmu" , - &cpu_armpmu); + err =request_percpu_irq_affinity (irq, handler,"arm-pmu" , + affinity, pcpu_armpmu); irq_ops = &percpu_pmuirq_ops; }else { has_nmi = true;
@@ -674,7 +681,7 @@ int armpmu_request_irq(int irq, int cpu) } }else {/* Per cpudevid irq was already requested by another CPU */ - irq_ops =armpmu_find_irq_ops (irq); + irq_ops =armpmu_find_irq_ops (affinity, irq);if (WARN_ON (!irq_ops)) err = -EINVAL ;
drivers/perf/arm_pmu_acpi.c +1 -1
@@ -218,7 +218,7 @@ static int arm_pmu_acpi_parse_irqs(void)* them with their PMUs. */ per_cpu (pmu_irqs, cpu) = irq; - err =armpmu_request_irq (irq, cpu); + err =armpmu_request_irq (&probed_pmus, irq, cpu);if (err) goto out_err; }
drivers/perf/arm_pmu_platform.c +2 -2
@@ -165,7 +165,7 @@ static int armpmu_request_irqs(struct arm_pmu *armpmu)if (!irq)continue ; - err =armpmu_request_irq (irq, cpu); + err =armpmu_request_irq (&hw_events->percpu_pmu, irq, cpu);if (err)break ; }
@@ -181,7 +181,7 @@ static void armpmu_free_irqs(struct arm_pmu *armpmu)for_each_cpu (cpu, &armpmu->supported_cpus) {int irq =per_cpu (hw_events->irq, cpu); -armpmu_free_irq (irq, cpu); +armpmu_free_irq (&hw_events->percpu_pmu, irq, cpu); } }
include/linux/perf/arm_pmu.h +2 -2
@@ -190,8 +190,8 @@ bool arm_pmu_irq_is_nmi(void);struct arm_pmu *armpmu_alloc (void );void armpmu_free (struct arm_pmu *pmu);int armpmu_register (struct arm_pmu *pmu); -int armpmu_request_irq (int irq,int cpu); -void armpmu_free_irq (int irq,int cpu); +int armpmu_request_irq (struct arm_pmu *__percpu *armpmu,int irq,int cpu); +void armpmu_free_irq (struct arm_pmu *__percpu *armpmu,int irq,int cpu);#define ARMV8_PMU_PDEV_NAME "armv8-pmu"
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 19/25 perf: arm_spe_pmu: Request specific affinities for percpu IRQ
In reply to Marc ZyngierLet the SPE driver request IRQs with an affinity mask matching the SPE implementation affinity.
--- drivers/perf/arm_spe_pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/perf/arm_spe_pmu.c +2 -2
@@ -1183,8 +1183,8 @@ static int arm_spe_pmu_dev_init(struct arm_spe_pmu *spe_pmu)return -ENXIO ;/* Request our PPIs (note that the IRQ is still disabled) */ - ret =request_percpu_irq (spe_pmu->irq, arm_spe_pmu_irq_handler,DRVNAME , - spe_pmu->handle); + ret =request_percpu_irq_affinity (spe_pmu->irq, arm_spe_pmu_irq_handler, +DRVNAME , mask, spe_pmu->handle);if (ret)return ret;
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 20/25 coresight: trbe: Request specific affinities for percpu IRQ
In reply to Marc ZyngierLet the TRBE driver request IRQs with an affinity mask matching the TRBE implementation affinity.
--- drivers/hwtracing/coresight/coresight-trbe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/hwtracing/coresight/coresight-trbe.c +2 -1
@@ -1492,7 +1492,8 @@ static int arm_trbe_probe_irq(struct platform_device *pdev,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;
Signature · 1 line
2.39.2
Re: [PATCH v2 20/25] coresight: trbe: Request specific affinities for percpu IRQ
Quoted 13 lines · Marc Zyngier
Let the TRBE driver request IRQs with an affinity mask matching the TRBE implementation affinity.
Signed-off-by Marc Zyngier <[email protected]>--- drivers/hwtracing/coresight/coresight-trbe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)drivers/hwtracing/coresight/coresight-trbe.c +0
-0
drivers/hwtracing/coresight/coresight-trbe.c static int arm_trbe_probe_irq(struct platform_device *pdev, · line 1499
Quoted 9 lines
drivers/hwtracing/coresight/coresight-trbe.c +2
-1@@ -1492,7 +1492,8 @@ static int arm_trbe_probe_irq(struct platform_device *pdev,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;
Marc Zyngier
maintainerPATCH v2 21/25 irqchip/gic-v3: Drop support for custom PPI partitions
In reply to Marc ZyngierThe only thing getting in the way of correctly handling PPIs the way they were intended is the GICv3 hack that deals with PPI partitions.
Remove that code, allowing the common code to kick in.
--- drivers/irqchip/Kconfig | 1 - drivers/irqchip/irq-gic-v3.c | 133 +++-------------------------------- 2 files changed, 8 insertions(+), 126 deletions(-)
drivers/irqchip/Kconfig +0 -1
@@ -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
drivers/irqchip/irq-gic-v3.c +8 -125
209 lines not on this page · raw message
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 22/25 irqchip/apple-aic: Drop support for custom PMU irq partitions
In reply to Marc ZyngierSimilarly to what has been done for GICv3, drop the irq partitioning support from the AIC driver, effectively merging the two per-cpu interrupts for the PMU.
--- drivers/irqchip/irq-apple-aic.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-)
drivers/irqchip/irq-apple-aic.c +7 -21
@@ -578,16 +578,9 @@ static void __exception_irq_entry aic_handle_fiq(struct pt_regs *regs) }if ((read_sysreg_s (SYS_IMP_APL_PMCR0_EL1 ) & (PMCR0_IMODE |PMCR0_IACT )) == - (FIELD_PREP (PMCR0_IMODE ,PMCR0_IMODE_FIQ ) |PMCR0_IACT )) { -int irq; -if (cpumask_test_cpu (smp_processor_id (), - &aic_irqc->fiq_aff[AIC_CPU_PMU_P ]->aff)) - irq =AIC_CPU_PMU_P ; -else - irq =AIC_CPU_PMU_E ; + (FIELD_PREP (PMCR0_IMODE ,PMCR0_IMODE_FIQ ) |PMCR0_IACT ))generic_handle_domain_irq (aic_irqc->hw_domain, -AIC_FIQ_HWIRQ (irq)); - } +AIC_FIQ_HWIRQ (AIC_CPU_PMU_P )); if (static_branch_likely(&use_fast_ipi) && (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == UPMCR0_IMODE_FIQ) &&
@@ -632,18 +625,7 @@ static int aic_irq_domain_map(struct irq_domain *id, unsigned int irq, handle_fasteoi_irq, NULL, NULL);irqd_set_single_target (irq_desc_get_irq_data (irq_to_desc (irq))); }else { -int fiq =FIELD_GET (AIC_EVENT_NUM , hw); - -switch (fiq) { -case AIC_CPU_PMU_P : -case AIC_CPU_PMU_E : -irq_set_percpu_devid_partition (irq, &ic->fiq_aff[fiq]->aff); -break ; -default : -irq_set_percpu_devid (irq); -break ; - } - +irq_set_percpu_devid (irq);irq_domain_set_info (id, irq, hw, &fiq_chip, id->host_data, handle_percpu_devid_irq,NULL ,NULL ); }
@@ -732,6 +714,10 @@ static int aic_irq_domain_translate(struct irq_domain *id,break ; } } + +/* Merge the two PMUs on a single interrupt */ +if (*hwirq ==AIC_CPU_PMU_E ) + *hwirq =AIC_CPU_PMU_P ;break ;default :return -EINVAL ;
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 23/25 irqchip: Kill irq-partition-percpu
In reply to Marc ZyngierThis code is now completely unused, and nobody will ever miss it.
--- drivers/irqchip/Kconfig | 3 - drivers/irqchip/Makefile | 1 - drivers/irqchip/irq-partition-percpu.c | 241 ------------------- include/linux/irqchip/irq-partition-percpu.h | 53 ---- 4 files changed, 298 deletions(-) delete mode 100644 drivers/irqchip/irq-partition-percpu.c delete mode 100644 include/linux/irqchip/irq-partition-percpu.h
drivers/irqchip/Kconfig +0 -3
@@ -450,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
drivers/irqchip/Makefile +0 -1
@@ -36,7 +36,6 @@ obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-v3-mbi.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_ITS_PARENT) += irq-gic-its-msi-parent.o obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v4.o obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o -obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o obj-$(CONFIG_ARM_GIC_V5) += irq-gic-v5.o irq-gic-v5-irs.o irq-gic-v5-its.o \ irq-gic-v5-iwb.o obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
drivers/irqchip/irq-partition-percpu.c deleted +0 -241
241 lines not on this page · raw message
include/linux/irqchip/irq-partition-percpu.h deleted +0 -53
53 lines not on this page · raw message
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 24/25 genirq: Kill irq_{g,s}et_percpu_devid_partition()
In reply to Marc ZyngierThese two helpers do not have any user anymore, and can be removed, together with the affinity field kept in the irqdesc structure.
--- include/linux/irq.h | 4 ---- include/linux/irqdesc.h | 1 - kernel/irq/irqdesc.c | 24 +----------------------- 3 files changed, 1 insertion(+), 28 deletions(-)
include/linux/irq.h +0 -4
@@ -716,10 +716,6 @@ static inline void irq_set_chip_and_handler(unsigned int irq, }extern int irq_set_percpu_devid (unsigned int irq); -extern int irq_set_percpu_devid_partition (unsigned int irq, -const struct cpumask *affinity); -extern int irq_get_percpu_devid_partition (unsigned int irq, -struct cpumask *affinity); extern void __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
include/linux/irqdesc.h +0 -1
@@ -82,7 +82,6 @@ struct irq_desc {int threads_handled_last;raw_spinlock_t lock;struct cpumask *percpu_enabled; -const struct cpumask *percpu_affinity;#ifdef CONFIG_SMP const struct cpumask *affinity_hint;struct irq_affinity_notify *affinity_notify;
kernel/irq/irqdesc.c +1 -23
@@ -886,8 +886,7 @@ void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)chip_bus_sync_unlock (desc); } -int irq_set_percpu_devid_partition (unsigned int irq, -const struct cpumask *affinity) +int irq_set_percpu_devid (unsigned int irq) {struct irq_desc *desc =irq_to_desc (irq);
@@ -899,31 +898,10 @@ int irq_set_percpu_devid_partition(unsigned int irq,if (!desc->percpu_enabled)return -ENOMEM ; - desc->percpu_affinity = affinity ? : cpu_possible_mask; -irq_set_percpu_devid_flags (irq);return 0 ; } -int irq_set_percpu_devid (unsigned int irq) -{ -return irq_set_percpu_devid_partition (irq,NULL ); -} - -int irq_get_percpu_devid_partition (unsigned int irq,struct cpumask *affinity) -{ -struct irq_desc *desc =irq_to_desc (irq); - -if (!desc || !desc->percpu_enabled) -return -EINVAL ; - -if (affinity) -cpumask_copy (affinity, desc->percpu_affinity); - -return 0 ; -} -EXPORT_SYMBOL_GPL (irq_get_percpu_devid_partition); -void kstat_incr_irq_this_cpu (unsigned int irq) {kstat_incr_irqs_this_cpu (irq_to_desc (irq));
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 25/25 perf: arm_pmu: Kill last use of per-CPU cpu_armpmu pointer
In reply to Marc ZyngierHaving removed the use of the cpu_armpmu per-CPU variable from the interrupt handling, the only user left is the BRBE scheduler hook.
It is easy to drop the use of this variable by following the pointer to the generic PMU structure, and get the arm_pmu structure from there.
Perform the conversion and kill cpu_armpmu altogether.
--- drivers/perf/arm_pmu.c | 5 ----- drivers/perf/arm_pmuv3.c | 2 +- include/linux/perf/arm_pmu.h | 2 -- 3 files changed, 1 insertion(+), 8 deletions(-)
drivers/perf/arm_pmu.c +0 -5
@@ -104,7 +104,6 @@ static const struct pmu_irq_ops percpu_pmunmi_ops = { .free_pmuirq = armpmu_free_percpu_pmunmi }; -DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu); static DEFINE_PER_CPU(int, cpu_irq); static DEFINE_PER_CPU(const struct pmu_irq_ops *, cpu_irq_ops);
@@ -726,8 +725,6 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)if (pmu->reset) pmu->reset (pmu); -per_cpu (cpu_armpmu, cpu) = pmu; - irq =armpmu_get_cpu_irq (pmu, cpu);if (irq)per_cpu (cpu_irq_ops, cpu)->enable_pmuirq (irq);
@@ -747,8 +744,6 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node)if (irq)per_cpu (cpu_irq_ops, cpu)->disable_pmuirq (irq); -per_cpu (cpu_armpmu, cpu) =NULL ; -return 0 ; }
drivers/perf/arm_pmuv3.c +1 -1
@@ -1039,7 +1039,7 @@ static int armv8pmu_user_event_idx(struct perf_event *event)static void armv8pmu_sched_task (struct perf_event_pmu_context *pmu_ctx,struct task_struct *task,bool sched_in) { -struct arm_pmu *armpmu = *this_cpu_ptr (&cpu_armpmu); +struct arm_pmu *armpmu =to_arm_pmu (pmu_ctx->pmu);struct pmu_hw_events *hw_events =this_cpu_ptr (armpmu->hw_events);if (!hw_events->branch_users)
include/linux/perf/arm_pmu.h +0 -2
@@ -132,8 +132,6 @@ struct arm_pmu {#define to_arm_pmu (p) (container_of(p, struct arm_pmu, pmu)) -DECLARE_PER_CPU(struct arm_pmu *, cpu_armpmu); -u64 armpmu_event_update (struct perf_event *event);int armpmu_event_set_period (struct perf_event *event);
Signature · 1 line
2.39.2