⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dpm-core-2.6.16.patch

📁 Linus Dynamic Power Management Soruce code
💻 PATCH
📖 第 1 页 / 共 5 页
字号:
+ * 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 + -