From patchwork Mon Nov 14 17:44:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chen Yu X-Patchwork-Id: 9428083 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E2AE260755 for ; Mon, 14 Nov 2016 17:35:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D613028950 for ; Mon, 14 Nov 2016 17:35:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CADD228AA3; Mon, 14 Nov 2016 17:35:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CFEC028A9B for ; Mon, 14 Nov 2016 17:35:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754927AbcKNRf2 (ORCPT ); Mon, 14 Nov 2016 12:35:28 -0500 Received: from mga03.intel.com ([134.134.136.65]:61020 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933194AbcKNRf0 (ORCPT ); Mon, 14 Nov 2016 12:35:26 -0500 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP; 14 Nov 2016 09:35:24 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,491,1473145200"; d="scan'208";a="1085057847" Received: from yu-desktop-1.sh.intel.com ([10.239.160.134]) by fmsmga002.fm.intel.com with ESMTP; 14 Nov 2016 09:35:22 -0800 From: Chen Yu To: linux-acpi@vger.kernel.org Cc: Rui Wang , linux-kernel@vger.kernel.org, Chen Yu , Len Brown , "Rafael J. Wysocki" , Pavel Machek , Matthew Garrett , Rui Zhang , linux-pm@vger.kernel.org Subject: [PATCH][RFC] ACPI throttling: Save/restore tstate for each CPUs across suspend/resume Date: Tue, 15 Nov 2016 01:44:04 +0800 Message-Id: <1479145444-29269-1-git-send-email-yu.c.chen@intel.com> X-Mailer: git-send-email 2.7.4 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This is a trial version and any comments are appreciated. Previously a bug was reported that on certain Broadwell platforms, after resuming from S3, the CPU is running at an anomalously low speed, due to BIOS has enabled the throttling across S3. The solution to this is to introduce a quirk framework to save/restore tstate MSR register around suspend/resume, in Commit 7a9c2dd08ead ("x86/pm: Introduce quirk framework to save/restore extra MSR registers around suspend/resume"). However more and more reports show that other platforms also experienced the same issue, because some BIOSes would like to adjust the tstate if he thinks the temperature is too high. To deal with this situation, the Linux uses a compensation strategy that, the thermal management leverages thermal_pm_notify() upon resume to check if the Processors inside the thermal zone should be throttled or not, thus tstate would be re-evaluated. Unfortunately on these bogus platforms, none of the Processors are inside any thermal zones due to BIOS's implementation. Thus tstate for Processors never has a chance to be brought back to normal. This patch tries to save/restore tstate on receiving the PM_SUSPEND_PREPARE and PM_POST_SUSPEND, to be more specific, the tstate is saved after thermal_pm_notify(PM_SUSPEND_PREPARE) is called, while it's restored before thermal_pm_notify(PM_POST_SUSPEND), in this way the thermal zone would adjust the tstate eventually and also help adjust the tstate for Processors which do not have thermal zone bound. Thus it does not imapct the old semantics. Another concern is that, each CPU should take care of the save/restore operation, thus this patch uses percpu workqueue to achieve this. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=90041 Reported-by: Matthew Garrett Reported-by: Kadir Cc: Len Brown Cc: "Rafael J. Wysocki" Cc: Pavel Machek Cc: Matthew Garrett Cc: Rui Zhang Cc: linux-pm@vger.kernel.org Signed-off-by: Chen Yu --- drivers/acpi/processor_throttling.c | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index d51ca1c..8ddc7d6 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -758,6 +759,75 @@ static int acpi_throttling_wrmsr(u64 value) } return ret; } + +#ifdef CONFIG_PM_SLEEP +static DEFINE_PER_CPU(u64, tstate_msr); + +static long tstate_pm_fn(void *data) +{ + u64 value; + bool save = *(bool *)data; + + if (save) { + acpi_throttling_rdmsr(&value); + this_cpu_write(tstate_msr, value); + } else { + value = this_cpu_read(tstate_msr); + if (value) + acpi_throttling_wrmsr(value); + } + return 0; +} + +static void tstate_check(unsigned long mode, bool suspend) +{ + int cpu; + bool save; + + if (suspend && mode == PM_SUSPEND_PREPARE) + save = true; + else if (!suspend && mode == PM_POST_SUSPEND) + save = false; + else + return; + + get_online_cpus(); + for_each_online_cpu(cpu) + work_on_cpu(cpu, tstate_pm_fn, &save); + put_online_cpus(); +} + +static int tstate_suspend(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + tstate_check(mode, true); + return 0; +} + +static int tstate_resume(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + tstate_check(mode, false); + return 0; +} + +static int __init tstate_pm_init(void) +{ + /* + * tstate_suspend should save tstate after + * thermal zone's update in thermal_pm_notify, + * vice versa tstate_resume restore tstate before + * thermal_pm_notify, thus the thermal framework + * has a chance to re-adjust tstate according to the + * temperature trend. + */ + pm_notifier(tstate_suspend, -1); + pm_notifier(tstate_resume, 1); + return 0; +} + +core_initcall(tstate_pm_init); +#endif #else static int acpi_throttling_rdmsr(u64 *value) {