Commit e8ad8d51 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge tag 'devfreq-fixes-for-5.5-rc2' of...

Merge tag 'devfreq-fixes-for-5.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux

Pull devfreq updates for 5.5-rc1 from Chanwoo Choi:

"Update devfreq core:

 - Add PM QoS support for devfreq device with following QoS type.
   External user of devfreq device can request the minimum and
   maximum frequency according to their multiple requirements.
   : DEV_PM_QOS_MIN_FREQUENCY is used for requesting the minimum
     device frequency.
   : DEV_PM_QOS_MAX_FREQUENCY is used for requesting the maximum
     device frequency.

 - Use PM QoS interface when entering the min/max_freq via sysfs
   interface.

 - Add get_freq_range() helper function in order to get the final
   min/max frequency among the multiple requirements of min/max
   frequency.

 - Fix a function return value and modify code for more correct
   exception handling if errors happen."

* tag 'devfreq-fixes-for-5.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux:
  PM / devfreq: Use PM QoS for sysfs min/max_freq
  PM / devfreq: Add PM QoS support
  PM / devfreq: Don't fail devfreq_dev_release if not in list
  PM / devfreq: Introduce get_freq_range helper
  PM / devfreq: Set scaling_max_freq to max on OPP notifier error
  PM / devfreq: Fix devfreq_notifier_call returning errno
parents e42617b8 27dbc542
Loading
Loading
Loading
Loading
+202 −71
Original line number Diff line number Diff line
@@ -24,11 +24,14 @@
#include <linux/printk.h>
#include <linux/hrtimer.h>
#include <linux/of.h>
#include <linux/pm_qos.h>
#include "governor.h"

#define CREATE_TRACE_POINTS
#include <trace/events/devfreq.h>

#define HZ_PER_KHZ	1000

static struct class *devfreq_class;

/*
@@ -98,6 +101,54 @@ 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;
	s32 qos_min_freq, qos_max_freq;

	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 PM QoS */
	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
					     DEV_PM_QOS_MIN_FREQUENCY);
	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
					     DEV_PM_QOS_MAX_FREQUENCY);
	*min_freq = max(*min_freq, (unsigned long)HZ_PER_KHZ * qos_min_freq);
	if (qos_max_freq != PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE)
		*max_freq = min(*max_freq,
				(unsigned long)HZ_PER_KHZ * qos_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 +402,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;
@@ -568,26 +610,69 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
				 void *devp)
{
	struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
	int ret;
	int err = -EINVAL;

	mutex_lock(&devfreq->lock);

	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
	if (!devfreq->scaling_min_freq) {
		mutex_unlock(&devfreq->lock);
		return -EINVAL;
	}
	if (!devfreq->scaling_min_freq)
		goto out;

	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
	if (!devfreq->scaling_max_freq) {
		devfreq->scaling_max_freq = ULONG_MAX;
		goto out;
	}

	err = update_devfreq(devfreq);

out:
	mutex_unlock(&devfreq->lock);
		return -EINVAL;
	if (err)
		dev_err(devfreq->dev.parent,
			"failed to update frequency from OPP notifier (%d)\n",
			err);

	return NOTIFY_OK;
}

	ret = update_devfreq(devfreq);
/**
 * qos_notifier_call() - Common handler for QoS constraints.
 * @devfreq:    the devfreq instance.
 */
static int qos_notifier_call(struct devfreq *devfreq)
{
	int err;

	mutex_lock(&devfreq->lock);
	err = update_devfreq(devfreq);
	mutex_unlock(&devfreq->lock);
	if (err)
		dev_err(devfreq->dev.parent,
			"failed to update frequency from PM QoS (%d)\n",
			err);

	return ret;
	return NOTIFY_OK;
}

/**
 * qos_min_notifier_call() - Callback for QoS min_freq changes.
 * @nb:		Should be devfreq->nb_min
 */
static int qos_min_notifier_call(struct notifier_block *nb,
					 unsigned long val, void *ptr)
{
	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
}

/**
 * qos_max_notifier_call() - Callback for QoS max_freq changes.
 * @nb:		Should be devfreq->nb_max
 */
static int qos_max_notifier_call(struct notifier_block *nb,
					 unsigned long val, void *ptr)
{
	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
}

