|
@@ -47,6 +47,11 @@ static LIST_HEAD(cpufreq_policy_list);
|
|
|
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
|
|
|
#endif
|
|
|
|
|
|
+static inline bool has_target(void)
|
|
|
+{
|
|
|
+ return cpufreq_driver->target_index || cpufreq_driver->target;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
|
|
|
* all cpufreq/hotplug/workqueue/etc related lock issues.
|
|
@@ -392,7 +397,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
|
|
|
*policy = CPUFREQ_POLICY_POWERSAVE;
|
|
|
err = 0;
|
|
|
}
|
|
|
- } else if (cpufreq_driver->target) {
|
|
|
+ } else if (has_target()) {
|
|
|
struct cpufreq_governor *t;
|
|
|
|
|
|
mutex_lock(&cpufreq_governor_mutex);
|
|
@@ -550,7 +555,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
|
|
|
ssize_t i = 0;
|
|
|
struct cpufreq_governor *t;
|
|
|
|
|
|
- if (!cpufreq_driver->target) {
|
|
|
+ if (!has_target()) {
|
|
|
i += sprintf(buf, "performance powersave");
|
|
|
goto out;
|
|
|
}
|
|
@@ -835,7 +840,7 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
|
|
|
if (ret)
|
|
|
goto err_out_kobj_put;
|
|
|
}
|
|
|
- if (cpufreq_driver->target) {
|
|
|
+ if (has_target()) {
|
|
|
ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
|
|
|
if (ret)
|
|
|
goto err_out_kobj_put;
|
|
@@ -884,10 +889,10 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
|
|
|
unsigned int cpu, struct device *dev,
|
|
|
bool frozen)
|
|
|
{
|
|
|
- int ret = 0, has_target = !!cpufreq_driver->target;
|
|
|
+ int ret = 0;
|
|
|
unsigned long flags;
|
|
|
|
|
|
- if (has_target) {
|
|
|
+ if (has_target()) {
|
|
|
ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
|
|
if (ret) {
|
|
|
pr_err("%s: Failed to stop governor\n", __func__);
|
|
@@ -905,7 +910,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
|
|
|
|
|
|
unlock_policy_rwsem_write(policy->cpu);
|
|
|
|
|
|
- if (has_target) {
|
|
|
+ if (has_target()) {
|
|
|
if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
|
|
|
(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
|
|
|
pr_err("%s: Failed to start governor\n", __func__);
|
|
@@ -1215,7 +1220,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- if (cpufreq_driver->target) {
|
|
|
+ if (has_target()) {
|
|
|
ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
|
|
if (ret) {
|
|
|
pr_err("%s: Failed to stop governor\n", __func__);
|
|
@@ -1280,7 +1285,7 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
|
|
|
|
|
|
/* If cpu is last user of policy, free policy */
|
|
|
if (cpus == 1) {
|
|
|
- if (cpufreq_driver->target) {
|
|
|
+ if (has_target()) {
|
|
|
ret = __cpufreq_governor(policy,
|
|
|
CPUFREQ_GOV_POLICY_EXIT);
|
|
|
if (ret) {
|
|
@@ -1323,7 +1328,7 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
|
|
|
if (!frozen)
|
|
|
cpufreq_policy_free(policy);
|
|
|
} else {
|
|
|
- if (cpufreq_driver->target) {
|
|
|
+ if (has_target()) {
|
|
|
if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
|
|
|
(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
|
|
|
pr_err("%s: Failed to start governor\n",
|
|
@@ -1694,12 +1699,41 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|
|
pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
|
|
|
policy->cpu, target_freq, relation, old_target_freq);
|
|
|
|
|
|
+ /*
|
|
|
+ * This might look like a redundant call as we are checking it again
|
|
|
+ * after finding index. But it is left intentionally for cases where
|
|
|
+ * exactly same freq is called again and so we can save on few function
|
|
|
+ * calls.
|
|
|
+ */
|
|
|
if (target_freq == policy->cur)
|
|
|
return 0;
|
|
|
|
|
|
if (cpufreq_driver->target)
|
|
|
retval = cpufreq_driver->target(policy, target_freq, relation);
|
|
|
+ else if (cpufreq_driver->target_index) {
|
|
|
+ struct cpufreq_frequency_table *freq_table;
|
|
|
+ int index;
|
|
|
|
|
|
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
|
|
|
+ if (unlikely(!freq_table)) {
|
|
|
+ pr_err("%s: Unable to find freq_table\n", __func__);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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__);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (freq_table[index].frequency == policy->cur)
|
|
|
+ retval = 0;
|
|
|
+ else
|
|
|
+ retval = cpufreq_driver->target_index(policy, index);
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
return retval;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
|
|
@@ -2025,7 +2059,7 @@ int cpufreq_update_policy(unsigned int cpu)
|
|
|
pr_debug("Driver did not initialize current freq");
|
|
|
policy->cur = new_policy.cur;
|
|
|
} else {
|
|
|
- if (policy->cur != new_policy.cur && cpufreq_driver->target)
|
|
|
+ if (policy->cur != new_policy.cur && has_target())
|
|
|
cpufreq_out_of_sync(cpu, policy->cur,
|
|
|
new_policy.cur);
|
|
|
}
|
|
@@ -2103,7 +2137,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
|
|
return -ENODEV;
|
|
|
|
|
|
if (!driver_data || !driver_data->verify || !driver_data->init ||
|
|
|
- ((!driver_data->setpolicy) && (!driver_data->target)))
|
|
|
+ !(driver_data->setpolicy || driver_data->target_index ||
|
|
|
+ driver_data->target))
|
|
|
return -EINVAL;
|
|
|
|
|
|
pr_debug("trying to register driver %s\n", driver_data->name);
|