From patchwork Mon Jul 30 14:32:12 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christopher SMITH X-Patchwork-Id: 1254901 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 54615DFE76 for ; Mon, 30 Jul 2012 14:40:55 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Svr45-0001NB-1F; Mon, 30 Jul 2012 14:35:21 +0000 Received: from eu1sys200aog104.obsmtp.com ([207.126.144.117]) by merlin.infradead.org with smtps (Exim 4.76 #1 (Red Hat Linux)) id 1Svr0o-0000fi-7p for linux-arm-kernel@lists.infradead.org; Mon, 30 Jul 2012 14:31:59 +0000 Received: from beta.dmz-eu.st.com ([164.129.1.35]) (using TLSv1) by eu1sys200aob104.postini.com ([207.126.147.11]) with SMTP ID DSNKUBaa0kNksWoWPlbWiAjuh/osLjf14Jit@postini.com; Mon, 30 Jul 2012 14:31:58 UTC Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 21C3714F; Mon, 30 Jul 2012 14:31:45 +0000 (GMT) Received: from Webmail-eu.st.com (safex1hubcas2.st.com [10.75.90.16]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id D7CB74579; Mon, 30 Jul 2012 14:31:45 +0000 (GMT) Received: from localhost (10.65.51.241) by webmail-eu.st.com (10.75.90.13) with Microsoft SMTP Server (TLS) id 8.3.192.1; Mon, 30 Jul 2012 16:31:45 +0200 From: Chris Smith To: , Subject: [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts. Date: Mon, 30 Jul 2012 15:32:12 +0100 Message-ID: <1343658732-31080-2-git-send-email-chris.smith@st.com> X-Mailer: git-send-email 1.7.6.5 In-Reply-To: <1343658732-31080-1-git-send-email-chris.smith@st.com> References: <1343658732-31080-1-git-send-email-chris.smith@st.com> MIME-Version: 1.0 X-Spam-Note: CRM114 invocation failed X-Spam-Note: SpamAssassin invocation failed Cc: Chris Smith , tglx@linutronix.de, will.deacon@arm.com, srinidhi.kasagar@stericsson.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org We have systems where the PMU interrupts are PPIs, and so per-cpu. This patch adds support for per-cpu PMU interrupts to the perf event code. Note that because the dev_id passed to request_percpu_irq has to be percpu data, we now pass cpu_hw_events as the dev_id rather than armpmu. This only place the dev_id was used was in armpmu_platform_irq, which is fixed up accordingly. Signed-off-by: Chris Smith --- arch/arm/kernel/perf_event.c | 91 +++++++++++++++++++++++++++++--------- arch/arm/kernel/perf_event_v6.c | 3 +- arch/arm/kernel/perf_event_v7.c | 3 +- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index b2abfa1..add9064 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -355,13 +356,27 @@ validate_group(struct perf_event *event) static irqreturn_t armpmu_platform_irq(int irq, void *dev) { - struct arm_pmu *armpmu = (struct arm_pmu *) dev; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; + struct arm_pmu *armpmu = to_arm_pmu((*(cpuc->events))->pmu); + struct platform_device *plat_device = armpmu->plat_device; struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); return plat->handle_irq(irq, dev, armpmu->handle_irq); } +/* Wrap enable_percpu_irq up as a smp_call_func_t */ +static void armpmu_enable_percpu_irq(void *irq) +{ + enable_percpu_irq((int)irq, IRQ_TYPE_NONE); +} + +/* Wrap disable_percpu_irq up as a smp_call_func_t */ +static void armpmu_disable_percpu_irq(void *irq) +{ + disable_percpu_irq((int)irq); +} + static void armpmu_release_hardware(struct arm_pmu *armpmu) { @@ -379,7 +394,14 @@ armpmu_release_hardware(struct arm_pmu *armpmu) if (irq >= 0) { if (plat && plat->disable_irq) plat->disable_irq(irq); - free_irq(irq, armpmu); + else if (irq_is_per_cpu(irq)) + on_each_cpu(armpmu_disable_percpu_irq, + (void *)irq, 1); + + if (irq_is_per_cpu(irq)) + free_percpu_irq(irq, &cpu_hw_events); + else + free_irq(irq, &per_cpu(cpu_hw_events, i)); } } @@ -421,28 +443,53 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) 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; + if (irq_is_per_cpu(irq)) { + /* + * We assume that if the PMU IRQ is per-cpu, then + * there is only one. + */ + WARN_ON(irqs > 1); + + err = request_percpu_irq(irq, handle_irq, + "arm-pmu", &cpu_hw_events); + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + armpmu_release_hardware(armpmu); + return err; + } else if (plat && plat->enable_irq) { + plat->enable_irq(irq); + } else { + on_each_cpu(armpmu_enable_percpu_irq, + (void *)irq, 1); + } + + } else { + /* + * 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, handle_irq, + IRQF_DISABLED | IRQF_NOBALANCING, + "arm-pmu", &per_cpu(cpu_hw_events, i)); + + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + armpmu_release_hardware(armpmu); + return err; + } else if (plat && plat->enable_irq) + plat->enable_irq(irq); } - err = request_irq(irq, handle_irq, - IRQF_DISABLED | 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; - } else if (plat && plat->enable_irq) - plat->enable_irq(irq); - cpumask_set_cpu(i, &armpmu->active_irqs); } diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index b78af0c..6b348f5 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c @@ -473,7 +473,7 @@ armv6pmu_handle_irq(int irq_num, { unsigned long pmcr = armv6_pmcr_read(); struct perf_sample_data data; - struct pmu_hw_events *cpuc; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; struct pt_regs *regs; int idx; @@ -491,7 +491,6 @@ armv6pmu_handle_irq(int irq_num, perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 4d7095a..56ddad7 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -933,7 +933,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) { u32 pmnc; struct perf_sample_data data; - struct pmu_hw_events *cpuc; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; struct pt_regs *regs; int idx; @@ -955,7 +955,6 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc;