Merge branch 'pm-devfreq'
* pm-devfreq: (23 commits) PM / devfreq: remove compiler error with module governors (2) PM / devfreq: Fix return value in devfreq_remove_governor() PM / devfreq: Fix incorrect argument in error message PM / devfreq: missing rcu_read_lock() added for find_device_opp() PM / devfreq: remove compiler error when a governor is module PM / devfreq: exynos4_bus.c: Fixed an alignment of the func call args. PM / devfreq: Add sysfs node to expose available governors PM / devfreq: allow sysfs governor node to switch governor PM / devfreq: governors: add GPL module license and allow module build PM / devfreq: map devfreq drivers to governor using name PM / devfreq: register governors with devfreq framework PM / devfreq: provide hooks for governors to be registered PM / devfreq: export update_devfreq PM / devfreq: Add sysfs node for representing frequency transition information. PM / devfreq: Add sysfs node to expose available frequencies PM / devfreq: documentation cleanups for devfreq header PM / devfreq: Use devm_* functions in exynos4_bus.c PM / devfreq: make devfreq_class static PM / devfreq: fix sscanf handling for writable sysfs entries PM / devfreq: kernel-doc typo corrections ...
This commit is contained in:
commit
bf58cdffac
|
@ -11,7 +11,7 @@ What: /sys/class/devfreq/.../governor
|
||||||
Date: September 2011
|
Date: September 2011
|
||||||
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||||
Description:
|
Description:
|
||||||
The /sys/class/devfreq/.../governor shows the name of the
|
The /sys/class/devfreq/.../governor show or set the name of the
|
||||||
governor used by the corresponding devfreq object.
|
governor used by the corresponding devfreq object.
|
||||||
|
|
||||||
What: /sys/class/devfreq/.../cur_freq
|
What: /sys/class/devfreq/.../cur_freq
|
||||||
|
@ -19,15 +19,16 @@ Date: September 2011
|
||||||
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||||
Description:
|
Description:
|
||||||
The /sys/class/devfreq/.../cur_freq shows the current
|
The /sys/class/devfreq/.../cur_freq shows the current
|
||||||
frequency of the corresponding devfreq object.
|
frequency of the corresponding devfreq object. Same as
|
||||||
|
target_freq when get_cur_freq() is not implemented by
|
||||||
|
devfreq driver.
|
||||||
|
|
||||||
What: /sys/class/devfreq/.../central_polling
|
What: /sys/class/devfreq/.../target_freq
|
||||||
Date: September 2011
|
Date: September 2012
|
||||||
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
Contact: Rajagopal Venkat <rajagopal.venkat@linaro.org>
|
||||||
Description:
|
Description:
|
||||||
The /sys/class/devfreq/.../central_polling shows whether
|
The /sys/class/devfreq/.../target_freq shows the next governor
|
||||||
the devfreq ojbect is using devfreq-provided central
|
predicted target frequency of the corresponding devfreq object.
|
||||||
polling mechanism or not.
|
|
||||||
|
|
||||||
What: /sys/class/devfreq/.../polling_interval
|
What: /sys/class/devfreq/.../polling_interval
|
||||||
Date: September 2011
|
Date: September 2011
|
||||||
|
@ -43,6 +44,17 @@ Description:
|
||||||
(/sys/class/devfreq/.../central_polling is 0), this value
|
(/sys/class/devfreq/.../central_polling is 0), this value
|
||||||
may be useless.
|
may be useless.
|
||||||
|
|
||||||
|
What: /sys/class/devfreq/.../trans_stat
|
||||||
|
Date: October 2012
|
||||||
|
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||||
|
Descrtiption:
|
||||||
|
This ABI shows the statistics of devfreq behavior on a
|
||||||
|
specific device. It shows the time spent in each state and
|
||||||
|
the number of transitions between states.
|
||||||
|
In order to activate this ABI, the devfreq target device
|
||||||
|
driver should provide the list of available frequencies
|
||||||
|
with its profile.
|
||||||
|
|
||||||
What: /sys/class/devfreq/.../userspace/set_freq
|
What: /sys/class/devfreq/.../userspace/set_freq
|
||||||
Date: September 2011
|
Date: September 2011
|
||||||
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||||
|
@ -50,3 +62,19 @@ Description:
|
||||||
The /sys/class/devfreq/.../userspace/set_freq shows and
|
The /sys/class/devfreq/.../userspace/set_freq shows and
|
||||||
sets the requested frequency for the devfreq object if
|
sets the requested frequency for the devfreq object if
|
||||||
userspace governor is in effect.
|
userspace governor is in effect.
|
||||||
|
|
||||||
|
What: /sys/class/devfreq/.../available_frequencies
|
||||||
|
Date: October 2012
|
||||||
|
Contact: Nishanth Menon <nm@ti.com>
|
||||||
|
Description:
|
||||||
|
The /sys/class/devfreq/.../available_frequencies shows
|
||||||
|
the available frequencies of the corresponding devfreq object.
|
||||||
|
This is a snapshot of available frequencies and not limited
|
||||||
|
by the min/max frequency restrictions.
|
||||||
|
|
||||||
|
What: /sys/class/devfreq/.../available_governors
|
||||||
|
Date: October 2012
|
||||||
|
Contact: Nishanth Menon <nm@ti.com>
|
||||||
|
Description:
|
||||||
|
The /sys/class/devfreq/.../available_governors shows
|
||||||
|
currently available governors in the system.
|
||||||
|
|
|
@ -30,7 +30,7 @@ if PM_DEVFREQ
|
||||||
comment "DEVFREQ Governors"
|
comment "DEVFREQ Governors"
|
||||||
|
|
||||||
config DEVFREQ_GOV_SIMPLE_ONDEMAND
|
config DEVFREQ_GOV_SIMPLE_ONDEMAND
|
||||||
bool "Simple Ondemand"
|
tristate "Simple Ondemand"
|
||||||
help
|
help
|
||||||
Chooses frequency based on the recent load on the device. Works
|
Chooses frequency based on the recent load on the device. Works
|
||||||
similar as ONDEMAND governor of CPUFREQ does. A device with
|
similar as ONDEMAND governor of CPUFREQ does. A device with
|
||||||
|
@ -39,7 +39,7 @@ config DEVFREQ_GOV_SIMPLE_ONDEMAND
|
||||||
values to the governor with data field at devfreq_add_device().
|
values to the governor with data field at devfreq_add_device().
|
||||||
|
|
||||||
config DEVFREQ_GOV_PERFORMANCE
|
config DEVFREQ_GOV_PERFORMANCE
|
||||||
bool "Performance"
|
tristate "Performance"
|
||||||
help
|
help
|
||||||
Sets the frequency at the maximum available frequency.
|
Sets the frequency at the maximum available frequency.
|
||||||
This governor always returns UINT_MAX as frequency so that
|
This governor always returns UINT_MAX as frequency so that
|
||||||
|
@ -47,7 +47,7 @@ config DEVFREQ_GOV_PERFORMANCE
|
||||||
at any time.
|
at any time.
|
||||||
|
|
||||||
config DEVFREQ_GOV_POWERSAVE
|
config DEVFREQ_GOV_POWERSAVE
|
||||||
bool "Powersave"
|
tristate "Powersave"
|
||||||
help
|
help
|
||||||
Sets the frequency at the minimum available frequency.
|
Sets the frequency at the minimum available frequency.
|
||||||
This governor always returns 0 as frequency so that
|
This governor always returns 0 as frequency so that
|
||||||
|
@ -55,7 +55,7 @@ config DEVFREQ_GOV_POWERSAVE
|
||||||
at any time.
|
at any time.
|
||||||
|
|
||||||
config DEVFREQ_GOV_USERSPACE
|
config DEVFREQ_GOV_USERSPACE
|
||||||
bool "Userspace"
|
tristate "Userspace"
|
||||||
help
|
help
|
||||||
Sets the frequency at the user specified one.
|
Sets the frequency at the user specified one.
|
||||||
This governor returns the user configured frequency if there
|
This governor returns the user configured frequency if there
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -987,7 +987,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
data = kzalloc(sizeof(struct busfreq_data), GFP_KERNEL);
|
data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data), GFP_KERNEL);
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
dev_err(dev, "Cannot allocate memory.\n");
|
dev_err(dev, "Cannot allocate memory.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1012,31 +1012,26 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
}
|
}
|
||||||
if (err)
|
if (err)
|
||||||
goto err_regulator;
|
return err;
|
||||||
|
|
||||||
data->vdd_int = regulator_get(dev, "vdd_int");
|
data->vdd_int = devm_regulator_get(dev, "vdd_int");
|
||||||
if (IS_ERR(data->vdd_int)) {
|
if (IS_ERR(data->vdd_int)) {
|
||||||
dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
|
dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
|
||||||
err = PTR_ERR(data->vdd_int);
|
return PTR_ERR(data->vdd_int);
|
||||||
goto err_regulator;
|
|
||||||
}
|
}
|
||||||
if (data->type == TYPE_BUSF_EXYNOS4x12) {
|
if (data->type == TYPE_BUSF_EXYNOS4x12) {
|
||||||
data->vdd_mif = regulator_get(dev, "vdd_mif");
|
data->vdd_mif = devm_regulator_get(dev, "vdd_mif");
|
||||||
if (IS_ERR(data->vdd_mif)) {
|
if (IS_ERR(data->vdd_mif)) {
|
||||||
dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
|
dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
|
||||||
err = PTR_ERR(data->vdd_mif);
|
return PTR_ERR(data->vdd_mif);
|
||||||
regulator_put(data->vdd_int);
|
|
||||||
goto err_regulator;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq);
|
opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
dev_err(dev, "Invalid initial frequency %lu kHz.\n",
|
dev_err(dev, "Invalid initial frequency %lu kHz.\n",
|
||||||
exynos4_devfreq_profile.initial_freq);
|
exynos4_devfreq_profile.initial_freq);
|
||||||
err = PTR_ERR(opp);
|
return PTR_ERR(opp);
|
||||||
goto err_opp_add;
|
|
||||||
}
|
}
|
||||||
data->curr_opp = opp;
|
data->curr_opp = opp;
|
||||||
|
|
||||||
|
@ -1045,30 +1040,20 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
|
||||||
busfreq_mon_reset(data);
|
busfreq_mon_reset(data);
|
||||||
|
|
||||||
data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
|
data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
|
||||||
&devfreq_simple_ondemand, NULL);
|
"simple_ondemand", NULL);
|
||||||
if (IS_ERR(data->devfreq)) {
|
if (IS_ERR(data->devfreq))
|
||||||
err = PTR_ERR(data->devfreq);
|
return PTR_ERR(data->devfreq);
|
||||||
goto err_opp_add;
|
|
||||||
}
|
|
||||||
|
|
||||||
devfreq_register_opp_notifier(dev, data->devfreq);
|
devfreq_register_opp_notifier(dev, data->devfreq);
|
||||||
|
|
||||||
err = register_pm_notifier(&data->pm_notifier);
|
err = register_pm_notifier(&data->pm_notifier);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(dev, "Failed to setup pm notifier\n");
|
dev_err(dev, "Failed to setup pm notifier\n");
|
||||||
goto err_devfreq_add;
|
devfreq_remove_device(data->devfreq);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err_devfreq_add:
|
|
||||||
devfreq_remove_device(data->devfreq);
|
|
||||||
err_opp_add:
|
|
||||||
if (data->vdd_mif)
|
|
||||||
regulator_put(data->vdd_mif);
|
|
||||||
regulator_put(data->vdd_int);
|
|
||||||
err_regulator:
|
|
||||||
kfree(data);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static __devexit int exynos4_busfreq_remove(struct platform_device *pdev)
|
static __devexit int exynos4_busfreq_remove(struct platform_device *pdev)
|
||||||
|
@ -1077,10 +1062,6 @@ static __devexit int exynos4_busfreq_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
unregister_pm_notifier(&data->pm_notifier);
|
unregister_pm_notifier(&data->pm_notifier);
|
||||||
devfreq_remove_device(data->devfreq);
|
devfreq_remove_device(data->devfreq);
|
||||||
regulator_put(data->vdd_int);
|
|
||||||
if (data->vdd_mif)
|
|
||||||
regulator_put(data->vdd_mif);
|
|
||||||
kfree(data);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,24 @@
|
||||||
|
|
||||||
#define to_devfreq(DEV) container_of((DEV), struct devfreq, dev)
|
#define to_devfreq(DEV) container_of((DEV), struct devfreq, dev)
|
||||||
|
|
||||||
|
/* Devfreq events */
|
||||||
|
#define DEVFREQ_GOV_START 0x1
|
||||||
|
#define DEVFREQ_GOV_STOP 0x2
|
||||||
|
#define DEVFREQ_GOV_INTERVAL 0x3
|
||||||
|
#define DEVFREQ_GOV_SUSPEND 0x4
|
||||||
|
#define DEVFREQ_GOV_RESUME 0x5
|
||||||
|
|
||||||
/* Caution: devfreq->lock must be locked before calling update_devfreq */
|
/* Caution: devfreq->lock must be locked before calling update_devfreq */
|
||||||
extern int update_devfreq(struct devfreq *devfreq);
|
extern int update_devfreq(struct devfreq *devfreq);
|
||||||
|
|
||||||
|
extern void devfreq_monitor_start(struct devfreq *devfreq);
|
||||||
|
extern void devfreq_monitor_stop(struct devfreq *devfreq);
|
||||||
|
extern void devfreq_monitor_suspend(struct devfreq *devfreq);
|
||||||
|
extern void devfreq_monitor_resume(struct devfreq *devfreq);
|
||||||
|
extern void devfreq_interval_update(struct devfreq *devfreq,
|
||||||
|
unsigned int *delay);
|
||||||
|
|
||||||
|
extern int devfreq_add_governor(struct devfreq_governor *governor);
|
||||||
|
extern int devfreq_remove_governor(struct devfreq_governor *governor);
|
||||||
|
|
||||||
#endif /* _GOVERNOR_H */
|
#endif /* _GOVERNOR_H */
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/devfreq.h>
|
#include <linux/devfreq.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include "governor.h"
|
#include "governor.h"
|
||||||
|
|
||||||
static int devfreq_performance_func(struct devfreq *df,
|
static int devfreq_performance_func(struct devfreq *df,
|
||||||
|
@ -26,14 +27,41 @@ static int devfreq_performance_func(struct devfreq *df,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int performance_init(struct devfreq *devfreq)
|
static int devfreq_performance_handler(struct devfreq *devfreq,
|
||||||
|
unsigned int event, void *data)
|
||||||
{
|
{
|
||||||
return update_devfreq(devfreq);
|
int ret = 0;
|
||||||
|
|
||||||
|
if (event == DEVFREQ_GOV_START) {
|
||||||
|
mutex_lock(&devfreq->lock);
|
||||||
|
ret = update_devfreq(devfreq);
|
||||||
|
mutex_unlock(&devfreq->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct devfreq_governor devfreq_performance = {
|
static struct devfreq_governor devfreq_performance = {
|
||||||
.name = "performance",
|
.name = "performance",
|
||||||
.init = performance_init,
|
|
||||||
.get_target_freq = devfreq_performance_func,
|
.get_target_freq = devfreq_performance_func,
|
||||||
.no_central_polling = true,
|
.event_handler = devfreq_performance_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int __init devfreq_performance_init(void)
|
||||||
|
{
|
||||||
|
return devfreq_add_governor(&devfreq_performance);
|
||||||
|
}
|
||||||
|
subsys_initcall(devfreq_performance_init);
|
||||||
|
|
||||||
|
static void __exit devfreq_performance_exit(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = devfreq_remove_governor(&devfreq_performance);
|
||||||
|
if (ret)
|
||||||
|
pr_err("%s: failed remove governor %d\n", __func__, ret);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
module_exit(devfreq_performance_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/devfreq.h>
|
#include <linux/devfreq.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include "governor.h"
|
#include "governor.h"
|
||||||
|
|
||||||
static int devfreq_powersave_func(struct devfreq *df,
|
static int devfreq_powersave_func(struct devfreq *df,
|
||||||
|
@ -23,14 +24,41 @@ static int devfreq_powersave_func(struct devfreq *df,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int powersave_init(struct devfreq *devfreq)
|
static int devfreq_powersave_handler(struct devfreq *devfreq,
|
||||||
|
unsigned int event, void *data)
|
||||||
{
|
{
|
||||||
return update_devfreq(devfreq);
|
int ret = 0;
|
||||||
|
|
||||||
|
if (event == DEVFREQ_GOV_START) {
|
||||||
|
mutex_lock(&devfreq->lock);
|
||||||
|
ret = update_devfreq(devfreq);
|
||||||
|
mutex_unlock(&devfreq->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct devfreq_governor devfreq_powersave = {
|
static struct devfreq_governor devfreq_powersave = {
|
||||||
.name = "powersave",
|
.name = "powersave",
|
||||||
.init = powersave_init,
|
|
||||||
.get_target_freq = devfreq_powersave_func,
|
.get_target_freq = devfreq_powersave_func,
|
||||||
.no_central_polling = true,
|
.event_handler = devfreq_powersave_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int __init devfreq_powersave_init(void)
|
||||||
|
{
|
||||||
|
return devfreq_add_governor(&devfreq_powersave);
|
||||||
|
}
|
||||||
|
subsys_initcall(devfreq_powersave_init);
|
||||||
|
|
||||||
|
static void __exit devfreq_powersave_exit(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = devfreq_remove_governor(&devfreq_powersave);
|
||||||
|
if (ret)
|
||||||
|
pr_err("%s: failed remove governor %d\n", __func__, ret);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
module_exit(devfreq_powersave_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -10,8 +10,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include <linux/devfreq.h>
|
#include <linux/devfreq.h>
|
||||||
#include <linux/math64.h>
|
#include <linux/math64.h>
|
||||||
|
#include "governor.h"
|
||||||
|
|
||||||
/* Default constants for DevFreq-Simple-Ondemand (DFSO) */
|
/* Default constants for DevFreq-Simple-Ondemand (DFSO) */
|
||||||
#define DFSO_UPTHRESHOLD (90)
|
#define DFSO_UPTHRESHOLD (90)
|
||||||
|
@ -88,7 +90,58 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct devfreq_governor devfreq_simple_ondemand = {
|
static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
|
||||||
|
unsigned int event, void *data)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case DEVFREQ_GOV_START:
|
||||||
|
devfreq_monitor_start(devfreq);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVFREQ_GOV_STOP:
|
||||||
|
devfreq_monitor_stop(devfreq);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVFREQ_GOV_INTERVAL:
|
||||||
|
devfreq_interval_update(devfreq, (unsigned int *)data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVFREQ_GOV_SUSPEND:
|
||||||
|
devfreq_monitor_suspend(devfreq);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVFREQ_GOV_RESUME:
|
||||||
|
devfreq_monitor_resume(devfreq);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct devfreq_governor devfreq_simple_ondemand = {
|
||||||
.name = "simple_ondemand",
|
.name = "simple_ondemand",
|
||||||
.get_target_freq = devfreq_simple_ondemand_func,
|
.get_target_freq = devfreq_simple_ondemand_func,
|
||||||
|
.event_handler = devfreq_simple_ondemand_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int __init devfreq_simple_ondemand_init(void)
|
||||||
|
{
|
||||||
|
return devfreq_add_governor(&devfreq_simple_ondemand);
|
||||||
|
}
|
||||||
|
subsys_initcall(devfreq_simple_ondemand_init);
|
||||||
|
|
||||||
|
static void __exit devfreq_simple_ondemand_exit(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = devfreq_remove_governor(&devfreq_simple_ondemand);
|
||||||
|
if (ret)
|
||||||
|
pr_err("%s: failed remove governor %d\n", __func__, ret);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
module_exit(devfreq_simple_ondemand_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/devfreq.h>
|
#include <linux/devfreq.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include "governor.h"
|
#include "governor.h"
|
||||||
|
|
||||||
struct userspace_data {
|
struct userspace_data {
|
||||||
|
@ -116,10 +117,46 @@ static void userspace_exit(struct devfreq *devfreq)
|
||||||
devfreq->data = NULL;
|
devfreq->data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct devfreq_governor devfreq_userspace = {
|
static int devfreq_userspace_handler(struct devfreq *devfreq,
|
||||||
|
unsigned int event, void *data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case DEVFREQ_GOV_START:
|
||||||
|
ret = userspace_init(devfreq);
|
||||||
|
break;
|
||||||
|
case DEVFREQ_GOV_STOP:
|
||||||
|
userspace_exit(devfreq);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct devfreq_governor devfreq_userspace = {
|
||||||
.name = "userspace",
|
.name = "userspace",
|
||||||
.get_target_freq = devfreq_userspace_func,
|
.get_target_freq = devfreq_userspace_func,
|
||||||
.init = userspace_init,
|
.event_handler = devfreq_userspace_handler,
|
||||||
.exit = userspace_exit,
|
|
||||||
.no_central_polling = true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int __init devfreq_userspace_init(void)
|
||||||
|
{
|
||||||
|
return devfreq_add_governor(&devfreq_userspace);
|
||||||
|
}
|
||||||
|
subsys_initcall(devfreq_userspace_init);
|
||||||
|
|
||||||
|
static void __exit devfreq_userspace_exit(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = devfreq_remove_governor(&devfreq_userspace);
|
||||||
|
if (ret)
|
||||||
|
pr_err("%s: failed remove governor %d\n", __func__, ret);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
module_exit(devfreq_userspace_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -25,12 +25,12 @@ struct devfreq;
|
||||||
* struct devfreq_dev_status - Data given from devfreq user device to
|
* struct devfreq_dev_status - Data given from devfreq user device to
|
||||||
* governors. Represents the performance
|
* governors. Represents the performance
|
||||||
* statistics.
|
* statistics.
|
||||||
* @total_time The total time represented by this instance of
|
* @total_time: The total time represented by this instance of
|
||||||
* devfreq_dev_status
|
* devfreq_dev_status
|
||||||
* @busy_time The time that the device was working among the
|
* @busy_time: The time that the device was working among the
|
||||||
* total_time.
|
* total_time.
|
||||||
* @current_frequency The operating frequency.
|
* @current_frequency: The operating frequency.
|
||||||
* @private_data An entry not specified by the devfreq framework.
|
* @private_data: An entry not specified by the devfreq framework.
|
||||||
* A device and a specific governor may have their
|
* A device and a specific governor may have their
|
||||||
* own protocol with private_data. However, because
|
* own protocol with private_data. However, because
|
||||||
* this is governor-specific, a governor using this
|
* this is governor-specific, a governor using this
|
||||||
|
@ -54,23 +54,27 @@ struct devfreq_dev_status {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct devfreq_dev_profile - Devfreq's user device profile
|
* struct devfreq_dev_profile - Devfreq's user device profile
|
||||||
* @initial_freq The operating frequency when devfreq_add_device() is
|
* @initial_freq: The operating frequency when devfreq_add_device() is
|
||||||
* called.
|
* called.
|
||||||
* @polling_ms The polling interval in ms. 0 disables polling.
|
* @polling_ms: The polling interval in ms. 0 disables polling.
|
||||||
* @target The device should set its operating frequency at
|
* @target: The device should set its operating frequency at
|
||||||
* freq or lowest-upper-than-freq value. If freq is
|
* freq or lowest-upper-than-freq value. If freq is
|
||||||
* higher than any operable frequency, set maximum.
|
* higher than any operable frequency, set maximum.
|
||||||
* Before returning, target function should set
|
* Before returning, target function should set
|
||||||
* freq at the current frequency.
|
* freq at the current frequency.
|
||||||
* The "flags" parameter's possible values are
|
* The "flags" parameter's possible values are
|
||||||
* explained above with "DEVFREQ_FLAG_*" macros.
|
* explained above with "DEVFREQ_FLAG_*" macros.
|
||||||
* @get_dev_status The device should provide the current performance
|
* @get_dev_status: The device should provide the current performance
|
||||||
* status to devfreq, which is used by governors.
|
* status to devfreq, which is used by governors.
|
||||||
* @exit An optional callback that is called when devfreq
|
* @get_cur_freq: The device should provide the current frequency
|
||||||
|
* at which it is operating.
|
||||||
|
* @exit: An optional callback that is called when devfreq
|
||||||
* is removing the devfreq object due to error or
|
* is removing the devfreq object due to error or
|
||||||
* from devfreq_remove_device() call. If the user
|
* from devfreq_remove_device() call. If the user
|
||||||
* has registered devfreq->nb at a notifier-head,
|
* has registered devfreq->nb at a notifier-head,
|
||||||
* this is the time to unregister it.
|
* this is the time to unregister it.
|
||||||
|
* @freq_table: Optional list of frequencies to support statistics.
|
||||||
|
* @max_state: The size of freq_table.
|
||||||
*/
|
*/
|
||||||
struct devfreq_dev_profile {
|
struct devfreq_dev_profile {
|
||||||
unsigned long initial_freq;
|
unsigned long initial_freq;
|
||||||
|
@ -79,63 +83,63 @@ struct devfreq_dev_profile {
|
||||||
int (*target)(struct device *dev, unsigned long *freq, u32 flags);
|
int (*target)(struct device *dev, unsigned long *freq, u32 flags);
|
||||||
int (*get_dev_status)(struct device *dev,
|
int (*get_dev_status)(struct device *dev,
|
||||||
struct devfreq_dev_status *stat);
|
struct devfreq_dev_status *stat);
|
||||||
|
int (*get_cur_freq)(struct device *dev, unsigned long *freq);
|
||||||
void (*exit)(struct device *dev);
|
void (*exit)(struct device *dev);
|
||||||
|
|
||||||
|
unsigned int *freq_table;
|
||||||
|
unsigned int max_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct devfreq_governor - Devfreq policy governor
|
* struct devfreq_governor - Devfreq policy governor
|
||||||
* @name Governor's name
|
* @node: list node - contains registered devfreq governors
|
||||||
* @get_target_freq Returns desired operating frequency for the device.
|
* @name: Governor's name
|
||||||
|
* @get_target_freq: Returns desired operating frequency for the device.
|
||||||
* Basically, get_target_freq will run
|
* Basically, get_target_freq will run
|
||||||
* devfreq_dev_profile.get_dev_status() to get the
|
* devfreq_dev_profile.get_dev_status() to get the
|
||||||
* status of the device (load = busy_time / total_time).
|
* status of the device (load = busy_time / total_time).
|
||||||
* If no_central_polling is set, this callback is called
|
* If no_central_polling is set, this callback is called
|
||||||
* only with update_devfreq() notified by OPP.
|
* only with update_devfreq() notified by OPP.
|
||||||
* @init Called when the devfreq is being attached to a device
|
* @event_handler: Callback for devfreq core framework to notify events
|
||||||
* @exit Called when the devfreq is being removed from a
|
* to governors. Events include per device governor
|
||||||
* device. Governor should stop any internal routines
|
* init and exit, opp changes out of devfreq, suspend
|
||||||
* before return because related data may be
|
* and resume of per device devfreq during device idle.
|
||||||
* freed after exit().
|
|
||||||
* @no_central_polling Do not use devfreq's central polling mechanism.
|
|
||||||
* When this is set, devfreq will not call
|
|
||||||
* get_target_freq with devfreq_monitor(). However,
|
|
||||||
* devfreq will call get_target_freq with
|
|
||||||
* devfreq_update() notified by OPP framework.
|
|
||||||
*
|
*
|
||||||
* Note that the callbacks are called with devfreq->lock locked by devfreq.
|
* Note that the callbacks are called with devfreq->lock locked by devfreq.
|
||||||
*/
|
*/
|
||||||
struct devfreq_governor {
|
struct devfreq_governor {
|
||||||
|
struct list_head node;
|
||||||
|
|
||||||
const char name[DEVFREQ_NAME_LEN];
|
const char name[DEVFREQ_NAME_LEN];
|
||||||
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
|
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
|
||||||
int (*init)(struct devfreq *this);
|
int (*event_handler)(struct devfreq *devfreq,
|
||||||
void (*exit)(struct devfreq *this);
|
unsigned int event, void *data);
|
||||||
const bool no_central_polling;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct devfreq - Device devfreq structure
|
* struct devfreq - Device devfreq structure
|
||||||
* @node list node - contains the devices with devfreq that have been
|
* @node: list node - contains the devices with devfreq that have been
|
||||||
* registered.
|
* registered.
|
||||||
* @lock a mutex to protect accessing devfreq.
|
* @lock: a mutex to protect accessing devfreq.
|
||||||
* @dev device registered by devfreq class. dev.parent is the device
|
* @dev: device registered by devfreq class. dev.parent is the device
|
||||||
* using devfreq.
|
* using devfreq.
|
||||||
* @profile device-specific devfreq profile
|
* @profile: device-specific devfreq profile
|
||||||
* @governor method how to choose frequency based on the usage.
|
* @governor: method how to choose frequency based on the usage.
|
||||||
* @nb notifier block used to notify devfreq object that it should
|
* @governor_name: devfreq governor name for use with this devfreq
|
||||||
|
* @nb: notifier block used to notify devfreq object that it should
|
||||||
* reevaluate operable frequencies. Devfreq users may use
|
* reevaluate operable frequencies. Devfreq users may use
|
||||||
* devfreq.nb to the corresponding register notifier call chain.
|
* devfreq.nb to the corresponding register notifier call chain.
|
||||||
* @polling_jiffies interval in jiffies.
|
* @work: delayed work for load monitoring.
|
||||||
* @previous_freq previously configured frequency value.
|
* @previous_freq: previously configured frequency value.
|
||||||
* @next_polling the number of remaining jiffies to poll with
|
* @data: Private data of the governor. The devfreq framework does not
|
||||||
* "devfreq_monitor" executions to reevaluate
|
|
||||||
* frequency/voltage of the device. Set by
|
|
||||||
* profile's polling_ms interval.
|
|
||||||
* @data Private data of the governor. The devfreq framework does not
|
|
||||||
* touch this.
|
* touch this.
|
||||||
* @being_removed a flag to mark that this object is being removed in
|
* @min_freq: Limit minimum frequency requested by user (0: none)
|
||||||
* order to prevent trying to remove the object multiple times.
|
* @max_freq: Limit maximum frequency requested by user (0: none)
|
||||||
* @min_freq Limit minimum frequency requested by user (0: none)
|
* @stop_polling: devfreq polling status of a device.
|
||||||
* @max_freq Limit maximum frequency requested by user (0: none)
|
* @total_trans: Number of devfreq transitions
|
||||||
|
* @trans_table: Statistics of devfreq transitions
|
||||||
|
* @time_in_state: Statistics of devfreq states
|
||||||
|
* @last_stat_updated: The last time stat updated
|
||||||
*
|
*
|
||||||
* This structure stores the devfreq information for a give device.
|
* This structure stores the devfreq information for a give device.
|
||||||
*
|
*
|
||||||
|
@ -152,26 +156,33 @@ struct devfreq {
|
||||||
struct device dev;
|
struct device dev;
|
||||||
struct devfreq_dev_profile *profile;
|
struct devfreq_dev_profile *profile;
|
||||||
const struct devfreq_governor *governor;
|
const struct devfreq_governor *governor;
|
||||||
|
char governor_name[DEVFREQ_NAME_LEN];
|
||||||
struct notifier_block nb;
|
struct notifier_block nb;
|
||||||
|
struct delayed_work work;
|
||||||
|
|
||||||
unsigned long polling_jiffies;
|
|
||||||
unsigned long previous_freq;
|
unsigned long previous_freq;
|
||||||
unsigned int next_polling;
|
|
||||||
|
|
||||||
void *data; /* private data for governors */
|
void *data; /* private data for governors */
|
||||||
|
|
||||||
bool being_removed;
|
|
||||||
|
|
||||||
unsigned long min_freq;
|
unsigned long min_freq;
|
||||||
unsigned long max_freq;
|
unsigned long max_freq;
|
||||||
|
bool stop_polling;
|
||||||
|
|
||||||
|
/* information for device freqeuncy transition */
|
||||||
|
unsigned int total_trans;
|
||||||
|
unsigned int *trans_table;
|
||||||
|
unsigned long *time_in_state;
|
||||||
|
unsigned long last_stat_updated;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_PM_DEVFREQ)
|
#if defined(CONFIG_PM_DEVFREQ)
|
||||||
extern struct devfreq *devfreq_add_device(struct device *dev,
|
extern struct devfreq *devfreq_add_device(struct device *dev,
|
||||||
struct devfreq_dev_profile *profile,
|
struct devfreq_dev_profile *profile,
|
||||||
const struct devfreq_governor *governor,
|
const char *governor_name,
|
||||||
void *data);
|
void *data);
|
||||||
extern int devfreq_remove_device(struct devfreq *devfreq);
|
extern int devfreq_remove_device(struct devfreq *devfreq);
|
||||||
|
extern int devfreq_suspend_device(struct devfreq *devfreq);
|
||||||
|
extern int devfreq_resume_device(struct devfreq *devfreq);
|
||||||
|
|
||||||
/* Helper functions for devfreq user device driver with OPP. */
|
/* Helper functions for devfreq user device driver with OPP. */
|
||||||
extern struct opp *devfreq_recommended_opp(struct device *dev,
|
extern struct opp *devfreq_recommended_opp(struct device *dev,
|
||||||
|
@ -181,23 +192,13 @@ extern int devfreq_register_opp_notifier(struct device *dev,
|
||||||
extern int devfreq_unregister_opp_notifier(struct device *dev,
|
extern int devfreq_unregister_opp_notifier(struct device *dev,
|
||||||
struct devfreq *devfreq);
|
struct devfreq *devfreq);
|
||||||
|
|
||||||
#ifdef CONFIG_DEVFREQ_GOV_POWERSAVE
|
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
|
||||||
extern const struct devfreq_governor devfreq_powersave;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_DEVFREQ_GOV_PERFORMANCE
|
|
||||||
extern const struct devfreq_governor devfreq_performance;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_DEVFREQ_GOV_USERSPACE
|
|
||||||
extern const struct devfreq_governor devfreq_userspace;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND
|
|
||||||
extern const struct devfreq_governor devfreq_simple_ondemand;
|
|
||||||
/**
|
/**
|
||||||
* struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
|
* struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
|
||||||
* and devfreq_add_device
|
* and devfreq_add_device
|
||||||
* @ upthreshold If the load is over this value, the frequency jumps.
|
* @upthreshold: If the load is over this value, the frequency jumps.
|
||||||
* Specify 0 to use the default. Valid value = 0 to 100.
|
* Specify 0 to use the default. Valid value = 0 to 100.
|
||||||
* @ downdifferential If the load is under upthreshold - downdifferential,
|
* @downdifferential: If the load is under upthreshold - downdifferential,
|
||||||
* the governor may consider slowing the frequency down.
|
* the governor may consider slowing the frequency down.
|
||||||
* Specify 0 to use the default. Valid value = 0 to 100.
|
* Specify 0 to use the default. Valid value = 0 to 100.
|
||||||
* downdifferential < upthreshold must hold.
|
* downdifferential < upthreshold must hold.
|
||||||
|
@ -214,7 +215,7 @@ struct devfreq_simple_ondemand_data {
|
||||||
#else /* !CONFIG_PM_DEVFREQ */
|
#else /* !CONFIG_PM_DEVFREQ */
|
||||||
static struct devfreq *devfreq_add_device(struct device *dev,
|
static struct devfreq *devfreq_add_device(struct device *dev,
|
||||||
struct devfreq_dev_profile *profile,
|
struct devfreq_dev_profile *profile,
|
||||||
struct devfreq_governor *governor,
|
const char *governor_name,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -225,6 +226,16 @@ static int devfreq_remove_device(struct devfreq *devfreq)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int devfreq_suspend_device(struct devfreq *devfreq)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devfreq_resume_device(struct devfreq *devfreq)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct opp *devfreq_recommended_opp(struct device *dev,
|
static struct opp *devfreq_recommended_opp(struct device *dev,
|
||||||
unsigned long *freq, u32 flags)
|
unsigned long *freq, u32 flags)
|
||||||
{
|
{
|
||||||
|
@ -243,11 +254,6 @@ static int devfreq_unregister_opp_notifier(struct device *dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define devfreq_powersave NULL
|
|
||||||
#define devfreq_performance NULL
|
|
||||||
#define devfreq_userspace NULL
|
|
||||||
#define devfreq_simple_ondemand NULL
|
|
||||||
|
|
||||||
#endif /* CONFIG_PM_DEVFREQ */
|
#endif /* CONFIG_PM_DEVFREQ */
|
||||||
|
|
||||||
#endif /* __LINUX_DEVFREQ_H__ */
|
#endif /* __LINUX_DEVFREQ_H__ */
|
||||||
|
|
Reference in New Issue