From: Matthias Kaehlcke <mka@chromium.org>
To: Leonard Crestez <leonard.crestez@nxp.com>
Cc: "MyungJoo Ham" <myungjoo.ham@samsung.com>,
"Kyungmin Park" <kyungmin.park@samsung.com>,
"Chanwoo Choi" <cw00.choi@samsung.com>,
"Artur Świgoń" <a.swigon@partner.samsung.com>,
"Saravana Kannan" <saravanak@google.com>,
"Krzysztof Kozlowski" <krzk@kernel.org>,
"Alexandre Bailon" <abailon@baylibre.com>,
"Georgi Djakov" <georgi.djakov@linaro.org>,
"Abel Vesa" <abel.vesa@nxp.com>, "Jacky Bai" <ping.bai@nxp.com>,
"Viresh Kumar" <viresh.kumar@linaro.org>,
linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 5/8] PM / devfreq: Introduce devfreq_get_freq_range
Date: Thu, 19 Sep 2019 11:07:22 -0700 [thread overview]
Message-ID: <20190919180722.GT133864@google.com> (raw)
In-Reply-To: <730613d6f7182c6a6784fd509d6324f28be2cac3.1568764439.git.leonard.crestez@nxp.com>
Hi Leonard,
On Wed, Sep 18, 2019 at 03:18:24AM +0300, Leonard Crestez wrote:
> 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: Leonard Crestez <leonard.crestez@nxp.com>
> ---
> drivers/devfreq/devfreq.c | 111 +++++++++++++++++++++-----------------
> 1 file changed, 63 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 860cbbab476c..51a4179e2c69 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -24,10 +24,12 @@
> #include <linux/printk.h>
> #include <linux/hrtimer.h>
> #include <linux/of.h>
> #include "governor.h"
>
> +#define HZ_PER_KHZ 1000
> +
> #define CREATE_TRACE_POINTS
> #include <trace/events/devfreq.h>
>
> static struct class *devfreq_class;
>
> @@ -96,10 +98,50 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
> dev_pm_opp_put(opp);
>
> return max_freq;
> }
>
> +/**
> + * devfreq_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 devfreq_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);
> +
> + /* Init min/max frequency from freq table */
> + 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];
> + }
> +
> + /* constraints from sysfs: */
> + *min_freq = max(*min_freq, devfreq->min_freq);
> + *max_freq = min(*max_freq, devfreq->max_freq);
> +
> + /* constraints from opp interface: */
nit: OPP
> + *min_freq = max(*min_freq, devfreq->scaling_min_freq);
> + /* scaling_max_freq can be zero on error */
> + if (devfreq->scaling_max_freq)
> + *max_freq = min(*max_freq, devfreq->scaling_max_freq);
> +
> + /* max_freq takes precedence over min_freq */
> + if (*min_freq > *max_freq)
> + *min_freq = *max_freq;
> +}
> +
> /**
> * devfreq_get_freq_level() - Lookup freq_table for the frequency
> * @devfreq: the devfreq instance
> * @freq: the target frequency
> */
> @@ -349,21 +391,13 @@ int update_devfreq(struct devfreq *devfreq)
>
> /* Reevaluate the proper frequency */
> err = devfreq->governor->get_target_freq(devfreq, &freq);
> if (err)
> return err;
> + devfreq_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);
> -
> + /* max freq takes priority over min freq */
> if (freq < min_freq) {
> freq = min_freq;
> flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
> }
> if (freq > max_freq) {
> @@ -1293,40 +1327,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
> 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);
> - 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);
> + devfreq_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,
> const char *buf, size_t count)
> {
> @@ -1338,40 +1360,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
> 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];
> - else
> - value = freq_table[0];
> - }
> + /* Interpret zero as "don't care" */
> + 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);
>
> 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);
> + devfreq_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 ssize_t available_frequencies_show(struct device *d,
> struct device_attribute *attr,
Nice, having the constraint evaluation in a single function makes it
easier to follow the code. Clamping userspace constraints at runtime
makes sense.
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
I plan to take a look at the rest of the series, but probably won't
find time for all of it before next week.
WARNING: multiple messages have this Message-ID (diff)
From: Matthias Kaehlcke <mka@chromium.org>
To: Leonard Crestez <leonard.crestez@nxp.com>
Cc: "Artur Świgoń" <a.swigon@partner.samsung.com>,
"Abel Vesa" <abel.vesa@nxp.com>,
"Saravana Kannan" <saravanak@google.com>,
linux-pm@vger.kernel.org,
"Viresh Kumar" <viresh.kumar@linaro.org>,
"Krzysztof Kozlowski" <krzk@kernel.org>,
"Chanwoo Choi" <cw00.choi@samsung.com>,
"Kyungmin Park" <kyungmin.park@samsung.com>,
"MyungJoo Ham" <myungjoo.ham@samsung.com>,
"Alexandre Bailon" <abailon@baylibre.com>,
"Georgi Djakov" <georgi.djakov@linaro.org>,
linux-arm-kernel@lists.infradead.org,
"Jacky Bai" <ping.bai@nxp.com>
Subject: Re: [PATCH 5/8] PM / devfreq: Introduce devfreq_get_freq_range
Date: Thu, 19 Sep 2019 11:07:22 -0700 [thread overview]
Message-ID: <20190919180722.GT133864@google.com> (raw)
In-Reply-To: <730613d6f7182c6a6784fd509d6324f28be2cac3.1568764439.git.leonard.crestez@nxp.com>
Hi Leonard,
On Wed, Sep 18, 2019 at 03:18:24AM +0300, Leonard Crestez wrote:
> 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: Leonard Crestez <leonard.crestez@nxp.com>
> ---
> drivers/devfreq/devfreq.c | 111 +++++++++++++++++++++-----------------
> 1 file changed, 63 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 860cbbab476c..51a4179e2c69 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -24,10 +24,12 @@
> #include <linux/printk.h>
> #include <linux/hrtimer.h>
> #include <linux/of.h>
> #include "governor.h"
>
> +#define HZ_PER_KHZ 1000
> +
> #define CREATE_TRACE_POINTS
> #include <trace/events/devfreq.h>
>
> static struct class *devfreq_class;
>
> @@ -96,10 +98,50 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
> dev_pm_opp_put(opp);
>
> return max_freq;
> }
>
> +/**
> + * devfreq_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 devfreq_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);
> +
> + /* Init min/max frequency from freq table */
> + 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];
> + }
> +
> + /* constraints from sysfs: */
> + *min_freq = max(*min_freq, devfreq->min_freq);
> + *max_freq = min(*max_freq, devfreq->max_freq);
> +
> + /* constraints from opp interface: */
nit: OPP
> + *min_freq = max(*min_freq, devfreq->scaling_min_freq);
> + /* scaling_max_freq can be zero on error */
> + if (devfreq->scaling_max_freq)
> + *max_freq = min(*max_freq, devfreq->scaling_max_freq);
> +
> + /* max_freq takes precedence over min_freq */
> + if (*min_freq > *max_freq)
> + *min_freq = *max_freq;
> +}
> +
> /**
> * devfreq_get_freq_level() - Lookup freq_table for the frequency
> * @devfreq: the devfreq instance
> * @freq: the target frequency
> */
> @@ -349,21 +391,13 @@ int update_devfreq(struct devfreq *devfreq)
>
> /* Reevaluate the proper frequency */
> err = devfreq->governor->get_target_freq(devfreq, &freq);
> if (err)
> return err;
> + devfreq_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);
> -
> + /* max freq takes priority over min freq */
> if (freq < min_freq) {
> freq = min_freq;
> flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
> }
> if (freq > max_freq) {
> @@ -1293,40 +1327,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
> 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);
> - 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);
> + devfreq_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,
> const char *buf, size_t count)
> {
> @@ -1338,40 +1360,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
> 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];
> - else
> - value = freq_table[0];
> - }
> + /* Interpret zero as "don't care" */
> + 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);
>
> 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);
> + devfreq_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 ssize_t available_frequencies_show(struct device *d,
> struct device_attribute *attr,
Nice, having the constraint evaluation in a single function makes it
easier to follow the code. Clamping userspace constraints at runtime
makes sense.
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
I plan to take a look at the rest of the series, but probably won't
find time for all of it before next week.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2019-09-19 18:07 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-09-18 0:18 [PATCH 0/8] PM / devfreq: Add dev_pm_qos support Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-18 0:18 ` [PATCH 1/8] PM / devfreq: Lock devfreq in trans_stat_show Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-18 21:28 ` Matthias Kaehlcke
2019-09-18 21:28 ` Matthias Kaehlcke
2019-09-19 18:42 ` Leonard Crestez
2019-09-19 18:42 ` Leonard Crestez
2019-09-19 19:25 ` Matthias Kaehlcke
2019-09-19 19:25 ` Matthias Kaehlcke
2019-09-18 0:18 ` [PATCH 2/8] PM / devfreq: Don't fail devfreq_dev_release if not in list Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-18 21:41 ` Matthias Kaehlcke
2019-09-18 21:41 ` Matthias Kaehlcke
2019-09-18 0:18 ` [PATCH 3/8] PM / devfreq: Move more initialization before registration Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-18 23:29 ` Matthias Kaehlcke
2019-09-18 23:29 ` Matthias Kaehlcke
2019-09-19 0:14 ` Matthias Kaehlcke
2019-09-19 0:14 ` Matthias Kaehlcke
2019-09-19 18:52 ` Leonard Crestez
2019-09-19 18:52 ` Leonard Crestez
2019-09-19 19:16 ` Matthias Kaehlcke
2019-09-19 19:16 ` Matthias Kaehlcke
2019-09-18 0:18 ` [PATCH 4/8] PM / devfreq: Don't take lock in devfreq_add_device Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-19 0:20 ` Matthias Kaehlcke
2019-09-19 0:20 ` Matthias Kaehlcke
2019-09-18 0:18 ` [PATCH 5/8] PM / devfreq: Introduce devfreq_get_freq_range Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-19 18:07 ` Matthias Kaehlcke [this message]
2019-09-19 18:07 ` Matthias Kaehlcke
2019-09-18 0:18 ` [PATCH 6/8] PM / devfreq: Add dev_pm_qos support Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-19 19:12 ` Matthias Kaehlcke
2019-09-19 19:12 ` Matthias Kaehlcke
2019-09-18 0:18 ` [PATCH 7/8] PM / devfreq: Use dev_pm_qos for sysfs min/max_freq Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-19 19:59 ` Matthias Kaehlcke
2019-09-19 19:59 ` Matthias Kaehlcke
2019-09-20 13:50 ` Leonard Crestez
2019-09-20 13:50 ` Leonard Crestez
2019-09-18 0:18 ` [PATCH 8/8] PM / devfreq: Move opp notifier registration to core Leonard Crestez
2019-09-18 0:18 ` Leonard Crestez
2019-09-30 21:49 ` Chanwoo Choi
2019-09-30 21:49 ` Chanwoo Choi
2019-10-01 15:14 ` Leonard Crestez
2019-10-01 15:14 ` Leonard Crestez
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190919180722.GT133864@google.com \
--to=mka@chromium.org \
--cc=a.swigon@partner.samsung.com \
--cc=abailon@baylibre.com \
--cc=abel.vesa@nxp.com \
--cc=cw00.choi@samsung.com \
--cc=georgi.djakov@linaro.org \
--cc=krzk@kernel.org \
--cc=kyungmin.park@samsung.com \
--cc=leonard.crestez@nxp.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-pm@vger.kernel.org \
--cc=myungjoo.ham@samsung.com \
--cc=ping.bai@nxp.com \
--cc=saravanak@google.com \
--cc=viresh.kumar@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.