From patchwork Tue Aug 31 10:24:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Donnefort X-Patchwork-Id: 504848 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 02351C4320A for ; Tue, 31 Aug 2021 10:24:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D1B10604AC for ; Tue, 31 Aug 2021 10:24:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240923AbhHaKZc (ORCPT ); Tue, 31 Aug 2021 06:25:32 -0400 Received: from foss.arm.com ([217.140.110.172]:52866 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240895AbhHaKZa (ORCPT ); Tue, 31 Aug 2021 06:25:30 -0400 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 447B31063; Tue, 31 Aug 2021 03:24:35 -0700 (PDT) Received: from e120877-lin.cambridge.arm.com (e120877-lin.cambridge.arm.com [10.1.194.43]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id CE8BE3F5A1; Tue, 31 Aug 2021 03:24:33 -0700 (PDT) From: Vincent Donnefort To: peterz@infradead.org, rjw@rjwysocki.net, viresh.kumar@linaro.org, vincent.guittot@linaro.org, qperret@google.com Cc: linux-pm@vger.kernel.org, ionela.voinescu@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, mka@chromium.org, Vincent Donnefort Subject: [PATCH v6 1/7] PM / EM: Fix inefficient states detection Date: Tue, 31 Aug 2021 11:24:07 +0100 Message-Id: <1630405453-275784-2-git-send-email-vincent.donnefort@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> References: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Currently, a debug message is printed if an inefficient state is detected in the Energy Model. Unfortunately, it won't detect if the first state is inefficient or if two successive states are. Fix this behavior. Fixes: 27871f7a8a34 (PM: Introduce an Energy Model management framework) Signed-off-by: Vincent Donnefort Reviewed-by: Quentin Perret Reviewed-by: Lukasz Luba Reviewed-by: Matthias Kaehlcke diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c index a332ccd829e2..97e62469a6b3 100644 --- a/kernel/power/energy_model.c +++ b/kernel/power/energy_model.c @@ -107,8 +107,7 @@ static void em_debug_remove_pd(struct device *dev) {} static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd, int nr_states, struct em_data_callback *cb) { - unsigned long opp_eff, prev_opp_eff = ULONG_MAX; - unsigned long power, freq, prev_freq = 0; + unsigned long power, freq, prev_freq = 0, prev_cost = ULONG_MAX; struct em_perf_state *table; int i, ret; u64 fmax; @@ -153,27 +152,21 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd, table[i].power = power; table[i].frequency = prev_freq = freq; - - /* - * The hertz/watts efficiency ratio should decrease as the - * frequency grows on sane platforms. But this isn't always - * true in practice so warn the user if a higher OPP is more - * power efficient than a lower one. - */ - opp_eff = freq / power; - if (opp_eff >= prev_opp_eff) - dev_dbg(dev, "EM: hertz/watts ratio non-monotonically decreasing: em_perf_state %d >= em_perf_state%d\n", - i, i - 1); - prev_opp_eff = opp_eff; } /* Compute the cost of each performance state. */ fmax = (u64) table[nr_states - 1].frequency; - for (i = 0; i < nr_states; i++) { + for (i = nr_states - 1; i >= 0; i--) { unsigned long power_res = em_scale_power(table[i].power); table[i].cost = div64_u64(fmax * power_res, table[i].frequency); + if (table[i].cost >= prev_cost) { + dev_dbg(dev, "EM: OPP:%lu is inefficient\n", + table[i].frequency); + } else { + prev_cost = table[i].cost; + } } pd->table = table; From patchwork Tue Aug 31 10:24:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Donnefort X-Patchwork-Id: 505411 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5AB4FC4320E for ; Tue, 31 Aug 2021 10:24:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 38EE860FC3 for ; Tue, 31 Aug 2021 10:24:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240895AbhHaKZc (ORCPT ); Tue, 31 Aug 2021 06:25:32 -0400 Received: from foss.arm.com ([217.140.110.172]:52878 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240908AbhHaKZc (ORCPT ); Tue, 31 Aug 2021 06:25:32 -0400 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 F419A11B3; Tue, 31 Aug 2021 03:24:36 -0700 (PDT) Received: from e120877-lin.cambridge.arm.com (e120877-lin.cambridge.arm.com [10.1.194.43]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 77EF43F5A1; Tue, 31 Aug 2021 03:24:35 -0700 (PDT) From: Vincent Donnefort To: peterz@infradead.org, rjw@rjwysocki.net, viresh.kumar@linaro.org, vincent.guittot@linaro.org, qperret@google.com Cc: linux-pm@vger.kernel.org, ionela.voinescu@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, mka@chromium.org, Vincent Donnefort Subject: [PATCH v6 2/7] PM / EM: Mark inefficient states Date: Tue, 31 Aug 2021 11:24:08 +0100 Message-Id: <1630405453-275784-3-git-send-email-vincent.donnefort@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> References: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Some SoCs, such as the sd855 have OPPs within the same performance domain, whose cost is higher than others with a higher frequency. Even though those OPPs are interesting from a cooling perspective, it makes no sense to use them when the device can run at full capacity. Those OPPs handicap the performance domain, when choosing the most energy-efficient CPU and are wasting energy. They are inefficient. Hence, add support for such OPPs to the Energy Model. The table can now be read skipping inefficient performance states (and by extension, inefficient OPPs). Signed-off-by: Vincent Donnefort Reviewed-by: Matthias Kaehlcke Reviewed-by: Lukasz Luba diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h index 1834752c5617..629f5f63a7d7 100644 --- a/include/linux/energy_model.h +++ b/include/linux/energy_model.h @@ -17,13 +17,25 @@ * device). It can be a total power: static and dynamic. * @cost: The cost coefficient associated with this level, used during * energy calculation. Equal to: power * max_frequency / frequency + * @flags: see "em_perf_state flags" description below. */ struct em_perf_state { unsigned long frequency; unsigned long power; unsigned long cost; + unsigned long flags; }; +/* + * em_perf_state flags: + * + * EM_PERF_STATE_INEFFICIENT: The performance state is inefficient. There is + * in this em_perf_domain, another performance state with a higher frequency + * but a lower or equal power cost. Such inefficient states are ignored when + * using em_pd_get_efficient_*() functions. + */ +#define EM_PERF_STATE_INEFFICIENT BIT(0) + /** * em_perf_domain - Performance domain * @table: List of performance states, in ascending order diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c index 97e62469a6b3..6d8438347535 100644 --- a/kernel/power/energy_model.c +++ b/kernel/power/energy_model.c @@ -2,7 +2,7 @@ /* * Energy Model of devices * - * Copyright (c) 2018-2020, Arm ltd. + * Copyright (c) 2018-2021, Arm ltd. * Written by: Quentin Perret, Arm ltd. * Improvements provided by: Lukasz Luba, Arm ltd. */ @@ -42,6 +42,7 @@ static void em_debug_create_ps(struct em_perf_state *ps, struct dentry *pd) debugfs_create_ulong("frequency", 0444, d, &ps->frequency); debugfs_create_ulong("power", 0444, d, &ps->power); debugfs_create_ulong("cost", 0444, d, &ps->cost); + debugfs_create_ulong("inefficient", 0444, d, &ps->flags); } static int em_debug_cpus_show(struct seq_file *s, void *unused) @@ -162,6 +163,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd, table[i].cost = div64_u64(fmax * power_res, table[i].frequency); if (table[i].cost >= prev_cost) { + table[i].flags = EM_PERF_STATE_INEFFICIENT; dev_dbg(dev, "EM: OPP:%lu is inefficient\n", table[i].frequency); } else { From patchwork Tue Aug 31 10:24:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Donnefort X-Patchwork-Id: 504847 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2CDDCC432BE for ; Tue, 31 Aug 2021 10:24:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0852F60FC0 for ; Tue, 31 Aug 2021 10:24:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240943AbhHaKZe (ORCPT ); Tue, 31 Aug 2021 06:25:34 -0400 Received: from foss.arm.com ([217.140.110.172]:52890 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240908AbhHaKZd (ORCPT ); Tue, 31 Aug 2021 06:25:33 -0400 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 9D43A11D4; Tue, 31 Aug 2021 03:24:38 -0700 (PDT) Received: from e120877-lin.cambridge.arm.com (e120877-lin.cambridge.arm.com [10.1.194.43]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 3309F3F5A1; Tue, 31 Aug 2021 03:24:37 -0700 (PDT) From: Vincent Donnefort To: peterz@infradead.org, rjw@rjwysocki.net, viresh.kumar@linaro.org, vincent.guittot@linaro.org, qperret@google.com Cc: linux-pm@vger.kernel.org, ionela.voinescu@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, mka@chromium.org, Vincent Donnefort Subject: [PATCH v6 3/7] PM / EM: Extend em_perf_domain with a flag field Date: Tue, 31 Aug 2021 11:24:09 +0100 Message-Id: <1630405453-275784-4-git-send-email-vincent.donnefort@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> References: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Merge the current "milliwatts" option into a "flag" field. This intends to prepare the extension of this structure for inefficient states support in the Energy Model. Signed-off-by: Vincent Donnefort Reviewed-by: Lukasz Luba diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h index 629f5f63a7d7..ac2f7d0ab946 100644 --- a/include/linux/energy_model.h +++ b/include/linux/energy_model.h @@ -40,8 +40,7 @@ struct em_perf_state { * em_perf_domain - Performance domain * @table: List of performance states, in ascending order * @nr_perf_states: Number of performance states - * @milliwatts: Flag indicating the power values are in milli-Watts - * or some other scale. + * @flags: See "em_perf_domain flags" * @cpus: Cpumask covering the CPUs of the domain. It's here * for performance reasons to avoid potential cache * misses during energy calculations in the scheduler @@ -56,10 +55,18 @@ struct em_perf_state { struct em_perf_domain { struct em_perf_state *table; int nr_perf_states; - int milliwatts; + unsigned long flags; unsigned long cpus[]; }; +/* + * em_perf_domain flags: + * + * EM_PERF_DOMAIN_MILLIWATTS: The power values are in milli-Watts or some + * other scale. + */ +#define EM_PERF_DOMAIN_MILLIWATTS BIT(0) + #define em_span_cpus(em) (to_cpumask((em)->cpus)) #ifdef CONFIG_ENERGY_MODEL diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c index 6d8438347535..3a7d1573b214 100644 --- a/kernel/power/energy_model.c +++ b/kernel/power/energy_model.c @@ -56,7 +56,8 @@ DEFINE_SHOW_ATTRIBUTE(em_debug_cpus); static int em_debug_units_show(struct seq_file *s, void *unused) { struct em_perf_domain *pd = s->private; - char *units = pd->milliwatts ? "milliWatts" : "bogoWatts"; + char *units = (pd->flags & EM_PERF_DOMAIN_MILLIWATTS) ? + "milliWatts" : "bogoWatts"; seq_printf(s, "%s\n", units); @@ -330,7 +331,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, if (ret) goto unlock; - dev->em_pd->milliwatts = milliwatts; + if (milliwatts) + dev->em_pd->flags |= EM_PERF_DOMAIN_MILLIWATTS; em_debug_create_pd(dev); dev_info(dev, "EM: created perf domain\n"); From patchwork Tue Aug 31 10:24:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Donnefort X-Patchwork-Id: 505410 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6089C4320E for ; Tue, 31 Aug 2021 10:24:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 97E4E60F42 for ; Tue, 31 Aug 2021 10:24:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240960AbhHaKZf (ORCPT ); Tue, 31 Aug 2021 06:25:35 -0400 Received: from foss.arm.com ([217.140.110.172]:52906 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240908AbhHaKZf (ORCPT ); Tue, 31 Aug 2021 06:25:35 -0400 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 4674B11FB; Tue, 31 Aug 2021 03:24:40 -0700 (PDT) Received: from e120877-lin.cambridge.arm.com (e120877-lin.cambridge.arm.com [10.1.194.43]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id D04F13F5A1; Tue, 31 Aug 2021 03:24:38 -0700 (PDT) From: Vincent Donnefort To: peterz@infradead.org, rjw@rjwysocki.net, viresh.kumar@linaro.org, vincent.guittot@linaro.org, qperret@google.com Cc: linux-pm@vger.kernel.org, ionela.voinescu@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, mka@chromium.org, Vincent Donnefort Subject: [PATCH v6 4/7] PM / EM: Allow skipping inefficient states Date: Tue, 31 Aug 2021 11:24:10 +0100 Message-Id: <1630405453-275784-5-git-send-email-vincent.donnefort@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> References: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The new performance domain flag EM_PERF_DOMAIN_SKIP_INEFFICIENCIES allows to not take into account inefficient states when estimating energy consumption. This intends to let the Energy Model know that CPUFreq itself will skip inefficiencies and such states don't need to be part of the estimation anymore. Signed-off-by: Vincent Donnefort Reviewed-by: Lukasz Luba diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h index ac2f7d0ab946..15d41f09f009 100644 --- a/include/linux/energy_model.h +++ b/include/linux/energy_model.h @@ -64,8 +64,12 @@ struct em_perf_domain { * * EM_PERF_DOMAIN_MILLIWATTS: The power values are in milli-Watts or some * other scale. + * + * EM_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip inefficient states when estimating + * energy consumption. */ #define EM_PERF_DOMAIN_MILLIWATTS BIT(0) +#define EM_PERF_DOMAIN_SKIP_INEFFICIENCIES BIT(1) #define em_span_cpus(em) (to_cpumask((em)->cpus)) @@ -121,6 +125,37 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, void em_dev_unregister_perf_domain(struct device *dev); /** + * em_pd_get_efficient_state() - Get an efficient performance state from the EM + * @pd : Performance domain for which we want an efficient frequency + * @freq : Frequency to map with the EM + * + * It is called from the scheduler code quite frequently and as a consequence + * doesn't implement any check. + * + * Return: An efficient performance state, high enough to meet @freq + * requirement. + */ +static inline +struct em_perf_state *em_pd_get_efficient_state(struct em_perf_domain *pd, + unsigned long freq) +{ + struct em_perf_state *ps; + int i; + + for (i = 0; i < pd->nr_perf_states; i++) { + ps = &pd->table[i]; + if (ps->frequency >= freq) { + if (pd->flags & EM_PERF_DOMAIN_SKIP_INEFFICIENCIES && + ps->flags & EM_PERF_STATE_INEFFICIENT) + continue; + break; + } + } + + return ps; +} + +/** * em_cpu_energy() - Estimates the energy consumed by the CPUs of a performance domain * @pd : performance domain for which energy has to be estimated @@ -142,7 +177,7 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd, { unsigned long freq, scale_cpu; struct em_perf_state *ps; - int i, cpu; + int cpu; if (!sum_util) return 0; @@ -167,11 +202,7 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd, * Find the lowest performance state of the Energy Model above the * requested frequency. */ - for (i = 0; i < pd->nr_perf_states; i++) { - ps = &pd->table[i]; - if (ps->frequency >= freq) - break; - } + ps = em_pd_get_efficient_state(pd, freq); /* * The capacity of a CPU in the domain at the performance state (ps) diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c index 3a7d1573b214..d353ef29e37f 100644 --- a/kernel/power/energy_model.c +++ b/kernel/power/energy_model.c @@ -65,6 +65,17 @@ static int em_debug_units_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(em_debug_units); +static int em_debug_skip_inefficiencies_show(struct seq_file *s, void *unused) +{ + struct em_perf_domain *pd = s->private; + int enabled = (pd->flags & EM_PERF_DOMAIN_SKIP_INEFFICIENCIES) ? 1 : 0; + + seq_printf(s, "%d\n", enabled); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(em_debug_skip_inefficiencies); + static void em_debug_create_pd(struct device *dev) { struct dentry *d; @@ -78,6 +89,8 @@ static void em_debug_create_pd(struct device *dev) &em_debug_cpus_fops); debugfs_create_file("units", 0444, d, dev->em_pd, &em_debug_units_fops); + debugfs_create_file("skip-inefficiencies", 0444, d, dev->em_pd, + &em_debug_skip_inefficiencies_fops); /* Create a sub-directory for each performance state */ for (i = 0; i < dev->em_pd->nr_perf_states; i++) From patchwork Tue Aug 31 10:24:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Donnefort X-Patchwork-Id: 504846 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9677CC432BE for ; Tue, 31 Aug 2021 10:24:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7D936604AC for ; Tue, 31 Aug 2021 10:24:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240952AbhHaKZh (ORCPT ); Tue, 31 Aug 2021 06:25:37 -0400 Received: from foss.arm.com ([217.140.110.172]:52918 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240908AbhHaKZh (ORCPT ); Tue, 31 Aug 2021 06:25:37 -0400 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 E3C7212FC; Tue, 31 Aug 2021 03:24:41 -0700 (PDT) Received: from e120877-lin.cambridge.arm.com (e120877-lin.cambridge.arm.com [10.1.194.43]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 799843F5A1; Tue, 31 Aug 2021 03:24:40 -0700 (PDT) From: Vincent Donnefort To: peterz@infradead.org, rjw@rjwysocki.net, viresh.kumar@linaro.org, vincent.guittot@linaro.org, qperret@google.com Cc: linux-pm@vger.kernel.org, ionela.voinescu@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, mka@chromium.org, Vincent Donnefort Subject: [PATCH v6 5/7] cpufreq: Add an interface to mark inefficient frequencies Date: Tue, 31 Aug 2021 11:24:11 +0100 Message-Id: <1630405453-275784-6-git-send-email-vincent.donnefort@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> References: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Some SoCs such as the sd855 have OPPs within the same policy whose cost is higher than others with a higher frequency. Those OPPs are inefficients and it might be interesting for a governor to not use them. The inefficient interface is composed of two calls: 1. cpufreq_table_set_inefficient() marks a frequency as inefficient. 2. cpufreq_table_update_efficiencies() use the inefficiences marked by the previous function to generate a mapping inefficient->efficient. Resolving an inefficient frequency to an efficient on can then be done by accessing the cpufreq_frequency_table member "efficient". The resolution doesn't guarantee the policy maximum. Signed-off-by: Vincent Donnefort diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 67e56cf638ef..d3fa38af2aa6 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -365,6 +365,59 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy) return set_freq_table_sorted(policy); } +/** + * cpufreq_table_update_efficiencies() - Update efficiency resolution + * + * @policy: the &struct cpufreq_policy to update + * + * Allow quick resolution from inefficient frequencies to efficient ones. + * Inefficient frequencies must have been previously marked with + * cpufreq_table_set_inefficient(). + * + * Return: %0 on success or a negative errno code + */ +int cpufreq_table_update_efficiencies(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *pos, *table = policy->freq_table; + enum cpufreq_table_sorting sort = policy->freq_table_sorted; + int efficient, idx; + + /* Not supported */ + if (sort == CPUFREQ_TABLE_UNSORTED) + return -EINVAL; + + /* The highest frequency is always efficient */ + cpufreq_for_each_valid_entry_idx(pos, table, idx) { + efficient = idx; + if (sort == CPUFREQ_TABLE_SORTED_DESCENDING) + break; + } + + for (;;) { + pos = &table[idx]; + + if (pos->frequency != CPUFREQ_ENTRY_INVALID) { + if (pos->flags & CPUFREQ_INEFFICIENT_FREQ) { + pos->efficient = efficient; + } else { + pos->efficient = idx; + efficient = idx; + } + } + + if (sort == CPUFREQ_TABLE_SORTED_ASCENDING) { + if (--idx < 0) + break; + } else { + if (table[++idx].frequency == CPUFREQ_TABLE_END) + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_table_update_efficiencies); + MODULE_AUTHOR("Dominik Brodowski "); MODULE_DESCRIPTION("CPUfreq frequency table helpers"); MODULE_LICENSE("GPL"); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index c65a1d7385f8..4e901ebd104d 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -664,13 +664,15 @@ struct governor_attr { #define CPUFREQ_ENTRY_INVALID ~0u #define CPUFREQ_TABLE_END ~1u /* Special Values of .flags field */ -#define CPUFREQ_BOOST_FREQ (1 << 0) +#define CPUFREQ_BOOST_FREQ (1 << 0) +#define CPUFREQ_INEFFICIENT_FREQ (1 << 1) struct cpufreq_frequency_table { unsigned int flags; unsigned int driver_data; /* driver specific data, not used by core */ unsigned int frequency; /* kHz - doesn't need to be in ascending * order */ + unsigned int efficient; /* idx of an efficient frequency */ }; #if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP) @@ -762,6 +764,7 @@ int cpufreq_boost_trigger_state(int state); int cpufreq_boost_enabled(void); int cpufreq_enable_boost_support(void); bool policy_has_boost_freq(struct cpufreq_policy *policy); +int cpufreq_table_update_efficiencies(struct cpufreq_policy *policy); /* Find lowest freq at or above target in a table in ascending order */ static inline int cpufreq_table_find_index_al(struct cpufreq_policy *policy, @@ -1003,6 +1006,29 @@ static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy return count; } + +/** + * cpufreq_table_set_inefficient() - Mark a frequency as inefficient + * + * @policy: the &struct cpufreq_policy containing the inefficient frequency + * @frequency: the inefficient frequency + * + * Once inefficiencies marked, the efficient resolution must be updated with the + * function cpufreq_table_update_efficiencies(). + */ +static inline void +cpufreq_table_set_inefficient(const struct cpufreq_policy *policy, + unsigned int frequency) +{ + struct cpufreq_frequency_table *pos; + + cpufreq_for_each_valid_entry(pos, policy->freq_table) { + if (pos->frequency == frequency) { + pos->flags |= CPUFREQ_INEFFICIENT_FREQ; + break; + } + } +} #else static inline int cpufreq_boost_trigger_state(int state) { @@ -1022,6 +1048,16 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy) { return false; } + +static inline void +cpufreq_table_set_inefficient(const struct cpufreq_policy *policy, + unsigned int frequency) {} + +static inline int +cpufreq_table_update_efficiencies(struct cpufreq_policy *policy) +{ + return -EINVAL; +} #endif #if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) From patchwork Tue Aug 31 10:24:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Donnefort X-Patchwork-Id: 505409 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 503BCC4320A for ; Tue, 31 Aug 2021 10:24:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3459F60FC3 for ; Tue, 31 Aug 2021 10:24:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240908AbhHaKZj (ORCPT ); Tue, 31 Aug 2021 06:25:39 -0400 Received: from foss.arm.com ([217.140.110.172]:52930 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240962AbhHaKZi (ORCPT ); Tue, 31 Aug 2021 06:25:38 -0400 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 8D61F139F; Tue, 31 Aug 2021 03:24:43 -0700 (PDT) Received: from e120877-lin.cambridge.arm.com (e120877-lin.cambridge.arm.com [10.1.194.43]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 22A5B3F5A1; Tue, 31 Aug 2021 03:24:42 -0700 (PDT) From: Vincent Donnefort To: peterz@infradead.org, rjw@rjwysocki.net, viresh.kumar@linaro.org, vincent.guittot@linaro.org, qperret@google.com Cc: linux-pm@vger.kernel.org, ionela.voinescu@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, mka@chromium.org, Vincent Donnefort Subject: [PATCH v6 6/7] cpufreq: Skip inefficient frequencies Date: Tue, 31 Aug 2021 11:24:12 +0100 Message-Id: <1630405453-275784-7-git-send-email-vincent.donnefort@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> References: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org CPUFreq governors that do DVFS (i.e. CPUFREQ_GOV_DYNAMIC_SWITCHING flag) can skip frequencies marked as inefficient, as long as the efficient frequency found meet the policy maximum requirement. Signed-off-by: Vincent Donnefort diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7d5f170ecad1..b46fe2d7baf1 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2295,6 +2295,44 @@ __weak struct cpufreq_governor *cpufreq_fallback_governor(void) return NULL; } +static inline bool +cpufreq_can_skip_inefficiencies(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *pos; + bool valid = false; + int idx; + + if (!(policy->governor->flags & CPUFREQ_GOV_DYNAMIC_SWITCHING)) + return false; + + if (policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED) + return false; + + /* Is there at least one inefficiency ? */ + cpufreq_for_each_valid_entry(pos, policy->freq_table) { + if (pos->flags & CPUFREQ_INEFFICIENT_FREQ) { + valid = true; + break; + } + } + + if (!valid) + return false; + + /* + * Has cpufreq_table_update_efficiencies been called? i.e. is the + * highest frequency efficient. + */ + cpufreq_for_each_valid_entry_idx(pos, policy->freq_table, idx) { + valid = !!(idx == pos->efficient); + if (policy->freq_table_sorted == + CPUFREQ_TABLE_SORTED_DESCENDING) + break; + } + + return valid; +} + static int cpufreq_init_governor(struct cpufreq_policy *policy) { int ret; @@ -2337,6 +2375,7 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy) } policy->strict_target = !!(policy->governor->flags & CPUFREQ_GOV_STRICT_TARGET); + policy->skip_inefficiencies = cpufreq_can_skip_inefficiencies(policy); return 0; } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 4e901ebd104d..cb09afbf01e2 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -117,6 +117,13 @@ struct cpufreq_policy { bool strict_target; /* + * Set if the CPUFREQ_GOV_DYNAMIC_SWITCHING flag is set for the current + * governor and if inefficient frequencies were found in the frequency + * table. + */ + bool skip_inefficiencies; + + /* * Preferred average time interval between consecutive invocations of * the driver to set the frequency for this policy. To be set by the * scaling driver (0, which is the default, means no preference). @@ -972,25 +979,46 @@ static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, return cpufreq_table_find_index_dc(policy, target_freq); } +static inline unsigned int +cpufreq_frequency_find_efficient(struct cpufreq_policy *policy, + unsigned int idx) +{ + struct cpufreq_frequency_table *table = policy->freq_table; + unsigned int efficient_idx = table[idx].efficient; + + return table[efficient_idx].frequency <= policy->max ? efficient_idx : + idx; +} + static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { + int idx; + if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED)) return cpufreq_table_index_unsorted(policy, target_freq, relation); switch (relation) { case CPUFREQ_RELATION_L: - return cpufreq_table_find_index_l(policy, target_freq); + idx = cpufreq_table_find_index_l(policy, target_freq); + break; case CPUFREQ_RELATION_H: - return cpufreq_table_find_index_h(policy, target_freq); + idx = cpufreq_table_find_index_h(policy, target_freq); + break; case CPUFREQ_RELATION_C: - return cpufreq_table_find_index_c(policy, target_freq); + idx = cpufreq_table_find_index_c(policy, target_freq); + break; default: WARN_ON_ONCE(1); return 0; } + + if (policy->skip_inefficiencies) + idx = cpufreq_frequency_find_efficient(policy, idx); + + return idx; } static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy *policy) From patchwork Tue Aug 31 10:24:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Donnefort X-Patchwork-Id: 504845 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 77CCEC43214 for ; Tue, 31 Aug 2021 10:24:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 570FD60FC3 for ; Tue, 31 Aug 2021 10:24:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240973AbhHaKZk (ORCPT ); Tue, 31 Aug 2021 06:25:40 -0400 Received: from foss.arm.com ([217.140.110.172]:52944 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240962AbhHaKZk (ORCPT ); Tue, 31 Aug 2021 06:25:40 -0400 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 363E41FB; Tue, 31 Aug 2021 03:24:45 -0700 (PDT) Received: from e120877-lin.cambridge.arm.com (e120877-lin.cambridge.arm.com [10.1.194.43]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id C06493F5A1; Tue, 31 Aug 2021 03:24:43 -0700 (PDT) From: Vincent Donnefort To: peterz@infradead.org, rjw@rjwysocki.net, viresh.kumar@linaro.org, vincent.guittot@linaro.org, qperret@google.com Cc: linux-pm@vger.kernel.org, ionela.voinescu@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, mka@chromium.org, Vincent Donnefort Subject: [PATCH v6 7/7] PM / EM: Mark inefficiencies in CPUFreq Date: Tue, 31 Aug 2021 11:24:13 +0100 Message-Id: <1630405453-275784-8-git-send-email-vincent.donnefort@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> References: <1630405453-275784-1-git-send-email-vincent.donnefort@arm.com> Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The Energy Model has a 1:1 mapping between OPPs and performance states (em_perf_state). If a CPUFreq driver registers an Energy Model, inefficiencies found by the latter can be applied to CPUFreq. Signed-off-by: Vincent Donnefort diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index cb09afbf01e2..153ddc7b0506 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -1121,7 +1121,6 @@ void cpufreq_generic_init(struct cpufreq_policy *policy, static inline void cpufreq_register_em_with_opp(struct cpufreq_policy *policy) { - dev_pm_opp_of_register_em(get_cpu_device(policy->cpu), - policy->related_cpus); + dev_pm_opp_of_register_em(get_cpu_device(policy->cpu), policy->related_cpus); } #endif /* _LINUX_CPUFREQ_H */ diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c index d353ef29e37f..dfcbb2deb794 100644 --- a/kernel/power/energy_model.c +++ b/kernel/power/energy_model.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) "energy_model: " fmt #include +#include #include #include #include @@ -231,6 +232,46 @@ static int em_create_pd(struct device *dev, int nr_states, return 0; } +static void em_cpufreq_update_efficiencies(struct device *dev) +{ + struct em_perf_domain *pd = dev->em_pd; + struct em_perf_state *table; + struct cpufreq_policy *policy; + bool found = false; + int i; + + if (!_is_cpu_device(dev) || !pd) + return; + + policy = cpufreq_cpu_get(cpumask_first(em_span_cpus(pd))); + if (!policy) { + dev_warn(dev, "EM: Access to CPUFreq policy failed"); + return; + } + + table = pd->table; + + for (i = 0; i < pd->nr_perf_states; i++) { + if (!(table[i].flags & EM_PERF_STATE_INEFFICIENT)) + continue; + + cpufreq_table_set_inefficient(policy, table[i].frequency); + found = true; + } + + if (!found) + return; + + if (cpufreq_table_update_efficiencies(policy)) + return; + + /* + * Efficiencies have been installed in CPUFreq, inefficient frequencies + * will be skipped. The EM can do the same. + */ + pd->flags |= EM_PERF_DOMAIN_SKIP_INEFFICIENCIES; +} + /** * em_pd_get() - Return the performance domain for a device * @dev : Device to find the performance domain for @@ -347,6 +388,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, if (milliwatts) dev->em_pd->flags |= EM_PERF_DOMAIN_MILLIWATTS; + em_cpufreq_update_efficiencies(dev); + em_debug_create_pd(dev); dev_info(dev, "EM: created perf domain\n");