Skip to content

Commit bbd6455

Browse files
bebarinowildea01
authored andcommitted
ARM: perf: support percpu irqs for the CPU PMU
Some CPU PMUs are wired up with one PPI for all the CPUs instead of with a different SPI for each CPU. Add support for these devices. Signed-off-by: Stephen Boyd <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent 6d0abec commit bbd6455

File tree

2 files changed

+80
-31
lines changed

2 files changed

+80
-31
lines changed

arch/arm/kernel/perf_event.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <linux/platform_device.h>
1717
#include <linux/pm_runtime.h>
1818
#include <linux/uaccess.h>
19+
#include <linux/irq.h>
20+
#include <linux/irqdesc.h>
1921

2022
#include <asm/irq_regs.h>
2123
#include <asm/pmu.h>
@@ -295,9 +297,15 @@ validate_group(struct perf_event *event)
295297

296298
static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
297299
{
298-
struct arm_pmu *armpmu = (struct arm_pmu *) dev;
299-
struct platform_device *plat_device = armpmu->plat_device;
300-
struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev);
300+
struct arm_pmu *armpmu;
301+
struct platform_device *plat_device;
302+
struct arm_pmu_platdata *plat;
303+
304+
if (irq_is_percpu(irq))
305+
dev = *(void **)dev;
306+
armpmu = dev;
307+
plat_device = armpmu->plat_device;
308+
plat = dev_get_platdata(&plat_device->dev);
301309

302310
if (plat && plat->handle_irq)
303311
return plat->handle_irq(irq, dev, armpmu->handle_irq);

arch/arm/kernel/perf_event_cpu.c

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <linux/platform_device.h>
2626
#include <linux/slab.h>
2727
#include <linux/spinlock.h>
28+
#include <linux/irq.h>
29+
#include <linux/irqdesc.h>
2830

2931
#include <asm/cputype.h>
3032
#include <asm/irq_regs.h>
@@ -33,6 +35,7 @@
3335
/* Set at runtime when we know what CPU type we are. */
3436
static struct arm_pmu *cpu_pmu;
3537

38+
static DEFINE_PER_CPU(struct arm_pmu *, percpu_pmu);
3639
static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
3740
static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
3841
static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
@@ -71,19 +74,45 @@ static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
7174
return this_cpu_ptr(&cpu_hw_events);
7275
}
7376

77+
static void cpu_pmu_enable_percpu_irq(void *data)
78+
{
79+
struct arm_pmu *cpu_pmu = data;
80+
struct platform_device *pmu_device = cpu_pmu->plat_device;
81+
int irq = platform_get_irq(pmu_device, 0);
82+
83+
enable_percpu_irq(irq, IRQ_TYPE_NONE);
84+
cpumask_set_cpu(smp_processor_id(), &cpu_pmu->active_irqs);
85+
}
86+
87+
static void cpu_pmu_disable_percpu_irq(void *data)
88+
{
89+
struct arm_pmu *cpu_pmu = data;
90+
struct platform_device *pmu_device = cpu_pmu->plat_device;
91+
int irq = platform_get_irq(pmu_device, 0);
92+
93+
cpumask_clear_cpu(smp_processor_id(), &cpu_pmu->active_irqs);
94+
disable_percpu_irq(irq);
95+
}
96+
7497
static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
7598
{
7699
int i, irq, irqs;
77100
struct platform_device *pmu_device = cpu_pmu->plat_device;
78101

79102
irqs = min(pmu_device->num_resources, num_possible_cpus());
80103

81-
for (i = 0; i < irqs; ++i) {
82-
if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
83-
continue;
84-
irq = platform_get_irq(pmu_device, i);
85-
if (irq >= 0)
86-
free_irq(irq, cpu_pmu);
104+
irq = platform_get_irq(pmu_device, 0);
105+
if (irq >= 0 && irq_is_percpu(irq)) {
106+
on_each_cpu(cpu_pmu_disable_percpu_irq, cpu_pmu, 1);
107+
free_percpu_irq(irq, &percpu_pmu);
108+
} else {
109+
for (i = 0; i < irqs; ++i) {
110+
if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
111+
continue;
112+
irq = platform_get_irq(pmu_device, i);
113+
if (irq >= 0)
114+
free_irq(irq, cpu_pmu);
115+
}
87116
}
88117
}
89118

@@ -101,33 +130,44 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
101130
return -ENODEV;
102131
}
103132

104-
for (i = 0; i < irqs; ++i) {
105-
err = 0;
106-
irq = platform_get_irq(pmu_device, i);
107-
if (irq < 0)
108-
continue;
109-
110-
/*
111-
* If we have a single PMU interrupt that we can't shift,
112-
* assume that we're running on a uniprocessor machine and
113-
* continue. Otherwise, continue without this interrupt.
114-
*/
115-
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
116-
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
117-
irq, i);
118-
continue;
119-
}
120-
121-
err = request_irq(irq, handler,
122-
IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
123-
cpu_pmu);
133+
irq = platform_get_irq(pmu_device, 0);
134+
if (irq >= 0 && irq_is_percpu(irq)) {
135+
err = request_percpu_irq(irq, handler, "arm-pmu", &percpu_pmu);
124136
if (err) {
125137
pr_err("unable to request IRQ%d for ARM PMU counters\n",
126138
irq);
127139
return err;
128140
}
129-
130-
cpumask_set_cpu(i, &cpu_pmu->active_irqs);
141+
on_each_cpu(cpu_pmu_enable_percpu_irq, cpu_pmu, 1);
142+
} else {
143+
for (i = 0; i < irqs; ++i) {
144+
err = 0;
145+
irq = platform_get_irq(pmu_device, i);
146+
if (irq < 0)
147+
continue;
148+
149+
/*
150+
* If we have a single PMU interrupt that we can't shift,
151+
* assume that we're running on a uniprocessor machine and
152+
* continue. Otherwise, continue without this interrupt.
153+
*/
154+
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
155+
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
156+
irq, i);
157+
continue;
158+
}
159+
160+
err = request_irq(irq, handler,
161+
IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
162+
cpu_pmu);
163+
if (err) {
164+
pr_err("unable to request IRQ%d for ARM PMU counters\n",
165+
irq);
166+
return err;
167+
}
168+
169+
cpumask_set_cpu(i, &cpu_pmu->active_irqs);
170+
}
131171
}
132172

133173
return 0;
@@ -141,6 +181,7 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu)
141181
events->events = per_cpu(hw_events, cpu);
142182
events->used_mask = per_cpu(used_mask, cpu);
143183
raw_spin_lock_init(&events->pmu_lock);
184+
per_cpu(percpu_pmu, cpu) = cpu_pmu;
144185
}
145186

146187
cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events;

0 commit comments

Comments
 (0)