Latest big LITTLE systems for ARM SoC's have following kind of ranges of freqs:
LITTLE CPU ranges: x MHz -> y MHz
big CPU ranges: y + delta -> z MHz
For these, we use hispeed_freq as y MHz, to avoid a switch of clusters from
LITTLE to big when load burst comes. Similar to non big.LITTLE systems, we also
need to avoid highest OPPs for load bursts and so need another "speed breaker".
Hence, we introduce hispeed2_freq here. This would normally be set to z - delta
MHz. For, non big.LITTLE systems if we don't set hispeed2_freq, it would be set
as policy->max frequency. And so, behavior would remain same as existing code.
Based on Initial work from Sudeep, hence his SOB.
Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/cpufreq_interactive.c | 119 +++++++++++++++++++++++++++++++---
1 file changed, 111 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 4dc7f04..0c5bb2c 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -68,6 +68,13 @@ static unsigned int hispeed_freq;
#define DEFAULT_GO_HISPEED_LOAD 85
static unsigned long go_hispeed_load;
+/* Hi speed2 to bump to from Hi speed when load bursts over hispeed freq */
+static unsigned int hispeed2_freq;
+
+/* Go to hi speed2 when CPU load at or above this value. */
+#define DEFAULT_GO_HISPEED2_LOAD 95
+static unsigned long go_hispeed2_load;
+
/* Target load. Lower values result in higher CPU speeds. */
#define DEFAULT_TARGET_LOAD 90
static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD};
@@ -88,12 +95,15 @@ static unsigned long min_sample_time;
static unsigned long timer_rate;
/*
- * Wait this long before raising speed above hispeed, by default a single
- * timer interval.
+ * Wait this long before raising speed above hispeed/hispeed2, by default a
+ * single timer interval.
*/
#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE
static unsigned long above_hispeed_delay_val;
+#define DEFAULT_ABOVE_HISPEED2_DELAY DEFAULT_TIMER_RATE
+static unsigned long above_hispeed2_delay_val;
+
/* Non-zero means indefinite speed boost active */
static int boost_val;
/* Duration of a boot pulse in usecs */
@@ -272,7 +282,7 @@ static void cpufreq_interactive_timer(unsigned long data)
int cpu_load;
struct cpufreq_interactive_cpuinfo *pcpu =
&per_cpu(cpuinfo, data);
- unsigned int new_freq;
+ unsigned int new_freq = 0, min_freq = 0;
unsigned int loadadjfreq;
unsigned int index;
unsigned long flags;
@@ -301,13 +311,22 @@ static void cpufreq_interactive_timer(unsigned long data)
if (pcpu->target_freq < hispeed_freq) {
new_freq = hispeed_freq;
} else {
- new_freq = choose_freq(pcpu, loadadjfreq);
-
- if (new_freq < hispeed_freq)
- new_freq = hispeed_freq;
+ if (cpu_load >= go_hispeed2_load) {
+ if (pcpu->target_freq < hispeed2_freq)
+ new_freq = hispeed2_freq;
+ else
+ min_freq = hispeed2_freq;
+ } else {
+ min_freq = hispeed_freq;
+ }
}
- } else {
+ }
+
+ if (!new_freq) {
new_freq = choose_freq(pcpu, loadadjfreq);
+
+ if (new_freq < min_freq)
+ new_freq = min_freq;
}
if (pcpu->target_freq >= hispeed_freq &&
@@ -319,6 +338,15 @@ static void cpufreq_interactive_timer(unsigned long data)
goto rearm;
}
+ if (pcpu->target_freq >= hispeed2_freq &&
+ new_freq > pcpu->target_freq &&
+ now - pcpu->hispeed_validate_time < above_hispeed2_delay_val) {
+ trace_cpufreq_interactive_notyet(
+ data, cpu_load, pcpu->target_freq,
+ pcpu->policy->cur, new_freq);
+ goto rearm;
+ }
+
pcpu->hispeed_validate_time = now;
if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
@@ -688,6 +716,51 @@ static ssize_t store_go_hispeed_load(struct kobject *kobj,
static struct global_attr go_hispeed_load_attr = __ATTR(go_hispeed_load, 0644,
show_go_hispeed_load, store_go_hispeed_load);
+static ssize_t show_hispeed2_freq(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", hispeed2_freq);
+}
+
+static ssize_t store_hispeed2_freq(struct kobject *kobj,
+ struct attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ long unsigned int val;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ hispeed2_freq = val;
+ return count;
+}
+
+static struct global_attr hispeed2_freq_attr = __ATTR(hispeed2_freq, 0644,
+ show_hispeed2_freq, store_hispeed2_freq);
+
+static ssize_t show_go_hispeed2_load(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", go_hispeed2_load);
+}
+
+static ssize_t store_go_hispeed2_load(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ go_hispeed2_load = val;
+ return count;
+}
+
+static struct global_attr go_hispeed2_load_attr = __ATTR(go_hispeed2_load, 0644,
+ show_go_hispeed2_load, store_go_hispeed2_load);
+
static ssize_t show_min_sample_time(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -732,6 +805,28 @@ static ssize_t store_above_hispeed_delay(struct kobject *kobj,
define_one_global_rw(above_hispeed_delay);
+static ssize_t show_above_hispeed2_delay(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", above_hispeed2_delay_val);
+}
+
+static ssize_t store_above_hispeed2_delay(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ above_hispeed2_delay_val = val;
+ return count;
+}
+
+define_one_global_rw(above_hispeed2_delay);
+
static ssize_t show_timer_rate(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -854,6 +949,9 @@ static struct attribute *interactive_attributes[] = {
&hispeed_freq_attr.attr,
&go_hispeed_load_attr.attr,
&above_hispeed_delay.attr,
+ &hispeed2_freq_attr.attr,
+ &go_hispeed2_load_attr.attr,
+ &above_hispeed2_delay.attr,
&min_sample_time_attr.attr,
&timer_rate_attr.attr,
&timer_slack.attr,
@@ -906,6 +1004,9 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
if (!hispeed_freq)
hispeed_freq = policy->max;
+ if (!hispeed2_freq || hispeed2_freq > policy->max)
+ hispeed2_freq = policy->max;
+
for_each_cpu(j, policy->cpus) {
unsigned long expires;
@@ -994,6 +1095,8 @@ static int __init cpufreq_interactive_init(void)
go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
above_hispeed_delay_val = DEFAULT_ABOVE_HISPEED_DELAY;
+ go_hispeed2_load = DEFAULT_GO_HISPEED2_LOAD;
+ above_hispeed2_delay_val = DEFAULT_ABOVE_HISPEED2_DELAY;
timer_rate = DEFAULT_TIMER_RATE;
/* Initalize per-cpu timers */
--
1.7.12.rc2.18.g61b472e