Skip to content

Commit 27dbc54

Browse files
cdleonardchanwoochoi
authored andcommitted
PM / devfreq: Use PM QoS for sysfs min/max_freq
Switch the handling of min_freq and max_freq from sysfs to use the dev_pm_qos_request interface. Since PM QoS handles frequencies as kHz this change reduces the precision of min_freq and max_freq. This shouldn't introduce problems because frequencies which are not an integer number of kHz are likely not an integer number of Hz either. Try to ensure compatibility by rounding min values down and rounding max values up. Signed-off-by: Leonard Crestez <[email protected]> Acked-by: Chanwoo Choi <[email protected]> Reviewed-by: Matthias Kaehlcke <[email protected]> Tested-by: Matthias Kaehlcke <[email protected]> [cw00.choi: Return -EAGAIN instead of -EINVAL if dev_pm_qos is inactive] Signed-off-by: Chanwoo Choi <[email protected]>
1 parent 05d7ae1 commit 27dbc54

File tree

2 files changed

+64
-21
lines changed

2 files changed

+64
-21
lines changed

drivers/devfreq/devfreq.c

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,6 @@ static void get_freq_range(struct devfreq *devfreq,
141141
*max_freq = min(*max_freq,
142142
(unsigned long)HZ_PER_KHZ * qos_max_freq);
143143

144-
/* Apply constraints from sysfs */
145-
*min_freq = max(*min_freq, devfreq->min_freq);
146-
*max_freq = min(*max_freq, devfreq->max_freq);
147-
148144
/* Apply constraints from OPP interface */
149145
*min_freq = max(*min_freq, devfreq->scaling_min_freq);
150146
*max_freq = min(*max_freq, devfreq->scaling_max_freq);
@@ -705,6 +701,19 @@ static void devfreq_dev_release(struct device *dev)
705701
dev_warn(dev->parent,
706702
"Failed to remove min_freq notifier: %d\n", err);
707703

704+
if (dev_pm_qos_request_active(&devfreq->user_max_freq_req)) {
705+
err = dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
706+
if (err)
707+
dev_warn(dev->parent,
708+
"Failed to remove max_freq request: %d\n", err);
709+
}
710+
if (dev_pm_qos_request_active(&devfreq->user_min_freq_req)) {
711+
err = dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
712+
if (err)
713+
dev_warn(dev->parent,
714+
"Failed to remove min_freq request: %d\n", err);
715+
}
716+
708717
if (devfreq->profile->exit)
709718
devfreq->profile->exit(devfreq->dev.parent);
710719

@@ -778,15 +787,13 @@ struct devfreq *devfreq_add_device(struct device *dev,
778787
err = -EINVAL;
779788
goto err_dev;
780789
}
781-
devfreq->min_freq = devfreq->scaling_min_freq;
782790

783791
devfreq->scaling_max_freq = find_available_max_freq(devfreq);
784792
if (!devfreq->scaling_max_freq) {
785793
mutex_unlock(&devfreq->lock);
786794
err = -EINVAL;
787795
goto err_dev;
788796
}
789-
devfreq->max_freq = devfreq->scaling_max_freq;
790797

791798
devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
792799
atomic_set(&devfreq->suspend_count, 0);
@@ -827,6 +834,16 @@ struct devfreq *devfreq_add_device(struct device *dev,
827834

828835
mutex_unlock(&devfreq->lock);
829836

837+
err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
838+
DEV_PM_QOS_MIN_FREQUENCY, 0);
839+
if (err < 0)
840+
goto err_devfreq;
841+
err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
842+
DEV_PM_QOS_MAX_FREQUENCY,
843+
PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
844+
if (err < 0)
845+
goto err_devfreq;
846+
830847
devfreq->nb_min.notifier_call = qos_min_notifier_call;
831848
err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
832849
DEV_PM_QOS_MIN_FREQUENCY);
@@ -1412,14 +1429,22 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
14121429
unsigned long value;
14131430
int ret;
14141431

1432+
/*
1433+
* Protect against theoretical sysfs writes between
1434+
* device_add and dev_pm_qos_add_request
1435+
*/
1436+
if (!dev_pm_qos_request_active(&df->user_min_freq_req))
1437+
return -EAGAIN;
1438+
14151439
ret = sscanf(buf, "%lu", &value);
14161440
if (ret != 1)
14171441
return -EINVAL;
14181442

1419-
mutex_lock(&df->lock);
1420-
df->min_freq = value;
1421-
update_devfreq(df);
1422-
mutex_unlock(&df->lock);
1443+
/* Round down to kHz for PM QoS */
1444+
ret = dev_pm_qos_update_request(&df->user_min_freq_req,
1445+
value / HZ_PER_KHZ);
1446+
if (ret < 0)
1447+
return ret;
14231448

14241449
return count;
14251450
}
@@ -1444,18 +1469,35 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
14441469
unsigned long value;
14451470
int ret;
14461471

1472+
/*
1473+
* Protect against theoretical sysfs writes between
1474+
* device_add and dev_pm_qos_add_request
1475+
*/
1476+
if (!dev_pm_qos_request_active(&df->user_max_freq_req))
1477+
return -EINVAL;
1478+
14471479
ret = sscanf(buf, "%lu", &value);
14481480
if (ret != 1)
14491481
return -EINVAL;
14501482

1451-
mutex_lock(&df->lock);
1452-
1453-
if (!value)
1454-
value = ULONG_MAX;
1483+
/*
1484+
* PM QoS frequencies are in kHz so we need to convert. Convert by
1485+
* rounding upwards so that the acceptable interval never shrinks.
1486+
*
1487+
* For example if the user writes "666666666" to sysfs this value will
1488+
* be converted to 666667 kHz and back to 666667000 Hz before an OPP
1489+
* lookup, this ensures that an OPP of 666666666Hz is still accepted.
1490+
*
1491+
* A value of zero means "no limit".
1492+
*/
1493+
if (value)
1494+
value = DIV_ROUND_UP(value, HZ_PER_KHZ);
1495+
else
1496+
value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
14551497

1456-
df->max_freq = value;
1457-
update_devfreq(df);
1458-
mutex_unlock(&df->lock);
1498+
ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
1499+
if (ret < 0)
1500+
return ret;
14591501

14601502
return count;
14611503
}

include/linux/devfreq.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/device.h>
1414
#include <linux/notifier.h>
1515
#include <linux/pm_opp.h>
16+
#include <linux/pm_qos.h>
1617

1718
#define DEVFREQ_NAME_LEN 16
1819

@@ -123,8 +124,8 @@ struct devfreq_dev_profile {
123124
* @previous_freq: previously configured frequency value.
124125
* @data: Private data of the governor. The devfreq framework does not
125126
* touch this.
126-
* @min_freq: Limit minimum frequency requested by user (0: none)
127-
* @max_freq: Limit maximum frequency requested by user (0: none)
127+
* @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs)
128+
* @user_max_freq_req: PM QoS maximum frequency request from user (via sysfs)
128129
* @scaling_min_freq: Limit minimum frequency requested by OPP interface
129130
* @scaling_max_freq: Limit maximum frequency requested by OPP interface
130131
* @stop_polling: devfreq polling status of a device.
@@ -163,8 +164,8 @@ struct devfreq {
163164

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

166-
unsigned long min_freq;
167-
unsigned long max_freq;
167+
struct dev_pm_qos_request user_min_freq_req;
168+
struct dev_pm_qos_request user_max_freq_req;
168169
unsigned long scaling_min_freq;
169170
unsigned long scaling_max_freq;
170171
bool stop_polling;

0 commit comments

Comments
 (0)