Commit 46cecc0b authored by Leonard Crestez's avatar Leonard Crestez Committed by Chanwoo Choi
Browse files

PM / devfreq: Introduce get_freq_range helper



Moving handling of min/max freq to a single function and call it from
update_devfreq and for printing min/max freq values in sysfs.

This changes the behavior of out-of-range min_freq/max_freq: clamping
is now done at evaluation time. This means that if an out-of-range
constraint is imposed by sysfs and it later becomes valid then it will
be enforced.

Signed-off-by: default avatarLeonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: default avatarMatthias Kaehlcke <mka@chromium.org>
Reviewed-by: default avatarChanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: default avatarChanwoo Choi <cw00.choi@samsung.com>
parent e7cc792d
Loading
Loading
Loading
Loading
+60 −48
Original line number Diff line number Diff line
@@ -98,6 +98,47 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
	return max_freq;
}

/**
 * get_freq_range() - Get the current freq range
 * @devfreq:	the devfreq instance
 * @min_freq:	the min frequency
 * @max_freq:	the max frequency
 *
 * This takes into consideration all constraints.
 */
static void get_freq_range(struct devfreq *devfreq,
			   unsigned long *min_freq,
			   unsigned long *max_freq)
{
	unsigned long *freq_table = devfreq->profile->freq_table;

	lockdep_assert_held(&devfreq->lock);

	/*
	 * Initialize minimum/maximum frequency from freq table.
	 * The devfreq drivers can initialize this in either ascending or
	 * descending order and devfreq core supports both.
	 */
	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
		*min_freq = freq_table[0];
		*max_freq = freq_table[devfreq->profile->max_state - 1];
	} else {
		*min_freq = freq_table[devfreq->profile->max_state - 1];
		*max_freq = freq_table[0];
	}

	/* Apply constraints from sysfs */
	*min_freq = max(*min_freq, devfreq->min_freq);
	*max_freq = min(*max_freq, devfreq->max_freq);

	/* Apply constraints from OPP interface */
	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
	*max_freq = min(*max_freq, devfreq->scaling_max_freq);

	if (*min_freq > *max_freq)
		*min_freq = *max_freq;
}

/**
 * devfreq_get_freq_level() - Lookup freq_table for the frequency
 * @devfreq:	the devfreq instance
@@ -351,16 +392,7 @@ int update_devfreq(struct devfreq *devfreq)
	err = devfreq->governor->get_target_freq(devfreq, &freq);
	if (err)
		return err;

	/*
	 * Adjust the frequency with user freq, QoS and available freq.
	 *
	 * List from the highest priority
	 * max_freq
	 * min_freq
	 */
	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
	get_freq_range(devfreq, &min_freq, &max_freq);

	if (freq < min_freq) {
		freq = min_freq;
@@ -1312,36 +1344,24 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
		return -EINVAL;

	mutex_lock(&df->lock);

	if (value) {
		if (value > df->max_freq) {
			ret = -EINVAL;
			goto unlock;
		}
	} else {
		unsigned long *freq_table = df->profile->freq_table;

		/* Get minimum frequency according to sorting order */
		if (freq_table[0] < freq_table[df->profile->max_state - 1])
			value = freq_table[0];
		else
			value = freq_table[df->profile->max_state - 1];
	}

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

	return count;
}

static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	struct devfreq *df = to_devfreq(dev);
	unsigned long min_freq, max_freq;

	mutex_lock(&df->lock);
	get_freq_range(df, &min_freq, &max_freq);
	mutex_unlock(&df->lock);

	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
	return sprintf(buf, "%lu\n", min_freq);
}

static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
@@ -1357,27 +1377,14 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,

	mutex_lock(&df->lock);

	if (value) {
		if (value < df->min_freq) {
			ret = -EINVAL;
			goto unlock;
		}
	} else {
		unsigned long *freq_table = df->profile->freq_table;

		/* Get maximum frequency according to sorting order */
		if (freq_table[0] < freq_table[df->profile->max_state - 1])
			value = freq_table[df->profile->max_state - 1];
		else
			value = freq_table[0];
	}
	if (!value)
		value = ULONG_MAX;

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

	return count;
}
static DEVICE_ATTR_RW(min_freq);

@@ -1385,8 +1392,13 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	struct devfreq *df = to_devfreq(dev);
	unsigned long min_freq, max_freq;

	mutex_lock(&df->lock);
	get_freq_range(df, &min_freq, &max_freq);
	mutex_unlock(&df->lock);

	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
	return sprintf(buf, "%lu\n", max_freq);
}
static DEVICE_ATTR_RW(max_freq);