From: David Mercado <david.merc...@windriver.com> The PMU interrupts were previously initialized at too early in the board init process, so IRQ affinity wasn't working. Moved PMU IRQ setup/teardown to PMU enable/disable routines instead. With this change, PMU interrupts correctly work across all cores.
Signed-off-by: David Mercado <david.merc...@windriver.com> --- arch/powerpc/perf/core-lsi-acp.c | 115 ++++++++++++++++++++++++++++++++++++++- arch/powerpc/perf/ppc476-pmu.c | 59 -------------------- 2 files changed, 113 insertions(+), 61 deletions(-) diff --git a/arch/powerpc/perf/core-lsi-acp.c b/arch/powerpc/perf/core-lsi-acp.c index 9e8986d..28437b5 100644 --- a/arch/powerpc/perf/core-lsi-acp.c +++ b/arch/powerpc/perf/core-lsi-acp.c @@ -12,6 +12,8 @@ */ #include <linux/kernel.h> +#include <linux/cpumask.h> +#include <linux/interrupt.h> #include <linux/sched.h> #include <linux/perf_event.h> #include <linux/percpu.h> @@ -53,6 +55,115 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs) static void perf_event_interrupt(struct pt_regs *regs); +static int cpu_to_pmu_irq(int cpu) +{ + int hwirq; + + /* + * NOTE: On the LSI ACP platform, the PMU interrupts are + * hard-wired as inputs to the MPIC. The irq numbers are + * fixed as follows: + * + * Core 0 PMU: IRQ 95 + * Core 1 PMU: IRQ 94 + * Core 2 PMU: IRQ 93 + * Core 3 PMU: IRQ 92 + * + * The IRQ assignment should probably be done in the DTB, + * like ARM does, but no other PowerPC platform does this. + * So for now, we hard-code the numbers here. + */ + if (cpu == 0) + hwirq = 95; + else if (cpu == 1) + hwirq = 94; + else if (cpu == 2) + hwirq = 93; + else if (cpu == 3) + hwirq = 92; + else + hwirq = 0; + + return hwirq; +} + +static cpumask_t active_irqs; + +/* PMU IRQ handler */ +static irqreturn_t acp_pmu_isr(int irq, void *dev_id) +{ + __get_cpu_var(irq_stat).pmu_irqs++; + perf_irq(get_irq_regs()); + return IRQ_HANDLED; +} + +static void acp_pmu_release_hardware(void) +{ + int i, irq, virq; + + for (i = 0; i < num_possible_cpus(); ++i) { + if (!cpumask_test_and_clear_cpu(i, &active_irqs)) + continue; + irq = cpu_to_pmu_irq(i); + if (irq) { + free_irq(irq, NULL); + virq = irq_find_mapping(NULL, irq); + if (virq) + irq_dispose_mapping(virq); + } + } + + release_pmc_hardware(); +} + +static int acp_pmu_reserve_hardware(void) +{ + int err = 0; + int i, irq, hwirq; + + err = reserve_pmc_hardware(perf_event_interrupt); + + if (err) { + pr_warning("unable to reserve pmu\n"); + return err; + } + + for (i = 0; i < num_possible_cpus(); ++i) { + err = 0; + + hwirq = cpu_to_pmu_irq(i); + if (!hwirq) + continue; + + irq = irq_create_mapping(NULL, hwirq); + if (irq == NO_IRQ) { + pr_err("PMU irq_create_mapping() failed\n"); + continue; + } + + irq = cpu_to_pmu_irq(i); + if (irq < 0) + continue; + + if (irq_set_affinity(irq, cpumask_of(i))) { + pr_warning("PMU IRQ affinity failed (irq=%d, cpu=%d)\n", + irq, i); + continue; + } + err = request_irq(irq, acp_pmu_isr, + IRQF_DISABLED | IRQF_NOBALANCING, + "pmu", NULL); + if (err) { + pr_err("PMU reqeust for IRQ%d failed\n", irq); + acp_pmu_release_hardware(); + return err; + } + cpumask_set_cpu(i, &active_irqs); + } + + return 0; +} + static void acp_pmu_read(struct perf_event *event) { @@ -339,7 +450,7 @@ static void hw_perf_event_destroy(struct perf_event *event) if (!atomic_add_unless(&num_events, -1, 1)) { mutex_lock(&pmc_reserve_mutex); if (atomic_dec_return(&num_events) == 0) - release_pmc_hardware(); + acp_pmu_release_hardware(); mutex_unlock(&pmc_reserve_mutex); } } @@ -445,7 +556,7 @@ static int acp_pmu_event_init(struct perf_event *event) mutex_lock(&pmc_reserve_mutex); if (atomic_read(&num_events) == 0 && - reserve_pmc_hardware(perf_event_interrupt)) + acp_pmu_reserve_hardware()) err = -EBUSY; else atomic_inc(&num_events); diff --git a/arch/powerpc/perf/ppc476-pmu.c b/arch/powerpc/perf/ppc476-pmu.c index 9bd9060..30c05d9 100644 --- a/arch/powerpc/perf/ppc476-pmu.c +++ b/arch/powerpc/perf/ppc476-pmu.c @@ -19,14 +19,6 @@ #include <asm/perf_event_acp.h> #include <asm/reg_acp_pmu.h> -/* PMU IRQ handler */ -static irqreturn_t acp_pmu_isr(int irq, void *dev_id) -{ - __get_cpu_var(irq_stat).pmu_irqs++; - perf_irq(get_irq_regs()); - return IRQ_HANDLED; -} - /* * Map of generic hardware event types to hardware events * Zero if unsupported @@ -129,13 +121,6 @@ static struct acp_pmu ppc476_pmu = { static int init_ppc476_pmu(void) { - unsigned int irq; - int intNum, core; - static const char * const irqname[] = { "pmu-core0", - "pmu-core1", - "pmu-core2", - "pmu-core3" }; - if (!cur_cpu_spec->oprofile_cpu_type) return -ENODEV; @@ -144,50 +129,6 @@ static int init_ppc476_pmu(void) else return -ENODEV; - /* - * Install the PMU interrupt handlers: - * - * NOTE: On the LSI ACP platform, the PMU interrupts are - * hard-wired as inputs to the MPIC. The irq numbers are - * fixed as follows: - * - * Core 0 PMU: IRQ 95 - * Core 1 PMU: IRQ 94 - * Core 2 PMU: IRQ 93 - * Core 3 PMU: IRQ 92 - * - * The IRQ assignment should probably be done in the DTB, - * like ARM does, but no other PowerPC platform does this. - * So for now, we hard-code the numbers here. - */ - for_each_possible_cpu(core) { - if (core == 0) - intNum = 95; - else if (core == 1) - intNum = 94; - else if (core == 2) - intNum = 93; - else if (core == 3) - intNum = 92; - else - break; - - irq = irq_create_mapping(NULL, intNum); - if (irq == NO_IRQ) { - pr_err("PMU irq_create_mapping() failed\n"); - break; - } - if (irq_set_affinity(irq, get_cpu_mask(core))) { - pr_warning("PMU IRQ affinity failed (irq=%d, cpu=%d)\n", - irq, core); - continue; - } - if (request_irq(irq, acp_pmu_isr, - IRQF_DISABLED | IRQF_NOBALANCING, - irqname[core], NULL)) - pr_err("PMU reqeust for IRQ%d failed\n", irq); - } - return register_acp_pmu(&ppc476_pmu); } -- 1.8.3.4 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto