mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-27 00:51:35 +00:00
arm64: perf: add support for percpu pmu interrupt
Add support for irq registration when pmu interrupt is percpu. Signed-off-by: Vinayak Kale <vkale@apm.com> Signed-off-by: Tuan Phan <tphan@apm.com> [will: tidied up cross-calling to pass &irq] Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
parent
7f4a8e7b19
commit
66aa8d6a14
1 changed files with 78 additions and 30 deletions
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include <linux/bitmap.h>
|
#include <linux/bitmap.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
@ -362,27 +363,54 @@ validate_group(struct perf_event *event)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
armpmu_disable_percpu_irq(void *data)
|
||||||
|
{
|
||||||
|
unsigned int irq = *(unsigned int *)data;
|
||||||
|
disable_percpu_irq(irq);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
armpmu_release_hardware(struct arm_pmu *armpmu)
|
armpmu_release_hardware(struct arm_pmu *armpmu)
|
||||||
{
|
{
|
||||||
int i, irq, irqs;
|
int irq;
|
||||||
|
unsigned int i, irqs;
|
||||||
struct platform_device *pmu_device = armpmu->plat_device;
|
struct platform_device *pmu_device = armpmu->plat_device;
|
||||||
|
|
||||||
irqs = min(pmu_device->num_resources, num_possible_cpus());
|
irqs = min(pmu_device->num_resources, num_possible_cpus());
|
||||||
|
if (!irqs)
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < irqs; ++i) {
|
irq = platform_get_irq(pmu_device, 0);
|
||||||
if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
|
if (irq <= 0)
|
||||||
continue;
|
return;
|
||||||
irq = platform_get_irq(pmu_device, i);
|
|
||||||
if (irq >= 0)
|
if (irq_is_percpu(irq)) {
|
||||||
free_irq(irq, armpmu);
|
on_each_cpu(armpmu_disable_percpu_irq, &irq, 1);
|
||||||
|
free_percpu_irq(irq, &cpu_hw_events);
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < irqs; ++i) {
|
||||||
|
if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
|
||||||
|
continue;
|
||||||
|
irq = platform_get_irq(pmu_device, i);
|
||||||
|
if (irq > 0)
|
||||||
|
free_irq(irq, armpmu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
armpmu_enable_percpu_irq(void *data)
|
||||||
|
{
|
||||||
|
unsigned int irq = *(unsigned int *)data;
|
||||||
|
enable_percpu_irq(irq, IRQ_TYPE_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
armpmu_reserve_hardware(struct arm_pmu *armpmu)
|
armpmu_reserve_hardware(struct arm_pmu *armpmu)
|
||||||
{
|
{
|
||||||
int i, err, irq, irqs;
|
int err, irq;
|
||||||
|
unsigned int i, irqs;
|
||||||
struct platform_device *pmu_device = armpmu->plat_device;
|
struct platform_device *pmu_device = armpmu->plat_device;
|
||||||
|
|
||||||
if (!pmu_device) {
|
if (!pmu_device) {
|
||||||
|
@ -391,39 +419,59 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
|
||||||
}
|
}
|
||||||
|
|
||||||
irqs = min(pmu_device->num_resources, num_possible_cpus());
|
irqs = min(pmu_device->num_resources, num_possible_cpus());
|
||||||
if (irqs < 1) {
|
if (!irqs) {
|
||||||
pr_err("no irqs for PMUs defined\n");
|
pr_err("no irqs for PMUs defined\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < irqs; ++i) {
|
irq = platform_get_irq(pmu_device, 0);
|
||||||
err = 0;
|
if (irq <= 0) {
|
||||||
irq = platform_get_irq(pmu_device, i);
|
pr_err("failed to get valid irq for PMU device\n");
|
||||||
if (irq < 0)
|
return -ENODEV;
|
||||||
continue;
|
}
|
||||||
|
|
||||||
/*
|
if (irq_is_percpu(irq)) {
|
||||||
* If we have a single PMU interrupt that we can't shift,
|
err = request_percpu_irq(irq, armpmu->handle_irq,
|
||||||
* assume that we're running on a uniprocessor machine and
|
"arm-pmu", &cpu_hw_events);
|
||||||
* continue. Otherwise, continue without this interrupt.
|
|
||||||
*/
|
|
||||||
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
|
|
||||||
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
|
|
||||||
irq, i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = request_irq(irq, armpmu->handle_irq,
|
|
||||||
IRQF_NOBALANCING,
|
|
||||||
"arm-pmu", armpmu);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("unable to request IRQ%d for ARM PMU counters\n",
|
pr_err("unable to request percpu IRQ%d for ARM PMU counters\n",
|
||||||
irq);
|
irq);
|
||||||
armpmu_release_hardware(armpmu);
|
armpmu_release_hardware(armpmu);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpumask_set_cpu(i, &armpmu->active_irqs);
|
on_each_cpu(armpmu_enable_percpu_irq, &irq, 1);
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < irqs; ++i) {
|
||||||
|
err = 0;
|
||||||
|
irq = platform_get_irq(pmu_device, i);
|
||||||
|
if (irq <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a single PMU interrupt that we can't shift,
|
||||||
|
* assume that we're running on a uniprocessor machine and
|
||||||
|
* continue. Otherwise, continue without this interrupt.
|
||||||
|
*/
|
||||||
|
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
|
||||||
|
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
|
||||||
|
irq, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = request_irq(irq, armpmu->handle_irq,
|
||||||
|
IRQF_NOBALANCING,
|
||||||
|
"arm-pmu", armpmu);
|
||||||
|
if (err) {
|
||||||
|
pr_err("unable to request IRQ%d for ARM PMU counters\n",
|
||||||
|
irq);
|
||||||
|
armpmu_release_hardware(armpmu);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpumask_set_cpu(i, &armpmu->active_irqs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue