Skip to content

Commit d8f6267

Browse files
Julien Thierrywilldeacon
authored andcommitted
arm_pmu: arm64: Use NMIs for PMU
Add required PMU interrupt operations for NMIs. Request interrupt lines as NMIs when possible, otherwise fall back to normal interrupts. NMIs are only supported on the arm64 architecture with a GICv3 irqchip. [Alexandru E.: Added that NMIs only work on arm64 + GICv3, print message when PMU is using NMIs] Signed-off-by: Julien Thierry <julien.thierry@arm.com> Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com> Tested-by: Sumit Garg <sumit.garg@linaro.org> (Developerbox) Cc: Julien Thierry <julien.thierry.kdev@gmail.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Mark Rutland <mark.rutland@arm.com> Link: https://lore.kernel.org/r/20200924110706.254996-8-alexandru.elisei@arm.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent f76b130 commit d8f6267

1 file changed

Lines changed: 63 additions & 8 deletions

File tree

drivers/perf/arm_pmu.c

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ static const struct pmu_irq_ops pmuirq_ops = {
4545
.free_pmuirq = armpmu_free_pmuirq
4646
};
4747

48+
static void armpmu_free_pmunmi(unsigned int irq, int cpu, void __percpu *devid)
49+
{
50+
free_nmi(irq, per_cpu_ptr(devid, cpu));
51+
}
52+
53+
static const struct pmu_irq_ops pmunmi_ops = {
54+
.enable_pmuirq = enable_nmi,
55+
.disable_pmuirq = disable_nmi_nosync,
56+
.free_pmuirq = armpmu_free_pmunmi
57+
};
58+
4859
static void armpmu_enable_percpu_pmuirq(unsigned int irq)
4960
{
5061
enable_percpu_irq(irq, IRQ_TYPE_NONE);
@@ -63,10 +74,37 @@ static const struct pmu_irq_ops percpu_pmuirq_ops = {
6374
.free_pmuirq = armpmu_free_percpu_pmuirq
6475
};
6576

77+
static void armpmu_enable_percpu_pmunmi(unsigned int irq)
78+
{
79+
if (!prepare_percpu_nmi(irq))
80+
enable_percpu_nmi(irq, IRQ_TYPE_NONE);
81+
}
82+
83+
static void armpmu_disable_percpu_pmunmi(unsigned int irq)
84+
{
85+
disable_percpu_nmi(irq);
86+
teardown_percpu_nmi(irq);
87+
}
88+
89+
static void armpmu_free_percpu_pmunmi(unsigned int irq, int cpu,
90+
void __percpu *devid)
91+
{
92+
if (armpmu_count_irq_users(irq) == 1)
93+
free_percpu_nmi(irq, devid);
94+
}
95+
96+
static const struct pmu_irq_ops percpu_pmunmi_ops = {
97+
.enable_pmuirq = armpmu_enable_percpu_pmunmi,
98+
.disable_pmuirq = armpmu_disable_percpu_pmunmi,
99+
.free_pmuirq = armpmu_free_percpu_pmunmi
100+
};
101+
66102
static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu);
67103
static DEFINE_PER_CPU(int, cpu_irq);
68104
static DEFINE_PER_CPU(const struct pmu_irq_ops *, cpu_irq_ops);
69105

106+
static bool has_nmi;
107+
70108
static inline u64 arm_pmu_event_max_period(struct perf_event *event)
71109
{
72110
if (event->hw.flags & ARMPMU_EVT_64BIT)
@@ -637,15 +675,31 @@ int armpmu_request_irq(int irq, int cpu)
637675
IRQF_NO_THREAD;
638676

639677
irq_set_status_flags(irq, IRQ_NOAUTOEN);
640-
err = request_irq(irq, handler, irq_flags, "arm-pmu",
678+
679+
err = request_nmi(irq, handler, irq_flags, "arm-pmu",
641680
per_cpu_ptr(&cpu_armpmu, cpu));
642681

643-
irq_ops = &pmuirq_ops;
682+
/* If cannot get an NMI, get a normal interrupt */
683+
if (err) {
684+
err = request_irq(irq, handler, irq_flags, "arm-pmu",
685+
per_cpu_ptr(&cpu_armpmu, cpu));
686+
irq_ops = &pmuirq_ops;
687+
} else {
688+
has_nmi = true;
689+
irq_ops = &pmunmi_ops;
690+
}
644691
} else if (armpmu_count_irq_users(irq) == 0) {
645-
err = request_percpu_irq(irq, handler, "arm-pmu",
646-
&cpu_armpmu);
647-
648-
irq_ops = &percpu_pmuirq_ops;
692+
err = request_percpu_nmi(irq, handler, "arm-pmu", &cpu_armpmu);
693+
694+
/* If cannot get an NMI, get a normal interrupt */
695+
if (err) {
696+
err = request_percpu_irq(irq, handler, "arm-pmu",
697+
&cpu_armpmu);
698+
irq_ops = &percpu_pmuirq_ops;
699+
} else {
700+
has_nmi= true;
701+
irq_ops = &percpu_pmunmi_ops;
702+
}
649703
} else {
650704
/* Per cpudevid irq was already requested by another CPU */
651705
irq_ops = armpmu_find_irq_ops(irq);
@@ -928,8 +982,9 @@ int armpmu_register(struct arm_pmu *pmu)
928982
if (!__oprofile_cpu_pmu)
929983
__oprofile_cpu_pmu = pmu;
930984

931-
pr_info("enabled with %s PMU driver, %d counters available\n",
932-
pmu->name, pmu->num_events);
985+
pr_info("enabled with %s PMU driver, %d counters available%s\n",
986+
pmu->name, pmu->num_events,
987+
has_nmi ? ", using NMIs" : "");
933988

934989
return 0;
935990

0 commit comments

Comments
 (0)