diff options
Diffstat (limited to 'drivers/cpuidle/governors/menu.c')
-rw-r--r-- | drivers/cpuidle/governors/menu.c | 128 |
1 files changed, 107 insertions, 21 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index c47f3d09c1e..ed28f774ca4 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -19,6 +19,8 @@ #include <linux/tick.h> #include <linux/sched.h> #include <linux/math64.h> +#include <linux/cpu.h> +#include <linux/sysfs.h> #define BUCKETS 12 #define INTERVALS 8 @@ -121,6 +123,8 @@ struct menu_device { int interval_ptr; }; +static int tune_multiplier = 1024; +static int forced_state; #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) @@ -170,6 +174,9 @@ static inline int performance_multiplier(void) { int mult = 1; + if (tune_multiplier <= 1) + return tune_multiplier; + /* for higher loadavg, we are more reluctant */ mult += 2 * get_loadavg(); @@ -177,6 +184,9 @@ static inline int performance_multiplier(void) /* for IO wait tasks (per cpu!) we add 5x each */ mult += 10 * nr_iowait_cpu(smp_processor_id()); + if (tune_multiplier != 1024) + mult = (tune_multiplier * mult) / 1024; + return mult; } @@ -281,26 +291,34 @@ static int menu_select(struct cpuidle_device *dev) if (data->expected_us > 5) data->last_state_idx = CPUIDLE_DRIVER_STATE_START; - /* - * Find the idle state with the lowest power while satisfying - * our constraints. - */ - for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { - struct cpuidle_state *s = &dev->states[i]; - - if (s->flags & CPUIDLE_FLAG_IGNORE) - continue; - if (s->target_residency > data->predicted_us) - continue; - if (s->exit_latency > latency_req) - continue; - if (s->exit_latency * multiplier > data->predicted_us) - continue; - - if (s->power_usage < power_usage) { - power_usage = s->power_usage; - data->last_state_idx = i; - data->exit_us = s->exit_latency; + WARN((forced_state >= dev->state_count), \ + "Forced state value out of range.\n"); + + if ((forced_state != 0) && (forced_state < dev->state_count)) { + data->exit_us = dev->states[forced_state].exit_latency; + data->last_state_idx = forced_state; + } else { + /* + * Find the idle state with the lowest power while satisfying + * our constraints. + */ + for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { + struct cpuidle_state *s = &dev->states[i]; + + if (s->flags & CPUIDLE_FLAG_IGNORE) + continue; + if (s->target_residency > data->predicted_us) + continue; + if (s->exit_latency > latency_req) + continue; + if (s->exit_latency * multiplier > data->predicted_us) + continue; + + if (s->power_usage < power_usage) { + power_usage = s->power_usage; + data->last_state_idx = i; + data->exit_us = s->exit_latency; + } } } @@ -381,6 +399,63 @@ static void menu_update(struct cpuidle_device *dev) data->interval_ptr = 0; } +int cpuidle_set_multiplier(unsigned int value) +{ + + if (value > 1024) + tune_multiplier = 1024; + else + tune_multiplier = value; + + return 0; +} +EXPORT_SYMBOL(cpuidle_set_multiplier); + +/* Writing 0 will remove the forced state. */ +int cpuidle_force_state(unsigned int state) +{ + forced_state = state; + + return 0; +} +EXPORT_SYMBOL(cpuidle_force_state); + +static ssize_t show_multiplier(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", tune_multiplier); +} + +static ssize_t store_multiplier(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + cpuidle_set_multiplier(input); + + return count; +} + + +static SYSDEV_CLASS_ATTR(multiplier, 0644, show_multiplier, store_multiplier); + +static struct attribute *dbs_attributes[] = { + &attr_multiplier.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "cpuidle", +}; + /** * menu_enable_device - scans a CPU's states and does setup * @dev: the CPU @@ -408,7 +483,15 @@ static struct cpuidle_governor menu_governor = { */ static int __init init_menu(void) { - return cpuidle_register_governor(&menu_governor); + int ret; + + ret = cpuidle_register_governor(&menu_governor); + + sysfs_merge_group(&(cpu_sysdev_class.kset.kobj), + &dbs_attr_group); + + return ret; + } /** @@ -416,6 +499,9 @@ static int __init init_menu(void) */ static void __exit exit_menu(void) { + sysfs_unmerge_group(&(cpu_sysdev_class.kset.kobj), + &dbs_attr_group); + cpuidle_unregister_governor(&menu_governor); } |