📄 dpm-core-2.6.16.patch
字号:
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA+ *+ * Copyright (C) 2002, MontaVista Software <source@mvista.com>.+ *+ * Based on ibm405lp_dpm.c by Bishop Brock, Copyright (C) 2002,+ * International Business Machines Corporation.+ */++#include <linux/config.h>+#include <linux/dpm.h>+#include <linux/errno.h>+#include <linux/init.h>+#include <linux/kernel.h>+#include <linux/kmod.h>+#include <linux/module.h>+#include <linux/proc_fs.h>+#include <linux/stat.h>+#include <linux/string.h>++#include <asm/delay.h>+#include <asm/hardirq.h>+#include <asm/page.h>+#include <asm/processor.h>+#include <asm/system.h>+#include <asm/uaccess.h>++/****************************************************************************+ * DPM Idle Handler+ ****************************************************************************/++/*+ The idle handler is one of the most important parts of DPM, as very+ significant amounts of energy are saved by moving to a low-power idle state+ whenever possible. The basic coding of the core of this routine is simply:++ dpm_set_os(DPM_IDLE_STATE);+ machine-dependent-idle-routine();+ dpm_set_os(DPM_IDLE_TASK_STATE);++ The added complexity found here is introduced to avoid unnecessary work, and+ especially to reduce the latencies associated with going in and out of idle.+ Idle power can be greatly reduced by moving to a very low-frequency+ operating point, but we also need to be aware of the impact on interrupt+ latencies. The DPM implementation of idle attempts to balance these+ competing needs.++ We support 2 "idle" states: DPM_IDLE_TASK_STATE and DPM_IDLE_STATE. The+ idle thread is marked as a "no-state" task, so that operating point changes+ are not automatically made when the idle thread is scheduled. The+ "idle-task" state is used for the majority of the idle thread. Interrupts+ that occur during idle are handled in this state as well. The "idle" state+ is only entered from the idle-task state, and only for the express purpose+ of allowing an ultra-low-power operating point.++ The introduction of the idle-task state supports a stepped voltage and+ frequency scaling at idle. On the IBM 405LP we would not want to go from,+ e.g., 266/133 @ 1.8 V directly to 8/8 @ 1.0 V and back. Why not? Because+ we would get "stuck" at 8MHz even though we need to wake up and resume+ useful work, e.g., we would have to set the 266/133 operating point while+ running at 8/8. So instead when going idle first step down to idle-task,+ e.g., 100/50 @ 1.0 V, and then step down to e.g. 8/8 to halt. The interrupt+ that takes us out of idle takes us back to idle-task (100/50) for interrupt+ processing and the potential return to 266/133.++ The best policies for this implementation will be able to transition between+ idle-task and idle without voltage scaling or driver notification. In these+ cases the transitions are handled with minimal latency by simple frequency+ scaling. */++static inline void+quick_idle(void)+{+ dpm_quick_enter_state(DPM_IDLE_STATE);+ dpm_md_idle();+ dpm_quick_enter_state(DPM_IDLE_TASK_STATE);+}++static void+full_idle(struct dpm_opt *idle_task_opt, struct dpm_opt *idle_opt)+{+ dpm_quick_enter_state(DPM_IDLE_STATE);+#ifdef CONFIG_DPM_STATS+ dpm_update_stats(&idle_opt->stats, &idle_task_opt->stats);+#endif+ dpm_set_opt(idle_opt, DPM_SYNC);+ dpm_md_idle();+ dpm_set_opt(idle_task_opt, DPM_SYNC);+ dpm_quick_enter_state(DPM_IDLE_TASK_STATE);+#ifdef CONFIG_DPM_STATS+ dpm_update_stats(&idle_task_opt->stats, &idle_opt->stats);+#endif+}+++/* If DPM is currently disabled here we simply do the standard+ idle wait.++ If we're not actually in DPM_IDLE_TASK_STATE, we need to go back and get+ into this state. This could happen in rare instances - an interrupt between+ dpm_set_os() and the critical section.++ If we are not yet at the idle-task operating point, or if there is no+ difference between idle-task and idle, we can enter/exit the idle state+ quickly since it's only for statistical purposes. This is also true if for+ some reason we can't get the DPM lock, since obviously an asynchronous event+ is going to have to occur to clear the lock, and this event is going to take+ us out of idle.++ Otherwise the full idle shutdown is done. */+++void+dpm_idle(void)+{+ unsigned long flags;+ struct dpm_opt *idle_task_opt, *idle_opt;++ current->dpm_state = DPM_NO_STATE;+ dpm_set_os(DPM_IDLE_TASK_STATE);+ local_irq_save(flags);++ if (! need_resched()) {+ if (!dpm_enabled) {+ dpm_md_idle();++ } else if (dpm_active_state != DPM_IDLE_TASK_STATE) {+++ } else {+ idle_task_opt = dpm_choose_opt(dpm_active_policy,+ DPM_IDLE_TASK_STATE);+ idle_opt = dpm_choose_opt(dpm_active_policy,+ DPM_IDLE_STATE);++ if (dpm_trylock()) {+ dpm_md_idle();+ } else {++ if ((dpm_active_opt != idle_task_opt) ||+ (idle_task_opt == idle_opt)) {++ quick_idle();+ dpm_unlock();+ } else {+ dpm_unlock();+ full_idle(idle_task_opt, idle_opt);+ }+ }+ }+ }+ local_irq_restore(flags);+}+Index: linux-2.6.16/drivers/dpm/dpm-ui.c===================================================================--- linux-2.6.16.orig/drivers/dpm/dpm-ui.c 1970-01-01 00:00:00.000000000 +0000+++ linux-2.6.16/drivers/dpm/dpm-ui.c 2006-04-11 06:35:40.000000000 +0000@@ -0,0 +1,1249 @@+/*+ * drivers/dpm/dpm-ui.c - userspace interface to Dynamic Power Management+ *+ * (c) 2003 MontaVista Software, Inc. This file is licensed under the+ * terms of the GNU General Public License version 2. This program is+ * licensed "as is" without any warranty of any kind, whether express or+ * implied.+ */++#include <linux/dpm.h>+#include <linux/device.h>+#include <linux/init.h>+#include <linux/errno.h>++/* Common sysfs/proc support */++char *dpm_state_names[DPM_STATES] = DPM_STATE_NAMES;+char *dpm_param_names[DPM_PP_NBR] = DPM_PARAM_NAMES;++#define MAXTOKENS 80++static int+tokenizer(char **tbuf, const char *userbuf, ssize_t n, char **tokptrs,+ int maxtoks)+{+ char *cp, *tok;+ char *whitespace = " \t\r\n";+ int ntoks = 0;++ if (!(cp = kmalloc(n + 1, GFP_KERNEL)))+ return -ENOMEM;++ *tbuf = cp;+ memcpy(cp, userbuf, n);+ cp[n] = '\0';++ do {+ cp = cp + strspn(cp, whitespace);+ tok = strsep(&cp, whitespace);+ if ((*tok == '\0') || (ntoks == maxtoks))+ break;+ tokptrs[ntoks++] = tok;+ } while(cp);++ return ntoks;+}+++/* SysFS Interface */++#define dpm_attr(_name,_prefix) \+static struct subsys_attribute _prefix##_attr = { \+ .attr = { \+ .name = __stringify(_name), \+ .mode = 0644, \+ }, \+ .show = _prefix##_show, \+ .store = _prefix##_store, \+}+++static void dpm_kobj_release(struct kobject *kobj)+{+ /*+ * No sysfs/kobject state to release, DPM layer will handle the+ * the containing object.+ */++ return;+}++/*+ * Top-level control+ */++static ssize_t dpm_control_show(struct subsystem * subsys, char * buf)+{+ unsigned long flags;+ ssize_t len = 0;++ if (dpm_lock_interruptible())+ return -ERESTARTSYS;++ if (!dpm_enabled) {+ len += sprintf(buf, "disabled\n");+ } else {+ spin_lock_irqsave(&dpm_policy_lock, flags);+ len += sprintf(buf,"enabled %s %d %s %s %s\n",+ dpm_active_policy->name,+ dpm_active_state,+ dpm_state_names[dpm_active_state],+ dpm_classopt_name(dpm_active_policy,+ dpm_active_state),+ dpm_active_opt ? dpm_active_opt->name : "[none]");+ spin_unlock_irqrestore(&dpm_policy_lock, flags);+ }++ dpm_unlock();+ return len;+}++static ssize_t dpm_control_store(struct subsystem * subsys, const char * buf,+ size_t n)+{+ int error = 0;++ if (strncmp(buf, "init", 4) == 0) {+ error = dynamicpower_init();+ } else if (strncmp(buf, "enable", 6) == 0) {+ error = dynamicpower_enable();+ } else if (strncmp(buf, "disable", 7) == 0) {+ error = dynamicpower_disable();+ } else if (strncmp(buf, "terminate", 9) == 0) {+ error = dynamicpower_terminate();+ } else+ error = -EINVAL;++ return error ? error : n;+}++dpm_attr(control,dpm_control);++static struct attribute * g[] = {+ &dpm_control_attr.attr,+ NULL,+};++static struct attribute_group dpm_attr_group = {+ .attrs = g,+};++decl_subsys(dpm, NULL, NULL);++/*+ * policy+ */++struct dpm_policy_attribute {+ struct attribute attr;+ ssize_t (*show)(struct kobject * kobj, char * buf);+ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count);+};++#define to_policy(obj) container_of(obj,struct dpm_policy,kobj)+#define to_policy_attr(_attr) container_of(_attr,struct dpm_policy_attribute,attr)++static struct kobject dpm_policy_kobj = {+ .kset = &dpm_subsys.kset,+};++static ssize_t policy_control_show(struct subsystem * subsys, char * buf)+{+ ssize_t len = 0;+ struct list_head * p;++ if (dpm_lock_interruptible())+ return -ERESTARTSYS;++ len += sprintf(buf + len, "policies: ");++ list_for_each(p, &dpm_policies) {+ len += sprintf(buf + len, "%s ",+ ((struct dpm_policy *)+ list_entry(p, struct dpm_policy, list))->name);+ }++ len += sprintf(buf + len, "\n");+ dpm_unlock();+ return len;+}++static ssize_t policy_control_store(struct subsystem * subsys, const char * buf,+ size_t n)+{+ int error = 0;+ char *tbuf = NULL;+ char *token[MAXTOKENS];+ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);++ if (ntoks <= 0) {+ error = ntoks;+ goto out;+ }++ if (strcmp(token[0],"create") == 0) {+ error = dpm_create_policy(token[1], &token[2], ntoks - 2);+ } else if (strcmp(token[0],"set") == 0) {+ if (ntoks != 2)+ printk("dpm: policy set requires 1 policy name argument\n");+ else+ error = dpm_set_policy(token[1]);+ } else+ error = -EINVAL;++ out:+ if (tbuf)+ kfree(tbuf);+ return error ? error : n;+}++static ssize_t active_policy_show(struct subsystem * subsys, char * buf)+{+ unsigned long flags;+ ssize_t len = 0;++ if (dpm_lock_interruptible())+ return -ERESTARTSYS;++ if (!dpm_enabled || (dpm_active_state == DPM_NO_STATE)) {+ len += sprintf(buf + len, "[none]\n");+ } else {+ spin_lock_irqsave(&dpm_policy_lock, flags);+ len += sprintf(buf + len,"%s\n",+ dpm_active_policy->name);+ spin_unlock_irqrestore(&dpm_policy_lock, flags);+ }++ dpm_unlock();+ return len;+}++static ssize_t active_policy_store(struct subsystem * subsys, const char * buf,+ size_t n)+{+ int error = 0;+ char *tbuf = NULL;+ char *token[MAXTOKENS];+ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);++ if (ntoks <= 0) {+ error = ntoks;+ goto out;+ }++ error = dpm_set_policy(token[0]);++ out:+ if (tbuf)+ kfree(tbuf);+ return error ? error : n;+}++dpm_attr(control,policy_control);+dpm_attr(active,active_policy);++#ifdef CONFIG_DPM_STATS+static ssize_t policy_stats_show(struct subsystem * subsys, char * buf)+{+ int len = 0;+ struct dpm_policy *policy;+ struct list_head *p;+ unsigned long long total_time;++ if (dpm_lock_interruptible())+ return -ERESTARTSYS;++ if (!dpm_enabled) {+ dpm_unlock();+ len += sprintf(buf + len, "DPM IS DISABLED\n");+ return len;+ }++ for (p = dpm_policies.next; p != &dpm_policies; p = p->next) {+ policy = list_entry(p, struct dpm_policy, list);+ len += sprintf(buf + len, "policy: %s", policy->name);+ total_time = policy->stats.total_time;+ if (policy == dpm_active_policy)+ total_time += (unsigned long long) dpm_time() -+ policy->stats.start_time;+ len += sprintf(buf + len, " ticks: %Lu times: %lu\n",+ (unsigned long long) dpm_time_to_usec(total_time),+ policy->stats.count);+ }++ dpm_unlock();+ return len;+}++static ssize_t policy_stats_store(struct subsystem * subsys, const char * buf,+ size_t n)+{+ return n;+}++dpm_attr(stats, policy_stats);+#endif /* CONFIG_DPM_STATS */++static ssize_t a_policy_control_show(struct kobject * kobj, char * buf)+{+ struct dpm_policy *policy = to_policy(kobj);+ ssize_t len = 0;+ int i;++ len += sprintf(buf + len, "ops/classes: ");++ for (i = 0; i < DPM_STATES; i++)+ len += sprintf(buf + len, "%s ", dpm_classopt_name(policy,i));++ len += sprintf(buf + len, "\n");+ return len;+}++static ssize_t a_policy_control_store(struct kobject * kobj, const char * buf,+ size_t n)+{+ struct dpm_policy *policy = to_policy(kobj);+ int error = 0;+ char *tbuf = NULL;+ char *token[MAXTOKENS];+ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);++ if (ntoks <= 0) {+ error = ntoks;+ goto out;+ }++ if (strcmp(token[0],"destroy") == 0) {+ dpm_destroy_policy(policy->name);+ } else+ error = -EINVAL;++ out:+ if (tbuf)+ kfree(tbuf);+ return error ? error : n;+}++#define POLICY_STATE_ATTR(index) \+static ssize_t policy_state ## index ## _show(struct kobject * kobj, \+ char * buf) \+{ \+ ssize_t len = 0; \+ struct dpm_policy *policy = to_policy(kobj); \+ len += sprintf(buf + len, "%s\n", policy->classopt[index].opt ? policy->classopt[index].opt->name :policy->classopt[index].class->name ); \+ return len; \+} \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -