| From c7d1f119c48f64bebf0fa1e326af577c6152fe30 Mon Sep 17 00:00:00 2001 |
| From: Tao Wang <kevin.wangtao@hisilicon.com> |
| Date: Sat, 26 May 2018 15:16:48 +0800 |
| Subject: cpufreq: Fix new policy initialization during limits updates via sysfs |
| |
| From: Tao Wang <kevin.wangtao@hisilicon.com> |
| |
| commit c7d1f119c48f64bebf0fa1e326af577c6152fe30 upstream. |
| |
| If the policy limits are updated via cpufreq_update_policy() and |
| subsequently via sysfs, the limits stored in user_policy may be |
| set incorrectly. |
| |
| For example, if both min and max are set via sysfs to the maximum |
| available frequency, user_policy.min and user_policy.max will also |
| be the maximum. If a policy notifier triggered by |
| cpufreq_update_policy() lowers both the min and the max at this |
| point, that change is not reflected by the user_policy limits, so |
| if the max is updated again via sysfs to the same lower value, |
| then user_policy.max will be lower than user_policy.min which |
| shouldn't happen. In particular, if one of the policy CPUs is |
| then taken offline and back online, cpufreq_set_policy() will |
| fail for it due to a failing limits check. |
| |
| To prevent that from happening, initialize the min and max fields |
| of the new_policy object to the ones stored in user_policy that |
| were previously set via sysfs. |
| |
| Signed-off-by: Kevin Wangtao <kevin.wangtao@hisilicon.com> |
| Acked-by: Viresh Kumar <viresh.kumar@linaro.org> |
| [ rjw: Subject & changelog ] |
| Cc: All applicable <stable@vger.kernel.org> |
| Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/cpufreq/cpufreq.c | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| --- a/drivers/cpufreq/cpufreq.c |
| +++ b/drivers/cpufreq/cpufreq.c |
| @@ -693,6 +693,8 @@ static ssize_t store_##file_name \ |
| struct cpufreq_policy new_policy; \ |
| \ |
| memcpy(&new_policy, policy, sizeof(*policy)); \ |
| + new_policy.min = policy->user_policy.min; \ |
| + new_policy.max = policy->user_policy.max; \ |
| \ |
| ret = sscanf(buf, "%u", &new_policy.object); \ |
| if (ret != 1) \ |