From patchwork Wed Jul 1 09:07:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ionela Voinescu X-Patchwork-Id: 11635871 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 039D3739 for ; Wed, 1 Jul 2020 09:23:47 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CDE3020722 for ; Wed, 1 Jul 2020 09:23:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="ZEbTOSca" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CDE3020722 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:References:In-Reply-To:Message-Id:Date:Subject:To: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=+8uqFLHAqNd0DMjfWqHvelhp0Wi2TTmYnLiEnvHvhYw=; b=ZEbTOScaQo23Bkw8Ge7lwmvBnb X0p9CxpzNBMkyGuPn/xv06vUQdPi0KlTYSr/ayEzVY+6EIVdatBMLFaIHnxxyHdapJxw+Q/eD5L79 wsamJJ+b2yt39ri8AXgpwZ6oZyljzuDom9/Yu0kAmJnQtTqcX1lCsUZnLQbarmfBA2VI6tLhSeGQ0 AvxZs+Zhq9DdORiLeP71bKleq0kWIqgS4eVsaWeI5cWxtCagBZeagTwgrF1+KN2vbtht9qU4+jhve 8mQpyORUa33Q5OrXsHropb823ATWZboxRinF9l6tWebEf9ZnqNqwZWQQyKSaLKmhyrOPc/IfK/1ks L3PDJetw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jqYwV-0000uy-R6; Wed, 01 Jul 2020 09:22:11 +0000 Received: from foss.arm.com ([217.140.110.172]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jqYkR-0001wN-LX for linux-arm-kernel@lists.infradead.org; Wed, 01 Jul 2020 09:09:46 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0E55E11FB; Wed, 1 Jul 2020 02:09:38 -0700 (PDT) Received: from e108754-lin.cambridge.arm.com (unknown [10.1.198.53]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 2DC843F68F; Wed, 1 Jul 2020 02:09:36 -0700 (PDT) From: Ionela Voinescu To: rjw@rjwysocki.net, viresh.kumar@linaro.org, catalin.marinas@arm.com, sudeep.holla@arm.com, will@kernel.org, linux@armlinux.org.uk, valentin.schneider@arm.com Subject: [PATCH 4/8] cpufreq, vexpress-spc: fix Frequency Invariance (FI) for bL switching Date: Wed, 1 Jul 2020 10:07:47 +0100 Message-Id: <20200701090751.7543-5-ionela.voinescu@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200701090751.7543-1-ionela.voinescu@arm.com> References: <20200701090751.7543-1-ionela.voinescu@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200701_050943_890515_F2F655F3 X-CRM114-Status: GOOD ( 16.83 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [217.140.110.172 listed in list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-pm@vger.kernel.org, peterz@infradead.org, Liviu Dudau , linux-kernel@vger.kernel.org, mingo@redhat.com, ionela.voinescu@arm.com, dietmar.eggemann@arm.com, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org In the majority of cases, the index argument to cpufreq's target_index() is meant to identify the frequency that is requested from the hardware, according to the frequency table: policy->freq_table[index].frequency. After successfully requesting it from the hardware, this value, together with the maximum hardware frequency (policy->cpuinfo.max_freq) are used as arguments to arch_set_freq_scale(), in order to set the task scheduler frequency scale factor. This is a normalized indication of a CPU's current performance. But for the vexpress-spc-cpufreq driver, when big.LITTLE switching [1] is enabled, there are three issues with using the above information for setting the FI scale factor: - cur_freq: policy->freq_table[index].frequency is not the frequency requested from the hardware. ve_spc_cpufreq_set_rate() will convert from this virtual frequency to an actual frequency, which is then requested from the hardware. For the A7 cluster, the virtual frequency is half the actual frequency. The use of the virtual policy->freq_table frequency results in an incorrect FI scale factor. - max_freq: policy->cpuinfo.max_freq does not correctly identify the maximum frequency of the physical cluster. This value identifies the maximum frequency achievable by the big-LITTLE pair, that is the maximum frequency of the big CPU. But when the LITTLE CPU in the group is used, the hardware maximum frquency passed to arch_set_freq_scale() is incorrect. - missing a scale factor update: when switching clusters, the driver recalculates the frequency of the old clock domain based on the requests of the remaining CPUs in the domain and asks for a clock change. But this does not result in an update in the scale factor. Therefore, introduce a local function bLs_set_sched_freq_scale() that helps call arch_set_freq_scale() with correct information for the is_bL_switching_enabled() case, while maintaining the old, more efficient, call site of arch_set_freq_scale() for when cluster switching is disabled. Also, because of these requirements in computing the scale factor, this driver is the only one that maintains custom support for FI, which is marked by the presence of the CPUFREQ_CUSTOM_SET_FREQ_SCALE flag. [1] https://lwn.net/Articles/481055/ Signed-off-by: Ionela Voinescu Cc: Viresh Kumar Cc: Sudeep Holla Cc: Rafael J. Wysocki Cc: Liviu Dudau --- drivers/cpufreq/vexpress-spc-cpufreq.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/vexpress-spc-cpufreq.c b/drivers/cpufreq/vexpress-spc-cpufreq.c index e0a1a3367ec5..f2caf67d4050 100644 --- a/drivers/cpufreq/vexpress-spc-cpufreq.c +++ b/drivers/cpufreq/vexpress-spc-cpufreq.c @@ -55,6 +55,8 @@ static atomic_t cluster_usage[MAX_CLUSTERS + 1]; static unsigned int clk_big_min; /* (Big) clock frequencies */ static unsigned int clk_little_max; /* Maximum clock frequency (Little) */ +static inline u32 get_table_max(struct cpufreq_frequency_table *table); + static DEFINE_PER_CPU(unsigned int, physical_cluster); static DEFINE_PER_CPU(unsigned int, cpu_last_req_freq); @@ -87,6 +89,18 @@ static unsigned int find_cluster_maxfreq(int cluster) return max_freq; } +static void bLs_set_sched_freq_scale(int cluster, unsigned long cur_freq) +{ + unsigned long max_freq = get_table_max(freq_table[cluster]); + int j; + + for_each_online_cpu(j) { + if (cluster == per_cpu(physical_cluster, j)) + arch_set_freq_scale(get_cpu_mask(j), cur_freq, + max_freq); + } +} + static unsigned int clk_get_cpu_rate(unsigned int cpu) { u32 cur_cluster = per_cpu(physical_cluster, cpu); @@ -154,6 +168,9 @@ ve_spc_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate) mutex_unlock(&cluster_lock[new_cluster]); + if (bLs) + bLs_set_sched_freq_scale(new_cluster, new_rate); + /* Recalc freq for old cluster when switching clusters */ if (old_cluster != new_cluster) { /* Switch cluster */ @@ -170,7 +187,11 @@ ve_spc_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate) pr_err("%s: clk_set_rate failed: %d, old cluster: %d\n", __func__, ret, old_cluster); } + mutex_unlock(&cluster_lock[old_cluster]); + + if (new_rate) + bLs_set_sched_freq_scale(old_cluster, new_rate); } return 0; @@ -200,7 +221,7 @@ static int ve_spc_cpufreq_set_target(struct cpufreq_policy *policy, ret = ve_spc_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new); - if (!ret) { + if (!is_bL_switching_enabled() && !ret) { arch_set_freq_scale(policy->related_cpus, freqs_new, policy->cpuinfo.max_freq); }