Hi Rafael,
These are rest of the patches that fix some more locking issues with policy->rwsem and do some minor optimization/cleanups.
V4->V5: - Changelog updated for 1-2 as suggested by Rafael - 4th patch is dropped, which moved common tunable callbacks to cpufreq_governor.c - 5-7 are resend on the V5 sent earlier, as reply to V4 of the series.
Viresh Kumar (6): cpufreq: Merge cpufreq_offline_prepare/finish routines cpufreq: Call __cpufreq_governor() with policy->rwsem held cpufreq: Remove cpufreq_governor_lock cpufreq: governor: No need to manage state machine now cpufreq: conservative: Update sample_delay_ns immediately cpufreq: ondemand: Rearrange od_dbs_timer() to avoid updating delay
drivers/cpufreq/cpufreq.c | 93 ++++++++++++++++------------------ drivers/cpufreq/cpufreq_conservative.c | 14 ----- drivers/cpufreq/cpufreq_governor.c | 90 ++++++++++++++++++++++++-------- drivers/cpufreq/cpufreq_governor.h | 3 +- drivers/cpufreq/cpufreq_ondemand.c | 78 ++-------------------------- 5 files changed, 117 insertions(+), 161 deletions(-)
Governor sysfs attributes are still removed in __cpufreq_governor(_EXIT), though, so had store() been used for them, the deadlock described in the changelog of commit 1aee40ac9c86 would have been possible.
Fortunately, we don't use store() (which still does get_online_cpus()) for those attributes now. We use governor_store() for them and that doesn't call get_online_cpus().
And so we don't need to split cpufreq-offline functionality into DOWN_PREPARE and POST_DEAD hotplug notifiers anymore.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org [ rjw: Changelog ] Tested-by: Juri Lelli juri.lelli@arm.com Tested-by: Shilpasri G Bhat shilpa.bhat@linux.vnet.ibm.com --- drivers/cpufreq/cpufreq.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9c62bf35b9dc..863ac26c4ecf 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1361,9 +1361,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) return ret; }
-static void cpufreq_offline_prepare(unsigned int cpu) +static void cpufreq_offline(unsigned int cpu) { struct cpufreq_policy *policy; + int ret;
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
@@ -1374,7 +1375,7 @@ static void cpufreq_offline_prepare(unsigned int cpu) }
if (has_target()) { - int ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); if (ret) pr_err("%s: Failed to stop governor\n", __func__); } @@ -1397,34 +1398,23 @@ static void cpufreq_offline_prepare(unsigned int cpu) /* Start governor again for active policy */ if (!policy_is_inactive(policy)) { if (has_target()) { - int ret = __cpufreq_governor(policy, CPUFREQ_GOV_START); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_START); if (!ret) ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
if (ret) pr_err("%s: Failed to start governor\n", __func__); } - } else if (cpufreq_driver->stop_cpu) { - cpufreq_driver->stop_cpu(policy); - } -}
-static void cpufreq_offline_finish(unsigned int cpu) -{ - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); - - if (!policy) { - pr_debug("%s: No cpu_data found\n", __func__); return; }
- /* Only proceed for inactive policies */ - if (!policy_is_inactive(policy)) - return; + if (cpufreq_driver->stop_cpu) + cpufreq_driver->stop_cpu(policy);
/* If cpu is last user of policy, free policy */ if (has_target()) { - int ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); if (ret) pr_err("%s: Failed to exit governor\n", __func__); } @@ -1453,10 +1443,8 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) if (!policy) return;
- if (cpu_online(cpu)) { - cpufreq_offline_prepare(cpu); - cpufreq_offline_finish(cpu); - } + if (cpu_online(cpu)) + cpufreq_offline(cpu);
cpumask_clear_cpu(cpu, policy->real_cpus); remove_cpu_dev_symlink(policy, cpu); @@ -2304,11 +2292,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, break;
case CPU_DOWN_PREPARE: - cpufreq_offline_prepare(cpu); - break; - - case CPU_POST_DEAD: - cpufreq_offline_finish(cpu); + cpufreq_offline(cpu); break;
case CPU_DOWN_FAILED:
The cpufreq core code is not consistent with respect to invoking __cpufreq_governor() under policy->rwsem.
Changing all code to always hold policy->rwsem around __cpufreq_governor() invocations will allow us to remove cpufreq_governor_lock, that is used today because we can't guarantee that __cpufreq_governor() isn't executed in parallel.
We should also ensure that the lock is held across state changes to the governors.
For example, while adding a CPU to the policy on cpu-online path, we need to stop the governor, change policy->cpus, start the governor and then refresh its limits. The complete sequence must be guaranteed to execute without any concurrent races. And that can be achieved using policy->rwsem around these use cases.
Also note that, after this patch cpufreq_driver->stop_cpu() and ->exit() will get called while policy->rwsem is held, which wasn't the case earlier. That shouldn't have any side effects though.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Juri Lelli juri.lelli@arm.com Tested-by: Shilpasri G Bhat shilpa.bhat@linux.vnet.ibm.com --- drivers/cpufreq/cpufreq.c | 49 +++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 863ac26c4ecf..51fb47cd38a0 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1048,30 +1048,29 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp if (cpumask_test_cpu(cpu, policy->cpus)) return 0;
+ down_write(&policy->rwsem); if (has_target()) { ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); if (ret) { pr_err("%s: Failed to stop governor\n", __func__); - return ret; + goto unlock; } }
- down_write(&policy->rwsem); cpumask_set_cpu(cpu, policy->cpus); - up_write(&policy->rwsem);
if (has_target()) { ret = __cpufreq_governor(policy, CPUFREQ_GOV_START); if (!ret) ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
- if (ret) { + if (ret) pr_err("%s: Failed to start governor\n", __func__); - return ret; - } }
- return 0; +unlock: + up_write(&policy->rwsem); + return ret; }
static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) @@ -1374,13 +1373,13 @@ static void cpufreq_offline(unsigned int cpu) return; }
+ down_write(&policy->rwsem); if (has_target()) { ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); if (ret) pr_err("%s: Failed to stop governor\n", __func__); }
- down_write(&policy->rwsem); cpumask_clear_cpu(cpu, policy->cpus);
if (policy_is_inactive(policy)) { @@ -1393,7 +1392,6 @@ static void cpufreq_offline(unsigned int cpu) /* Nominate new CPU */ policy->cpu = cpumask_any(policy->cpus); } - up_write(&policy->rwsem);
/* Start governor again for active policy */ if (!policy_is_inactive(policy)) { @@ -1406,7 +1404,7 @@ static void cpufreq_offline(unsigned int cpu) pr_err("%s: Failed to start governor\n", __func__); }
- return; + goto unlock; }
if (cpufreq_driver->stop_cpu) @@ -1428,6 +1426,9 @@ static void cpufreq_offline(unsigned int cpu) cpufreq_driver->exit(policy); policy->freq_table = NULL; } + +unlock: + up_write(&policy->rwsem); }
/** @@ -1624,6 +1625,7 @@ EXPORT_SYMBOL(cpufreq_generic_suspend); void cpufreq_suspend(void) { struct cpufreq_policy *policy; + int ret;
if (!cpufreq_driver) return; @@ -1634,7 +1636,11 @@ void cpufreq_suspend(void) pr_debug("%s: Suspending Governors\n", __func__);
for_each_active_policy(policy) { - if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP)) + down_write(&policy->rwsem); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + up_write(&policy->rwsem); + + if (ret) pr_err("%s: Failed to stop governor for policy: %p\n", __func__, policy); else if (cpufreq_driver->suspend @@ -1656,6 +1662,7 @@ void cpufreq_suspend(void) void cpufreq_resume(void) { struct cpufreq_policy *policy; + int ret;
if (!cpufreq_driver) return; @@ -1668,13 +1675,20 @@ void cpufreq_resume(void) pr_debug("%s: Resuming Governors\n", __func__);
for_each_active_policy(policy) { - if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) + if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) { pr_err("%s: Failed to resume driver: %p\n", __func__, policy); - else if (__cpufreq_governor(policy, CPUFREQ_GOV_START) - || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS)) - pr_err("%s: Failed to start governor for policy: %p\n", - __func__, policy); + } else { + down_write(&policy->rwsem); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_START); + if (!ret) + __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); + up_write(&policy->rwsem); + + if (ret) + pr_err("%s: Failed to start governor for policy: %p\n", + __func__, policy); + } }
/* @@ -2325,8 +2339,11 @@ static int cpufreq_boost_set_sw(int state) __func__); break; } + + down_write(&policy->rwsem); policy->user_policy.max = policy->max; __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); + up_write(&policy->rwsem); } }
We used to drop policy->rwsem just before calling __cpufreq_governor() in some cases earlier and so it was possible that __cpufreq_governor() runs concurrently via separate threads.
In order to guarantee valid state transitions for governors, 'governor_enabled' was required to be protected using some locking and we created cpufreq_governor_lock for that.
But now, __cpufreq_governor() is always called from within policy->rwsem held and so 'governor_enabled' is protected against races even without cpufreq_governor_lock.
Get rid of the extra lock now.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Juri Lelli juri.lelli@arm.com Tested-by: Shilpasri G Bhat shilpa.bhat@linux.vnet.ibm.com --- drivers/cpufreq/cpufreq.c | 8 -------- drivers/cpufreq/cpufreq_governor.h | 1 - 2 files changed, 9 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 51fb47cd38a0..745da90d7b38 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -146,8 +146,6 @@ void cpufreq_update_util(u64 time, unsigned long util, unsigned long max) rcu_read_unlock(); }
-DEFINE_MUTEX(cpufreq_governor_lock); - /* Flag to suspend/resume CPUFreq governors */ static bool cpufreq_suspended;
@@ -2014,11 +2012,9 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
pr_debug("%s: for CPU %u, event %u\n", __func__, policy->cpu, event);
- mutex_lock(&cpufreq_governor_lock); if ((policy->governor_enabled && event == CPUFREQ_GOV_START) || (!policy->governor_enabled && (event == CPUFREQ_GOV_LIMITS || event == CPUFREQ_GOV_STOP))) { - mutex_unlock(&cpufreq_governor_lock); return -EBUSY; }
@@ -2027,8 +2023,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, else if (event == CPUFREQ_GOV_START) policy->governor_enabled = true;
- mutex_unlock(&cpufreq_governor_lock); - ret = policy->governor->governor(policy, event);
if (!ret) { @@ -2038,12 +2032,10 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, policy->governor->initialized--; } else { /* Restore original values */ - mutex_lock(&cpufreq_governor_lock); if (event == CPUFREQ_GOV_STOP) policy->governor_enabled = true; else if (event == CPUFREQ_GOV_START) policy->governor_enabled = false; - mutex_unlock(&cpufreq_governor_lock); }
if (((event == CPUFREQ_GOV_POLICY_INIT) && ret) || diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 4e77efb7db67..02885e353dfc 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -232,7 +232,6 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate) }
extern struct mutex dbs_data_mutex; -extern struct mutex cpufreq_governor_lock; void dbs_check_cpu(struct cpufreq_policy *policy); int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event); void od_register_powersave_bias_handler(unsigned int (*f)
The cpufreq core now guarantees that policy->rwsem won't be dropped while running the ->governor callback for the CPUFREQ_GOV_POLICY_EXIT event and will be held acquired until the complete sequence of governor state changes has finished.
This allows governor state machine checks to be dropped from multiple functions in cpufreq_governor.c.
This also means that policy_dbs->policy can be initialized upfront, so the entire initialization of struct policy_dbs is carried out in one place.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Juri Lelli juri.lelli@arm.com Tested-by: Shilpasri G Bhat shilpa.bhat@linux.vnet.ibm.com --- drivers/cpufreq/cpufreq_governor.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 3a9dab752148..481585611097 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -233,8 +233,10 @@ static inline void gov_clear_update_util(struct cpufreq_policy *policy) synchronize_rcu(); }
-static void gov_cancel_work(struct policy_dbs_info *policy_dbs) +static void gov_cancel_work(struct cpufreq_policy *policy) { + struct policy_dbs_info *policy_dbs = policy->governor_data; + /* Tell dbs_update_util_handler() to skip queuing up work items. */ atomic_inc(&policy_dbs->skip_work); /* @@ -330,6 +332,7 @@ static struct policy_dbs_info *alloc_policy_dbs_info(struct cpufreq_policy *poli if (!policy_dbs) return NULL;
+ policy_dbs->policy = policy; mutex_init(&policy_dbs->timer_mutex); atomic_set(&policy_dbs->skip_work, 0); init_irq_work(&policy_dbs->irq_work, dbs_irq_work); @@ -460,10 +463,6 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy) struct dbs_data *dbs_data = policy_dbs->dbs_data; int count;
- /* State should be equivalent to INIT */ - if (policy_dbs->policy) - return -EBUSY; - mutex_lock(&dbs_data->mutex); list_del(&policy_dbs->list); count = --dbs_data->usage_count; @@ -499,10 +498,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy) if (!policy->cur) return -EINVAL;
- /* State should be equivalent to INIT */ - if (policy_dbs->policy) - return -EBUSY; - sampling_rate = dbs_data->sampling_rate; ignore_nice = dbs_data->ignore_nice_load;
@@ -527,7 +522,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy) if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; } - policy_dbs->policy = policy;
if (gov->governor == GOV_CONSERVATIVE) { struct cs_cpu_dbs_info_s *cs_dbs_info = @@ -550,14 +544,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy)
static int cpufreq_governor_stop(struct cpufreq_policy *policy) { - struct policy_dbs_info *policy_dbs = policy->governor_data; - - /* State should be equivalent to START */ - if (!policy_dbs->policy) - return -EBUSY; - - gov_cancel_work(policy_dbs); - policy_dbs->policy = NULL; + gov_cancel_work(policy);
return 0; } @@ -566,10 +553,6 @@ static int cpufreq_governor_limits(struct cpufreq_policy *policy) { struct policy_dbs_info *policy_dbs = policy->governor_data;
- /* State should be equivalent to START */ - if (!policy_dbs->policy) - return -EBUSY; - mutex_lock(&policy_dbs->timer_mutex); if (policy->max < policy->cur) __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
Ondemand governor already updates sample_delay_ns immediately on updates to sampling rate, but conservative isn't doing that.
It was left out earlier as the code has been really complex to get that done easily. But now things are sorted out very well, and we can follow the same for conservative governor as well.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Juri Lelli juri.lelli@arm.com Tested-by: Shilpasri G Bhat shilpa.bhat@linux.vnet.ibm.com --- drivers/cpufreq/cpufreq_conservative.c | 14 ------- drivers/cpufreq/cpufreq_governor.c | 63 +++++++++++++++++++++++++++++++ drivers/cpufreq/cpufreq_governor.h | 2 + drivers/cpufreq/cpufreq_ondemand.c | 69 ---------------------------------- 4 files changed, 65 insertions(+), 83 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index ed081dbce00c..6243502ce24d 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -136,20 +136,6 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, return count; }
-static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, - size_t count) -{ - unsigned int input; - int ret; - ret = sscanf(buf, "%u", &input); - - if (ret != 1) - return -EINVAL; - - dbs_data->sampling_rate = max(input, dbs_data->min_sampling_rate); - return count; -} - static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf, size_t count) { diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 481585611097..17c51bca2df1 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -25,6 +25,69 @@ DEFINE_MUTEX(dbs_data_mutex); EXPORT_SYMBOL_GPL(dbs_data_mutex);
+/* Common sysfs tunables */ +/** + * store_sampling_rate - update sampling rate effective immediately if needed. + * + * If new rate is smaller than the old, simply updating + * dbs.sampling_rate might not be appropriate. For example, if the + * original sampling_rate was 1 second and the requested new sampling rate is 10 + * ms because the user needs immediate reaction from ondemand governor, but not + * sure if higher frequency will be required or not, then, the governor may + * change the sampling rate too late; up to 1 second later. Thus, if we are + * reducing the sampling rate, we need to make the new value effective + * immediately. + * + * On the other hand, if new rate is larger than the old, then we may evaluate + * the load too soon, and it might we worth updating sample_delay_ns then as + * well. + * + * This must be called with dbs_data->mutex held, otherwise traversing + * policy_dbs_list isn't safe. + */ +ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, + size_t count) +{ + struct policy_dbs_info *policy_dbs; + unsigned int rate; + int ret; + ret = sscanf(buf, "%u", &rate); + if (ret != 1) + return -EINVAL; + + dbs_data->sampling_rate = max(rate, dbs_data->min_sampling_rate); + + /* + * We are operating under dbs_data->mutex and so the list and its + * entries can't be freed concurrently. + */ + list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) { + mutex_lock(&policy_dbs->timer_mutex); + /* + * On 32-bit architectures this may race with the + * sample_delay_ns read in dbs_update_util_handler(), but that + * really doesn't matter. If the read returns a value that's + * too big, the sample will be skipped, but the next invocation + * of dbs_update_util_handler() (when the update has been + * completed) will take a sample. If the returned value is too + * small, the sample will be taken immediately, but that isn't a + * problem, as we want the new rate to take effect immediately + * anyway. + * + * If this runs in parallel with dbs_work_handler(), we may end + * up overwriting the sample_delay_ns value that it has just + * written, but the difference should not be too big and it will + * be corrected next time a sample is taken, so it shouldn't be + * significant. + */ + gov_update_sample_delay(policy_dbs, dbs_data->sampling_rate); + mutex_unlock(&policy_dbs->timer_mutex); + } + + return count; +} +EXPORT_SYMBOL_GPL(store_sampling_rate); + static inline struct dbs_data *to_dbs_data(struct kobject *kobj) { return container_of(kobj, struct dbs_data, kobj); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 02885e353dfc..2f5ca7393653 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -238,4 +238,6 @@ void od_register_powersave_bias_handler(unsigned int (*f) (struct cpufreq_policy *, unsigned int, unsigned int), unsigned int powersave_bias); void od_unregister_powersave_bias_handler(void); +ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, + size_t count); #endif /* _CPUFREQ_GOVERNOR_H */ diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 38301c6b31c7..12213823cc93 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -221,75 +221,6 @@ static unsigned int od_dbs_timer(struct cpufreq_policy *policy) /************************** sysfs interface ************************/ static struct dbs_governor od_dbs_gov;
-/** - * update_sampling_rate - update sampling rate effective immediately if needed. - * @new_rate: new sampling rate - * - * If new rate is smaller than the old, simply updating - * dbs.sampling_rate might not be appropriate. For example, if the - * original sampling_rate was 1 second and the requested new sampling rate is 10 - * ms because the user needs immediate reaction from ondemand governor, but not - * sure if higher frequency will be required or not, then, the governor may - * change the sampling rate too late; up to 1 second later. Thus, if we are - * reducing the sampling rate, we need to make the new value effective - * immediately. - * - * On the other hand, if new rate is larger than the old, then we may evaluate - * the load too soon, and it might we worth updating sample_delay_ns then as - * well. - * - * This must be called with dbs_data->mutex held, otherwise traversing - * policy_dbs_list isn't safe. - */ -static void update_sampling_rate(struct dbs_data *dbs_data, - unsigned int new_rate) -{ - struct policy_dbs_info *policy_dbs; - - dbs_data->sampling_rate = new_rate = max(new_rate, - dbs_data->min_sampling_rate); - - /* - * We are operating under dbs_data->mutex and so the list and its - * entries can't be freed concurrently. - */ - list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) { - mutex_lock(&policy_dbs->timer_mutex); - /* - * On 32-bit architectures this may race with the - * sample_delay_ns read in dbs_update_util_handler(), but that - * really doesn't matter. If the read returns a value that's - * too big, the sample will be skipped, but the next invocation - * of dbs_update_util_handler() (when the update has been - * completed) will take a sample. If the returned value is too - * small, the sample will be taken immediately, but that isn't a - * problem, as we want the new rate to take effect immediately - * anyway. - * - * If this runs in parallel with dbs_work_handler(), we may end - * up overwriting the sample_delay_ns value that it has just - * written, but the difference should not be too big and it will - * be corrected next time a sample is taken, so it shouldn't be - * significant. - */ - gov_update_sample_delay(policy_dbs, new_rate); - mutex_unlock(&policy_dbs->timer_mutex); - } -} - -static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, - size_t count) -{ - unsigned int input; - int ret; - ret = sscanf(buf, "%u", &input); - if (ret != 1) - return -EINVAL; - - update_sampling_rate(dbs_data, input); - return count; -} - static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf, size_t count) {
'delay' is updated properly in all paths of the routine od_dbs_timer(), leaving just one. And can be 0 only in that case.
Move the update to 'delay' as an else part of the if block.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- drivers/cpufreq/cpufreq_ondemand.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 12213823cc93..0b79f1488be4 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -194,7 +194,7 @@ static unsigned int od_dbs_timer(struct cpufreq_policy *policy) struct policy_dbs_info *policy_dbs = policy->governor_data; struct dbs_data *dbs_data = policy_dbs->dbs_data; struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu); - int delay = 0, sample_type = dbs_info->sample_type; + int delay, sample_type = dbs_info->sample_type;
/* Common NORMAL_SAMPLE setup */ dbs_info->sample_type = OD_NORMAL_SAMPLE; @@ -208,13 +208,12 @@ static unsigned int od_dbs_timer(struct cpufreq_policy *policy) /* Setup timer for SUB_SAMPLE */ dbs_info->sample_type = OD_SUB_SAMPLE; delay = dbs_info->freq_hi_jiffies; + } else { + delay = delay_for_sampling_rate(dbs_data->sampling_rate + * dbs_info->rate_mult); } }
- if (!delay) - delay = delay_for_sampling_rate(dbs_data->sampling_rate - * dbs_info->rate_mult); - return delay; }
On Thursday, February 11, 2016 05:31:10 PM Viresh Kumar wrote:
Hi Rafael,
These are rest of the patches that fix some more locking issues with policy->rwsem and do some minor optimization/cleanups.
V4->V5:
- Changelog updated for 1-2 as suggested by Rafael
- 4th patch is dropped, which moved common tunable callbacks to cpufreq_governor.c
- 5-7 are resend on the V5 sent earlier, as reply to V4 of the series.
Viresh Kumar (6): cpufreq: Merge cpufreq_offline_prepare/finish routines cpufreq: Call __cpufreq_governor() with policy->rwsem held cpufreq: Remove cpufreq_governor_lock cpufreq: governor: No need to manage state machine now cpufreq: conservative: Update sample_delay_ns immediately cpufreq: ondemand: Rearrange od_dbs_timer() to avoid updating delay
drivers/cpufreq/cpufreq.c | 93 ++++++++++++++++------------------ drivers/cpufreq/cpufreq_conservative.c | 14 ----- drivers/cpufreq/cpufreq_governor.c | 90 ++++++++++++++++++++++++-------- drivers/cpufreq/cpufreq_governor.h | 3 +- drivers/cpufreq/cpufreq_ondemand.c | 78 ++-------------------------- 5 files changed, 117 insertions(+), 161 deletions(-)
OK, queued up for 0-day testing with some rebase and changelog (sigh) fixups.
Thanks, Rafael
linaro-kernel@lists.linaro.org