mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Lukasz Luba <lukasz.luba@arm.com>
To: linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org
Cc: sudeep.holla@arm.com, cristian.marussi@arm.com,
	viresh.kumar@linaro.org, lukasz.luba@arm.com, rjw@rjwysocki.net
Subject: [PATCH 1/4] cpufreq: Add support for statistics read from drivers
Date: Wed, 29 Jul 2020 16:12:05 +0100	[thread overview]
Message-ID: <20200729151208.27737-2-lukasz.luba@arm.com> (raw)
In-Reply-To: <20200729151208.27737-1-lukasz.luba@arm.com>

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 <lukasz.luba@arm.com>
---
 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 <linux/module.h>
 #include <linux/slab.h>
 
-
-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);
 
-- 
2.17.1


  reply	other threads:[~2020-07-29 15:12 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-29 15:12 [PATCH 0/4] CPUFreq statistics retrieved by drivers Lukasz Luba
2020-07-29 15:12 ` Lukasz Luba [this message]
2020-07-29 15:12 ` [PATCH 2/4] scmi: perf: Extend protocol to support performance statistics Lukasz Luba
2020-07-31  1:50   ` kernel test robot
2020-07-31 15:15   ` Cristian Marussi
2020-08-04 11:10     ` Lukasz Luba
2020-07-29 15:12 ` [PATCH 3/4] cpufreq: scmi: Move scmi_cpufreq_driver structure to the top Lukasz Luba
2020-07-29 15:12 ` [PATCH 4/4] cpufreq: scmi: Read statistics from FW shared memory Lukasz Luba
2020-07-30  8:53 ` [PATCH 0/4] CPUFreq statistics retrieved by drivers Viresh Kumar
2020-07-30  9:10   ` Sudeep Holla
2020-07-30  9:36     ` Lukasz Luba
2020-07-31 15:56       ` Sudeep Holla
2020-08-04 17:19         ` Florian Fainelli
2020-08-05 12:36           ` Sudeep Holla
2020-08-04  5:35       ` Viresh Kumar
2020-08-04 10:29         ` Lukasz Luba
2020-08-04 10:38           ` Viresh Kumar
2020-08-04 10:44             ` Lukasz Luba
2020-09-02  7:26               ` Viresh Kumar
2020-08-04 17:27 ` Florian Fainelli
2020-08-05 11:04   ` Lukasz Luba
2020-08-05 13:04     ` Viresh Kumar
2020-08-05 16:03       ` Sudeep Holla
2020-08-05 17:33         ` Florian Fainelli
2020-08-06 13:37           ` Sudeep Holla

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200729151208.27737-2-lukasz.luba@arm.com \
    --to=lukasz.luba@arm.com \
    --cc=cristian.marussi@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=rjw@rjwysocki.net \
    --cc=sudeep.holla@arm.com \
    --cc=viresh.kumar@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®