Skip to content

Commit 9fd85eb

Browse files
committed
ARM: pmu: add support for interrupt-affinity property
Historically, the PMU devicetree bindings have expected SPIs to be listed in order of *logical* CPU number. This is problematic for bootloaders, especially when the boot CPU (logical ID 0) isn't listed first in the devicetree. This patch adds a new optional property, interrupt-affinity, to the PMU node which allows the interrupt affinity to be described using a list of phandled to CPU nodes, with each entry in the list corresponding to the SPI at the same index in the interrupts property. Cc: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
1 parent e429817 commit 9fd85eb

File tree

2 files changed

+63
-7
lines changed

2 files changed

+63
-7
lines changed

arch/arm/include/asm/pmu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ struct pmu_hw_events {
9292
struct arm_pmu {
9393
struct pmu pmu;
9494
cpumask_t active_irqs;
95+
int *irq_affinity;
9596
char *name;
9697
irqreturn_t (*handle_irq)(int irq_num, void *dev);
9798
void (*enable)(struct perf_event *event);

arch/arm/kernel/perf_event_cpu.c

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,16 @@ static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
9292
free_percpu_irq(irq, &hw_events->percpu_pmu);
9393
} else {
9494
for (i = 0; i < irqs; ++i) {
95-
if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
95+
int cpu = i;
96+
97+
if (cpu_pmu->irq_affinity)
98+
cpu = cpu_pmu->irq_affinity[i];
99+
100+
if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs))
96101
continue;
97102
irq = platform_get_irq(pmu_device, i);
98103
if (irq >= 0)
99-
free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, i));
104+
free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu));
100105
}
101106
}
102107
}
@@ -128,32 +133,37 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
128133
on_each_cpu(cpu_pmu_enable_percpu_irq, &irq, 1);
129134
} else {
130135
for (i = 0; i < irqs; ++i) {
136+
int cpu = i;
137+
131138
err = 0;
132139
irq = platform_get_irq(pmu_device, i);
133140
if (irq < 0)
134141
continue;
135142

143+
if (cpu_pmu->irq_affinity)
144+
cpu = cpu_pmu->irq_affinity[i];
145+
136146
/*
137147
* If we have a single PMU interrupt that we can't shift,
138148
* assume that we're running on a uniprocessor machine and
139149
* continue. Otherwise, continue without this interrupt.
140150
*/
141-
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
151+
if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) {
142152
pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n",
143-
irq, i);
153+
irq, cpu);
144154
continue;
145155
}
146156

147157
err = request_irq(irq, handler,
148158
IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
149-
per_cpu_ptr(&hw_events->percpu_pmu, i));
159+
per_cpu_ptr(&hw_events->percpu_pmu, cpu));
150160
if (err) {
151161
pr_err("unable to request IRQ%d for ARM PMU counters\n",
152162
irq);
153163
return err;
154164
}
155165

156-
cpumask_set_cpu(i, &cpu_pmu->active_irqs);
166+
cpumask_set_cpu(cpu, &cpu_pmu->active_irqs);
157167
}
158168
}
159169

@@ -291,6 +301,48 @@ static int probe_current_pmu(struct arm_pmu *pmu)
291301
return ret;
292302
}
293303

304+
static int of_pmu_irq_cfg(struct platform_device *pdev)
305+
{
306+
int i;
307+
int *irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
308+
309+
if (!irqs)
310+
return -ENOMEM;
311+
312+
for (i = 0; i < pdev->num_resources; ++i) {
313+
struct device_node *dn;
314+
int cpu;
315+
316+
dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity",
317+
i);
318+
if (!dn) {
319+
pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
320+
of_node_full_name(dn), i);
321+
break;
322+
}
323+
324+
for_each_possible_cpu(cpu)
325+
if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
326+
break;
327+
328+
of_node_put(dn);
329+
if (cpu >= nr_cpu_ids) {
330+
pr_warn("Failed to find logical CPU for %s\n",
331+
dn->name);
332+
break;
333+
}
334+
335+
irqs[i] = cpu;
336+
}
337+
338+
if (i == pdev->num_resources)
339+
cpu_pmu->irq_affinity = irqs;
340+
else
341+
kfree(irqs);
342+
343+
return 0;
344+
}
345+
294346
static int cpu_pmu_device_probe(struct platform_device *pdev)
295347
{
296348
const struct of_device_id *of_id;
@@ -315,7 +367,10 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
315367

316368
if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
317369
init_fn = of_id->data;
318-
ret = init_fn(pmu);
370+
371+
ret = of_pmu_irq_cfg(pdev);
372+
if (!ret)
373+
ret = init_fn(pmu);
319374
} else {
320375
ret = probe_current_pmu(pmu);
321376
}

0 commit comments

Comments
 (0)