Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -128,6 +128,11 @@ void disable_cpufreq(void)
static LIST_HEAD(cpufreq_governor_list);
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)
{
	struct cpufreq_policy *data;
@@ -1546,10 +1551,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
						policy->cpu, event);
	ret = policy->governor->governor(policy, event);

	if (event == CPUFREQ_GOV_START)
	if (!ret) {
		if (event == CPUFREQ_GOV_POLICY_INIT)
			policy->governor->initialized++;
	else if (event == CPUFREQ_GOV_STOP)
		else if (event == CPUFREQ_GOV_POLICY_EXIT)
			policy->governor->initialized--;
	}

	/* we keep one module reference alive for
			each CPU governed by this CPU */
+118 −75
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/percpu-defs.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/types.h>

@@ -31,17 +32,8 @@
#define DEF_SAMPLING_DOWN_FACTOR		(1)
#define MAX_SAMPLING_DOWN_FACTOR		(10)

static struct dbs_data cs_dbs_data;
static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info);

static struct cs_dbs_tuners cs_tuners = {
	.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
	.down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
	.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
	.ignore_nice = 0,
	.freq_step = 5,
};

/*
 * Every sampling_rate, we check, if current idle time is less than 20%
 * (default), then we try to increase frequency Every sampling_rate *
@@ -55,24 +47,26 @@ static void cs_check_cpu(int cpu, unsigned int load)
{
	struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu);
	struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
	struct dbs_data *dbs_data = policy->governor_data;
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	unsigned int freq_target;

	/*
	 * break out if we 'cannot' reduce the speed as the user might
	 * want freq_step to be zero
	 */
	if (cs_tuners.freq_step == 0)
	if (cs_tuners->freq_step == 0)
		return;

	/* Check for frequency increase */
	if (load > cs_tuners.up_threshold) {
	if (load > cs_tuners->up_threshold) {
		dbs_info->down_skip = 0;

		/* if we are already at full speed then break out early */
		if (dbs_info->requested_freq == policy->max)
			return;

		freq_target = (cs_tuners.freq_step * policy->max) / 100;
		freq_target = (cs_tuners->freq_step * policy->max) / 100;

		/* max freq cannot be less than 100. But who knows.... */
		if (unlikely(freq_target == 0))
@@ -92,8 +86,8 @@ static void cs_check_cpu(int cpu, unsigned int load)
	 * support the current CPU usage without triggering the up policy. To be
	 * safe, we focus 10 points under the threshold.
	 */
	if (load < (cs_tuners.down_threshold - 10)) {
		freq_target = (cs_tuners.freq_step * policy->max) / 100;
	if (load < (cs_tuners->down_threshold - 10)) {
		freq_target = (cs_tuners->freq_step * policy->max) / 100;

		dbs_info->requested_freq -= freq_target;
		if (dbs_info->requested_freq < policy->min)
@@ -119,11 +113,13 @@ static void cs_dbs_timer(struct work_struct *work)
	unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
	struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info,
			cpu);
	int delay = delay_for_sampling_rate(cs_tuners.sampling_rate);
	struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data;
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	int delay = delay_for_sampling_rate(cs_tuners->sampling_rate);

	mutex_lock(&core_dbs_info->cdbs.timer_mutex);
	if (need_load_eval(&core_dbs_info->cdbs, cs_tuners.sampling_rate))
		dbs_check_cpu(&cs_dbs_data, cpu);
	if (need_load_eval(&core_dbs_info->cdbs, cs_tuners->sampling_rate))
		dbs_check_cpu(dbs_data, cpu);

	schedule_delayed_work_on(smp_processor_id(), dw, delay);
	mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
@@ -154,16 +150,12 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
}

/************************** sysfs interface ************************/
static ssize_t show_sampling_rate_min(struct kobject *kobj,
				      struct attribute *attr, char *buf)
{
	return sprintf(buf, "%u\n", cs_dbs_data.min_sampling_rate);
}
static struct common_dbs_data cs_dbs_cdata;

static ssize_t store_sampling_down_factor(struct kobject *a,
					  struct attribute *b,
static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
		const char *buf, size_t count)
{
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	unsigned int input;
	int ret;
	ret = sscanf(buf, "%u", &input);
@@ -171,13 +163,14 @@ static ssize_t store_sampling_down_factor(struct kobject *a,
	if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
		return -EINVAL;

	cs_tuners.sampling_down_factor = input;
	cs_tuners->sampling_down_factor = input;
	return count;
}

static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
				   const char *buf, size_t count)
static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
		size_t count)
{
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	unsigned int input;
	int ret;
	ret = sscanf(buf, "%u", &input);
@@ -185,43 +178,46 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
	if (ret != 1)
		return -EINVAL;

	cs_tuners.sampling_rate = max(input, cs_dbs_data.min_sampling_rate);
	cs_tuners->sampling_rate = max(input, dbs_data->min_sampling_rate);
	return count;
}

static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
				  const char *buf, size_t count)
static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
		size_t count)
{
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	unsigned int input;
	int ret;
	ret = sscanf(buf, "%u", &input);

	if (ret != 1 || input > 100 || input <= cs_tuners.down_threshold)
	if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold)
		return -EINVAL;

	cs_tuners.up_threshold = input;
	cs_tuners->up_threshold = input;
	return count;
}

static ssize_t store_down_threshold(struct kobject *a, struct attribute *b,
				    const char *buf, size_t count)
static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
		size_t count)
{
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	unsigned int input;
	int ret;
	ret = sscanf(buf, "%u", &input);

	/* cannot be lower than 11 otherwise freq will not fall */
	if (ret != 1 || input < 11 || input > 100 ||
			input >= cs_tuners.up_threshold)
			input >= cs_tuners->up_threshold)
		return -EINVAL;

	cs_tuners.down_threshold = input;
	cs_tuners->down_threshold = input;
	return count;
}

static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
				      const char *buf, size_t count)
static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
		size_t count)
{
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	unsigned int input, j;
	int ret;

@@ -232,10 +228,10 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
	if (input > 1)
		input = 1;

	if (input == cs_tuners.ignore_nice) /* nothing to do */
	if (input == cs_tuners->ignore_nice) /* nothing to do */
		return count;

	cs_tuners.ignore_nice = input;
	cs_tuners->ignore_nice = input;

	/* we need to re-evaluate prev_cpu_idle */
	for_each_online_cpu(j) {
@@ -243,16 +239,17 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
		dbs_info = &per_cpu(cs_cpu_dbs_info, j);
		dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
						&dbs_info->cdbs.prev_cpu_wall);
		if (cs_tuners.ignore_nice)
		if (cs_tuners->ignore_nice)
			dbs_info->cdbs.prev_cpu_nice =
				kcpustat_cpu(j).cpustat[CPUTIME_NICE];
	}
	return count;
}

static ssize_t store_freq_step(struct kobject *a, struct attribute *b,
			       const char *buf, size_t count)
static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf,
		size_t count)
{
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	unsigned int input;
	int ret;
	ret = sscanf(buf, "%u", &input);
@@ -267,43 +264,88 @@ static ssize_t store_freq_step(struct kobject *a, struct attribute *b,
	 * no need to test here if freq_step is zero as the user might actually
	 * want this, they would be crazy though :)
	 */
	cs_tuners.freq_step = input;
	cs_tuners->freq_step = input;
	return count;
}

show_one(cs, sampling_rate, sampling_rate);
show_one(cs, sampling_down_factor, sampling_down_factor);
show_one(cs, up_threshold, up_threshold);
show_one(cs, down_threshold, down_threshold);
show_one(cs, ignore_nice_load, ignore_nice);
show_one(cs, freq_step, freq_step);

define_one_global_rw(sampling_rate);
define_one_global_rw(sampling_down_factor);
define_one_global_rw(up_threshold);
define_one_global_rw(down_threshold);
define_one_global_rw(ignore_nice_load);
define_one_global_rw(freq_step);
define_one_global_ro(sampling_rate_min);

static struct attribute *dbs_attributes[] = {
	&sampling_rate_min.attr,
	&sampling_rate.attr,
	&sampling_down_factor.attr,
	&up_threshold.attr,
	&down_threshold.attr,
	&ignore_nice_load.attr,
	&freq_step.attr,
show_store_one(cs, sampling_rate);
show_store_one(cs, sampling_down_factor);
show_store_one(cs, up_threshold);
show_store_one(cs, down_threshold);
show_store_one(cs, ignore_nice);
show_store_one(cs, freq_step);
declare_show_sampling_rate_min(cs);

gov_sys_pol_attr_rw(sampling_rate);
gov_sys_pol_attr_rw(sampling_down_factor);
gov_sys_pol_attr_rw(up_threshold);
gov_sys_pol_attr_rw(down_threshold);
gov_sys_pol_attr_rw(ignore_nice);
gov_sys_pol_attr_rw(freq_step);
gov_sys_pol_attr_ro(sampling_rate_min);

static struct attribute *dbs_attributes_gov_sys[] = {
	&sampling_rate_min_gov_sys.attr,
	&sampling_rate_gov_sys.attr,
	&sampling_down_factor_gov_sys.attr,
	&up_threshold_gov_sys.attr,
	&down_threshold_gov_sys.attr,
	&ignore_nice_gov_sys.attr,
	&freq_step_gov_sys.attr,
	NULL
};

static struct attribute_group cs_attr_group_gov_sys = {
	.attrs = dbs_attributes_gov_sys,
	.name = "conservative",
};

static struct attribute *dbs_attributes_gov_pol[] = {
	&sampling_rate_min_gov_pol.attr,
	&sampling_rate_gov_pol.attr,
	&sampling_down_factor_gov_pol.attr,
	&up_threshold_gov_pol.attr,
	&down_threshold_gov_pol.attr,
	&ignore_nice_gov_pol.attr,
	&freq_step_gov_pol.attr,
	NULL
};

static struct attribute_group cs_attr_group = {
	.attrs = dbs_attributes,
static struct attribute_group cs_attr_group_gov_pol = {
	.attrs = dbs_attributes_gov_pol,
	.name = "conservative",
};

/************************** sysfs end ************************/

static int cs_init(struct dbs_data *dbs_data)
{
	struct cs_dbs_tuners *tuners;

	tuners = kzalloc(sizeof(struct cs_dbs_tuners), GFP_KERNEL);
	if (!tuners) {
		pr_err("%s: kzalloc failed\n", __func__);
		return -ENOMEM;
	}

	tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
	tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
	tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
	tuners->ignore_nice = 0;
	tuners->freq_step = 5;

	dbs_data->tuners = tuners;
	dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
		jiffies_to_usecs(10);
	mutex_init(&dbs_data->mutex);
	return 0;
}

static void cs_exit(struct dbs_data *dbs_data)
{
	kfree(dbs_data->tuners);
}

define_get_cpu_dbs_routines(cs_cpu_dbs_info);

static struct notifier_block cs_cpufreq_notifier_block = {
@@ -314,21 +356,23 @@ static struct cs_ops cs_ops = {
	.notifier_block = &cs_cpufreq_notifier_block,
};

static struct dbs_data cs_dbs_data = {
static struct common_dbs_data cs_dbs_cdata = {
	.governor = GOV_CONSERVATIVE,
	.attr_group = &cs_attr_group,
	.tuners = &cs_tuners,
	.attr_group_gov_sys = &cs_attr_group_gov_sys,
	.attr_group_gov_pol = &cs_attr_group_gov_pol,
	.get_cpu_cdbs = get_cpu_cdbs,
	.get_cpu_dbs_info_s = get_cpu_dbs_info_s,
	.gov_dbs_timer = cs_dbs_timer,
	.gov_check_cpu = cs_check_cpu,
	.gov_ops = &cs_ops,
	.init = cs_init,
	.exit = cs_exit,
};

static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
				   unsigned int event)
{
	return cpufreq_governor_dbs(&cs_dbs_data, policy, event);
	return cpufreq_governor_dbs(policy, &cs_dbs_cdata, event);
}

#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
@@ -343,7 +387,6 @@ struct cpufreq_governor cpufreq_gov_conservative = {

static int __init cpufreq_gov_dbs_init(void)
{
	mutex_init(&cs_dbs_data.mutex);
	return cpufreq_register_governor(&cpufreq_gov_conservative);
}

+142 −70
Original line number Diff line number Diff line
@@ -22,12 +22,29 @@
#include <linux/export.h>
#include <linux/kernel_stat.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/tick.h>
#include <linux/types.h>
#include <linux/workqueue.h>

#include "cpufreq_governor.h"

static struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
{
	if (have_governor_per_policy())
		return &policy->kobj;
	else
		return cpufreq_global_kobject;
}

static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data)
{
	if (have_governor_per_policy())
		return dbs_data->cdata->attr_group_gov_pol;
	else
		return dbs_data->cdata->attr_group_gov_sys;
}

static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
{
	u64 idle_time;
@@ -65,7 +82,7 @@ EXPORT_SYMBOL_GPL(get_cpu_idle_time);

void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
{
	struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
	struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
	struct od_dbs_tuners *od_tuners = dbs_data->tuners;
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	struct cpufreq_policy *policy;
@@ -73,7 +90,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
	unsigned int ignore_nice;
	unsigned int j;

	if (dbs_data->governor == GOV_ONDEMAND)
	if (dbs_data->cdata->governor == GOV_ONDEMAND)
		ignore_nice = od_tuners->ignore_nice;
	else
		ignore_nice = cs_tuners->ignore_nice;
@@ -87,7 +104,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
		unsigned int idle_time, wall_time, iowait_time;
		unsigned int load;

		j_cdbs = dbs_data->get_cpu_cdbs(j);
		j_cdbs = dbs_data->cdata->get_cpu_cdbs(j);

		cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);

@@ -117,9 +134,9 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
			idle_time += jiffies_to_usecs(cur_nice_jiffies);
		}

		if (dbs_data->governor == GOV_ONDEMAND) {
		if (dbs_data->cdata->governor == GOV_ONDEMAND) {
			struct od_cpu_dbs_info_s *od_j_dbs_info =
				dbs_data->get_cpu_dbs_info_s(cpu);
				dbs_data->cdata->get_cpu_dbs_info_s(cpu);

			cur_iowait_time = get_cpu_iowait_time_us(j,
					&cur_wall_time);
@@ -145,7 +162,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)

		load = 100 * (wall_time - idle_time) / wall_time;

		if (dbs_data->governor == GOV_ONDEMAND) {
		if (dbs_data->cdata->governor == GOV_ONDEMAND) {
			int freq_avg = __cpufreq_driver_getavg(policy, j);
			if (freq_avg <= 0)
				freq_avg = policy->cur;
@@ -157,7 +174,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
			max_load = load;
	}

	dbs_data->gov_check_cpu(cpu, max_load);
	dbs_data->cdata->gov_check_cpu(cpu, max_load);
}
EXPORT_SYMBOL_GPL(dbs_check_cpu);

@@ -165,14 +182,14 @@ static inline void dbs_timer_init(struct dbs_data *dbs_data, int cpu,
				  unsigned int sampling_rate)
{
	int delay = delay_for_sampling_rate(sampling_rate);
	struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
	struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);

	schedule_delayed_work_on(cpu, &cdbs->work, delay);
}

static inline void dbs_timer_exit(struct dbs_data *dbs_data, int cpu)
{
	struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
	struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);

	cancel_delayed_work_sync(&cdbs->work);
}
@@ -196,31 +213,128 @@ bool need_load_eval(struct cpu_dbs_common_info *cdbs,
}
EXPORT_SYMBOL_GPL(need_load_eval);

int cpufreq_governor_dbs(struct dbs_data *dbs_data,
		struct cpufreq_policy *policy, unsigned int event)
static void set_sampling_rate(struct dbs_data *dbs_data,
		unsigned int sampling_rate)
{
	if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
		struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
		cs_tuners->sampling_rate = sampling_rate;
	} else {
		struct od_dbs_tuners *od_tuners = dbs_data->tuners;
		od_tuners->sampling_rate = sampling_rate;
	}
}

int cpufreq_governor_dbs(struct cpufreq_policy *policy,
		struct common_dbs_data *cdata, unsigned int event)
{
	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 = dbs_data->tuners;
	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
	struct od_dbs_tuners *od_tuners = NULL;
	struct cs_dbs_tuners *cs_tuners = NULL;
	struct cpu_dbs_common_info *cpu_cdbs;
	unsigned int *sampling_rate, latency, ignore_nice, j, cpu = policy->cpu;
	unsigned int sampling_rate, latency, ignore_nice, j, cpu = policy->cpu;
	int rc;

	cpu_cdbs = dbs_data->get_cpu_cdbs(cpu);
	if (have_governor_per_policy())
		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:
		if (have_governor_per_policy()) {
			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__);
			return -ENOMEM;
		}

		dbs_data->cdata = cdata;
		rc = cdata->init(dbs_data);
		if (rc) {
			pr_err("%s: POLICY_INIT: init() failed\n", __func__);
			kfree(dbs_data);
			return rc;
		}

		rc = sysfs_create_group(get_governor_parent_kobj(policy),
				get_sysfs_attr(dbs_data));
		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 */
		latency = policy->cpuinfo.transition_latency / 1000;
		if (latency == 0)
			latency = 1;

		/* Bring kernel and HW constraints together */
		dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
				MIN_LATENCY_MULTIPLIER * latency);
		set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
					latency * LATENCY_MULTIPLIER));

	if (dbs_data->governor == GOV_CONSERVATIVE) {
		cs_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
		sampling_rate = &cs_tuners->sampling_rate;
		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_governor_per_policy())
			cdata->gdbs_data = dbs_data;

		return 0;
	case CPUFREQ_GOV_POLICY_EXIT:
		if ((policy->governor->initialized == 1) ||
				have_governor_per_policy()) {
			sysfs_remove_group(get_governor_parent_kobj(policy),
					get_sysfs_attr(dbs_data));

			if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
				struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;

				cpufreq_unregister_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;
	}

	cpu_cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);

	if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
		cs_tuners = dbs_data->tuners;
		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->gov_ops;
	} else {
		od_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
		sampling_rate = &od_tuners->sampling_rate;
		od_tuners = dbs_data->tuners;
		od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
		sampling_rate = od_tuners->sampling_rate;
		ignore_nice = od_tuners->ignore_nice;
		od_ops = dbs_data->gov_ops;
		od_ops = dbs_data->cdata->gov_ops;
	}

	switch (event) {
@@ -232,7 +346,7 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data,

		for_each_cpu(j, policy->cpus) {
			struct cpu_dbs_common_info *j_cdbs =
				dbs_data->get_cpu_cdbs(j);
				dbs_data->cdata->get_cpu_cdbs(j);

			j_cdbs->cpu = j;
			j_cdbs->cur_policy = policy;
@@ -244,69 +358,34 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data,

			mutex_init(&j_cdbs->timer_mutex);
			INIT_DEFERRABLE_WORK(&j_cdbs->work,
					     dbs_data->gov_dbs_timer);
		}

		if (!policy->governor->initialized) {
			rc = sysfs_create_group(cpufreq_global_kobject,
					dbs_data->attr_group);
			if (rc) {
				mutex_unlock(&dbs_data->mutex);
				return rc;
			}
					     dbs_data->cdata->gov_dbs_timer);
		}

		/*
		 * conservative does not implement micro like ondemand
		 * governor, thus we are bound to jiffes/HZ
		 */
		if (dbs_data->governor == GOV_CONSERVATIVE) {
		if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
			cs_dbs_info->down_skip = 0;
			cs_dbs_info->enable = 1;
			cs_dbs_info->requested_freq = policy->cur;

			if (!policy->governor->initialized) {
				cpufreq_register_notifier(cs_ops->notifier_block,
						CPUFREQ_TRANSITION_NOTIFIER);

				dbs_data->min_sampling_rate =
					MIN_SAMPLING_RATE_RATIO *
					jiffies_to_usecs(10);
			}
		} else {
			od_dbs_info->rate_mult = 1;
			od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
			od_ops->powersave_bias_init_cpu(cpu);

			if (!policy->governor->initialized)
				od_tuners->io_is_busy = od_ops->io_busy();
		}

		if (policy->governor->initialized)
			goto unlock;

		/* policy latency is in nS. Convert it to uS first */
		latency = policy->cpuinfo.transition_latency / 1000;
		if (latency == 0)
			latency = 1;

		/* Bring kernel and HW constraints together */
		dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
				MIN_LATENCY_MULTIPLIER * latency);
		*sampling_rate = max(dbs_data->min_sampling_rate, latency *
				LATENCY_MULTIPLIER);
unlock:
		mutex_unlock(&dbs_data->mutex);

		/* Initiate timer time stamp */
		cpu_cdbs->time_stamp = ktime_get();

		for_each_cpu(j, policy->cpus)
			dbs_timer_init(dbs_data, j, *sampling_rate);
			dbs_timer_init(dbs_data, j, sampling_rate);
		break;

	case CPUFREQ_GOV_STOP:
		if (dbs_data->governor == GOV_CONSERVATIVE)
		if (dbs_data->cdata->governor == GOV_CONSERVATIVE)
			cs_dbs_info->enable = 0;

		for_each_cpu(j, policy->cpus)
@@ -315,13 +394,6 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data,
		mutex_lock(&dbs_data->mutex);
		mutex_destroy(&cpu_cdbs->timer_mutex);

		if (policy->governor->initialized == 1) {
			sysfs_remove_group(cpufreq_global_kobject,
					dbs_data->attr_group);
			if (dbs_data->governor == GOV_CONSERVATIVE)
				cpufreq_unregister_notifier(cs_ops->notifier_block,
						CPUFREQ_TRANSITION_NOTIFIER);
		}
		mutex_unlock(&dbs_data->mutex);

		break;
+102 −15

File changed.

Preview size limit exceeded, changes collapsed.

+157 −106

File changed.

Preview size limit exceeded, changes collapsed.

Loading