From patchwork Mon Aug 8 17:16:04 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 1046202 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p78HHf5n012578 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 8 Aug 2011 17:18:02 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QqTS5-0002VG-Jj; Mon, 08 Aug 2011 17:17:22 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QqTS4-0005Hj-Vn; Mon, 08 Aug 2011 17:17:21 +0000 Received: from cam-admin0.cambridge.arm.com ([217.140.96.50]) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QqTR6-00053C-Ph for linux-arm-kernel@lists.infradead.org; Mon, 08 Aug 2011 17:16:23 +0000 Received: from localhost.localdomain (e102144-lin.cambridge.arm.com [10.1.69.60]) by cam-admin0.cambridge.arm.com (8.12.6/8.12.6) with ESMTP id p78HFi14021547; Mon, 8 Aug 2011 18:15:44 +0100 (BST) From: Will Deacon To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 03/10] ARM: perf: use cpumask_t to record active IRQs Date: Mon, 8 Aug 2011 18:16:04 +0100 Message-Id: <1312823771-9952-4-git-send-email-will.deacon@arm.com> X-Mailer: git-send-email 1.7.0.4 MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1312823771-9952-1-git-send-email-will.deacon@arm.com> References: <1312823771-9952-1-git-send-email-will.deacon@arm.com> X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110808_131621_240696_393B0ABF X-CRM114-Status: GOOD ( 18.32 ) X-Spam-Score: -3.1 (---) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-3.1 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [217.140.96.50 listed in list.dnswl.org] -0.8 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain Cc: jamie@jamieiles.com, Will Deacon , j-pihet@ti.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 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 X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 08 Aug 2011 17:18:02 +0000 (UTC) Commit 5dfc54e0 ("ARM: GIC: avoid routing interrupts to offline CPUs") prevents the GIC from setting the affinity of an IRQ to a CPU with id >= nr_cpu_ids. This was previously abused by perf on some platforms where more IRQs were registered than possible CPUs. This patch fixes the problem by using a cpumask_t to keep track of the active (requested) interrupts in perf. The same effect could be achieved by limiting the number of IRQs to the number of CPUs, but using a mask instead will be useful for adding extended CPU hotplug support in the future. Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event.c | 64 ++++++++++++++++++++--------------------- 1 files changed, 31 insertions(+), 33 deletions(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 8514855..d507fe1 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -69,6 +69,7 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); struct arm_pmu { enum arm_perf_pmu_ids id; + cpumask_t active_irqs; const char *name; irqreturn_t (*handle_irq)(int irq_num, void *dev); void (*enable)(struct hw_perf_event *evt, int idx); @@ -388,6 +389,25 @@ static irqreturn_t armpmu_platform_irq(int irq, void *dev) return plat->handle_irq(irq, dev, armpmu->handle_irq); } +static void +armpmu_release_hardware(void) +{ + int i, irq, irqs; + + irqs = min(pmu_device->num_resources, num_possible_cpus()); + + 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, NULL); + } + + armpmu->stop(); + release_pmu(ARM_PMU_DEVICE_CPU); +} + static int armpmu_reserve_hardware(void) { @@ -401,20 +421,20 @@ armpmu_reserve_hardware(void) return err; } - irqs = pmu_device->num_resources; - plat = dev_get_platdata(&pmu_device->dev); if (plat && plat->handle_irq) handle_irq = armpmu_platform_irq; else handle_irq = armpmu->handle_irq; + irqs = min(pmu_device->num_resources, num_possible_cpus()); if (irqs < 1) { pr_err("no irqs for PMUs defined\n"); return -ENODEV; } for (i = 0; i < irqs; ++i) { + err = 0; irq = platform_get_irq(pmu_device, i); if (irq < 0) continue; @@ -422,13 +442,12 @@ armpmu_reserve_hardware(void) /* * If we have a single PMU interrupt that we can't shift, * assume that we're running on a uniprocessor machine and - * continue. + * continue. Otherwise, continue without this interrupt. */ - err = irq_set_affinity(irq, cpumask_of(i)); - if (err && irqs > 1) { - pr_err("unable to set irq affinity (irq=%d, cpu=%u)\n", - irq, i); - break; + 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, @@ -437,35 +456,14 @@ armpmu_reserve_hardware(void) if (err) { pr_err("unable to request IRQ%d for ARM PMU counters\n", irq); - break; + armpmu_release_hardware(); + return err; } - } - if (err) { - for (i = i - 1; i >= 0; --i) { - irq = platform_get_irq(pmu_device, i); - if (irq >= 0) - free_irq(irq, NULL); - } - release_pmu(ARM_PMU_DEVICE_CPU); + cpumask_set_cpu(i, &armpmu->active_irqs); } - return err; -} - -static void -armpmu_release_hardware(void) -{ - int i, irq; - - for (i = pmu_device->num_resources - 1; i >= 0; --i) { - irq = platform_get_irq(pmu_device, i); - if (irq >= 0) - free_irq(irq, NULL); - } - armpmu->stop(); - - release_pmu(ARM_PMU_DEVICE_CPU); + return 0; } static atomic_t active_events = ATOMIC_INIT(0);