Commit 4d5dcc42 authored by Viresh Kumar's avatar Viresh Kumar Committed by Rafael J. Wysocki

cpufreq: governor: Implement per policy instances of governors

Currently, there can't be multiple instances of single governor_type.
If we have a multi-package system, where we have multiple instances
of struct policy (per package), we can't have multiple instances of
same governor. i.e. We can't have multiple instances of ondemand
governor for multiple packages.

Governors directory in sysfs is created at /sys/devices/system/cpu/cpufreq/
governor-name/. Which again reflects that there can be only one
instance of a governor_type in the system.

This is a bottleneck for multicluster system, where we want different
packages to use same governor type, but with different tunables.

This patch uses the infrastructure provided by earlier patch and
implements init/exit routines for ondemand and conservative
governors.
Signed-off-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 7bd353a9
...@@ -128,6 +128,11 @@ void disable_cpufreq(void) ...@@ -128,6 +128,11 @@ void disable_cpufreq(void)
static LIST_HEAD(cpufreq_governor_list); static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX(cpufreq_governor_mutex); static DEFINE_MUTEX(cpufreq_governor_mutex);
bool have_governor_per_policy(void)
{
return cpufreq_driver->have_governor_per_policy;
}
static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
{ {
struct cpufreq_policy *data; struct cpufreq_policy *data;
...@@ -1546,10 +1551,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, ...@@ -1546,10 +1551,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
policy->cpu, event); policy->cpu, event);
ret = policy->governor->governor(policy, event); ret = policy->governor->governor(policy, event);
if (event == CPUFREQ_GOV_START) if (!ret) {
policy->governor->initialized++; if (event == CPUFREQ_GOV_POLICY_INIT)
else if (event == CPUFREQ_GOV_STOP) policy->governor->initialized++;
policy->governor->initialized--; else if (event == CPUFREQ_GOV_POLICY_EXIT)
policy->governor->initialized--;
}
/* we keep one module reference alive for /* we keep one module reference alive for
each CPU governed by this CPU */ each CPU governed by this CPU */
......
This diff is collapsed.
This diff is collapsed.
...@@ -40,14 +40,75 @@ ...@@ -40,14 +40,75 @@
/* Ondemand Sampling types */ /* Ondemand Sampling types */
enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE}; enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};
/* Macro creating sysfs show routines */ /*
#define show_one(_gov, file_name, object) \ * Macro for creating governors sysfs routines
static ssize_t show_##file_name \ *
* - gov_sys: One governor instance per whole system
* - gov_pol: One governor instance per policy
*/
/* Create attributes */
#define gov_sys_attr_ro(_name) \
static struct global_attr _name##_gov_sys = \
__ATTR(_name, 0444, show_##_name##_gov_sys, NULL)
#define gov_sys_attr_rw(_name) \
static struct global_attr _name##_gov_sys = \
__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
#define gov_pol_attr_ro(_name) \
static struct freq_attr _name##_gov_pol = \
__ATTR(_name, 0444, show_##_name##_gov_pol, NULL)
#define gov_pol_attr_rw(_name) \
static struct freq_attr _name##_gov_pol = \
__ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
#define gov_sys_pol_attr_rw(_name) \
gov_sys_attr_rw(_name); \
gov_pol_attr_rw(_name)
#define gov_sys_pol_attr_ro(_name) \
gov_sys_attr_ro(_name); \
gov_pol_attr_ro(_name)
/* Create show/store routines */
#define show_one(_gov, file_name) \
static ssize_t show_##file_name##_gov_sys \
(struct kobject *kobj, struct attribute *attr, char *buf) \ (struct kobject *kobj, struct attribute *attr, char *buf) \
{ \ { \
return sprintf(buf, "%u\n", _gov##_tuners.object); \ struct _gov##_dbs_tuners *tuners = _gov##_dbs_cdata.gdbs_data->tuners; \
return sprintf(buf, "%u\n", tuners->file_name); \
} \
\
static ssize_t show_##file_name##_gov_pol \
(struct cpufreq_policy *policy, char *buf) \
{ \
struct dbs_data *dbs_data = policy->governor_data; \
struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \
return sprintf(buf, "%u\n", tuners->file_name); \
}
#define store_one(_gov, file_name) \
static ssize_t store_##file_name##_gov_sys \
(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
{ \
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
return store_##file_name(dbs_data, buf, count); \
} \
\
static ssize_t store_##file_name##_gov_pol \
(struct cpufreq_policy *policy, const char *buf, size_t count) \
{ \
struct dbs_data *dbs_data = policy->governor_data; \
return store_##file_name(dbs_data, buf, count); \
} }
#define show_store_one(_gov, file_name) \
show_one(_gov, file_name); \
store_one(_gov, file_name)
/* create helper routines */
#define define_get_cpu_dbs_routines(_dbs_info) \ #define define_get_cpu_dbs_routines(_dbs_info) \
static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \ static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \
{ \ { \
...@@ -103,7 +164,7 @@ struct cs_cpu_dbs_info_s { ...@@ -103,7 +164,7 @@ struct cs_cpu_dbs_info_s {
unsigned int enable:1; unsigned int enable:1;
}; };
/* Governers sysfs tunables */ /* Per policy Governers sysfs tunables */
struct od_dbs_tuners { struct od_dbs_tuners {
unsigned int ignore_nice; unsigned int ignore_nice;
unsigned int sampling_rate; unsigned int sampling_rate;
...@@ -123,31 +184,42 @@ struct cs_dbs_tuners { ...@@ -123,31 +184,42 @@ struct cs_dbs_tuners {
unsigned int freq_step; unsigned int freq_step;
}; };
/* Per Governer data */ /* Common Governer data across policies */
struct dbs_data { struct dbs_data;
struct common_dbs_data {
/* Common across governors */ /* Common across governors */
#define GOV_ONDEMAND 0 #define GOV_ONDEMAND 0
#define GOV_CONSERVATIVE 1 #define GOV_CONSERVATIVE 1
int governor; int governor;
unsigned int min_sampling_rate; struct attribute_group *attr_group_gov_sys; /* one governor - system */
struct attribute_group *attr_group; struct attribute_group *attr_group_gov_pol; /* one governor - policy */
void *tuners;
/* dbs_mutex protects dbs_enable in governor start/stop */ /* Common data for platforms that don't set have_governor_per_policy */
struct mutex mutex; struct dbs_data *gdbs_data;
struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu); struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu);
void *(*get_cpu_dbs_info_s)(int cpu); void *(*get_cpu_dbs_info_s)(int cpu);
void (*gov_dbs_timer)(struct work_struct *work); void (*gov_dbs_timer)(struct work_struct *work);
void (*gov_check_cpu)(int cpu, unsigned int load); void (*gov_check_cpu)(int cpu, unsigned int load);
int (*init)(struct dbs_data *dbs_data);
void (*exit)(struct dbs_data *dbs_data);
/* Governor specific ops, see below */ /* Governor specific ops, see below */
void *gov_ops; void *gov_ops;
}; };
/* Governer Per policy data */
struct dbs_data {
struct common_dbs_data *cdata;
unsigned int min_sampling_rate;
void *tuners;
/* dbs_mutex protects dbs_enable in governor start/stop */
struct mutex mutex;
};
/* Governor specific ops, will be passed to dbs_data->gov_ops */ /* Governor specific ops, will be passed to dbs_data->gov_ops */
struct od_ops { struct od_ops {
int (*io_busy)(void);
void (*powersave_bias_init_cpu)(int cpu); void (*powersave_bias_init_cpu)(int cpu);
unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy, unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy,
unsigned int freq_next, unsigned int relation); unsigned int freq_next, unsigned int relation);
...@@ -169,10 +241,25 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate) ...@@ -169,10 +241,25 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate)
return delay; return delay;
} }
#define declare_show_sampling_rate_min(_gov) \
static ssize_t show_sampling_rate_min_gov_sys \
(struct kobject *kobj, struct attribute *attr, char *buf) \
{ \
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
} \
\
static ssize_t show_sampling_rate_min_gov_pol \
(struct cpufreq_policy *policy, char *buf) \
{ \
struct dbs_data *dbs_data = policy->governor_data; \
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
}
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall); u64 get_cpu_idle_time(unsigned int cpu, u64 *wall);
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
bool need_load_eval(struct cpu_dbs_common_info *cdbs, bool need_load_eval(struct cpu_dbs_common_info *cdbs,
unsigned int sampling_rate); unsigned int sampling_rate);
int cpufreq_governor_dbs(struct dbs_data *dbs_data, int cpufreq_governor_dbs(struct cpufreq_policy *policy,
struct cpufreq_policy *policy, unsigned int event); struct common_dbs_data *cdata, unsigned int event);
#endif /* _CPUFREQ_GOVERNER_H */ #endif /* _CPUFREQ_GOVERNER_H */
This diff is collapsed.
...@@ -232,6 +232,13 @@ struct cpufreq_driver { ...@@ -232,6 +232,13 @@ struct cpufreq_driver {
struct module *owner; struct module *owner;
char name[CPUFREQ_NAME_LEN]; char name[CPUFREQ_NAME_LEN];
u8 flags; u8 flags;
/*
* This should be set by platforms having multiple clock-domains, i.e.
* supporting multiple policies. With this sysfs directories of governor
* would be created in cpu/cpu<num>/cpufreq/ directory and so they can
* use the same governor with different tunables for different clusters.
*/
bool have_governor_per_policy;
/* needed by all drivers */ /* needed by all drivers */
int (*init) (struct cpufreq_policy *policy); int (*init) (struct cpufreq_policy *policy);
...@@ -332,6 +339,7 @@ const char *cpufreq_get_current_driver(void); ...@@ -332,6 +339,7 @@ const char *cpufreq_get_current_driver(void);
*********************************************************************/ *********************************************************************/
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu); int cpufreq_update_policy(unsigned int cpu);
bool have_governor_per_policy(void);
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */ /* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment