From patchwork Mon Aug 8 09:03:07 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: MyungJoo Ham X-Patchwork-Id: 1043452 Received: from smtp1.linux-foundation.org (smtp1.linux-foundation.org [140.211.169.13]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p7895jfO008102 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Mon, 8 Aug 2011 09:06:05 GMT Received: from daredevil.linux-foundation.org (localhost [127.0.0.1]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p7894NgE020653; Mon, 8 Aug 2011 02:04:24 -0700 Received: from mailout2.samsung.com (mailout2.samsung.com [203.254.224.25]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p7893Gor020394 for ; Mon, 8 Aug 2011 02:03:20 -0700 Received: from epcpsbgm1.samsung.com (mailout2.samsung.com [203.254.224.25]) by mailout2.samsung.com (Oracle Communications Messaging Exchange Server 7u4-19.01 64bit (built Sep 7 2010)) with ESMTP id <0LPL00K5KQH0GYB0@mailout2.samsung.com> for linux-pm@lists.linux-foundation.org; Mon, 08 Aug 2011 18:03:10 +0900 (KST) X-AuditID: cbfee61a-b7cf0ae000006bc6-d0-4e3fa64dd2cb Received: from epmmp1 ( [203.254.227.16]) by epcpsbgm1.samsung.com (MMPCPMTA) with SMTP id 6B.AF.27590.D46AF3E4; Mon, 08 Aug 2011 18:03:09 +0900 (KST) Received: from TNRNDGASPAPP1.tn.corp.samsungelectronics.net ([165.213.149.150]) by mmp1.samsung.com (iPlanet Messaging Server 5.2 Patch 2 (built Jul 14 2004)) with ESMTPA id <0LPL00C96QHAGL@mmp1.samsung.com> for linux-pm@lists.linux-foundation.org; Mon, 08 Aug 2011 18:03:10 +0900 (KST) Received: from localhost.localdomain ([165.213.219.116]) by TNRNDGASPAPP1.tn.corp.samsungelectronics.net with Microsoft SMTPSVC(6.0.3790.4675); Mon, 08 Aug 2011 18:03:45 +0900 Date: Mon, 08 Aug 2011 18:03:07 +0900 From: MyungJoo Ham In-reply-to: <1312794188-9823-1-git-send-email-myungjoo.ham@samsung.com> To: linux-pm@lists.linux-foundation.org Message-id: <1312794188-9823-3-git-send-email-myungjoo.ham@samsung.com> X-Mailer: git-send-email 1.7.4.1 References: <1312794188-9823-1-git-send-email-myungjoo.ham@samsung.com> X-OriginalArrivalTime: 08 Aug 2011 09:03:45.0426 (UTC) FILETIME=[13F0EF20:01CC55AA] X-Brightmail-Tracker: AAAAAA== Received-SPF: pass (localhost is always allowed.) X-Spam-Status: No, hits=-12.101 required=5 tests=AWL, BAYES_00, OSDL_HEADER_SUBJECT_BRACKETED, SAMSUNG_WEBMAIL_OSDL X-Spam-Checker-Version: SpamAssassin 3.2.4-osdl_revision__1.47__ X-MIMEDefang-Filter: lf$Revision: 1.188 $ X-Scanned-By: MIMEDefang 2.63 on 140.211.169.21 Cc: Len Brown , Greg Kroah-Hartman , Kyungmin Park , Thomas Gleixner Subject: [linux-pm] [PATCH v5 2/3] PM / DEVFREQ: add basic governors X-BeenThere: linux-pm@lists.linux-foundation.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux power management List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-pm-bounces@lists.linux-foundation.org Errors-To: linux-pm-bounces@lists.linux-foundation.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 08 Aug 2011 09:06:06 +0000 (UTC) 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 Signed-off-by: Kyungmin Park --- Changes from v4: - Added userspace governor Changes from v3: - Bugfixes on simple-ondemand governor (divide by zero / overflow) - Style fixes - Give names to governors --- drivers/base/power/devfreq.c | 100 ++++++++++++++++++++++++++++++++++++++++++ include/linux/devfreq.h | 8 +++ 2 files changed, 108 insertions(+), 0 deletions(-) diff --git a/drivers/base/power/devfreq.c b/drivers/base/power/devfreq.c index 6f4bd3a..c53bca9 100644 --- a/drivers/base/power/devfreq.c +++ b/drivers/base/power/devfreq.c @@ -301,3 +301,103 @@ 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 = { + .name = "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 = { + .name = "performance", + .get_target_freq = devfreq_performance_func, +}; + +static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq) +{ + if (df->user_set_freq == 0) + *freq = df->previous_freq; /* No user freq specified yet */ + else + *freq = df->user_set_freq; + + return 0; +} + +struct devfreq_governor devfreq_userspace = { + .name = "userspace", + .get_target_freq = devfreq_userspace_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; + + /* 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_DOWNDIFFERENCTIAL)) { + *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_DOWNDIFFERENCTIAL / 2)); + *freq = (unsigned long) b; + + return 0; +} + +struct devfreq_governor devfreq_simple_ondemand = { + .name = "simple_ondemand", + .get_target_freq = devfreq_simple_ondemand_func, +}; diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 6ec630b..7131d2a 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -57,6 +57,8 @@ struct devfreq_governor { * @next_polling the number of remaining "devfreq_monitor" executions to * reevaluate frequency/voltage of the device. Set by * profile's polling_ms interval. + * @user_set_freq User specified adequete frequency value (thru sysfs + * interface). Governors may and may not use this value. * @data Private data of the governor. The devfreq framework does not * touch this. * @@ -72,6 +74,7 @@ struct devfreq { unsigned long previous_freq; unsigned int next_polling; + unsigned long user_set_freq; /* governors may ignore this. */ void *data; /* private data for governors */ }; @@ -81,6 +84,11 @@ extern int devfreq_add_device(struct device *dev, struct devfreq_governor *governor); extern int devfreq_remove_device(struct device *dev); extern int devfreq_update(struct device *dev); + +extern struct devfreq_governor devfreq_powersave; +extern struct devfreq_governor devfreq_performance; +extern struct devfreq_governor devfreq_userspace; +extern struct devfreq_governor devfreq_simple_ondemand; #else /* !CONFIG_PM_DEVFREQ */ static int devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile,