/drivers/cpufreq/cpufreq_ondemand.c
C | 759 lines | 534 code | 116 blank | 109 comment | 73 complexity | 5ef5db4d0d2e43ca42175635ecde430c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * drivers/cpufreq/cpufreq_ondemand.c
- *
- * Copyright (C) 2001 Russell King
- * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
- * Jun Nakajima <jun.nakajima@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/cpufreq.h>
- #include <linux/cpu.h>
- #include <linux/jiffies.h>
- #include <linux/kernel_stat.h>
- #include <linux/mutex.h>
- #include <linux/hrtimer.h>
- #include <linux/tick.h>
- #include <linux/ktime.h>
- #include <linux/sched.h>
- /*
- * dbs is used in this file as a shortform for demandbased switching
- * It helps to keep variable names smaller, simpler
- */
- #define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10)
- #define DEF_FREQUENCY_UP_THRESHOLD (80)
- #define DEF_SAMPLING_DOWN_FACTOR (1)
- #define MAX_SAMPLING_DOWN_FACTOR (100000)
- #define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3)
- #define MICRO_FREQUENCY_UP_THRESHOLD (95)
- #define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000)
- #define MIN_FREQUENCY_UP_THRESHOLD (11)
- #define MAX_FREQUENCY_UP_THRESHOLD (100)
- /*
- * The polling frequency of this governor depends on the capability of
- * the processor. Default polling frequency is 1000 times the transition
- * latency of the processor. The governor will work on any processor with
- * transition latency <= 10mS, using appropriate sampling
- * rate.
- * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
- * this governor will not work.
- * All times here are in uS.
- */
- #define MIN_SAMPLING_RATE_RATIO (2)
- static unsigned int min_sampling_rate;
- #define LATENCY_MULTIPLIER (1000)
- #define MIN_LATENCY_MULTIPLIER (100)
- #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
- static void do_dbs_timer(struct work_struct *work);
- static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event);
- #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
- static
- #endif
- struct cpufreq_governor cpufreq_gov_ondemand = {
- .name = "ondemand",
- .governor = cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
- };
- /* Sampling types */
- enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
- struct cpu_dbs_info_s {
- cputime64_t prev_cpu_idle;
- cputime64_t prev_cpu_iowait;
- cputime64_t prev_cpu_wall;
- cputime64_t prev_cpu_nice;
- struct cpufreq_policy *cur_policy;
- struct delayed_work work;
- struct cpufreq_frequency_table *freq_table;
- unsigned int freq_lo;
- unsigned int freq_lo_jiffies;
- unsigned int freq_hi_jiffies;
- unsigned int rate_mult;
- int cpu;
- unsigned int sample_type:1;
- /*
- * percpu mutex that serializes governor limit change with
- * do_dbs_timer invocation. We do not want do_dbs_timer to run
- * when user is changing the governor or limits.
- */
- struct mutex timer_mutex;
- };
- static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
- static unsigned int dbs_enable; /* number of CPUs using this policy */
- /*
- * dbs_mutex protects dbs_enable in governor start/stop.
- */
- static DEFINE_MUTEX(dbs_mutex);
- static struct dbs_tuners {
- unsigned int sampling_rate;
- unsigned int up_threshold;
- unsigned int down_differential;
- unsigned int ignore_nice;
- unsigned int sampling_down_factor;
- unsigned int powersave_bias;
- unsigned int io_is_busy;
- } dbs_tuners_ins = {
- .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
- .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
- .ignore_nice = 0,
- .powersave_bias = 0,
- };
- static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
- cputime64_t *wall)
- {
- cputime64_t idle_time;
- cputime64_t cur_wall_time;
- cputime64_t busy_time;
- cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
- busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user,
- kstat_cpu(cpu).cpustat.system);
- busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.irq);
- busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.softirq);
- busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.steal);
- busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.nice);
- idle_time = cputime64_sub(cur_wall_time, busy_time);
- if (wall)
- *wall = (cputime64_t)jiffies_to_usecs(cur_wall_time);
- return (cputime64_t)jiffies_to_usecs(idle_time);
- }
- static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
- {
- u64 idle_time = get_cpu_idle_time_us(cpu, wall);
- if (idle_time == -1ULL)
- return get_cpu_idle_time_jiffy(cpu, wall);
- return idle_time;
- }
- static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall)
- {
- u64 iowait_time = get_cpu_iowait_time_us(cpu, wall);
- if (iowait_time == -1ULL)
- return 0;
- return iowait_time;
- }
- /*
- * Find right freq to be set now with powersave_bias on.
- * Returns the freq_hi to be used right now and will set freq_hi_jiffies,
- * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs.
- */
- static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
- unsigned int freq_next,
- unsigned int relation)
- {
- unsigned int freq_req, freq_reduc, freq_avg;
- unsigned int freq_hi, freq_lo;
- unsigned int index = 0;
- unsigned int jiffies_total, jiffies_hi, jiffies_lo;
- struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
- policy->cpu);
- if (!dbs_info->freq_table) {
- dbs_info->freq_lo = 0;
- dbs_info->freq_lo_jiffies = 0;
- return freq_next;
- }
- cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next,
- relation, &index);
- freq_req = dbs_info->freq_table[index].frequency;
- freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000;
- freq_avg = freq_req - freq_reduc;
- /* Find freq bounds for freq_avg in freq_table */
- index = 0;
- cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
- CPUFREQ_RELATION_H, &index);
- freq_lo = dbs_info->freq_table[index].frequency;
- index = 0;
- cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
- CPUFREQ_RELATION_L, &index);
- freq_hi = dbs_info->freq_table[index].frequency;
- /* Find out how long we have to be in hi and lo freqs */
- if (freq_hi == freq_lo) {
- dbs_info->freq_lo = 0;
- dbs_info->freq_lo_jiffies = 0;
- return freq_lo;
- }
- jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
- jiffies_hi = (freq_avg - freq_lo) * jiffies_total;
- jiffies_hi += ((freq_hi - freq_lo) / 2);
- jiffies_hi /= (freq_hi - freq_lo);
- jiffies_lo = jiffies_total - jiffies_hi;
- dbs_info->freq_lo = freq_lo;
- dbs_info->freq_lo_jiffies = jiffies_lo;
- dbs_info->freq_hi_jiffies = jiffies_hi;
- return freq_hi;
- }
- static void ondemand_powersave_bias_init_cpu(int cpu)
- {
- struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
- dbs_info->freq_table = cpufreq_frequency_get_table(cpu);
- dbs_info->freq_lo = 0;
- }
- static void ondemand_powersave_bias_init(void)
- {
- int i;
- for_each_online_cpu(i) {
- ondemand_powersave_bias_init_cpu(i);
- }
- }
- /************************** sysfs interface ************************/
- static ssize_t show_sampling_rate_min(struct kobject *kobj,
- struct attribute *attr, char *buf)
- {
- return sprintf(buf, "%u\n", min_sampling_rate);
- }
- define_one_global_ro(sampling_rate_min);
- /* cpufreq_ondemand Governor Tunables */
- #define show_one(file_name, object) \
- static ssize_t show_##file_name \