Skip to content

Commit

Permalink
cpufreq: governor: Get rid of governor events
Browse files Browse the repository at this point in the history
The design of the cpufreq governor API is not very straightforward,
as struct cpufreq_governor provides only one callback to be invoked
from different code paths for different purposes.  The purpose it is
invoked for is determined by its second "event" argument, causing it
to act as a "callback multiplexer" of sorts.

Unfortunately, that leads to extra complexity in governors, some of
which implement the ->governor() callback as a switch statement
that simply checks the event argument and invokes a separate function
to handle that specific event.

That extra complexity can be eliminated by replacing the all-purpose
->governor() callback with a family of callbacks to carry out specific
governor operations: initialization and exit, start and stop and policy
limits updates.  That also turns out to reduce the code size too, so
do it.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
  • Loading branch information
Rafael J. Wysocki committed Jun 2, 2016
1 parent a92604b commit e788892
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 204 deletions.
72 changes: 34 additions & 38 deletions arch/powerpc/platforms/cell/cpufreq_spudemand.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,61 +85,57 @@ static void spu_gov_cancel_work(struct spu_gov_info_struct *info)
cancel_delayed_work_sync(&info->work);
}

static int spu_gov_govern(struct cpufreq_policy *policy, unsigned int event)
static int spu_gov_start(struct cpufreq_policy *policy)
{
unsigned int cpu = policy->cpu;
struct spu_gov_info_struct *info, *affected_info;
struct spu_gov_info_struct *info = &per_cpu(spu_gov_info, cpu);
struct spu_gov_info_struct *affected_info;
int i;
int ret = 0;

info = &per_cpu(spu_gov_info, cpu);

switch (event) {
case CPUFREQ_GOV_START:
if (!cpu_online(cpu)) {
printk(KERN_ERR "cpu %d is not online\n", cpu);
ret = -EINVAL;
break;
}
if (!cpu_online(cpu)) {
printk(KERN_ERR "cpu %d is not online\n", cpu);
return -EINVAL;
}

if (!policy->cur) {
printk(KERN_ERR "no cpu specified in policy\n");
ret = -EINVAL;
break;
}
if (!policy->cur) {
printk(KERN_ERR "no cpu specified in policy\n");
return -EINVAL;
}

/* initialize spu_gov_info for all affected cpus */
for_each_cpu(i, policy->cpus) {
affected_info = &per_cpu(spu_gov_info, i);
affected_info->policy = policy;
}
/* initialize spu_gov_info for all affected cpus */
for_each_cpu(i, policy->cpus) {
affected_info = &per_cpu(spu_gov_info, i);
affected_info->policy = policy;
}

info->poll_int = POLL_TIME;
info->poll_int = POLL_TIME;

/* setup timer */
spu_gov_init_work(info);
/* setup timer */
spu_gov_init_work(info);

break;
return 0;
}

case CPUFREQ_GOV_STOP:
/* cancel timer */
spu_gov_cancel_work(info);
static void spu_gov_stop(struct cpufreq_policy *policy)
{
unsigned int cpu = policy->cpu;
struct spu_gov_info_struct *info = &per_cpu(spu_gov_info, cpu);
int i;

/* clean spu_gov_info for all affected cpus */
for_each_cpu (i, policy->cpus) {
info = &per_cpu(spu_gov_info, i);
info->policy = NULL;
}
/* cancel timer */
spu_gov_cancel_work(info);

break;
/* clean spu_gov_info for all affected cpus */
for_each_cpu (i, policy->cpus) {
info = &per_cpu(spu_gov_info, i);
info->policy = NULL;
}

return ret;
}

static struct cpufreq_governor spu_governor = {
.name = "spudemand",
.governor = spu_gov_govern,
.start = spu_gov_start,
.stop = spu_gov_stop,
.owner = THIS_MODULE,
};

Expand Down
31 changes: 20 additions & 11 deletions drivers/cpufreq/cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -2023,10 +2023,12 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy)

pr_debug("%s: for CPU %u\n", __func__, policy->cpu);

ret = policy->governor->governor(policy, CPUFREQ_GOV_POLICY_INIT);
if (ret) {
module_put(policy->governor->owner);
return ret;
if (policy->governor->init) {
ret = policy->governor->init(policy);
if (ret) {
module_put(policy->governor->owner);
return ret;
}
}

policy->governor->initialized++;
Expand All @@ -2040,7 +2042,8 @@ static void cpufreq_exit_governor(struct cpufreq_policy *policy)

pr_debug("%s: for CPU %u\n", __func__, policy->cpu);

policy->governor->governor(policy, CPUFREQ_GOV_POLICY_EXIT);
if (policy->governor->exit)
policy->governor->exit(policy);

policy->governor->initialized--;
module_put(policy->governor->owner);
Expand All @@ -2061,11 +2064,15 @@ static int cpufreq_start_governor(struct cpufreq_policy *policy)
if (cpufreq_driver->get && !cpufreq_driver->setpolicy)
cpufreq_update_current_freq(policy);

ret = policy->governor->governor(policy, CPUFREQ_GOV_START);
if (ret)
return ret;
if (policy->governor->start) {
ret = policy->governor->start(policy);
if (ret)
return ret;
}

if (policy->governor->limits)
policy->governor->limits(policy);

policy->governor->governor(policy, CPUFREQ_GOV_LIMITS);
return 0;
}

Expand All @@ -2076,7 +2083,8 @@ static void cpufreq_stop_governor(struct cpufreq_policy *policy)

pr_debug("%s: for CPU %u\n", __func__, policy->cpu);

policy->governor->governor(policy, CPUFREQ_GOV_STOP);
if (policy->governor->stop)
policy->governor->stop(policy);
}

static void cpufreq_governor_limits(struct cpufreq_policy *policy)
Expand All @@ -2086,7 +2094,8 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy)

pr_debug("%s: for CPU %u\n", __func__, policy->cpu);

policy->governor->governor(policy, CPUFREQ_GOV_LIMITS);
if (policy->governor->limits)
policy->governor->limits(policy);
}

int cpufreq_register_governor(struct cpufreq_governor *governor)
Expand Down
7 changes: 1 addition & 6 deletions drivers/cpufreq/cpufreq_conservative.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,12 +313,7 @@ static void cs_start(struct cpufreq_policy *policy)
}

static struct dbs_governor cs_dbs_gov = {
.gov = {
.name = "conservative",
.governor = cpufreq_governor_dbs,
.max_transition_latency = TRANSITION_LATENCY_LIMIT,
.owner = THIS_MODULE,
},
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
.kobj_type = { .default_attrs = cs_attributes },
.gov_dbs_timer = cs_dbs_timer,
.alloc = cs_alloc,
Expand Down
39 changes: 10 additions & 29 deletions drivers/cpufreq/cpufreq_governor.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ static void free_policy_dbs_info(struct policy_dbs_info *policy_dbs,
gov->free(policy_dbs);
}

static int cpufreq_governor_init(struct cpufreq_policy *policy)
int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
{
struct dbs_governor *gov = dbs_governor_of(policy);
struct dbs_data *dbs_data;
Expand Down Expand Up @@ -474,8 +474,9 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy)
mutex_unlock(&gov_dbs_data_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_init);

static int cpufreq_governor_exit(struct cpufreq_policy *policy)
void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy)
{
struct dbs_governor *gov = dbs_governor_of(policy);
struct policy_dbs_info *policy_dbs = policy->governor_data;
Expand All @@ -500,10 +501,10 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy)
free_policy_dbs_info(policy_dbs, gov);

mutex_unlock(&gov_dbs_data_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_exit);

static int cpufreq_governor_start(struct cpufreq_policy *policy)
int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
{
struct dbs_governor *gov = dbs_governor_of(policy);
struct policy_dbs_info *policy_dbs = policy->governor_data;
Expand Down Expand Up @@ -539,14 +540,15 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy)
gov_set_update_util(policy_dbs, sampling_rate);
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_start);

static int cpufreq_governor_stop(struct cpufreq_policy *policy)
void cpufreq_dbs_governor_stop(struct cpufreq_policy *policy)
{
gov_cancel_work(policy);
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);

static int cpufreq_governor_limits(struct cpufreq_policy *policy)
void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
{
struct policy_dbs_info *policy_dbs = policy->governor_data;

Expand All @@ -560,26 +562,5 @@ static int cpufreq_governor_limits(struct cpufreq_policy *policy)
gov_update_sample_delay(policy_dbs, 0);

mutex_unlock(&policy_dbs->timer_mutex);

return 0;
}

int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event)
{
if (event == CPUFREQ_GOV_POLICY_INIT) {
return cpufreq_governor_init(policy);
} else if (policy->governor_data) {
switch (event) {
case CPUFREQ_GOV_POLICY_EXIT:
return cpufreq_governor_exit(policy);
case CPUFREQ_GOV_START:
return cpufreq_governor_start(policy);
case CPUFREQ_GOV_STOP:
return cpufreq_governor_stop(policy);
case CPUFREQ_GOV_LIMITS:
return cpufreq_governor_limits(policy);
}
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(cpufreq_governor_dbs);
EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_limits);
20 changes: 19 additions & 1 deletion drivers/cpufreq/cpufreq_governor.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,32 @@ static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy
return container_of(policy->governor, struct dbs_governor, gov);
}

/* Governor callback routines */
int cpufreq_dbs_governor_init(struct cpufreq_policy *policy);
void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy);
int cpufreq_dbs_governor_start(struct cpufreq_policy *policy);
void cpufreq_dbs_governor_stop(struct cpufreq_policy *policy);
void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy);

#define CPUFREQ_DBS_GOVERNOR_INITIALIZER(_name_) \
{ \
.name = _name_, \
.max_transition_latency = TRANSITION_LATENCY_LIMIT, \
.owner = THIS_MODULE, \
.init = cpufreq_dbs_governor_init, \
.exit = cpufreq_dbs_governor_exit, \
.start = cpufreq_dbs_governor_start, \
.stop = cpufreq_dbs_governor_stop, \
.limits = cpufreq_dbs_governor_limits, \
}

/* Governor specific operations */
struct od_ops {
unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy,
unsigned int freq_next, unsigned int relation);
};

unsigned int dbs_update(struct cpufreq_policy *policy);
int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event);
void od_register_powersave_bias_handler(unsigned int (*f)
(struct cpufreq_policy *, unsigned int, unsigned int),
unsigned int powersave_bias);
Expand Down
7 changes: 1 addition & 6 deletions drivers/cpufreq/cpufreq_ondemand.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,12 +420,7 @@ static struct od_ops od_ops = {
};

static struct dbs_governor od_dbs_gov = {
.gov = {
.name = "ondemand",
.governor = cpufreq_governor_dbs,
.max_transition_latency = TRANSITION_LATENCY_LIMIT,
.owner = THIS_MODULE,
},
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("ondemand"),
.kobj_type = { .default_attrs = od_attributes },
.gov_dbs_timer = od_dbs_timer,
.alloc = od_alloc,
Expand Down
17 changes: 4 additions & 13 deletions drivers/cpufreq/cpufreq_performance.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,16 @@
#include <linux/init.h>
#include <linux/module.h>

static int cpufreq_governor_performance(struct cpufreq_policy *policy,
unsigned int event)
static void cpufreq_gov_performance_limits(struct cpufreq_policy *policy)
{
switch (event) {
case CPUFREQ_GOV_LIMITS:
pr_debug("setting to %u kHz\n", policy->max);
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
break;
default:
break;
}
return 0;
pr_debug("setting to %u kHz\n", policy->max);
__cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
}

static struct cpufreq_governor cpufreq_gov_performance = {
.name = "performance",
.governor = cpufreq_governor_performance,
.owner = THIS_MODULE,
.limits = cpufreq_gov_performance_limits,
};

static int __init cpufreq_gov_performance_init(void)
Expand Down
17 changes: 4 additions & 13 deletions drivers/cpufreq/cpufreq_powersave.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,15 @@
#include <linux/init.h>
#include <linux/module.h>

static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
unsigned int event)
static void cpufreq_gov_powersave_limits(struct cpufreq_policy *policy)
{
switch (event) {
case CPUFREQ_GOV_LIMITS:
pr_debug("setting to %u kHz\n", policy->min);
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L);
break;
default:
break;
}
return 0;
pr_debug("setting to %u kHz\n", policy->min);
__cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
}

static struct cpufreq_governor cpufreq_gov_powersave = {
.name = "powersave",
.governor = cpufreq_governor_powersave,
.limits = cpufreq_gov_powersave_limits,
.owner = THIS_MODULE,
};

Expand Down
Loading

0 comments on commit e788892

Please sign in to comment.