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

Commit 6530b9de authored by MyungJoo Ham's avatar MyungJoo Ham
Browse files

PM / devfreq: add min/max_freq limit requested by users.



The frequency requested to devfreq device driver from devfreq governors
is restricted by min_freq and max_freq input.

Signed-off-by: default avatarMyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
parent a95e1f5d
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -501,12 +501,82 @@ static ssize_t show_central_polling(struct device *dev,
		       !to_devfreq(dev)->governor->no_central_polling);
}

static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr,
			      const char *buf, size_t count)
{
	struct devfreq *df = to_devfreq(dev);
	unsigned long value;
	int ret;
	unsigned long max;

	ret = sscanf(buf, "%lu", &value);
	if (ret != 1)
		goto out;

	mutex_lock(&df->lock);
	max = df->max_freq;
	if (value && max && value > max) {
		ret = -EINVAL;
		goto unlock;
	}

	df->min_freq = value;
	update_devfreq(df);
	ret = count;
unlock:
	mutex_unlock(&df->lock);
out:
	return ret;
}

static ssize_t show_min_freq(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	return sprintf(buf, "%lu\n", to_devfreq(dev)->min_freq);
}

static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr,
			      const char *buf, size_t count)
{
	struct devfreq *df = to_devfreq(dev);
	unsigned long value;
	int ret;
	unsigned long min;

	ret = sscanf(buf, "%lu", &value);
	if (ret != 1)
		goto out;

	mutex_lock(&df->lock);
	min = df->min_freq;
	if (value && min && value < min) {
		ret = -EINVAL;
		goto unlock;
	}

	df->max_freq = value;
	update_devfreq(df);
	ret = count;
unlock:
	mutex_unlock(&df->lock);
out:
	return ret;
}

static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq);
}

static struct device_attribute devfreq_attrs[] = {
	__ATTR(governor, S_IRUGO, show_governor, NULL),
	__ATTR(cur_freq, S_IRUGO, show_freq, NULL),
	__ATTR(central_polling, S_IRUGO, show_central_polling, NULL),
	__ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
	       store_polling_interval),
	__ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
	__ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
	{ },
};

+4 −1
Original line number Diff line number Diff line
@@ -18,7 +18,10 @@ static int devfreq_performance_func(struct devfreq *df,
	 * target callback should be able to get floor value as
	 * said in devfreq.h
	 */
	if (!df->max_freq)
		*freq = UINT_MAX;
	else
		*freq = df->max_freq;
	return 0;
}

+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ static int devfreq_powersave_func(struct devfreq *df,
	 * target callback should be able to get ceiling value as
	 * said in devfreq.h
	 */
	*freq = 0;
	*freq = df->min_freq;
	return 0;
}

+9 −3
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
	unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
	unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
	struct devfreq_simple_ondemand_data *data = df->data;
	unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;

	if (err)
		return err;
@@ -41,7 +42,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,

	/* Assume MAX if it is going to be divided by zero */
	if (stat.total_time == 0) {
		*freq = UINT_MAX;
		*freq = max;
		return 0;
	}

@@ -54,13 +55,13 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
	/* Set MAX if it's busy enough */
	if (stat.busy_time * 100 >
	    stat.total_time * dfso_upthreshold) {
		*freq = UINT_MAX;
		*freq = max;
		return 0;
	}

	/* Set MAX if we do not know the initial frequency */
	if (stat.current_frequency == 0) {
		*freq = UINT_MAX;
		*freq = max;
		return 0;
	}

@@ -79,6 +80,11 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
	b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
	*freq = (unsigned long) b;

	if (df->min_freq && *freq < df->min_freq)
		*freq = df->min_freq;
	if (df->max_freq && *freq > df->max_freq)
		*freq = df->max_freq;

	return 0;
}

+12 −3
Original line number Diff line number Diff line
@@ -25,10 +25,19 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
{
	struct userspace_data *data = df->data;

	if (!data->valid)
	if (data->valid) {
		unsigned long adjusted_freq = data->user_frequency;

		if (df->max_freq && adjusted_freq > df->max_freq)
			adjusted_freq = df->max_freq;

		if (df->min_freq && adjusted_freq < df->min_freq)
			adjusted_freq = df->min_freq;

		*freq = adjusted_freq;
	} else {
		*freq = df->previous_freq; /* No user freq specified yet */
	else
		*freq = data->user_frequency;
	}
	return 0;
}

Loading