From patchwork Fri Nov 18 03:15:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 9435725 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 3FD0860238 for ; Fri, 18 Nov 2016 03:19:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9594B28178 for ; Fri, 18 Nov 2016 03:19:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7244F2675C; Fri, 18 Nov 2016 03:19:17 +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 F22E828D83 for ; Fri, 18 Nov 2016 03:18:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752150AbcKRDST (ORCPT ); Thu, 17 Nov 2016 22:18:19 -0500 Received: from mga05.intel.com ([192.55.52.43]:19230 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751974AbcKRDST (ORCPT ); Thu, 17 Nov 2016 22:18:19 -0500 Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga105.fm.intel.com with ESMTP; 17 Nov 2016 19:15:07 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,655,1473145200"; d="scan'208";a="32104006" Received: from spandruv-desk.jf.intel.com ([10.54.75.13]) by orsmga004.jf.intel.com with ESMTP; 17 Nov 2016 19:15:07 -0800 From: Srinivas Pandruvada To: lenb@kernel.org, rjw@rjwysocki.net Cc: linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [PATCH] cpufreq: intel_pstate: Set EPP/EPB to 0 in performance mode Date: Thu, 17 Nov 2016 19:15:02 -0800 Message-Id: <1479438902-167977-1-git-send-email-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.7.4 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When user has selected performance policy, then set the EPP (Energy Performance Preference) or EPB (Energy Performance Bias) to maximum performance mode. Also when user switch back to powersave, then restore EPP/EPB to power on default value. It is also possible to change EPP/EPB using direct MSR writes or using x86_energy_perf_policy utility. When user changes the default EPP/EPB value using the above methods in powersave policy, then this change preserves those settings, whenever intel_pstate_hwp_set() is called. Signed-off-by: Srinivas Pandruvada --- drivers/cpufreq/intel_pstate.c | 104 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 4737520..2dade36 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -196,6 +196,8 @@ struct _pid { * @sample: Storage for storing last Sample data * @acpi_perf_data: Stores ACPI perf information read from _PSS * @valid_pss_table: Set to true for valid ACPI _PSS entries found + * @epp_default: Power on default HWP energy performance preference + * or energy performance bias * * This structure stores per CPU instance data for all CPUs. */ @@ -222,6 +224,7 @@ struct cpudata { bool valid_pss_table; #endif unsigned int iowait_boost; + int epp_default; }; static struct cpudata **all_cpu_data; @@ -559,12 +562,76 @@ static inline void update_turbo_state(void) cpu->pstate.max_pstate == cpu->pstate.turbo_pstate); } +static int intel_pstate_get_epb(struct cpudata *cpu_data) +{ + u64 epb; + int ret; + + if (!static_cpu_has(X86_FEATURE_EPB)) + return -ENXIO; + + ret = rdmsrl_on_cpu(cpu_data->cpu, MSR_IA32_ENERGY_PERF_BIAS, &epb); + if (ret) + return ret; + + return (int)(epb & 0x0f); +} + +static int intel_pstate_get_epp(struct cpudata *cpu_data, u64 hwp_req_data) +{ + int epp; + + if (static_cpu_has(X86_FEATURE_HWP_EPP)) { + if (!hwp_req_data) { + int ret; + + ret = rdmsrl_on_cpu(cpu_data->cpu, + MSR_HWP_REQUEST, + &hwp_req_data); + if (ret) + return ret; + } + epp = (hwp_req_data >> 24) & 0xff; + } else { + /* When there is no EPP present, HWP uses EPB settings */ + epp = intel_pstate_get_epb(cpu_data); + } + + return epp; +} + +static void intel_pstate_update_epp(struct cpudata *cpu_data) +{ + int epp; + + epp = intel_pstate_get_epp(cpu_data, 0); + + if (!cpu_data->epp_default) + cpu_data->epp_default = epp; +} + +static void intel_pstate_set_epb(int cpu, int pref) +{ + u64 epb; + + if (!static_cpu_has(X86_FEATURE_EPB)) + return; + + if (rdmsrl_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, &epb)) + return; + + epb = (epb & ~0x0f) | pref; + wrmsrl_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, epb); +} + static void intel_pstate_hwp_set(const struct cpumask *cpumask) { int min, hw_min, max, hw_max, cpu, range, adj_range; u64 value, cap; for_each_cpu(cpu, cpumask) { + struct cpudata *cpu_data = all_cpu_data[cpu]; + rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap); hw_min = HWP_LOWEST_PERF(cap); hw_max = HWP_HIGHEST_PERF(cap); @@ -586,6 +653,42 @@ static void intel_pstate_hwp_set(const struct cpumask *cpumask) value &= ~HWP_MAX_PERF(~0L); value |= HWP_MAX_PERF(max); + /* + * If there was error reading during epp/epb, then don't + * set EPP/EPB values. In this case + * cpu_data->epp_default will be set to -errno + */ + if (cpu_data->epp_default >= 0) { + int epp; + + if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) { + epp = 0; + } else { + /* + * If epp was non zero after policy switch to + * powersave policy or already in powersave + * policy, then EPP was never changed from + * power on value or user manually changed via + * some utilities. In this case don't set + * EPP/EPB in this case. + * Otherwise restore power on default EPP/EPB + * after policy switch from performance. + */ + epp = intel_pstate_get_epp(cpu_data, value); + if (epp) + goto skip_epp; + else + epp = cpu_data->epp_default; + } + + if (static_cpu_has(X86_FEATURE_HWP_EPP)) { + value &= ~GENMASK_ULL(31, 24); + value |= (u64)epp << 24; + } else { + intel_pstate_set_epb(cpu, epp); + } + } +skip_epp: wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value); } } @@ -818,6 +921,7 @@ static void intel_pstate_hwp_enable(struct cpudata *cpudata) wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00); wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1); + intel_pstate_update_epp(cpudata); } static int atom_get_min_pstate(void)