diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d98ff688b2f110b8249c6be6c019a632f0c65d43..bdf1f280ae395034350ca7ced30f0fcac2f10ea6 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2031,7 +2031,6 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy) } } - policy->governor->initialized++; return 0; } @@ -2045,7 +2044,6 @@ static void cpufreq_exit_governor(struct cpufreq_policy *policy) if (policy->governor->exit) policy->governor->exit(policy); - policy->governor->initialized--; module_put(policy->governor->owner); } @@ -2110,7 +2108,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor) mutex_lock(&cpufreq_governor_mutex); - governor->initialized = 0; err = -EBUSY; if (!find_governor(governor->name)) { err = 0; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 78faa9fbc384f889f5e21e187bc4b92d12cc9391..f967ec6c572001437205796f10bd7244a48ea3a1 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -127,7 +127,6 @@ static struct notifier_block cs_cpufreq_notifier_block = { }; /************************** sysfs interface ************************/ -static struct dbs_governor cs_dbs_gov; static ssize_t store_sampling_down_factor(struct gov_attr_set *attr_set, const char *buf, size_t count) @@ -255,6 +254,13 @@ static struct attribute *cs_attributes[] = { /************************** sysfs end ************************/ +struct cs_governor { + struct dbs_governor dbs_gov; + unsigned int usage_count; +}; + +static struct cs_governor cs_gov; + static struct policy_dbs_info *cs_alloc(void) { struct cs_policy_dbs_info *dbs_info; @@ -268,7 +274,7 @@ static void cs_free(struct policy_dbs_info *policy_dbs) kfree(to_dbs_info(policy_dbs)); } -static int cs_init(struct dbs_data *dbs_data, bool notify) +static int cs_init(struct dbs_data *dbs_data) { struct cs_dbs_tuners *tuners; @@ -286,16 +292,22 @@ static int cs_init(struct dbs_data *dbs_data, bool notify) dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); - if (notify) + /* + * This function and cs_exit() are only called under gov_dbs_data_mutex + * which is global, so the cs_gov.usage_count accesses are guaranteed + * to be serialized. + */ + if (!cs_gov.usage_count++) cpufreq_register_notifier(&cs_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); return 0; } -static void cs_exit(struct dbs_data *dbs_data, bool notify) +static void cs_exit(struct dbs_data *dbs_data) { - if (notify) + /* Protected by gov_dbs_data_mutex - see the comment in cs_init(). */ + if (!--cs_gov.usage_count) cpufreq_unregister_notifier(&cs_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); @@ -310,18 +322,20 @@ static void cs_start(struct cpufreq_policy *policy) dbs_info->requested_freq = policy->cur; } -static struct dbs_governor cs_dbs_gov = { - .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"), - .kobj_type = { .default_attrs = cs_attributes }, - .gov_dbs_timer = cs_dbs_timer, - .alloc = cs_alloc, - .free = cs_free, - .init = cs_init, - .exit = cs_exit, - .start = cs_start, +static struct cs_governor cs_gov = { + .dbs_gov = { + .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"), + .kobj_type = { .default_attrs = cs_attributes }, + .gov_dbs_timer = cs_dbs_timer, + .alloc = cs_alloc, + .free = cs_free, + .init = cs_init, + .exit = cs_exit, + .start = cs_start, + }, }; -#define CPU_FREQ_GOV_CONSERVATIVE (&cs_dbs_gov.gov) +#define CPU_FREQ_GOV_CONSERVATIVE (&cs_gov.dbs_gov.gov) static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 4b88b5bec4ef6fc4c3df1abe8c85a150ab943ea4..31369e247192fcb035fabb777949b6fb542c9474 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -429,7 +429,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) gov_attr_set_init(&dbs_data->attr_set, &policy_dbs->list); - ret = gov->init(dbs_data, !policy->governor->initialized); + ret = gov->init(dbs_data); if (ret) goto free_policy_dbs_info; @@ -464,7 +464,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) if (!have_governor_per_policy()) gov->gdbs_data = NULL; - gov->exit(dbs_data, !policy->governor->initialized); + gov->exit(dbs_data); kfree(dbs_data); free_policy_dbs_info: @@ -494,7 +494,7 @@ void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy) if (!have_governor_per_policy()) gov->gdbs_data = NULL; - gov->exit(dbs_data, policy->governor->initialized == 1); + gov->exit(dbs_data); kfree(dbs_data); } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 36f0d19dd8691e51e2d86102fae614d09592b6db..ef1037e9c92b107564d99940a9f5b381e20c9614 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -138,8 +138,8 @@ struct dbs_governor { unsigned int (*gov_dbs_timer)(struct cpufreq_policy *policy); struct policy_dbs_info *(*alloc)(void); void (*free)(struct policy_dbs_info *policy_dbs); - int (*init)(struct dbs_data *dbs_data, bool notify); - void (*exit)(struct dbs_data *dbs_data, bool notify); + int (*init)(struct dbs_data *dbs_data); + void (*exit)(struct dbs_data *dbs_data); void (*start)(struct cpufreq_policy *policy); }; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 4441a11139f1a68ab14f1bbdac8dc6fc55e1d64a..c84fc2240d495493749fc0642b74ae15f6c263c5 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -361,7 +361,7 @@ static void od_free(struct policy_dbs_info *policy_dbs) kfree(to_dbs_info(policy_dbs)); } -static int od_init(struct dbs_data *dbs_data, bool notify) +static int od_init(struct dbs_data *dbs_data) { struct od_dbs_tuners *tuners; u64 idle_time; @@ -400,7 +400,7 @@ static int od_init(struct dbs_data *dbs_data, bool notify) return 0; } -static void od_exit(struct dbs_data *dbs_data, bool notify) +static void od_exit(struct dbs_data *dbs_data) { kfree(dbs_data->tuners); } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 3be54a0b43732c7c5a8c50d05ca39563f0e5f260..fbd696edf5bd3526066479e101988e05f62a908f 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -457,7 +457,6 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; - int initialized; int (*init)(struct cpufreq_policy *policy); void (*exit)(struct cpufreq_policy *policy); int (*start)(struct cpufreq_policy *policy);