summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/cpufreq/cpufreq.c49
-rw-r--r--kernel/pm_qos_params.c4
2 files changed, 49 insertions, 4 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index dda10dcd09f3..65fba49d3f07 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -29,6 +29,7 @@
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/syscore_ops.h>
+#include <linux/pm_qos_params.h>
#include <trace/events/power.h>
@@ -1632,9 +1633,17 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
struct cpufreq_policy *policy)
{
int ret = 0;
+ unsigned int pmin = policy->min;
+ unsigned int pmax = policy->max;
+ unsigned int qmin = pm_qos_request(PM_QOS_CPU_FREQ_MIN);
+ unsigned int qmax = pm_qos_request(PM_QOS_CPU_FREQ_MAX);
- pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
- policy->min, policy->max);
+ pr_debug("setting new policy for CPU %u: %u - %u (%u - %u) kHz\n",
+ policy->cpu, pmin, pmax, qmin, qmax);
+
+ /* clamp the new policy to PM QoS limits */
+ policy->min = max(pmin, qmin);
+ policy->max = min(pmax, qmax);
memcpy(&policy->cpuinfo, &data->cpuinfo,
sizeof(struct cpufreq_cpuinfo));
@@ -1709,6 +1718,9 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
}
error_out:
+ /* restore the limits that the policy requested */
+ policy->min = pmin;
+ policy->max = pmax;
return ret;
}
@@ -1904,9 +1916,36 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
}
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
+static int cpu_freq_notify(struct notifier_block *b,
+ unsigned long l, void *v);
+
+static struct notifier_block min_freq_notifier = {
+ .notifier_call = cpu_freq_notify,
+};
+static struct notifier_block max_freq_notifier = {
+ .notifier_call = cpu_freq_notify,
+};
+
+static int cpu_freq_notify(struct notifier_block *b,
+ unsigned long l, void *v)
+{
+ int cpu;
+ pr_debug("PM QoS %s %lu\n",
+ b == &min_freq_notifier ? "min" : "max", l);
+ for_each_online_cpu(cpu) {
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ if (policy) {
+ cpufreq_update_policy(policy->cpu);
+ cpufreq_cpu_put(policy);
+ }
+ }
+ return NOTIFY_OK;
+}
+
static int __init cpufreq_core_init(void)
{
int cpu;
+ int rc;
for_each_possible_cpu(cpu) {
per_cpu(cpufreq_policy_cpu, cpu) = -1;
@@ -1917,6 +1956,12 @@ static int __init cpufreq_core_init(void)
&cpu_sysdev_class.kset.kobj);
BUG_ON(!cpufreq_global_kobject);
register_syscore_ops(&cpufreq_syscore_ops);
+ rc = pm_qos_add_notifier(PM_QOS_CPU_FREQ_MIN,
+ &min_freq_notifier);
+ BUG_ON(rc);
+ rc = pm_qos_add_notifier(PM_QOS_CPU_FREQ_MAX,
+ &max_freq_notifier);
+ BUG_ON(rc);
return 0;
}
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index f798df9b2b0d..324f3422b5da 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -116,7 +116,7 @@ static struct pm_qos_object max_online_cpus_pm_qos = {
static BLOCKING_NOTIFIER_HEAD(cpu_freq_min_notifier);
static struct pm_qos_object cpu_freq_min_pm_qos = {
- .requests = PLIST_HEAD_INIT(cpu_freq_min_pm_qos.requests, pm_qos_lock),
+ .requests = PLIST_HEAD_INIT(cpu_freq_min_pm_qos.requests),
.notifiers = &cpu_freq_min_notifier,
.name = "cpu_freq_min",
.target_value = PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE,
@@ -127,7 +127,7 @@ static struct pm_qos_object cpu_freq_min_pm_qos = {
static BLOCKING_NOTIFIER_HEAD(cpu_freq_max_notifier);
static struct pm_qos_object cpu_freq_max_pm_qos = {
- .requests = PLIST_HEAD_INIT(cpu_freq_max_pm_qos.requests, pm_qos_lock),
+ .requests = PLIST_HEAD_INIT(cpu_freq_max_pm_qos.requests),
.notifiers = &cpu_freq_max_notifier,
.name = "cpu_freq_max",
.target_value = PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE,