From 3899a0f11c4dade59cfd9ca0fbdb459f77af4cb2 Mon Sep 17 00:00:00 2001 From: Antti P Miettinen Date: Tue, 27 Dec 2011 12:41:39 +0200 Subject: cpufreq: Enforce PM QoS min/max limits Observe PM QoS CPU frequency minimum and maximum in addition to policy settings. Bug 888312 Change-Id: Ia4f60a1649a9952e02f6847c8add3b2ea5d47524 Reviewed-on: http://git-master/r/72207 Signed-off-by: Antti P Miettinen Signed-off-by: Varun Wadekar Reviewed-on: http://git-master/r/75884 Reviewed-by: Automatic_Commit_Validation_User --- drivers/cpufreq/cpufreq.c | 49 +++++++++++++++++++++++++++++++++++++++++++++-- kernel/pm_qos_params.c | 4 ++-- 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 #include #include +#include #include @@ -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, -- cgit v1.2.3