/**
@@ -599,16 +684,36 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
static void devfreq_dev_release(struct device *dev)
{
	struct devfreq *devfreq = to_devfreq(dev);
	int err;

	mutex_lock(&devfreq_list_lock);
	if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
		mutex_unlock(&devfreq_list_lock);
		dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n");
		return;
	}
	list_del(&devfreq->node);
	mutex_unlock(&devfreq_list_lock);

	err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
					 DEV_PM_QOS_MAX_FREQUENCY);
	if (err && err != -ENOENT)
		dev_warn(dev->parent,
			"Failed to remove max_freq notifier: %d\n", err);
	err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
					 DEV_PM_QOS_MIN_FREQUENCY);
	if (err && err != -ENOENT)
		dev_warn(dev->parent,
			"Failed to remove min_freq notifier: %d\n", err);

	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req)) {
		err = dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
		if (err)
			dev_warn(dev->parent,
				"Failed to remove max_freq request: %d\n", err);
	}
	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req)) {
		err = dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
		if (err)
			dev_warn(dev->parent,
				"Failed to remove min_freq request: %d\n", err);
	}

	if (devfreq->profile->exit)
		devfreq->profile->exit(devfreq->dev.parent);

@@ -660,6 +765,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
	devfreq->dev.parent = dev;
	devfreq->dev.class = devfreq_class;
	devfreq->dev.release = devfreq_dev_release;
	INIT_LIST_HEAD(&devfreq->node);
	devfreq->profile = profile;
	strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
	devfreq->previous_freq = profile->initial_freq;
@@ -681,7 +787,6 @@ struct devfreq *devfreq_add_device(struct device *dev,
		err = -EINVAL;
		goto err_dev;
	}
	devfreq->min_freq = devfreq->scaling_min_freq;

	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
	if (!devfreq->scaling_max_freq) {
@@ -689,7 +794,6 @@ struct devfreq *devfreq_add_device(struct device *dev,
		err = -EINVAL;
		goto err_dev;
	}
	devfreq->max_freq = devfreq->scaling_max_freq;

	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
	atomic_set(&devfreq->suspend_count, 0);
@@ -730,6 +834,28 @@ struct devfreq *devfreq_add_device(struct device *dev,

	mutex_unlock(&devfreq->lock);

	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
				     DEV_PM_QOS_MIN_FREQUENCY, 0);
	if (err < 0)
		goto err_devfreq;
	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
				     DEV_PM_QOS_MAX_FREQUENCY,
				     PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
	if (err < 0)
		goto err_devfreq;

	devfreq->nb_min.notifier_call = qos_min_notifier_call;
	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
				      DEV_PM_QOS_MIN_FREQUENCY);
	if (err)
		goto err_devfreq;

	devfreq->nb_max.notifier_call = qos_max_notifier_call;
	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
				      DEV_PM_QOS_MAX_FREQUENCY);
	if (err)
		goto err_devfreq;

	mutex_lock(&devfreq_list_lock);

	governor = try_then_request_governor(devfreq->governor_name);
@@ -1303,41 +1429,37 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
	unsigned long value;
	int ret;

	/*
	 * Protect against theoretical sysfs writes between
	 * device_add and dev_pm_qos_add_request
	 */
	if (!dev_pm_qos_request_active(&df->user_min_freq_req))
		return -EAGAIN;

	ret = sscanf(buf, "%lu", &value);
	if (ret != 1)
		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);
	/* Round down to kHz for PM QoS */
	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
					value / HZ_PER_KHZ);
	if (ret < 0)
		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;

	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
	mutex_lock(&df->lock);
	get_freq_range(df, &min_freq, &max_freq);
	mutex_unlock(&df->lock);

	return sprintf(buf, "%lu\n", min_freq);
}

static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
@@ -1347,33 +1469,37 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
	unsigned long value;
	int ret;

	/*
	 * Protect against theoretical sysfs writes between
	 * device_add and dev_pm_qos_add_request
	 */
	if (!dev_pm_qos_request_active(&df->user_max_freq_req))
		return -EINVAL;

	ret = sscanf(buf, "%lu", &value);
	if (ret != 1)
		return -EINVAL;

	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];
	/*
	 * PM QoS frequencies are in kHz so we need to convert. Convert by
	 * rounding upwards so that the acceptable interval never shrinks.
	 *
	 * For example if the user writes "666666666" to sysfs this value will
	 * be converted to 666667 kHz and back to 666667000 Hz before an OPP
	 * lookup, this ensures that an OPP of 666666666Hz is still accepted.
	 *
	 * A value of zero means "no limit".
	 */
	if (value)
		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
	else
			value = freq_table[0];
	}
		value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;

	df->max_freq = value;
	update_devfreq(df);
	ret = count;
unlock:
	mutex_unlock(&df->lock);
	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
	if (ret < 0)
		return ret;

	return count;
}
static DEVICE_ATTR_RW(min_freq);

@@ -1381,8 +1507,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);

+10 −4
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/pm_opp.h>
#include <linux/pm_qos.h>

#define DEVFREQ_NAME_LEN 16

@@ -123,8 +124,8 @@ struct devfreq_dev_profile {
 * @previous_freq:	previously configured frequency value.
 * @data:	Private data of the governor. The devfreq framework does not
 *		touch this.
 * @min_freq:	Limit minimum frequency requested by user (0: none)
 * @max_freq:	Limit maximum frequency requested by user (0: none)
 * @user_min_freq_req:	PM QoS minimum frequency request from user (via sysfs)
 * @user_max_freq_req:	PM QoS maximum frequency request from user (via sysfs)
 * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
 * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
 * @stop_polling:	 devfreq polling status of a device.
@@ -136,6 +137,8 @@ struct devfreq_dev_profile {
 * @time_in_state:	Statistics of devfreq states
 * @last_stat_updated:	The last time stat updated
 * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
 * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
 * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
 *
 * This structure stores the devfreq information for a give device.
 *
@@ -161,8 +164,8 @@ struct devfreq {

	void *data; /* private data for governors */

	unsigned long min_freq;
	unsigned long max_freq;
	struct dev_pm_qos_request user_min_freq_req;
	struct dev_pm_qos_request user_max_freq_req;
	unsigned long scaling_min_freq;
	unsigned long scaling_max_freq;
	bool stop_polling;
@@ -178,6 +181,9 @@ struct devfreq {
	unsigned long last_stat_updated;

	struct srcu_notifier_head transition_notifier_list;

	struct notifier_block nb_min;
	struct notifier_block nb_max;
};

struct devfreq_freqs {