diff options
Diffstat (limited to 'drivers/perf')
-rw-r--r-- | drivers/perf/arm_pmu.c | 88 |
1 files changed, 52 insertions, 36 deletions
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 3c4e97df8331..c09c379b038d 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -527,65 +527,81 @@ int perf_num_counters(void) } EXPORT_SYMBOL_GPL(perf_num_counters); -static void armpmu_free_irqs(struct arm_pmu *armpmu) +static void armpmu_free_irq(struct arm_pmu *armpmu, int cpu) { - int cpu; struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; + int irq = per_cpu(hw_events->irq, cpu); - for_each_cpu(cpu, &armpmu->supported_cpus) { - int irq = per_cpu(hw_events->irq, cpu); - if (!irq) - continue; + if (!cpumask_test_and_clear_cpu(cpu, &armpmu->active_irqs)) + return; - if (irq_is_percpu(irq)) { - free_percpu_irq(irq, &hw_events->percpu_pmu); - break; - } + if (irq_is_percpu(irq)) { + free_percpu_irq(irq, &hw_events->percpu_pmu); + cpumask_clear(&armpmu->active_irqs); + return; + } - if (!cpumask_test_and_clear_cpu(cpu, &armpmu->active_irqs)) - continue; + free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); +} - free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); - } +static void armpmu_free_irqs(struct arm_pmu *armpmu) +{ + int cpu; + + for_each_cpu(cpu, &armpmu->supported_cpus) + armpmu_free_irq(armpmu, cpu); } -static int armpmu_request_irqs(struct arm_pmu *armpmu) +static int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) { - int cpu, err; + int err = 0; struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; const irq_handler_t handler = armpmu_dispatch_irq; + int irq = per_cpu(hw_events->irq, cpu); + if (!irq) + return 0; - for_each_cpu(cpu, &armpmu->supported_cpus) { - int irq = per_cpu(hw_events->irq, cpu); - if (!irq) - continue; + if (irq_is_percpu(irq) && cpumask_empty(&armpmu->active_irqs)) { + err = request_percpu_irq(irq, handler, "arm-pmu", + &hw_events->percpu_pmu); + } else if (irq_is_percpu(irq)) { + int other_cpu = cpumask_first(&armpmu->active_irqs); + int other_irq = per_cpu(hw_events->irq, other_cpu); - if (irq_is_percpu(irq)) { - err = request_percpu_irq(irq, handler, "arm-pmu", - &hw_events->percpu_pmu); - if (err) { - pr_err("unable to request IRQ%d for ARM PMU counters\n", - irq); - } - - return err; + if (irq != other_irq) { + pr_warn("mismatched PPIs detected.\n"); + err = -EINVAL; } - + } else { err = request_irq(irq, handler, IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu", per_cpu_ptr(&hw_events->percpu_pmu, cpu)); - if (err) { - pr_err("unable to request IRQ%d for ARM PMU counters\n", - irq); - return err; - } + } - cpumask_set_cpu(cpu, &armpmu->active_irqs); + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + return err; } + cpumask_set_cpu(cpu, &armpmu->active_irqs); + return 0; } +static int armpmu_request_irqs(struct arm_pmu *armpmu) +{ + int cpu, err; + + for_each_cpu(cpu, &armpmu->supported_cpus) { + err = armpmu_request_irq(armpmu, cpu); + if (err) + break; + } + + return err; +} + static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu) { struct pmu_hw_events __percpu *hw_events = pmu->hw_events; |