genirq, perf: Cleanup the abuse of irq_set_affinity_hint()
Subsystems (6)
cover genirq, perf: Cleanup the abuse of irq_set_affinity_hint()
The modular PMU drivers use irq_set_affinity_hint() to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.
Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from irq_set_affinity_hint() is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Sigh, if people would at least talk if something is missing...
Clean up the mess by exposing irq_set_affinity() and converting the drivers over to that.
Thanks,
tglx
--- drivers/perf/arm-ccn.c | 6 +--- drivers/perf/arm-cmn.c | 9 +----- drivers/perf/arm_dmc620_pmu.c | 5 +-- drivers/perf/arm_dsu_pmu.c | 8 +---- drivers/perf/arm_smmuv3_pmu.c | 10 ++----- drivers/perf/fsl_imx8_ddr_perf.c | 5 +-- drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 3 -- drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 3 -- drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 3 -- drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 3 -- drivers/perf/hisilicon/hisi_uncore_pmu.c | 4 +- drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 3 -- include/linux/interrupt.h | 35 +------------------------- kernel/irq/manage.c | 33 +++++++++++++++++++++++- 14 files changed, 49 insertions(+), 81 deletions(-)
PATCH 1/8 genirq: Export affinity setter for modules
Perf modules abuse irq_set_affinity_hint() to set the affinity of system PMU interrupts just because irq_set_affinity() was not exported.
The fact that irq_set_affinity_hint() actually sets the affinity is a non-documented side effect and the name is clearly saying it's a hint.
To clean this up, export the real affinity setter.
--- include/linux/interrupt.h | 35 ++--------------------------------- kernel/irq/manage.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 34 deletions(-)
include/linux/interrupt.h +2 -33
@@ -322,39 +322,8 @@ struct irq_affinity_desc {extern cpumask_var_t irq_default_affinity; -/* Internal implementation. Use the helpers below */ -extern int __irq_set_affinity (unsigned int irq,const struct cpumask *cpumask, -bool force); - -/** -* irq_set_affinity - Set the irq affinity of a given irq -* @irq: Interrupt to set affinity -* @cpumask: cpumask -* -* Fails if cpumask does not contain an online CPU -*/ -static inline int -irq_set_affinity (unsigned int irq,const struct cpumask *cpumask) -{ -return __irq_set_affinity (irq, cpumask, false); -} - -/** -* irq_force_affinity - Force the irq affinity of a given irq -* @irq: Interrupt to set affinity -* @cpumask: cpumask -* -* Same as irq_set_affinity, but without checking the mask against -* online cpus. -* -* Solely for low level cpu hotplug code, where we need to make per -* cpu interrupts affine before the cpu becomes online. -*/ -static inline int -irq_force_affinity (unsigned int irq,const struct cpumask *cpumask) -{ -return __irq_set_affinity (irq, cpumask, true); -} +extern int irq_set_affinity (unsigned int irq,const struct cpumask *cpumask); +extern int irq_force_affinity (unsigned int irq,const struct cpumask *cpumask);extern int irq_can_set_affinity (unsigned int irq);extern int irq_select_affinity (unsigned int irq);
kernel/irq/manage.c +32 -1
@@ -441,7 +441,8 @@ int irq_update_affinity_desc(unsigned inreturn ret; } -int __irq_set_affinity (unsigned int irq,const struct cpumask *mask,bool force) +static int __irq_set_affinity (unsigned int irq,const struct cpumask *mask, +bool force) {struct irq_desc *desc =irq_to_desc (irq);unsigned long flags;
@@ -456,6 +457,36 @@ int __irq_set_affinity(unsigned int irq,return ret; } +/** +* irq_set_affinity - Set the irq affinity of a given irq +* @irq: Interrupt to set affinity +* @cpumask: cpumask +* +* Fails if cpumask does not contain an online CPU +*/ +int irq_set_affinity (unsigned int irq,const struct cpumask *cpumask) +{ +return __irq_set_affinity (irq, cpumask, false); +} +EXPORT_SYMBOL_GPL (irq_set_affinity); + +/** +* irq_force_affinity - Force the irq affinity of a given irq +* @irq: Interrupt to set affinity +* @cpumask: cpumask +* +* Same as irq_set_affinity, but without checking the mask against +* online cpus. +* +* Solely for low level cpu hotplug code, where we need to make per +* cpu interrupts affine before the cpu becomes online. +*/ +int irq_force_affinity (unsigned int irq,const struct cpumask *cpumask) +{ +return __irq_set_affinity (irq, cpumask, true); +} +EXPORT_SYMBOL_GPL (irq_force_affinity); +int irq_set_affinity_hint (unsigned int irq,const struct cpumask *m) {unsigned long flags;
[tip: irq/core] genirq: Export affinity setter for modules
The following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: 4d80d6ca5d77fde9880da8466e5b64f250e5bf82 Gitweb: https://git.kernel.org/tip/4d80d6ca5d77fde9880da8466e5b64f250e5bf82 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 18 May 2021 11:17:26 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Wed, 19 May 2021 11:01:51 +02:00
genirq: Export affinity setter for modules
Perf modules abuse irq_set_affinity_hint() to set the affinity of system PMU interrupts just because irq_set_affinity() was not exported.
The fact that irq_set_affinity_hint() actually sets the affinity is a non-documented side effect and the name is clearly saying it's a hint.
To clean this up, export the real affinity setter.
--- include/linux/interrupt.h | 35 ++--------------------------------- kernel/irq/manage.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 34 deletions(-)
include/linux/interrupt.h +2 -33
@@ -319,39 +319,8 @@ struct irq_affinity_desc {extern cpumask_var_t irq_default_affinity; -/* Internal implementation. Use the helpers below */ -extern int __irq_set_affinity (unsigned int irq,const struct cpumask *cpumask, -bool force); - -/** -* irq_set_affinity - Set the irq affinity of a given irq -* @irq: Interrupt to set affinity -* @cpumask: cpumask -* -* Fails if cpumask does not contain an online CPU -*/ -static inline int -irq_set_affinity (unsigned int irq,const struct cpumask *cpumask) -{ -return __irq_set_affinity (irq, cpumask, false); -} - -/** -* irq_force_affinity - Force the irq affinity of a given irq -* @irq: Interrupt to set affinity -* @cpumask: cpumask -* -* Same as irq_set_affinity, but without checking the mask against -* online cpus. -* -* Solely for low level cpu hotplug code, where we need to make per -* cpu interrupts affine before the cpu becomes online. -*/ -static inline int -irq_force_affinity (unsigned int irq,const struct cpumask *cpumask) -{ -return __irq_set_affinity (irq, cpumask, true); -} +extern int irq_set_affinity (unsigned int irq,const struct cpumask *cpumask); +extern int irq_force_affinity (unsigned int irq,const struct cpumask *cpumask);extern int irq_can_set_affinity (unsigned int irq);extern int irq_select_affinity (unsigned int irq);
kernel/irq/manage.c +32 -1
@@ -441,7 +441,8 @@ out_unlock:return ret; } -int __irq_set_affinity (unsigned int irq,const struct cpumask *mask,bool force) +static int __irq_set_affinity (unsigned int irq,const struct cpumask *mask, +bool force) {struct irq_desc *desc =irq_to_desc (irq);unsigned long flags;
@@ -456,6 +457,36 @@ int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force)return ret; } +/** +* irq_set_affinity - Set the irq affinity of a given irq +* @irq: Interrupt to set affinity +* @cpumask: cpumask +* +* Fails if cpumask does not contain an online CPU +*/ +int irq_set_affinity (unsigned int irq,const struct cpumask *cpumask) +{ +return __irq_set_affinity (irq, cpumask, false); +} +EXPORT_SYMBOL_GPL (irq_set_affinity); + +/** +* irq_force_affinity - Force the irq affinity of a given irq +* @irq: Interrupt to set affinity +* @cpumask: cpumask +* +* Same as irq_set_affinity, but without checking the mask against +* online cpus. +* +* Solely for low level cpu hotplug code, where we need to make per +* cpu interrupts affine before the cpu becomes online. +*/ +int irq_force_affinity (unsigned int irq,const struct cpumask *cpumask) +{ +return __irq_set_affinity (irq, cpumask, true); +} +EXPORT_SYMBOL_GPL (irq_force_affinity); +int irq_set_affinity_hint (unsigned int irq,const struct cpumask *m) {unsigned long flags;
PATCH 2/8 perf/arm-ccn: Use irq_set_affinity()
In reply to Thomas GleixnerThe driver uses irq_set_affinity_hint() to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.
Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from irq_set_affinity_hint() is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Replace the mindless abuse with irq_set_affinity().
--- drivers/perf/arm-ccn.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/perf/arm-ccn.c +2 -4
@@ -1211,7 +1211,7 @@ static int arm_ccn_pmu_offline_cpu(unsigperf_pmu_migrate_context (&dt->pmu, cpu, target); dt->cpu = target;if (ccn->irq) -WARN_ON (irq_set_affinity_hint (ccn->irq,cpumask_of (dt->cpu))); +WARN_ON (irq_set_affinity (ccn->irq,cpumask_of (dt->cpu)));return 0 ; }
@@ -1291,7 +1291,7 @@ static int arm_ccn_pmu_init(struct arm_c/* Also make sure that the overflow interrupt is handled by this CPU */ if (ccn->irq) { - err =irq_set_affinity_hint (ccn->irq,cpumask_of (ccn->dt.cpu)); + err =irq_set_affinity (ccn->irq,cpumask_of (ccn->dt.cpu));if (err) {dev_err (ccn->dev,"Failed to set interrupt affinity!\n" ); goto error_set_affinity;
@@ -1325,8 +1325,6 @@ static void arm_ccn_pmu_cleanup(struct acpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_CCN_ONLINE , &ccn->dt.node); -if (ccn->irq) -irq_set_affinity_hint (ccn->irq,NULL );for (i =0 ; i < ccn->num_xps; i++)writel (0 , ccn->xp[i].base +CCN_XP_DT_CONTROL );writel (0 , ccn->dt.base +CCN_DT_PMCR );
PATCH 3/8 perf/arm-cmn: Use irq_set_affinity()
In reply to Thomas GleixnerThe driver uses irq_set_affinity_hint() to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.
Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from irq_set_affinity_hint() is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Replace the mindless abuse with irq_set_affinity().
--- drivers/perf/arm-cmn.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
drivers/perf/arm-cmn.c +2 -7
@@ -1162,7 +1162,7 @@ static int arm_cmn_pmu_offline_cpu(unsigperf_pmu_migrate_context (&cmn->pmu, cpu, target);for (i =0 ; i < cmn->num_dtcs; i++) -irq_set_affinity_hint (cmn->dtc[i].irq,cpumask_of (target)); +irq_set_affinity (cmn->dtc[i].irq,cpumask_of (target)); cmn->cpu = target;return 0 ; }
@@ -1222,7 +1222,7 @@ static int arm_cmn_init_irqs(struct arm_if (err)return err; - err =irq_set_affinity_hint (irq,cpumask_of (cmn->cpu)); + err =irq_set_affinity (irq,cpumask_of (cmn->cpu));if (err)return err; next:
@@ -1568,16 +1568,11 @@ static int arm_cmn_probe(struct platformstatic int arm_cmn_remove (struct platform_device *pdev) {struct arm_cmn *cmn =platform_get_drvdata (pdev); -int i;writel_relaxed (0 , cmn->dtc[0 ].base +CMN_DT_DTC_CTL );perf_pmu_unregister (&cmn->pmu);cpuhp_state_remove_instance (arm_cmn_hp_state, &cmn->cpuhp_node); - -for (i =0 ; i < cmn->num_dtcs; i++) -irq_set_affinity_hint (cmn->dtc[i].irq,NULL ); -return 0 ; }
PATCH 4/8 perf/arm-dmc620: Use irq_set_affinity()
In reply to Thomas GleixnerThe driver uses irq_set_affinity_hint() to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.
Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from irq_set_affinity_hint() is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Replace the mindless abuse with irq_set_affinity().
--- drivers/perf/arm_dmc620_pmu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/perf/arm_dmc620_pmu.c +2 -3
@@ -421,7 +421,7 @@ static struct dmc620_pmu_irq *__dmc620_pif (ret) goto out_free_aff; - ret =irq_set_affinity_hint (irq_num,cpumask_of (irq->cpu)); + ret =irq_set_affinity (irq_num,cpumask_of (irq->cpu));if (ret) goto out_free_irq;
@@ -475,7 +475,6 @@ static void dmc620_pmu_put_irq(struct dmlist_del (&irq->irqs_node);mutex_unlock (&dmc620_pmu_irqs_lock); -WARN_ON (irq_set_affinity_hint (irq->irq_num,NULL ));free_irq (irq->irq_num, irq);cpuhp_state_remove_instance_nocalls (cpuhp_state_num, &irq->node);kfree (irq);
@@ -622,7 +621,7 @@ static int dmc620_pmu_cpu_teardown(unsigperf_pmu_migrate_context (&dmc620_pmu->pmu, irq->cpu, target);mutex_unlock (&dmc620_pmu_irqs_lock); -WARN_ON (irq_set_affinity_hint (irq->irq_num,cpumask_of (target))); +WARN_ON (irq_set_affinity (irq->irq_num,cpumask_of (target))); irq->cpu = target;return 0 ;
PATCH 5/8 perf/arm-dsu: Use irq_set_affinity()
In reply to Thomas GleixnerThe driver uses irq_set_affinity_hint() to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.
Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from irq_set_affinity_hint() is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Replace the mindless abuse with irq_set_affinity().
--- drivers/perf/arm_dsu_pmu.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/perf/arm_dsu_pmu.c +2 -6
@@ -687,7 +687,7 @@ static void dsu_pmu_probe_pmu(struct dsustatic void dsu_pmu_set_active_cpu (int cpu,struct dsu_pmu *dsu_pmu) {cpumask_set_cpu (cpu, &dsu_pmu->active_cpu); -if (irq_set_affinity_hint (dsu_pmu->irq, &dsu_pmu->active_cpu)) +if (irq_set_affinity (dsu_pmu->irq, &dsu_pmu->active_cpu))pr_warn ("Failed to set irq affinity to %d\n" , cpu); }
@@ -769,7 +769,6 @@ static int dsu_pmu_device_probe(struct pif (rc) {cpuhp_state_remove_instance (dsu_pmu_cpuhp_state, &dsu_pmu->cpuhp_node); -irq_set_affinity_hint (dsu_pmu->irq,NULL ); }return rc;
@@ -781,7 +780,6 @@ static int dsu_pmu_device_remove(structperf_pmu_unregister (&dsu_pmu->pmu);cpuhp_state_remove_instance (dsu_pmu_cpuhp_state, &dsu_pmu->cpuhp_node); -irq_set_affinity_hint (dsu_pmu->irq,NULL );return 0 ; }
@@ -840,10 +838,8 @@ static int dsu_pmu_cpu_teardown(unsigned dst =dsu_pmu_get_online_cpu_any_but (dsu_pmu, cpu);/* If there are no active CPUs in the DSU, leave IRQ disabled */ -if (dst >= nr_cpu_ids) { -irq_set_affinity_hint (dsu_pmu->irq,NULL ); +if (dst >= nr_cpu_ids)return 0 ; - }perf_pmu_migrate_context (&dsu_pmu->pmu, cpu, dst);dsu_pmu_set_active_cpu (dst, dsu_pmu);
Re: [patch 5/8] perf/arm-dsu: Use irq_set_affinity()
drivers/perf/arm_dsu_pmu.c static int dsu_pmu_device_probe(struct p · line 769
Quoted 3 lines · Thomas Gleixner
drivers/perf/arm_dsu_pmu.c +0
-0@@ -769,7 +769,6 @@ static int dsu_pmu_device_probe(struct pif (rc) {
nit: I think that someone will send a patch to remove these {} later...
drivers/perf/arm_dsu_pmu.c static int dsu_pmu_device_probe(struct p · line 772
Quoted 4 lines
drivers/perf/arm_dsu_pmu.c +0
-1cpuhp_state_remove_instance (dsu_pmu_cpuhp_state, &dsu_pmu->cpuhp_node); -irq_set_affinity_hint (dsu_pmu->irq,NULL ); }
Thanks,
John
Re: [patch 5/8] perf/arm-dsu: Use irq_set_affinity()
Quoted 11 lines · John Garry
drivers/perf/arm_dsu_pmu.c static int dsu_pmu_device_probe(struct p · line 769
Quoted 3 lines · Thomas Gleixner
drivers/perf/arm_dsu_pmu.c +0
-0@@ -769,7 +769,6 @@ static int dsu_pmu_device_probe(struct pif (rc) {nit: I think that someone will send a patch to remove these {} later...
drivers/perf/arm_dsu_pmu.c static int dsu_pmu_device_probe(struct p · line 772
Quoted 4 lines
drivers/perf/arm_dsu_pmu.c +0
-1cpuhp_state_remove_instance (dsu_pmu_cpuhp_state, &dsu_pmu->cpuhp_node); -irq_set_affinity_hint (dsu_pmu->irq,NULL ); }
which should be rejected because
cpuhp_state_remove_instance(dsu_pmu_cpuhp_state,
&dsu_pmu->cpuhp_node);
is _NOT_ a one line statement.
if (foo) cpuhp_state_remove_instance(state, &node);
is fine, but
if (foo)
cpuhp_state_remove_instance(dsu_pmu_cpuhp_state,
&dsu_pmu->cpuhp_node);
breaks the expectation of a single line following the condition which confuses my brain based OCR. :)
So I left the brackets there on purpose.
Thanks,
tglx
PATCH 6/8 perf/arm-smmuv3: Use irq_set_affinity()
In reply to Thomas GleixnerThe driver uses irq_set_affinity_hint() to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.
Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from irq_set_affinity_hint() is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Replace the mindless abuse with irq_set_affinity().
--- drivers/perf/arm_smmuv3_pmu.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
drivers/perf/arm_smmuv3_pmu.c +3 -7
@@ -628,7 +628,7 @@ static int smmu_pmu_offline_cpu(unsignedperf_pmu_migrate_context (&smmu_pmu->pmu, cpu, target); smmu_pmu->on_cpu = target; -WARN_ON (irq_set_affinity_hint (smmu_pmu->irq,cpumask_of (target))); +WARN_ON (irq_set_affinity (smmu_pmu->irq,cpumask_of (target)));return 0 ; }
@@ -839,15 +839,14 @@ static int smmu_pmu_probe(struct platfor/* Pick one CPU to be the preferred one to use */ smmu_pmu->on_cpu =raw_smp_processor_id (); -WARN_ON (irq_set_affinity_hint (smmu_pmu->irq, -cpumask_of (smmu_pmu->on_cpu))); +WARN_ON (irq_set_affinity (smmu_pmu->irq,cpumask_of (smmu_pmu->on_cpu))); err =cpuhp_state_add_instance_nocalls (cpuhp_state_num, &smmu_pmu->node);if (err) {dev_err (dev,"Error %d registering hotplug, PMU @%pa\n" , err, &res_0->start); - goto out_clear_affinity; +return err; } err =perf_pmu_register (&smmu_pmu->pmu, name,-1 );
@@ -866,8 +865,6 @@ static int smmu_pmu_probe(struct platfor out_unregister:cpuhp_state_remove_instance_nocalls (cpuhp_state_num, &smmu_pmu->node); -out_clear_affinity: -irq_set_affinity_hint (smmu_pmu->irq,NULL );return err; }
@@ -877,7 +874,6 @@ static int smmu_pmu_remove(struct platfoperf_pmu_unregister (&smmu_pmu->pmu);cpuhp_state_remove_instance_nocalls (cpuhp_state_num, &smmu_pmu->node); -irq_set_affinity_hint (smmu_pmu->irq,NULL );return 0 ; }
PATCH 7/8 perf/imx_ddr: Use irq_set_affinity()
In reply to Thomas GleixnerThe driver uses irq_set_affinity_hint() to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.
Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from irq_set_affinity_hint() is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Replace the mindless abuse with irq_set_affinity().
--- drivers/perf/fsl_imx8_ddr_perf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/perf/fsl_imx8_ddr_perf.c +2 -3
@@ -674,7 +674,7 @@ static int ddr_perf_offline_cpu(unsignedperf_pmu_migrate_context (&pmu->pmu, cpu, target); pmu->cpu = target; -WARN_ON (irq_set_affinity_hint (pmu->irq,cpumask_of (pmu->cpu))); +WARN_ON (irq_set_affinity (pmu->irq,cpumask_of (pmu->cpu)));return 0 ; }
@@ -749,7 +749,7 @@ static int ddr_perf_probe(struct platfor } pmu->irq = irq; - ret =irq_set_affinity_hint (pmu->irq,cpumask_of (pmu->cpu)); + ret =irq_set_affinity (pmu->irq,cpumask_of (pmu->cpu));if (ret) {dev_err (pmu->dev,"Failed to set interrupt affinity!\n" ); goto ddr_perf_err;
@@ -777,7 +777,6 @@ static int ddr_perf_remove(struct platfocpuhp_state_remove_instance_nocalls (pmu->cpuhp_state, &pmu->node);cpuhp_remove_multi_state (pmu->cpuhp_state); -irq_set_affinity_hint (pmu->irq,NULL );perf_pmu_unregister (&pmu->pmu);
PATCH 8/8 perf/hisi: Use irq_set_affinity()
In reply to Thomas GleixnerThese drivers use irq_set_affinity_hint() to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.
Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from irq_set_affinity_hint() is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Replace the mindless abuse with irq_set_affinity().
--- drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 3 --- drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 3 --- drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 3 --- drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 3 --- drivers/perf/hisilicon/hisi_uncore_pmu.c | 4 ++-- drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 3 --- 6 files changed, 2 insertions(+), 17 deletions(-)
drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c +0 -3
@@ -537,7 +537,6 @@ static int hisi_ddrc_pmu_probe(struct pldev_err (ddrc_pmu->dev,"DDRC PMU register failed!\n" );cpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE , &ddrc_pmu->node); -irq_set_affinity_hint (ddrc_pmu->irq,NULL ); }return ret;
@@ -550,8 +549,6 @@ static int hisi_ddrc_pmu_remove(struct pperf_pmu_unregister (&ddrc_pmu->pmu);cpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE , &ddrc_pmu->node); -irq_set_affinity_hint (ddrc_pmu->irq,NULL ); -return 0 ; }
drivers/perf/hisilicon/hisi_uncore_hha_pmu.c +0 -3
@@ -540,7 +540,6 @@ static int hisi_hha_pmu_probe(struct pladev_err (hha_pmu->dev,"HHA PMU register failed!\n" );cpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE , &hha_pmu->node); -irq_set_affinity_hint (hha_pmu->irq,NULL ); }return ret;
@@ -553,8 +552,6 @@ static int hisi_hha_pmu_remove(struct plperf_pmu_unregister (&hha_pmu->pmu);cpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE , &hha_pmu->node); -irq_set_affinity_hint (hha_pmu->irq,NULL ); -return 0 ; }
drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c +0 -3
@@ -578,7 +578,6 @@ static int hisi_l3c_pmu_probe(struct pladev_err (l3c_pmu->dev,"L3C PMU register failed!\n" );cpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_HISI_L3_ONLINE , &l3c_pmu->node); -irq_set_affinity_hint (l3c_pmu->irq,NULL ); }return ret;
@@ -591,8 +590,6 @@ static int hisi_l3c_pmu_remove(struct plperf_pmu_unregister (&l3c_pmu->pmu);cpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_HISI_L3_ONLINE , &l3c_pmu->node); -irq_set_affinity_hint (l3c_pmu->irq,NULL ); -return 0 ; }
drivers/perf/hisilicon/hisi_uncore_pa_pmu.c +0 -3
@@ -436,7 +436,6 @@ static int hisi_pa_pmu_probe(struct platdev_err (pa_pmu->dev,"PMU register failed, ret = %d\n" , ret);cpuhp_state_remove_instance (CPUHP_AP_PERF_ARM_HISI_PA_ONLINE , &pa_pmu->node); -irq_set_affinity_hint (pa_pmu->irq,NULL );return ret; }
@@ -451,8 +450,6 @@ static int hisi_pa_pmu_remove(struct plaperf_pmu_unregister (&pa_pmu->pmu);cpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_HISI_PA_ONLINE , &pa_pmu->node); -irq_set_affinity_hint (pa_pmu->irq,NULL ); -return 0 ; }
drivers/perf/hisilicon/hisi_uncore_pmu.c +2 -2
@@ -488,7 +488,7 @@ int hisi_uncore_pmu_online_cpu(unsigned hisi_pmu->on_cpu = cpu;/* Overflow interrupt also should use the same CPU */ -WARN_ON (irq_set_affinity_hint (hisi_pmu->irq,cpumask_of (cpu))); +WARN_ON (irq_set_affinity (hisi_pmu->irq,cpumask_of (cpu)));return 0 ; }
@@ -521,7 +521,7 @@ int hisi_uncore_pmu_offline_cpu(unsignedperf_pmu_migrate_context (&hisi_pmu->pmu, cpu, target);/* Use this CPU for event counting */ hisi_pmu->on_cpu = target; -WARN_ON (irq_set_affinity_hint (hisi_pmu->irq,cpumask_of (target))); +WARN_ON (irq_set_affinity (hisi_pmu->irq,cpumask_of (target)));return 0 ; }
drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c +0 -3
@@ -465,7 +465,6 @@ static int hisi_sllc_pmu_probe(struct pldev_err (sllc_pmu->dev,"PMU register failed, ret = %d\n" , ret);cpuhp_state_remove_instance (CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE , &sllc_pmu->node); -irq_set_affinity_hint (sllc_pmu->irq,NULL );return ret; }
@@ -481,8 +480,6 @@ static int hisi_sllc_pmu_remove(struct pperf_pmu_unregister (&sllc_pmu->pmu);cpuhp_state_remove_instance_nocalls (CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE , &sllc_pmu->node); -irq_set_affinity_hint (sllc_pmu->irq,NULL ); -return 0 ; }
Hi Thomas,
Quoted 14 lines · Thomas Gleixner
The modular PMU drivers use
irq_set_affinity_hint()to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from
irq_set_affinity_hint()is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Quoted 4 lines
Sigh, if people would at least talk if something is missing...
Clean up the mess by exposing
irq_set_affinity()and converting the drivers over to that.
Sorry about this, and thanks for cleaning this up.
For the series:
Mark.
Quoted 22 lines
Thanks,
tglx
--- drivers/perf/arm-ccn.c | 6 +--- drivers/perf/arm-cmn.c | 9 +----- drivers/perf/arm_dmc620_pmu.c | 5 +-- drivers/perf/arm_dsu_pmu.c | 8 +---- drivers/perf/arm_smmuv3_pmu.c | 10 ++----- drivers/perf/fsl_imx8_ddr_perf.c | 5 +-- drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 3 -- drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 3 -- drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 3 -- drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 3 -- drivers/perf/hisilicon/hisi_uncore_pmu.c | 4 +- drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 3 -- include/linux/interrupt.h | 35 +------------------------- kernel/irq/manage.c | 33 +++++++++++++++++++++++- 14 files changed, 49 insertions(+), 81 deletions(-)
Will Deacon
maintainerHi Thomas,
Quoted 14 lines · Thomas Gleixner
The modular PMU drivers use
irq_set_affinity_hint()to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from
irq_set_affinity_hint()is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.
Quoted 4 lines
Sigh, if people would at least talk if something is missing...
Clean up the mess by exposing
irq_set_affinity()and converting the drivers over to that.
This all looks good to me, thanks. Given the number of PMU drivers it touches, it may well conflict with driver work for 5.14. If you put the IRQ core stuff on a stable branch, then I could pull that into the Arm perf tree and stick all the driver changes on top. That also means any new drivers that come in can use irq_set_affinity() right away.
Does that work for you?
Cheers,
Will
Quoted 20 lines · Will Deacon
Quoted 14 lines · Thomas Gleixner
The modular PMU drivers use
irq_set_affinity_hint()to set the affinity for the PMU interrupts, which relies on the undocumented side effect that this function actually sets the affinity under the hood.Setting an hint is clearly not a guarantee and for these PMU interrupts an affinity hint, which is supposed to guide userspace for setting affinity, is beyond pointless, because the affinity of these interrupts cannot be modified from user space.
Aside of that the error checks are bogus because the only error which is returned from
irq_set_affinity_hint()is when there is no irq descriptor for the interrupt number, but not when the affinity set fails. That's on purpose because the hint can point to an offline CPU.Quoted 4 lines
Sigh, if people would at least talk if something is missing...
Clean up the mess by exposing
irq_set_affinity()and converting the drivers over to that.
Quoted 7 lines
This all looks good to me, thanks. Given the number of PMU drivers it touches, it may well conflict with driver work for 5.14. If you put the IRQ core stuff on a stable branch, then I could pull that into the Arm perf tree and stick all the driver changes on top. That also means any new drivers that come in can use
irq_set_affinity()right away.Does that work for you?
Sure. I'll send you a tag to pull ...
Thanks,
tglx
Quoted 1 line · Thomas Gleixner
Sure. I'll send you a tag to pull ...
Here you go:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq-export-set-affinity
Thanks,
tglx
Will Deacon
maintainerQuoted 6 lines · Thomas Gleixner
Quoted 1 line · Thomas Gleixner
Sure. I'll send you a tag to pull ...
Here you go:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.gitirq-export-set-affinity
Cheers, I've pulled that in and stuck the driver patches on top.
Will