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

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
...@@ -24,11 +24,14 @@ ...@@ -24,11 +24,14 @@
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/pm_qos.h>
#include "governor.h" #include "governor.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/devfreq.h> #include <trace/events/devfreq.h>
#define HZ_PER_KHZ 1000
static struct class *devfreq_class; static struct class *devfreq_class;
/* /*
...@@ -98,6 +101,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq) ...@@ -98,6 +101,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
return max_freq; 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_get_freq_level() - Lookup freq_table for the frequency
* @devfreq: the devfreq instance * @devfreq: the devfreq instance
...@@ -351,16 +402,7 @@ int update_devfreq(struct devfreq *devfreq) ...@@ -351,16 +402,7 @@ int update_devfreq(struct devfreq *devfreq)
err = devfreq->governor->get_target_freq(devfreq, &freq); err = devfreq->governor->get_target_freq(devfreq, &freq);
if (err) if (err)
return err; return err;
get_freq_range(devfreq, &min_freq, &max_freq);
/*
* 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);
if (freq < min_freq) { if (freq < min_freq) {
freq = min_freq; freq = min_freq;
...@@ -568,26 +610,69 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, ...@@ -568,26 +610,69 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
void *devp) void *devp)
{ {
struct devfreq *devfreq = container_of(nb, struct devfreq, nb); struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
int ret; int err = -EINVAL;
mutex_lock(&devfreq->lock); mutex_lock(&devfreq->lock);
devfreq->scaling_min_freq = find_available_min_freq(devfreq); devfreq->scaling_min_freq = find_available_min_freq(devfreq);
if (!devfreq->scaling_min_freq) { if (!devfreq->scaling_min_freq)
mutex_unlock(&devfreq->lock); goto out;
return -EINVAL;
}
devfreq->scaling_max_freq = find_available_max_freq(devfreq); devfreq->scaling_max_freq = find_available_max_freq(devfreq);
if (!devfreq->scaling_max_freq) { if (!devfreq->scaling_max_freq) {
mutex_unlock(&devfreq->lock); devfreq->scaling_max_freq = ULONG_MAX;
return -EINVAL; goto out;
} }
ret = update_devfreq(devfreq); err = update_devfreq(devfreq);
out:
mutex_unlock(&devfreq->lock); mutex_unlock(&devfreq->lock);
if (err)
dev_err(devfreq->dev.parent,
"failed to update frequency from OPP notifier (%d)\n",
err);
return ret; return NOTIFY_OK;
}
/**
* 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 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, ...@@ -599,16 +684,36 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
static void devfreq_dev_release(struct device *dev) static void devfreq_dev_release(struct device *dev)
{ {
struct devfreq *devfreq = to_devfreq(dev); struct devfreq *devfreq = to_devfreq(dev);
int err;
mutex_lock(&devfreq_list_lock); 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); list_del(&devfreq->node);
mutex_unlock(&devfreq_list_lock); 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) if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent); devfreq->profile->exit(devfreq->dev.parent);
...@@ -660,6 +765,7 @@ struct devfreq *devfreq_add_device(struct device *dev, ...@@ -660,6 +765,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq->dev.parent = dev; devfreq->dev.parent = dev;
devfreq->dev.class = devfreq_class; devfreq->dev.class = devfreq_class;
devfreq->dev.release = devfreq_dev_release; devfreq->dev.release = devfreq_dev_release;
INIT_LIST_HEAD(&devfreq->node);
devfreq->profile = profile; devfreq->profile = profile;
strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN); strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
devfreq->previous_freq = profile->initial_freq; devfreq->previous_freq = profile->initial_freq;
...@@ -681,7 +787,6 @@ struct devfreq *devfreq_add_device(struct device *dev, ...@@ -681,7 +787,6 @@ struct devfreq *devfreq_add_device(struct device *dev,
err = -EINVAL; err = -EINVAL;
goto err_dev; goto err_dev;
} }
devfreq->min_freq = devfreq->scaling_min_freq;
devfreq->scaling_max_freq = find_available_max_freq(devfreq); devfreq->scaling_max_freq = find_available_max_freq(devfreq);
if (!devfreq->scaling_max_freq) { if (!devfreq->scaling_max_freq) {
...@@ -689,7 +794,6 @@ struct devfreq *devfreq_add_device(struct device *dev, ...@@ -689,7 +794,6 @@ struct devfreq *devfreq_add_device(struct device *dev,
err = -EINVAL; err = -EINVAL;
goto err_dev; goto err_dev;
} }
devfreq->max_freq = devfreq->scaling_max_freq;
devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev); devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
atomic_set(&devfreq->suspend_count, 0); atomic_set(&devfreq->suspend_count, 0);
...@@ -730,6 +834,28 @@ struct devfreq *devfreq_add_device(struct device *dev, ...@@ -730,6 +834,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
mutex_unlock(&devfreq->lock); 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); mutex_lock(&devfreq_list_lock);
governor = try_then_request_governor(devfreq->governor_name); 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, ...@@ -1303,41 +1429,37 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
unsigned long value; unsigned long value;
int ret; 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); ret = sscanf(buf, "%lu", &value);
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
mutex_lock(&df->lock); /* Round down to kHz for PM QoS */
ret = dev_pm_qos_update_request(&df->user_min_freq_req,
if (value) { value / HZ_PER_KHZ);
if (value > df->max_freq) { if (ret < 0)
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 ret;
return count;
} }
static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct devfreq *df = to_devfreq(dev); 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, 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, ...@@ -1347,33 +1469,37 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
unsigned long value; unsigned long value;
int ret; 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); ret = sscanf(buf, "%lu", &value);
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
mutex_lock(&df->lock); /*
* PM QoS frequencies are in kHz so we need to convert. Convert by
if (value) { * rounding upwards so that the acceptable interval never shrinks.
if (value < df->min_freq) { *
ret = -EINVAL; * For example if the user writes "666666666" to sysfs this value will
goto unlock; * be converted to 666667 kHz and back to 666667000 Hz before an OPP
} * lookup, this ensures that an OPP of 666666666Hz is still accepted.
} else { *
unsigned long *freq_table = df->profile->freq_table; * A value of zero means "no limit".
*/
/* Get maximum frequency according to sorting order */ if (value)
if (freq_table[0] < freq_table[df->profile->max_state - 1]) value = DIV_ROUND_UP(value, HZ_PER_KHZ);
value = freq_table[df->profile->max_state - 1];
else else
value = freq_table[0]; value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
}
df->max_freq = value; ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
update_devfreq(df); if (ret < 0)
ret = count;
unlock:
mutex_unlock(&df->lock);
return ret; return ret;
return count;
} }
static DEVICE_ATTR_RW(min_freq); static DEVICE_ATTR_RW(min_freq);
...@@ -1381,8 +1507,13 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, ...@@ -1381,8 +1507,13 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct devfreq *df = to_devfreq(dev); 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); static DEVICE_ATTR_RW(max_freq);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/pm_qos.h>
#define DEVFREQ_NAME_LEN 16 #define DEVFREQ_NAME_LEN 16
...@@ -123,8 +124,8 @@ struct devfreq_dev_profile { ...@@ -123,8 +124,8 @@ struct devfreq_dev_profile {
* @previous_freq: previously configured frequency value. * @previous_freq: previously configured frequency value.
* @data: Private data of the governor. The devfreq framework does not * @data: Private data of the governor. The devfreq framework does not
* touch this. * touch this.
* @min_freq: Limit minimum frequency requested by user (0: none) * @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs)
* @max_freq: Limit maximum frequency requested by user (0: none) * @user_max_freq_req: PM QoS maximum frequency request from user (via sysfs)
* @scaling_min_freq: Limit minimum frequency requested by OPP interface * @scaling_min_freq: Limit minimum frequency requested by OPP interface
* @scaling_max_freq: Limit maximum frequency requested by OPP interface * @scaling_max_freq: Limit maximum frequency requested by OPP interface
* @stop_polling: devfreq polling status of a device. * @stop_polling: devfreq polling status of a device.
...@@ -136,6 +137,8 @@ struct devfreq_dev_profile { ...@@ -136,6 +137,8 @@ struct devfreq_dev_profile {
* @time_in_state: Statistics of devfreq states * @time_in_state: Statistics of devfreq states
* @last_stat_updated: The last time stat updated * @last_stat_updated: The last time stat updated
* @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier * @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. * This structure stores the devfreq information for a give device.
* *
...@@ -161,8 +164,8 @@ struct devfreq { ...@@ -161,8 +164,8 @@ struct devfreq {
void *data; /* private data for governors */ void *data; /* private data for governors */
unsigned long min_freq; struct dev_pm_qos_request user_min_freq_req;
unsigned long max_freq; struct dev_pm_qos_request user_max_freq_req;
unsigned long scaling_min_freq; unsigned long scaling_min_freq;
unsigned long scaling_max_freq; unsigned long scaling_max_freq;
bool stop_polling; bool stop_polling;
...@@ -178,6 +181,9 @@ struct devfreq { ...@@ -178,6 +181,9 @@ struct devfreq {
unsigned long last_stat_updated; unsigned long last_stat_updated;
struct srcu_notifier_head transition_notifier_list; struct srcu_notifier_head transition_notifier_list;
struct notifier_block nb_min;
struct notifier_block nb_max;
}; };
struct devfreq_freqs { struct devfreq_freqs {
......
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