From patchwork Tue Mar 10 17:31:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Pieralisi X-Patchwork-Id: 5979831 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9CFA89F39E for ; Tue, 10 Mar 2015 17:33:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B3FE52022A for ; Tue, 10 Mar 2015 17:33:58 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C6C1520220 for ; Tue, 10 Mar 2015 17:33:57 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YVO0n-0001vl-EA; Tue, 10 Mar 2015 17:32:09 +0000 Received: from foss.arm.com ([217.140.101.70]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YVO0T-0001Xj-3A for linux-arm-kernel@lists.infradead.org; Tue, 10 Mar 2015 17:31:49 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4F7744D; Tue, 10 Mar 2015 10:31:44 -0700 (PDT) Received: from red-moon.cambridge.arm.com (red-moon.cambridge.arm.com [10.1.203.137]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6154F3F7E6; Tue, 10 Mar 2015 10:31:25 -0700 (PDT) From: Lorenzo Pieralisi To: linux-arm-kernel@lists.infradead.org Subject: [RFC PATCH 2/2] arm64: kernel: perf: add pmu CPU PM notifier Date: Tue, 10 Mar 2015 17:31:22 +0000 Message-Id: <1426008682-5680-2-git-send-email-lorenzo.pieralisi@arm.com> X-Mailer: git-send-email 2.2.1 In-Reply-To: <1426008682-5680-1-git-send-email-lorenzo.pieralisi@arm.com> References: <1426008682-5680-1-git-send-email-lorenzo.pieralisi@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150310_103149_334983_2CC91E6D X-CRM114-Status: GOOD ( 15.60 ) X-Spam-Score: -5.0 (-----) Cc: Mark Rutland , Lorenzo Pieralisi , Mathieu Poirier , linux-pm@vger.kernel.org, Daniel Lezcano , Will Deacon , Kevin Hilman , Sudeep Holla X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When a CPU is being profiled through PMU events and it enters suspend or idle states, the PMU registers content can be lost, which means that counters that were relied upon on power down entry are reset on power up to values that are incosistent with the profile session. This patch adds a CPU PM notifier to arm64 perf code, that detects on entry if events are being monitored, and if so, it returns failure to the CPU PM notification chain, causing the suspend thread or the idle thread to abort power down, therefore preventing registers content loss. By triggering CPU PM notification failure this patch prevents suspending a system if the suspend thread is being profiled and it also prevents entering idle deep states on cores that have profile events in use, somehow limiting power management capabilities when there are active perf sessions. Cc: Will Deacon Cc: Kevin Hilman Cc: Sudeep Holla Cc: Daniel Lezcano Cc: Mathieu Poirier Cc: Mark Rutland Signed-off-by: Lorenzo Pieralisi --- arch/arm64/kernel/perf_event.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 83f21d8..4809fca 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -1316,6 +1317,53 @@ static struct pmu_hw_events *armpmu_get_cpu_events(void) return this_cpu_ptr(&cpu_hw_events); } +#ifdef CONFIG_CPU_PM +static int cpu_pm_pmu_notifier(struct notifier_block *self, + unsigned long cmd, void *v) +{ + switch (cmd) { + case CPU_PM_ENTER: { + /* + * Check events in use and fail if events are being monitored. + * On failure, system suspend and idle entry will consequently + * abort power down operations, preventing CPU reset on power + * down, that would cause PMU registers reset in turn. + * The obvious drawback is that we can't enter idle + * states if a cpu is being profiled, and we can't + * profile the suspend thread (ie profiling it has the side + * effect of disabling system suspend), but that's the price + * to pay to keep the PMU registers powered up. + */ + struct pmu_hw_events *hw_events = cpu_pmu->get_hw_events(); + int enabled = bitmap_weight(hw_events->used_mask, + cpu_pmu->num_events); + return enabled ? NOTIFY_BAD : NOTIFY_OK; + } + case CPU_PM_EXIT: + if (cpu_pmu->reset) + cpu_pmu->reset(NULL); + return NOTIFY_OK; + case CPU_PM_ENTER_FAILED: + default: + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block cpu_pm_pmu_notifier_block = { + .notifier_call = cpu_pm_pmu_notifier, +}; + +static void cpu_pm_pmu_init(void) +{ + cpu_pm_register_notifier(&cpu_pm_pmu_notifier_block); +} + +#else +static inline void cpu_pm_pmu_init(void) { } +#endif /* CONFIG_CPU_PM */ + /* * PMU hardware loses all context when a CPU goes offline. * When a CPU is hotplugged back in, since some hardware registers are @@ -1352,6 +1400,8 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu) armpmu->get_hw_events = armpmu_get_cpu_events; register_cpu_notifier(&cpu_pmu_notifier_block); + + cpu_pm_pmu_init(); } static int __init init_hw_perf_events(void)