From caca8b15798ecc5ae1a46dc2dc8ed66c2ff7519b Mon Sep 17 00:00:00 2001 Message-Id: From: Viresh Kumar Date: Tue, 26 Mar 2013 23:20:18 +0530 Subject: [PATCH] fixup! cpufreq: governor: Implement per policy instances of governors --- drivers/cpufreq/cpufreq.c | 13 +++++++ drivers/cpufreq/cpufreq_conservative.c | 24 ++++++------ drivers/cpufreq/cpufreq_governor.c | 71 ++++++++++++++++++++++++---------- drivers/cpufreq/cpufreq_governor.h | 28 ++++++++++++-- drivers/cpufreq/cpufreq_ondemand.c | 25 ++++++------ include/linux/cpufreq.h | 2 + 6 files changed, 113 insertions(+), 50 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3d83b02..3d990b4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -136,6 +136,11 @@ struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) return cpufreq_global_kobject; } +bool have_multiple_policies(void) +{ + return cpufreq_driver->have_multiple_policies; +} + static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) { struct cpufreq_policy *data; @@ -1554,6 +1559,13 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, policy->cpu, event); ret = policy->governor->governor(policy, event); + if (!ret) { + if (event == CPUFREQ_GOV_POLICY_INIT) + policy->governor->initialized++; + else if (event == CPUFREQ_GOV_POLICY_EXIT) + policy->governor->initialized--; + } + /* we keep one module reference alive for each CPU governed by this CPU */ if ((event != CPUFREQ_GOV_START) || ret) @@ -1577,6 +1589,7 @@ int cpufreq_register_governor(struct cpufreq_governor *governor) mutex_lock(&cpufreq_governor_mutex); + governor->initialized = 0; err = -EBUSY; if (__find_governor(governor->name) == NULL) { err = 0; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 63499c8..c09d7c8 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -157,11 +157,13 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, } /************************** sysfs interface ************************/ +static struct common_dbs_data cs_dbs_cdata; +declare_get_tuners(cs); + static ssize_t store_sampling_down_factor(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = cs_get_tuners(policy, NULL); unsigned int input; int ret; ret = sscanf(buf, "%u", &input); @@ -176,8 +178,8 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *policy, static ssize_t store_sampling_rate(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct dbs_data *dbs_data = NULL; + struct cs_dbs_tuners *cs_tuners = cs_get_tuners(policy, &dbs_data); unsigned int input; int ret; ret = sscanf(buf, "%u", &input); @@ -192,8 +194,7 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *policy, static ssize_t store_up_threshold(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = cs_get_tuners(policy, NULL); unsigned int input; int ret; ret = sscanf(buf, "%u", &input); @@ -208,8 +209,7 @@ static ssize_t store_up_threshold(struct cpufreq_policy *policy, static ssize_t store_down_threshold(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = cs_get_tuners(policy, NULL); unsigned int input; int ret; ret = sscanf(buf, "%u", &input); @@ -226,8 +226,7 @@ static ssize_t store_down_threshold(struct cpufreq_policy *policy, static ssize_t store_ignore_nice(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = cs_get_tuners(policy, NULL); unsigned int input, j; int ret; @@ -259,8 +258,7 @@ static ssize_t store_ignore_nice(struct cpufreq_policy *policy, static ssize_t store_freq_step(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = cs_get_tuners(policy, NULL); unsigned int input; int ret; ret = sscanf(buf, "%u", &input); @@ -285,7 +283,7 @@ show_one(cs, up_threshold, up_threshold); show_one(cs, down_threshold, down_threshold); show_one(cs, ignore_nice, ignore_nice); show_one(cs, freq_step, freq_step); -declare_show_sampling_rate_min(); +declare_show_sampling_rate_min(cs); cpufreq_freq_attr_rw(sampling_rate); cpufreq_freq_attr_rw(sampling_down_factor); diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 41e5e56..54ca5fc 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -216,10 +216,9 @@ static void set_sampling_rate(struct dbs_data *dbs_data, int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event) { - struct dbs_data *dbs_data = policy->governor_data; + struct dbs_data *dbs_data; struct od_cpu_dbs_info_s *od_dbs_info = NULL; struct cs_cpu_dbs_info_s *cs_dbs_info = NULL; - struct cs_ops *cs_ops = NULL; struct od_ops *od_ops = NULL; struct od_dbs_tuners *od_tuners = NULL; struct cs_dbs_tuners *cs_tuners = NULL; @@ -228,11 +227,22 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, int io_busy = 0; int rc; + if (have_multiple_policies()) + dbs_data = policy->governor_data; + else + dbs_data = cdata->gdbs_data; + WARN_ON(!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT)); switch (event) { case CPUFREQ_GOV_POLICY_INIT: - WARN_ON(dbs_data); + if (have_multiple_policies()) { + WARN_ON(dbs_data); + } else if (dbs_data) { + policy->governor_data = dbs_data; + return 0; + } + dbs_data = kzalloc(sizeof(*dbs_data), GFP_KERNEL); if (!dbs_data) { pr_err("%s: POLICY_INIT: kzalloc failed\n", __func__); @@ -246,6 +256,15 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, kfree(dbs_data); return rc; } + + rc = sysfs_create_group(get_governor_parent_kobj(policy), + dbs_data->cdata->attr_group); + if (rc) { + cdata->exit(dbs_data); + kfree(dbs_data); + return rc; + } + policy->governor_data = dbs_data; /* policy latency is in nS. Convert it to uS first */ @@ -258,10 +277,36 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, MIN_LATENCY_MULTIPLIER * latency); set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate, latency * LATENCY_MULTIPLIER)); + + if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { + struct cs_ops *cs_ops = dbs_data->cdata->gov_ops; + + cpufreq_register_notifier(cs_ops->notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + } + + if (!have_multiple_policies()) + cdata->gdbs_data = dbs_data; + return 0; case CPUFREQ_GOV_POLICY_EXIT: - cdata->exit(dbs_data); - kfree(dbs_data); + if ((policy->governor->initialized == 1) || + have_multiple_policies()) { + sysfs_remove_group(get_governor_parent_kobj(policy), + dbs_data->cdata->attr_group); + + if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { + struct cs_ops *cs_ops = dbs_data->cdata->gov_ops; + + cpufreq_register_notifier(cs_ops->notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + } + + cdata->exit(dbs_data); + kfree(dbs_data); + cdata->gdbs_data = NULL; + } + policy->governor_data = NULL; return 0; } @@ -273,7 +318,6 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, cs_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu); sampling_rate = cs_tuners->sampling_rate; ignore_nice = cs_tuners->ignore_nice; - cs_ops = dbs_data->cdata->gov_ops; } else { od_tuners = dbs_data->tuners; od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu); @@ -307,13 +351,6 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, dbs_data->cdata->gov_dbs_timer); } - rc = sysfs_create_group(get_governor_parent_kobj(policy), - dbs_data->cdata->attr_group); - if (rc) { - mutex_unlock(&dbs_data->mutex); - return rc; - } - /* * conservative does not implement micro like ondemand * governor, thus we are bound to jiffes/HZ @@ -322,9 +359,6 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, cs_dbs_info->down_skip = 0; cs_dbs_info->enable = 1; cs_dbs_info->requested_freq = policy->cur; - - cpufreq_register_notifier(cs_ops->notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); } else { od_dbs_info->rate_mult = 1; od_dbs_info->sample_type = OD_NORMAL_SAMPLE; @@ -349,11 +383,6 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, mutex_lock(&dbs_data->mutex); mutex_destroy(&cpu_cdbs->timer_mutex); - sysfs_remove_group(get_governor_parent_kobj(policy), - dbs_data->cdata->attr_group); - if (dbs_data->cdata->governor == GOV_CONSERVATIVE) - cpufreq_unregister_notifier(cs_ops->notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); mutex_unlock(&dbs_data->mutex); break; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 8b18d25..fcf10d9 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -40,13 +40,29 @@ /* Ondemand Sampling types */ enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE}; + +#define declare_get_tuners(_gov) \ +static struct _gov##_dbs_tuners *_gov##_get_tuners \ +(struct cpufreq_policy *policy, struct dbs_data **ldbs_data) \ +{ \ + if (have_multiple_policies()) { \ + struct dbs_data *dbs_data = policy->governor_data; \ + if (ldbs_data) \ + *ldbs_data = dbs_data; \ + return dbs_data->tuners; \ + } else { \ + if (ldbs_data) \ + *ldbs_data = _gov##_dbs_cdata.gdbs_data; \ + return _gov##_dbs_cdata.gdbs_data->tuners; \ + } \ +} + /* Macro creating sysfs show routines */ #define show_one(_gov, file_name, object) \ static ssize_t show_##file_name \ (struct cpufreq_policy *policy, char *buf) \ { \ - struct dbs_data *dbs_data = policy->governor_data; \ - struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \ + struct _gov##_dbs_tuners *tuners = _gov##_get_tuners(policy, NULL); \ return sprintf(buf, "%u\n", tuners->file_name); \ } @@ -133,6 +149,9 @@ struct common_dbs_data { int governor; struct attribute_group *attr_group; + /* Common data for platforms that don't set have_multiple_policies */ + struct dbs_data *gdbs_data; + struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu); void *(*get_cpu_dbs_info_s)(int cpu); void (*gov_dbs_timer)(struct work_struct *work); @@ -177,11 +196,12 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate) return delay; } -#define declare_show_sampling_rate_min() \ +#define declare_show_sampling_rate_min(_gov) \ static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, \ char *buf) \ { \ - struct dbs_data *dbs_data = policy->governor_data; \ + struct dbs_data *dbs_data = NULL; \ + _gov##_get_tuners(policy, &dbs_data); \ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \ } diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 29ed48a..4860137 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -257,6 +257,9 @@ max_delay: } /************************** sysfs interface ************************/ +static struct common_dbs_data od_dbs_cdata; +declare_get_tuners(od); + /** * update_sampling_rate - update sampling rate effective immediately if needed. * @new_rate: new sampling rate @@ -321,12 +324,14 @@ static void update_sampling_rate(struct dbs_data *dbs_data, static ssize_t store_sampling_rate(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; + struct dbs_data *dbs_data = NULL; unsigned int input; int ret; ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; + + od_get_tuners(policy, &dbs_data); update_sampling_rate(dbs_data, input); return count; } @@ -334,8 +339,7 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *policy, static ssize_t store_io_is_busy(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct od_dbs_tuners *od_tuners = od_get_tuners(policy, NULL); unsigned int input; int ret; unsigned int j; @@ -358,8 +362,7 @@ static ssize_t store_io_is_busy(struct cpufreq_policy *policy, const char *buf, static ssize_t store_up_threshold(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct od_dbs_tuners *od_tuners = od_get_tuners(policy, NULL); unsigned int input; int ret; ret = sscanf(buf, "%u", &input); @@ -379,8 +382,7 @@ static ssize_t store_up_threshold(struct cpufreq_policy *policy, static ssize_t store_sampling_down_factor(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct od_dbs_tuners *od_tuners = od_get_tuners(policy, NULL); unsigned int input, j; int ret; ret = sscanf(buf, "%u", &input); @@ -401,8 +403,7 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *policy, static ssize_t store_ignore_nice(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct od_dbs_tuners *od_tuners = od_get_tuners(policy, NULL); unsigned int input; int ret; @@ -437,8 +438,7 @@ static ssize_t store_ignore_nice(struct cpufreq_policy *policy, const char *buf, static ssize_t store_powersave_bias(struct cpufreq_policy *policy, const char *buf, size_t count) { - struct dbs_data *dbs_data = policy->governor_data; - struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct od_dbs_tuners *od_tuners = od_get_tuners(policy, NULL); unsigned int input; int ret; ret = sscanf(buf, "%u", &input); @@ -460,7 +460,7 @@ show_one(od, up_threshold, up_threshold); show_one(od, sampling_down_factor, sampling_down_factor); show_one(od, ignore_nice, ignore_nice); show_one(od, powersave_bias, powersave_bias); -declare_show_sampling_rate_min(); +declare_show_sampling_rate_min(od); cpufreq_freq_attr_rw(sampling_rate); cpufreq_freq_attr_rw(io_is_busy); @@ -530,6 +530,7 @@ static int od_init(struct dbs_data *dbs_data) tuners->io_is_busy = should_io_be_busy(); dbs_data->tuners = tuners; + pr_info("%s: tuners %p\n", __func__, tuners); mutex_init(&dbs_data->mutex); return 0; } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index dd53cea..394ea0d 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -187,6 +187,7 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; + int initialized; int (*governor) (struct cpufreq_policy *policy, unsigned int event); ssize_t (*show_setspeed) (struct cpufreq_policy *policy, @@ -323,6 +324,7 @@ const char *cpufreq_get_current_driver(void); int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); int cpufreq_update_policy(unsigned int cpu); struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy); +bool have_multiple_policies(void); #ifdef CONFIG_CPU_FREQ /* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */ -- 1.7.12.rc2.18.g61b472e