|
@@ -74,19 +74,12 @@ static inline bool has_target(void)
|
|
|
}
|
|
|
|
|
|
/* internal prototypes */
|
|
|
-static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
|
|
|
static unsigned int __cpufreq_get(struct cpufreq_policy *policy);
|
|
|
+static int cpufreq_init_governor(struct cpufreq_policy *policy);
|
|
|
+static void cpufreq_exit_governor(struct cpufreq_policy *policy);
|
|
|
static int cpufreq_start_governor(struct cpufreq_policy *policy);
|
|
|
-
|
|
|
-static inline void cpufreq_exit_governor(struct cpufreq_policy *policy)
|
|
|
-{
|
|
|
- (void)cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
|
|
|
-}
|
|
|
-
|
|
|
-static inline void cpufreq_stop_governor(struct cpufreq_policy *policy)
|
|
|
-{
|
|
|
- (void)cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
|
|
-}
|
|
|
+static void cpufreq_stop_governor(struct cpufreq_policy *policy);
|
|
|
+static void cpufreq_governor_limits(struct cpufreq_policy *policy);
|
|
|
|
|
|
/**
|
|
|
* Two notifier lists: the "policy" list is involved in the
|
|
@@ -133,15 +126,6 @@ struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(get_governor_parent_kobj);
|
|
|
|
|
|
-struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
|
|
|
-{
|
|
|
- struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
|
|
|
-
|
|
|
- return policy && !policy_is_inactive(policy) ?
|
|
|
- policy->freq_table : NULL;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
|
|
|
-
|
|
|
static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
|
|
|
{
|
|
|
u64 idle_time;
|
|
@@ -354,6 +338,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
|
|
pr_debug("FREQ: %lu - CPU: %lu\n",
|
|
|
(unsigned long)freqs->new, (unsigned long)freqs->cpu);
|
|
|
trace_cpu_frequency(freqs->new, freqs->cpu);
|
|
|
+ cpufreq_stats_record_transition(policy, freqs->new);
|
|
|
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
|
|
CPUFREQ_POSTCHANGE, freqs);
|
|
|
if (likely(policy) && likely(policy->cpu == freqs->cpu))
|
|
@@ -1115,6 +1100,7 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify)
|
|
|
CPUFREQ_REMOVE_POLICY, policy);
|
|
|
|
|
|
down_write(&policy->rwsem);
|
|
|
+ cpufreq_stats_free_table(policy);
|
|
|
cpufreq_remove_dev_symlink(policy);
|
|
|
kobj = &policy->kobj;
|
|
|
cmp = &policy->kobj_unregister;
|
|
@@ -1265,13 +1251,12 @@ static int cpufreq_online(unsigned int cpu)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
|
|
- CPUFREQ_START, policy);
|
|
|
-
|
|
|
if (new_policy) {
|
|
|
ret = cpufreq_add_dev_interface(policy);
|
|
|
if (ret)
|
|
|
goto out_exit_policy;
|
|
|
+
|
|
|
+ cpufreq_stats_create_table(policy);
|
|
|
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
|
|
CPUFREQ_CREATE_POLICY, policy);
|
|
|
|
|
@@ -1280,6 +1265,9 @@ static int cpufreq_online(unsigned int cpu)
|
|
|
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
|
|
}
|
|
|
|
|
|
+ blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
|
|
+ CPUFREQ_START, policy);
|
|
|
+
|
|
|
ret = cpufreq_init_policy(policy);
|
|
|
if (ret) {
|
|
|
pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n",
|
|
@@ -1864,14 +1852,17 @@ static int __target_intermediate(struct cpufreq_policy *policy,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int __target_index(struct cpufreq_policy *policy,
|
|
|
- struct cpufreq_frequency_table *freq_table, int index)
|
|
|
+static int __target_index(struct cpufreq_policy *policy, int index)
|
|
|
{
|
|
|
struct cpufreq_freqs freqs = {.old = policy->cur, .flags = 0};
|
|
|
unsigned int intermediate_freq = 0;
|
|
|
+ unsigned int newfreq = policy->freq_table[index].frequency;
|
|
|
int retval = -EINVAL;
|
|
|
bool notify;
|
|
|
|
|
|
+ if (newfreq == policy->cur)
|
|
|
+ return 0;
|
|
|
+
|
|
|
notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
|
|
|
if (notify) {
|
|
|
/* Handle switching to intermediate frequency */
|
|
@@ -1886,7 +1877,7 @@ static int __target_index(struct cpufreq_policy *policy,
|
|
|
freqs.old = freqs.new;
|
|
|
}
|
|
|
|
|
|
- freqs.new = freq_table[index].frequency;
|
|
|
+ freqs.new = newfreq;
|
|
|
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
|
|
|
__func__, policy->cpu, freqs.old, freqs.new);
|
|
|
|
|
@@ -1923,17 +1914,13 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|
|
unsigned int relation)
|
|
|
{
|
|
|
unsigned int old_target_freq = target_freq;
|
|
|
- struct cpufreq_frequency_table *freq_table;
|
|
|
- int index, retval;
|
|
|
+ int index;
|
|
|
|
|
|
if (cpufreq_disabled())
|
|
|
return -ENODEV;
|
|
|
|
|
|
/* Make sure that target_freq is within supported range */
|
|
|
- if (target_freq > policy->max)
|
|
|
- target_freq = policy->max;
|
|
|
- if (target_freq < policy->min)
|
|
|
- target_freq = policy->min;
|
|
|
+ target_freq = clamp_val(target_freq, policy->min, policy->max);
|
|
|
|
|
|
pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
|
|
|
policy->cpu, target_freq, relation, old_target_freq);
|
|
@@ -1956,23 +1943,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|
|
if (!cpufreq_driver->target_index)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- freq_table = cpufreq_frequency_get_table(policy->cpu);
|
|
|
- if (unlikely(!freq_table)) {
|
|
|
- pr_err("%s: Unable to find freq_table\n", __func__);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- retval = cpufreq_frequency_table_target(policy, freq_table, target_freq,
|
|
|
- relation, &index);
|
|
|
- if (unlikely(retval)) {
|
|
|
- pr_err("%s: Unable to find matching freq\n", __func__);
|
|
|
- return retval;
|
|
|
- }
|
|
|
-
|
|
|
- if (freq_table[index].frequency == policy->cur)
|
|
|
- return 0;
|
|
|
+ index = cpufreq_frequency_table_target(policy, target_freq, relation);
|
|
|
|
|
|
- return __target_index(policy, freq_table, index);
|
|
|
+ return __target_index(policy, index);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
|
|
|
|
|
@@ -1997,7 +1970,7 @@ __weak struct cpufreq_governor *cpufreq_fallback_governor(void)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
|
|
|
+static int cpufreq_init_governor(struct cpufreq_policy *policy)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
@@ -2025,36 +1998,82 @@ static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (event == CPUFREQ_GOV_POLICY_INIT)
|
|
|
- if (!try_module_get(policy->governor->owner))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- pr_debug("%s: for CPU %u, event %u\n", __func__, policy->cpu, event);
|
|
|
+ if (!try_module_get(policy->governor->owner))
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- ret = policy->governor->governor(policy, event);
|
|
|
+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
|
|
|
|
|
|
- if (event == CPUFREQ_GOV_POLICY_INIT) {
|
|
|
- if (ret)
|
|
|
+ if (policy->governor->init) {
|
|
|
+ ret = policy->governor->init(policy);
|
|
|
+ if (ret) {
|
|
|
module_put(policy->governor->owner);
|
|
|
- else
|
|
|
- policy->governor->initialized++;
|
|
|
- } else if (event == CPUFREQ_GOV_POLICY_EXIT) {
|
|
|
- policy->governor->initialized--;
|
|
|
- module_put(policy->governor->owner);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return ret;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void cpufreq_exit_governor(struct cpufreq_policy *policy)
|
|
|
+{
|
|
|
+ if (cpufreq_suspended || !policy->governor)
|
|
|
+ return;
|
|
|
+
|
|
|
+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
|
|
|
+
|
|
|
+ if (policy->governor->exit)
|
|
|
+ policy->governor->exit(policy);
|
|
|
+
|
|
|
+ module_put(policy->governor->owner);
|
|
|
}
|
|
|
|
|
|
static int cpufreq_start_governor(struct cpufreq_policy *policy)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
+ if (cpufreq_suspended)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (!policy->governor)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
|
|
|
+
|
|
|
if (cpufreq_driver->get && !cpufreq_driver->setpolicy)
|
|
|
cpufreq_update_current_freq(policy);
|
|
|
|
|
|
- ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
|
|
|
- return ret ? ret : cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
|
|
+ if (policy->governor->start) {
|
|
|
+ ret = policy->governor->start(policy);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (policy->governor->limits)
|
|
|
+ policy->governor->limits(policy);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void cpufreq_stop_governor(struct cpufreq_policy *policy)
|
|
|
+{
|
|
|
+ if (cpufreq_suspended || !policy->governor)
|
|
|
+ return;
|
|
|
+
|
|
|
+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
|
|
|
+
|
|
|
+ if (policy->governor->stop)
|
|
|
+ policy->governor->stop(policy);
|
|
|
+}
|
|
|
+
|
|
|
+static void cpufreq_governor_limits(struct cpufreq_policy *policy)
|
|
|
+{
|
|
|
+ if (cpufreq_suspended || !policy->governor)
|
|
|
+ return;
|
|
|
+
|
|
|
+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
|
|
|
+
|
|
|
+ if (policy->governor->limits)
|
|
|
+ policy->governor->limits(policy);
|
|
|
}
|
|
|
|
|
|
int cpufreq_register_governor(struct cpufreq_governor *governor)
|
|
@@ -2069,7 +2088,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
|
|
|
|
|
|
mutex_lock(&cpufreq_governor_mutex);
|
|
|
|
|
|
- governor->initialized = 0;
|
|
|
err = -EBUSY;
|
|
|
if (!find_governor(governor->name)) {
|
|
|
err = 0;
|
|
@@ -2195,7 +2213,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
|
|
|
|
|
if (new_policy->governor == policy->governor) {
|
|
|
pr_debug("cpufreq: governor limits update\n");
|
|
|
- return cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
|
|
+ cpufreq_governor_limits(policy);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
pr_debug("governor switch\n");
|
|
@@ -2210,7 +2229,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
|
|
|
|
|
/* start new governor */
|
|
|
policy->governor = new_policy->governor;
|
|
|
- ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
|
|
|
+ ret = cpufreq_init_governor(policy);
|
|
|
if (!ret) {
|
|
|
ret = cpufreq_start_governor(policy);
|
|
|
if (!ret) {
|
|
@@ -2224,7 +2243,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
|
|
pr_debug("starting governor %s failed\n", policy->governor->name);
|
|
|
if (old_gov) {
|
|
|
policy->governor = old_gov;
|
|
|
- if (cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT))
|
|
|
+ if (cpufreq_init_governor(policy))
|
|
|
policy->governor = NULL;
|
|
|
else
|
|
|
cpufreq_start_governor(policy);
|
|
@@ -2305,26 +2324,25 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
|
|
|
*********************************************************************/
|
|
|
static int cpufreq_boost_set_sw(int state)
|
|
|
{
|
|
|
- struct cpufreq_frequency_table *freq_table;
|
|
|
struct cpufreq_policy *policy;
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
for_each_active_policy(policy) {
|
|
|
- freq_table = cpufreq_frequency_get_table(policy->cpu);
|
|
|
- if (freq_table) {
|
|
|
- ret = cpufreq_frequency_table_cpuinfo(policy,
|
|
|
- freq_table);
|
|
|
- if (ret) {
|
|
|
- pr_err("%s: Policy frequency update failed\n",
|
|
|
- __func__);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- down_write(&policy->rwsem);
|
|
|
- policy->user_policy.max = policy->max;
|
|
|
- cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
|
|
- up_write(&policy->rwsem);
|
|
|
+ if (!policy->freq_table)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ret = cpufreq_frequency_table_cpuinfo(policy,
|
|
|
+ policy->freq_table);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("%s: Policy frequency update failed\n",
|
|
|
+ __func__);
|
|
|
+ break;
|
|
|
}
|
|
|
+
|
|
|
+ down_write(&policy->rwsem);
|
|
|
+ policy->user_policy.max = policy->max;
|
|
|
+ cpufreq_governor_limits(policy);
|
|
|
+ up_write(&policy->rwsem);
|
|
|
}
|
|
|
|
|
|
return ret;
|