diff mbox

[v2,2/3] PM / DEVFREQ: add example governors

Message ID 1305100723-29161-2-git-send-email-myungjoo.ham@samsung.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

MyungJoo Ham May 11, 2011, 7:58 a.m. UTC
Three 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.

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, or any other "static" governors.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/base/power/devfreq.c |   69 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/devfreq.h      |    5 +++
 2 files changed, 74 insertions(+), 0 deletions(-)

Comments

Rafael Wysocki May 17, 2011, 10:39 p.m. UTC | #1
On Wednesday, May 11, 2011, MyungJoo Ham wrote:
> Three 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.
> 
> 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, or any other "static" governors.

Well, do you expect anyone to actually use them?  If not, it would make
more sense to put them into a doc.

Thanks,
Rafael


> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  drivers/base/power/devfreq.c |   69 ++++++++++++++++++++++++++++++++++++++++++
>  include/linux/devfreq.h      |    5 +++
>  2 files changed, 74 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/base/power/devfreq.c b/drivers/base/power/devfreq.c
> index 8e2e45b..251d761 100644
> --- a/drivers/base/power/devfreq.c
> +++ b/drivers/base/power/devfreq.c
> @@ -351,3 +351,72 @@ static int __init devfreq_init(void)
>  	return 0;
>  }
>  late_initcall(devfreq_init);
> +
> +static int devfreq_powersave_func(struct devfreq *df,
> +				  unsigned long *freq)
> +{
> +	*freq = 0; /* devfreq_do will run "ceiling" to 0 */
> +	return 0;
> +}
> +
> +struct devfreq_governor devfreq_powersave = {
> +	.get_target_freq = devfreq_powersave_func,
> +};
> +
> +static int devfreq_performance_func(struct devfreq *df,
> +				    unsigned long *freq)
> +{
> +	*freq = UINT_MAX; /* devfreq_do will run "floor" */
> +	return 0;
> +}
> +
> +struct devfreq_governor devfreq_performance = {
> +	.get_target_freq = devfreq_performance_func,
> +};
> +
> +/* 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, &stat);
> +	unsigned long long a, b;
> +
> +	if (err)
> +		return err;
> +
> +	/* 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_DOWNDIFFERENCTIAL)) {
> +		*freq = stat.current_frequency;
> +		return 0;
> +	}
> +
> +	/* Set the desired frequency based on the load */
> +	a = (unsigned long long) stat.busy_time * stat.current_frequency;
> +	b = div_u64(a, stat.total_time);
> +	b *= 100;
> +	b = div_u64(b, (DFSO_UPTHRESHOLD - DFSO_DOWNDIFFERENCTIAL / 2));
> +	*freq = (unsigned long) b;
> +
> +	return 0;
> +}
> +
> +struct devfreq_governor devfreq_simple_ondemand = {
> +	.get_target_freq = devfreq_simple_ondemand_func,
> +};
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index d08e9f5..ec41ba6 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -81,6 +81,11 @@ extern int devfreq_add_device(struct device *dev,
>  extern int devfreq_remove_device(struct device *dev);
>  extern int devfreq_update(struct device *dev, bool may_not_exist);
>  extern int devfreq_tickle_device(struct device *dev, unsigned long duration_ms);
> +
> +extern struct devfreq_governor devfreq_powersave;
> +extern struct devfreq_governor devfreq_performance;
> +extern struct devfreq_governor devfreq_simple_ondemand;
> +
>  #else /* !CONFIG_PM_DEVFREQ */
>  static int devfreq_add_device(struct device *dev,
>  			   struct devfreq_dev_profile *profile,
>
MyungJoo Ham May 18, 2011, 12:48 a.m. UTC | #2
2011/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday, May 11, 2011, MyungJoo Ham wrote:
>> Three 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.
>>
>> 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, or any other "static" governors.
>
> Well, do you expect anyone to actually use them?  If not, it would make
> more sense to put them into a doc.

According to our experiences of DVFS(although this "DEVFREQ" is not
applied to them, yet) in memory-bus and GPU,
I expect most DEVFREQ users might use "simple_ondemand" and
expect "powersave" and "performance" will probably mostly used while
testing and debugging.
("userspace"-like governor would be also useful for that purpose, but
I'd add it later)


Cheers!
- MyungJoo

>
> Thanks,
> Rafael
>
>
>> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>  drivers/base/power/devfreq.c |   69 ++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/devfreq.h      |    5 +++
>>  2 files changed, 74 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/base/power/devfreq.c b/drivers/base/power/devfreq.c
>> index 8e2e45b..251d761 100644
>> --- a/drivers/base/power/devfreq.c
>> +++ b/drivers/base/power/devfreq.c
>> @@ -351,3 +351,72 @@ static int __init devfreq_init(void)
>>       return 0;
>>  }
>>  late_initcall(devfreq_init);
>> +
>> +static int devfreq_powersave_func(struct devfreq *df,
>> +                               unsigned long *freq)
>> +{
>> +     *freq = 0; /* devfreq_do will run "ceiling" to 0 */
>> +     return 0;
>> +}
>> +
>> +struct devfreq_governor devfreq_powersave = {
>> +     .get_target_freq = devfreq_powersave_func,
>> +};
>> +
>> +static int devfreq_performance_func(struct devfreq *df,
>> +                                 unsigned long *freq)
>> +{
>> +     *freq = UINT_MAX; /* devfreq_do will run "floor" */
>> +     return 0;
>> +}
>> +
>> +struct devfreq_governor devfreq_performance = {
>> +     .get_target_freq = devfreq_performance_func,
>> +};
>> +
>> +/* 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, &stat);
>> +     unsigned long long a, b;
>> +
>> +     if (err)
>> +             return err;
>> +
>> +     /* 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_DOWNDIFFERENCTIAL)) {
>> +             *freq = stat.current_frequency;
>> +             return 0;
>> +     }
>> +
>> +     /* Set the desired frequency based on the load */
>> +     a = (unsigned long long) stat.busy_time * stat.current_frequency;
>> +     b = div_u64(a, stat.total_time);
>> +     b *= 100;
>> +     b = div_u64(b, (DFSO_UPTHRESHOLD - DFSO_DOWNDIFFERENCTIAL / 2));
>> +     *freq = (unsigned long) b;
>> +
>> +     return 0;
>> +}
>> +
>> +struct devfreq_governor devfreq_simple_ondemand = {
>> +     .get_target_freq = devfreq_simple_ondemand_func,
>> +};
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index d08e9f5..ec41ba6 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -81,6 +81,11 @@ extern int devfreq_add_device(struct device *dev,
>>  extern int devfreq_remove_device(struct device *dev);
>>  extern int devfreq_update(struct device *dev, bool may_not_exist);
>>  extern int devfreq_tickle_device(struct device *dev, unsigned long duration_ms);
>> +
>> +extern struct devfreq_governor devfreq_powersave;
>> +extern struct devfreq_governor devfreq_performance;
>> +extern struct devfreq_governor devfreq_simple_ondemand;
>> +
>>  #else /* !CONFIG_PM_DEVFREQ */
>>  static int devfreq_add_device(struct device *dev,
>>                          struct devfreq_dev_profile *profile,
>>
>
>
Rafael Wysocki May 18, 2011, 7:46 p.m. UTC | #3
On Wednesday, May 18, 2011, MyungJoo Ham wrote:
> 2011/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Wednesday, May 11, 2011, MyungJoo Ham wrote:
> >> Three 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.
> >>
> >> 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, or any other "static" governors.
> >
> > Well, do you expect anyone to actually use them?  If not, it would make
> > more sense to put them into a doc.
> 
> According to our experiences of DVFS(although this "DEVFREQ" is not
> applied to them, yet) in memory-bus and GPU,
> I expect most DEVFREQ users might use "simple_ondemand" and
> expect "powersave" and "performance" will probably mostly used while
> testing and debugging.
> ("userspace"-like governor would be also useful for that purpose, but
> I'd add it later)

It would be good to have at least one in-tree user for each of them
(not necessarily from the start, but at one point in the future at least).

So if you have any _specific_ users in mind, please let me know.

Thanks,
Rafael
MyungJoo Ham May 27, 2011, 4:42 a.m. UTC | #4
On Thu, May 19, 2011 at 4:46 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Wednesday, May 18, 2011, MyungJoo Ham wrote:
>> 2011/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Wednesday, May 11, 2011, MyungJoo Ham wrote:
>> >> Three 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.
>> >>
>> >> 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, or any other "static" governors.
>> >
>> > Well, do you expect anyone to actually use them?  If not, it would make
>> > more sense to put them into a doc.
>>
>> According to our experiences of DVFS(although this "DEVFREQ" is not
>> applied to them, yet) in memory-bus and GPU,
>> I expect most DEVFREQ users might use "simple_ondemand" and
>> expect "powersave" and "performance" will probably mostly used while
>> testing and debugging.
>> ("userspace"-like governor would be also useful for that purpose, but
>> I'd add it later)
>
> It would be good to have at least one in-tree user for each of them
> (not necessarily from the start, but at one point in the future at least).
>
> So if you have any _specific_ users in mind, please let me know.

For Exynos4, the DRAM bus, which is included in cpufreq and altered
along with CPU, but would be better to alter independently, and the
G3D core (MALI) are the candidate. In our kernel hacks, the DRAM bus
frequency varies independently from CPU with DRAM usage monitoring and
I think it can be easily modified to use DEVFREQ; thus, I'm going to
"translate" this to DEVFREQ next time. For MALI, I don't know whether
there is non-copyrighted driver or now, but they do support DVFS and
are using DVFS with some PITA driver support.

These two (EXYNOS4 DRAM bus and MALI) are the specific users in mind for now.
Probably, out-of-SoC devices such as WiFi, BT, and others may be the
candidate as well.

>
> Thanks,
> Rafael
>
diff mbox

Patch

diff --git a/drivers/base/power/devfreq.c b/drivers/base/power/devfreq.c
index 8e2e45b..251d761 100644
--- a/drivers/base/power/devfreq.c
+++ b/drivers/base/power/devfreq.c
@@ -351,3 +351,72 @@  static int __init devfreq_init(void)
 	return 0;
 }
 late_initcall(devfreq_init);
+
+static int devfreq_powersave_func(struct devfreq *df,
+				  unsigned long *freq)
+{
+	*freq = 0; /* devfreq_do will run "ceiling" to 0 */
+	return 0;
+}
+
+struct devfreq_governor devfreq_powersave = {
+	.get_target_freq = devfreq_powersave_func,
+};
+
+static int devfreq_performance_func(struct devfreq *df,
+				    unsigned long *freq)
+{
+	*freq = UINT_MAX; /* devfreq_do will run "floor" */
+	return 0;
+}
+
+struct devfreq_governor devfreq_performance = {
+	.get_target_freq = devfreq_performance_func,
+};
+
+/* 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, &stat);
+	unsigned long long a, b;
+
+	if (err)
+		return err;
+
+	/* 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_DOWNDIFFERENCTIAL)) {
+		*freq = stat.current_frequency;
+		return 0;
+	}
+
+	/* Set the desired frequency based on the load */
+	a = (unsigned long long) stat.busy_time * stat.current_frequency;
+	b = div_u64(a, stat.total_time);
+	b *= 100;
+	b = div_u64(b, (DFSO_UPTHRESHOLD - DFSO_DOWNDIFFERENCTIAL / 2));
+	*freq = (unsigned long) b;
+
+	return 0;
+}
+
+struct devfreq_governor devfreq_simple_ondemand = {
+	.get_target_freq = devfreq_simple_ondemand_func,
+};
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index d08e9f5..ec41ba6 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -81,6 +81,11 @@  extern int devfreq_add_device(struct device *dev,
 extern int devfreq_remove_device(struct device *dev);
 extern int devfreq_update(struct device *dev, bool may_not_exist);
 extern int devfreq_tickle_device(struct device *dev, unsigned long duration_ms);
+
+extern struct devfreq_governor devfreq_powersave;
+extern struct devfreq_governor devfreq_performance;
+extern struct devfreq_governor devfreq_simple_ondemand;
+
 #else /* !CONFIG_PM_DEVFREQ */
 static int devfreq_add_device(struct device *dev,
 			   struct devfreq_dev_profile *profile,