-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Four cpufreq-like governors are provided as examples. powersave: use the lowest frequency possible. The user (device) should set the polling_ms as 0 because polling is useless for this governor. performance: use the highest freqeuncy possible. The user (device) should set the polling_ms as 0 because polling is useless for this governor. userspace: use the user specified frequency stored at devfreq.user_set_freq. With sysfs support in the following patch, a user may set the value with the sysfs interface. simple_ondemand: simplified version of cpufreq's ondemand governor. When a user updates OPP entries (enable/disable/add), OPP framework automatically notifies devfreq to update operating frequency accordingly. Thus, devfreq users (device drivers) do not need to update devfreq manually with OPP entry updates or set polling_ms for powersave , performance, userspace, or any other "static" governors. Note that these are given only as basic examples for governors and any devices with devfreq may implement their own governors with the drivers and use them. Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Mike Turquette <mturquette@ti.com> Acked-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
- Loading branch information
Showing
8 changed files
with
345 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
obj-$(CONFIG_PM_DEVFREQ) += devfreq.o | ||
obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) += governor_simpleondemand.o | ||
obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o | ||
obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o | ||
obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* linux/drivers/devfreq/governor_performance.c | ||
* | ||
* Copyright (C) 2011 Samsung Electronics | ||
* MyungJoo Ham <myungjoo.ham@samsung.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/devfreq.h> | ||
|
||
static int devfreq_performance_func(struct devfreq *df, | ||
unsigned long *freq) | ||
{ | ||
/* | ||
* target callback should be able to get floor value as | ||
* said in devfreq.h | ||
*/ | ||
*freq = UINT_MAX; | ||
return 0; | ||
} | ||
|
||
const struct devfreq_governor devfreq_performance = { | ||
.name = "performance", | ||
.get_target_freq = devfreq_performance_func, | ||
.no_central_polling = true, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* linux/drivers/devfreq/governor_powersave.c | ||
* | ||
* Copyright (C) 2011 Samsung Electronics | ||
* MyungJoo Ham <myungjoo.ham@samsung.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/devfreq.h> | ||
|
||
static int devfreq_powersave_func(struct devfreq *df, | ||
unsigned long *freq) | ||
{ | ||
/* | ||
* target callback should be able to get ceiling value as | ||
* said in devfreq.h | ||
*/ | ||
*freq = 0; | ||
return 0; | ||
} | ||
|
||
const struct devfreq_governor devfreq_powersave = { | ||
.name = "powersave", | ||
.get_target_freq = devfreq_powersave_func, | ||
.no_central_polling = true, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* linux/drivers/devfreq/governor_simpleondemand.c | ||
* | ||
* Copyright (C) 2011 Samsung Electronics | ||
* MyungJoo Ham <myungjoo.ham@samsung.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/errno.h> | ||
#include <linux/devfreq.h> | ||
#include <linux/math64.h> | ||
|
||
/* Default constants for DevFreq-Simple-Ondemand (DFSO) */ | ||
#define DFSO_UPTHRESHOLD (90) | ||
#define DFSO_DOWNDIFFERENCTIAL (5) | ||
static int devfreq_simple_ondemand_func(struct devfreq *df, | ||
unsigned long *freq) | ||
{ | ||
struct devfreq_dev_status stat; | ||
int err = df->profile->get_dev_status(df->dev.parent, &stat); | ||
unsigned long long a, b; | ||
unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; | ||
unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; | ||
struct devfreq_simple_ondemand_data *data = df->data; | ||
|
||
if (err) | ||
return err; | ||
|
||
if (data) { | ||
if (data->upthreshold) | ||
dfso_upthreshold = data->upthreshold; | ||
if (data->downdifferential) | ||
dfso_downdifferential = data->downdifferential; | ||
} | ||
if (dfso_upthreshold > 100 || | ||
dfso_upthreshold < dfso_downdifferential) | ||
return -EINVAL; | ||
|
||
/* Assume MAX if it is going to be divided by zero */ | ||
if (stat.total_time == 0) { | ||
*freq = UINT_MAX; | ||
return 0; | ||
} | ||
|
||
/* Prevent overflow */ | ||
if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) { | ||
stat.busy_time >>= 7; | ||
stat.total_time >>= 7; | ||
} | ||
|
||
/* Set MAX if it's busy enough */ | ||
if (stat.busy_time * 100 > | ||
stat.total_time * dfso_upthreshold) { | ||
*freq = UINT_MAX; | ||
return 0; | ||
} | ||
|
||
/* Set MAX if we do not know the initial frequency */ | ||
if (stat.current_frequency == 0) { | ||
*freq = UINT_MAX; | ||
return 0; | ||
} | ||
|
||
/* Keep the current frequency */ | ||
if (stat.busy_time * 100 > | ||
stat.total_time * (dfso_upthreshold - dfso_downdifferential)) { | ||
*freq = stat.current_frequency; | ||
return 0; | ||
} | ||
|
||
/* Set the desired frequency based on the load */ | ||
a = stat.busy_time; | ||
a *= stat.current_frequency; | ||
b = div_u64(a, stat.total_time); | ||
b *= 100; | ||
b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); | ||
*freq = (unsigned long) b; | ||
|
||
return 0; | ||
} | ||
|
||
const struct devfreq_governor devfreq_simple_ondemand = { | ||
.name = "simple_ondemand", | ||
.get_target_freq = devfreq_simple_ondemand_func, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* linux/drivers/devfreq/governor_simpleondemand.c | ||
* | ||
* Copyright (C) 2011 Samsung Electronics | ||
* MyungJoo Ham <myungjoo.ham@samsung.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/slab.h> | ||
#include <linux/device.h> | ||
#include <linux/devfreq.h> | ||
#include <linux/pm.h> | ||
#include <linux/mutex.h> | ||
#include "governor.h" | ||
|
||
struct userspace_data { | ||
unsigned long user_frequency; | ||
bool valid; | ||
}; | ||
|
||
static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq) | ||
{ | ||
struct userspace_data *data = df->data; | ||
|
||
if (!data->valid) | ||
*freq = df->previous_freq; /* No user freq specified yet */ | ||
else | ||
*freq = data->user_frequency; | ||
return 0; | ||
} | ||
|
||
static ssize_t store_freq(struct device *dev, struct device_attribute *attr, | ||
const char *buf, size_t count) | ||
{ | ||
struct devfreq *devfreq = to_devfreq(dev); | ||
struct userspace_data *data; | ||
unsigned long wanted; | ||
int err = 0; | ||
|
||
|
||
mutex_lock(&devfreq->lock); | ||
data = devfreq->data; | ||
|
||
sscanf(buf, "%lu", &wanted); | ||
data->user_frequency = wanted; | ||
data->valid = true; | ||
err = update_devfreq(devfreq); | ||
if (err == 0) | ||
err = count; | ||
mutex_unlock(&devfreq->lock); | ||
return err; | ||
} | ||
|
||
static ssize_t show_freq(struct device *dev, struct device_attribute *attr, | ||
char *buf) | ||
{ | ||
struct devfreq *devfreq = to_devfreq(dev); | ||
struct userspace_data *data; | ||
int err = 0; | ||
|
||
mutex_lock(&devfreq->lock); | ||
data = devfreq->data; | ||
|
||
if (data->valid) | ||
err = sprintf(buf, "%lu\n", data->user_frequency); | ||
else | ||
err = sprintf(buf, "undefined\n"); | ||
mutex_unlock(&devfreq->lock); | ||
return err; | ||
} | ||
|
||
static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq); | ||
static struct attribute *dev_entries[] = { | ||
&dev_attr_set_freq.attr, | ||
NULL, | ||
}; | ||
static struct attribute_group dev_attr_group = { | ||
.name = "userspace", | ||
.attrs = dev_entries, | ||
}; | ||
|
||
static int userspace_init(struct devfreq *devfreq) | ||
{ | ||
int err = 0; | ||
struct userspace_data *data = kzalloc(sizeof(struct userspace_data), | ||
GFP_KERNEL); | ||
|
||
if (!data) { | ||
err = -ENOMEM; | ||
goto out; | ||
} | ||
data->valid = false; | ||
devfreq->data = data; | ||
|
||
err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group); | ||
out: | ||
return err; | ||
} | ||
|
||
static void userspace_exit(struct devfreq *devfreq) | ||
{ | ||
sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); | ||
kfree(devfreq->data); | ||
devfreq->data = NULL; | ||
} | ||
|
||
const struct devfreq_governor devfreq_userspace = { | ||
.name = "userspace", | ||
.get_target_freq = devfreq_userspace_func, | ||
.init = userspace_init, | ||
.exit = userspace_exit, | ||
.no_central_polling = true, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters