From patchwork Wed Jul 29 15:12:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukasz Luba X-Patchwork-Id: 11691185 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 6E57D13B6 for ; Wed, 29 Jul 2020 15:14:28 +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 4752920829 for ; Wed, 29 Jul 2020 15:14:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="VnRu7HXM" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4752920829 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=4up2CUCKpy2IgpRudOS6GGVy1M2ExfqLsDvGrmUGemI=; b=VnRu7HXMwhM3kSFaToIiXGngbG 5s3oCf0AvY/MKiqHDx8hxZW42co7gjWAWwMtsZPb+7CsXcm6xvZ3I+VudD7PB6p1AKhfzbaNSFVFN SssMdYNFnO6Lrq6OXbGqRpkXwopxJ9O+0YSD4vQMftzPHVLT1GrwVQXW5s1w0UmHgalq2/Brx8Aof h3C5OAbURW+ivgg/aycEJu6LgKosnjv/2THLe4e21Nh9rQDIXtu0VzeqzTEtIico0uOwQpyZiT2sT 5pB+UxLS07RQMe5r6/N5d/B07/Tm3ktlTfT7myV0asTogiCeehPfYMpaSvUqN//Of7//ACDu82YFg WW6UbTxQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1k0nl4-00063D-IZ; Wed, 29 Jul 2020 15:12:42 +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 1k0nkn-0005wl-9e for linux-arm-kernel@lists.infradead.org; Wed, 29 Jul 2020 15:12:27 +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 2D067D6E; Wed, 29 Jul 2020 08:12:23 -0700 (PDT) Received: from e123648.arm.com (unknown [10.37.12.35]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 0CA0D3F66E; Wed, 29 Jul 2020 08:12:20 -0700 (PDT) From: Lukasz Luba To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org Subject: [PATCH 1/4] cpufreq: Add support for statistics read from drivers Date: Wed, 29 Jul 2020 16:12:05 +0100 Message-Id: <20200729151208.27737-2-lukasz.luba@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200729151208.27737-1-lukasz.luba@arm.com> References: <20200729151208.27737-1-lukasz.luba@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200729_111225_458496_97746CA3 X-CRM114-Status: GOOD ( 22.80 ) 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_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an 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: viresh.kumar@linaro.org, rjw@rjwysocki.net, lukasz.luba@arm.com, cristian.marussi@arm.com, sudeep.holla@arm.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org The cpufreq statistics are not collected when the 'fast switch' is in use. The information can be retrieved from firmware by the cpufreq driver, but the cpufreq interfaces must be extended in order to support it. Introduce callback in cpufreq driver structure and additional flag in cpufreq policy to provide support for statistics maintained in firmware. Since the cpufreq driver structure can be shared by many policy objects, the flag 'has_driver_stats' in policy makes sure that the framework will only use the statistics from cpufreq driver for actually supported CPUs. Signed-off-by: Lukasz Luba --- drivers/cpufreq/cpufreq.c | 22 +++++++++++++++++++ drivers/cpufreq/cpufreq_stats.c | 38 +++++++++++++++++++++------------ include/linux/cpufreq.h | 32 +++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 17c1c3becd92..83098205e739 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2543,6 +2543,28 @@ void cpufreq_update_limits(unsigned int cpu) } EXPORT_SYMBOL_GPL(cpufreq_update_limits); +#ifdef CONFIG_CPU_FREQ_STAT +/** + * cpufreq_update_statistics - Update statistics for a given policy. + * @policy: struct cpufreq_policy into which the current cpufreq_policy + * is written + * + * Invoke the driver's ->get_statistics callback if present to fetch + * newest statistics from the driver. + */ +int cpufreq_update_statistics(struct cpufreq_policy *policy) +{ + if (!cpufreq_driver || !policy) + return -EINVAL; + + if (cpufreq_driver->get_statistics) + return cpufreq_driver->get_statistics(policy); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(cpufreq_update_statistics); +#endif + /********************************************************************* * BOOST * *********************************************************************/ diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 94d959a8e954..d2d975b3cc6d 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -11,19 +11,6 @@ #include #include - -struct cpufreq_stats { - unsigned int total_trans; - unsigned long long last_time; - unsigned int max_state; - unsigned int state_num; - unsigned int last_index; - u64 *time_in_state; - spinlock_t lock; - unsigned int *freq_table; - unsigned int *trans_table; -}; - static void cpufreq_stats_update(struct cpufreq_stats *stats) { unsigned long long cur_time = get_jiffies_64(); @@ -50,13 +37,36 @@ static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) } cpufreq_freq_attr_ro(total_trans); +static ssize_t cpufreq_stats_present_driver_data(struct cpufreq_policy *policy, char *buf) +{ + struct cpufreq_stats *stats = policy->stats; + ssize_t len = 0; + int i, ret; + + spin_lock(&stats->lock); + ret = cpufreq_update_statistics(policy); + spin_unlock(&stats->lock); + + if (ret) + return 0; + + for (i = 0; i < stats->state_num; i++) { + len += sprintf(buf + len, "%u %llu\n", + stats->freq_table[i], + stats->time_in_state[i]); + } + return len; +} + static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) { struct cpufreq_stats *stats = policy->stats; ssize_t len = 0; int i; - if (policy->fast_switch_enabled) + if (policy->has_driver_stats) + return cpufreq_stats_present_driver_data(policy, buf); + else if (policy->fast_switch_enabled) return 0; spin_lock(&stats->lock); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index e62b022cb07e..21074703e08c 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -138,6 +138,14 @@ struct cpufreq_policy { /* cpufreq-stats */ struct cpufreq_stats *stats; + /* + * Flag indicating that cpufreq statistics can be taken from device driver. + * The statistics are collected by firmware and the driver is able to retrieve + * them. It is useful when the 'fast switch' is used or the firmware changes + * frequency independently due to e.g. thermal issues. + */ + bool has_driver_stats; + /* For cpufreq driver's internal use */ void *driver_data; @@ -169,6 +177,18 @@ struct cpufreq_freqs { u8 flags; /* flags of cpufreq_driver, see below. */ }; +struct cpufreq_stats { + unsigned int total_trans; + unsigned long long last_time; + unsigned int max_state; + unsigned int state_num; + unsigned int last_index; + u64 *time_in_state; + spinlock_t lock; + unsigned int *freq_table; + unsigned int *trans_table; +}; + /* Only for ACPI */ #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ @@ -245,11 +265,17 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy); void cpufreq_stats_free_table(struct cpufreq_policy *policy); void cpufreq_stats_record_transition(struct cpufreq_policy *policy, unsigned int new_freq); +int cpufreq_update_statistics(struct cpufreq_policy *policy); #else static inline void cpufreq_stats_create_table(struct cpufreq_policy *policy) { } static inline void cpufreq_stats_free_table(struct cpufreq_policy *policy) { } static inline void cpufreq_stats_record_transition(struct cpufreq_policy *policy, unsigned int new_freq) { } +static int __maybe_unused +cpufreq_update_statistics(struct cpufreq_policy *policy) +{ + return -EINVAL; +} #endif /* CONFIG_CPU_FREQ_STAT */ /********************************************************************* @@ -350,6 +376,12 @@ struct cpufreq_driver { /* Called to update policy limits on firmware notifications. */ void (*update_limits)(unsigned int cpu); + /* + * Optional, used when driver can fetch statistics from firmware. + * This callback function cannot sleep. + */ + int (*get_statistics)(struct cpufreq_policy *policy); + /* optional */ int (*bios_limit)(int cpu, unsigned int *limit);