Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cpufreq: Fix GOV_LIMITS handling for the userspace governor

Currently, the userspace governor only updates frequency on GOV_LIMITS
if policy->cur falls outside policy->{min/max}. However, it is also
necessary to update current frequency on GOV_LIMITS to match the user
requested value if it can be achieved within the new policy->{max/min}.

This was previously the behaviour in the governor until commit d1922f0
("cpufreq: Simplify userspace governor") which incorrectly assumed that
policy->cur == user requested frequency via scaling_setspeed. This won't
be true if the user requested frequency falls outside policy->{min/max}.
Ex: a temporary thermal cap throttled the user requested frequency.

Fix this by storing the user requested frequency in a seperate variable.
The governor will then try to achieve this request on every GOV_LIMITS
change.

Fixes: d1922f02562f (cpufreq: Simplify userspace governor)
Signed-off-by: Sai Gurrappadi <sgurrappadi@nvidia.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Sai Gurrappadi and committed by
Rafael J. Wysocki
e43e94c1 9f123def

+38 -5
+38 -5
drivers/cpufreq/cpufreq_userspace.c
··· 17 17 #include <linux/init.h> 18 18 #include <linux/module.h> 19 19 #include <linux/mutex.h> 20 + #include <linux/slab.h> 20 21 21 22 static DEFINE_PER_CPU(unsigned int, cpu_is_managed); 22 23 static DEFINE_MUTEX(userspace_mutex); ··· 32 31 static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) 33 32 { 34 33 int ret = -EINVAL; 34 + unsigned int *setspeed = policy->governor_data; 35 35 36 36 pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); 37 37 38 38 mutex_lock(&userspace_mutex); 39 39 if (!per_cpu(cpu_is_managed, policy->cpu)) 40 40 goto err; 41 + 42 + *setspeed = freq; 41 43 42 44 ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 43 45 err: ··· 53 49 return sprintf(buf, "%u\n", policy->cur); 54 50 } 55 51 52 + static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) 53 + { 54 + unsigned int *setspeed; 55 + 56 + setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL); 57 + if (!setspeed) 58 + return -ENOMEM; 59 + 60 + policy->governor_data = setspeed; 61 + return 0; 62 + } 63 + 56 64 static int cpufreq_governor_userspace(struct cpufreq_policy *policy, 57 65 unsigned int event) 58 66 { 67 + unsigned int *setspeed = policy->governor_data; 59 68 unsigned int cpu = policy->cpu; 60 69 int rc = 0; 61 70 71 + if (event == CPUFREQ_GOV_POLICY_INIT) 72 + return cpufreq_userspace_policy_init(policy); 73 + 74 + if (!setspeed) 75 + return -EINVAL; 76 + 62 77 switch (event) { 78 + case CPUFREQ_GOV_POLICY_EXIT: 79 + mutex_lock(&userspace_mutex); 80 + policy->governor_data = NULL; 81 + kfree(setspeed); 82 + mutex_unlock(&userspace_mutex); 83 + break; 63 84 case CPUFREQ_GOV_START: 64 85 BUG_ON(!policy->cur); 65 86 pr_debug("started managing cpu %u\n", cpu); 66 87 67 88 mutex_lock(&userspace_mutex); 68 89 per_cpu(cpu_is_managed, cpu) = 1; 90 + *setspeed = policy->cur; 69 91 mutex_unlock(&userspace_mutex); 70 92 break; 71 93 case CPUFREQ_GOV_STOP: ··· 99 69 100 70 mutex_lock(&userspace_mutex); 101 71 per_cpu(cpu_is_managed, cpu) = 0; 72 + *setspeed = 0; 102 73 mutex_unlock(&userspace_mutex); 103 74 break; 104 75 case CPUFREQ_GOV_LIMITS: 105 76 mutex_lock(&userspace_mutex); 106 - pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n", 107 - cpu, policy->min, policy->max, 108 - policy->cur); 77 + pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", 78 + cpu, policy->min, policy->max, policy->cur, *setspeed); 109 79 110 - if (policy->max < policy->cur) 80 + if (policy->max < *setspeed) 111 81 __cpufreq_driver_target(policy, policy->max, 112 82 CPUFREQ_RELATION_H); 113 - else if (policy->min > policy->cur) 83 + else if (policy->min > *setspeed) 114 84 __cpufreq_driver_target(policy, policy->min, 85 + CPUFREQ_RELATION_L); 86 + else 87 + __cpufreq_driver_target(policy, *setspeed, 115 88 CPUFREQ_RELATION_L); 116 89 mutex_unlock(&userspace_mutex); 117 90 break;