diff options
Diffstat (limited to 'packages/linux/linux-ezx/dpm-core-2.6.16.patch')
| -rw-r--r-- | packages/linux/linux-ezx/dpm-core-2.6.16.patch | 5197 |
1 files changed, 0 insertions, 5197 deletions
diff --git a/packages/linux/linux-ezx/dpm-core-2.6.16.patch b/packages/linux/linux-ezx/dpm-core-2.6.16.patch deleted file mode 100644 index d0d34d1225..0000000000 --- a/packages/linux/linux-ezx/dpm-core-2.6.16.patch +++ /dev/null @@ -1,5197 +0,0 @@ -This is the Dynamic Power Management Core, as released by the upstream -project for 2.6.16. - -Index: linux-2.6.16/arch/arm/Kconfig -=================================================================== ---- linux-2.6.16.orig/arch/arm/Kconfig 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/arch/arm/Kconfig 2006-04-11 06:34:10.000000000 +0000 -@@ -832,3 +832,5 @@ - source "crypto/Kconfig" - - source "lib/Kconfig" -+ -+source "drivers/dpm/Kconfig" -Index: linux-2.6.16/arch/i386/Kconfig -=================================================================== ---- linux-2.6.16.orig/arch/i386/Kconfig 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/arch/i386/Kconfig 2006-04-11 06:34:10.000000000 +0000 -@@ -908,6 +908,7 @@ - endmenu - - source "arch/i386/kernel/cpu/cpufreq/Kconfig" -+source "arch/i386/kernel/cpu/dpm/Kconfig" - - endmenu - -Index: linux-2.6.16/arch/i386/kernel/cpu/Makefile -=================================================================== ---- linux-2.6.16.orig/arch/i386/kernel/cpu/Makefile 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/arch/i386/kernel/cpu/Makefile 2006-04-11 06:34:10.000000000 +0000 -@@ -17,3 +17,4 @@ - - obj-$(CONFIG_MTRR) += mtrr/ - obj-$(CONFIG_CPU_FREQ) += cpufreq/ -+obj-$(CONFIG_DPM) += dpm/ -Index: linux-2.6.16/arch/i386/kernel/cpu/dpm/Kconfig -=================================================================== ---- linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/Kconfig 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16/arch/i386/kernel/cpu/dpm/Kconfig 2006-04-11 06:34:10.000000000 +0000 -@@ -0,0 +1,10 @@ -+# -+# Dynamic Power Management -+# -+ -+source "drivers/dpm/Kconfig" -+ -+config DPM_CENTRINO -+ tristate "DPM for Intel Centrino Enhanced Speedstep" -+ depends on DPM -+ default n -Index: linux-2.6.16/arch/i386/kernel/cpu/dpm/Makefile -=================================================================== ---- linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16/arch/i386/kernel/cpu/dpm/Makefile 2006-04-11 06:34:10.000000000 +0000 -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_DPM) += x86_dpm.o -+obj-$(CONFIG_DPM_CENTRINO) += centrino_dpm.o -+ -Index: linux-2.6.16/arch/i386/kernel/cpu/dpm/centrino_dpm.c -=================================================================== ---- linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/centrino_dpm.c 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16/arch/i386/kernel/cpu/dpm/centrino_dpm.c 2006-04-11 06:34:10.000000000 +0000 -@@ -0,0 +1,133 @@ -+/* -+ * 2003 (c) 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. -+ * -+ * Based on speedstep-centrino.c by Jeremy Fitzhardinge <jeremy@goop.org> -+ */ -+ -+#include <linux/config.h> -+#include <linux/dpm.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/delay.h> -+ -+#include <asm/msr.h> -+#include <asm/processor.h> -+#include <asm/cpufeature.h> -+ -+/* Extract clock in kHz from PERF_CTL value */ -+static unsigned extract_clock(unsigned msr) -+{ -+ msr = (msr >> 8) & 0xff; -+ return msr * 100000; -+} -+ -+/* Return the current CPU frequency in kHz */ -+static unsigned get_cur_freq(void) -+{ -+ unsigned l, h; -+ -+ rdmsr(MSR_IA32_PERF_STATUS, l, h); -+ return extract_clock(l); -+} -+ -+static int -+dpm_centrino_init_opt(struct dpm_opt *opt) -+{ -+ int v = opt->pp[DPM_MD_V]; -+ int cpu = opt->pp[DPM_MD_CPU_FREQ]; -+ -+ struct dpm_md_opt *md_opt = &opt->md_opt; -+ -+ md_opt->v = v; -+ md_opt->cpu = cpu; -+ return 0; -+} -+ -+/* Fully determine the current machine-dependent operating point, and fill in a -+ structure presented by the caller. This should only be called when the -+ dpm_sem is held. This call can return an error if the system is currently at -+ an operating point that could not be constructed by dpm_md_init_opt(). */ -+ -+static int -+dpm_centrino_get_opt(struct dpm_opt *opt) -+{ -+ struct dpm_md_opt *md_opt = &opt->md_opt; -+ -+ md_opt->v = 100; /* TODO. */ -+ md_opt->cpu = get_cur_freq(); -+ return 0; -+} -+ -+static int -+dpm_centrino_set_opt(struct dpm_md_opt *md_opt) -+{ -+ unsigned int msr = 0, oldmsr, h, mask = 0; -+ -+ if (md_opt->cpu != -1) { -+ msr |= ((md_opt->cpu)/100) << 8; -+ mask |= 0xff00; -+ } -+ -+ if (md_opt->v != -1) { -+ msr |= ((md_opt->v - 700) / 16); -+ mask |= 0xff; -+ } -+ -+ rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); -+ -+ if (msr == (oldmsr & mask)) -+ return 0; -+ -+ /* all but 16 LSB are "reserved", so treat them with -+ care */ -+ oldmsr &= ~mask; -+ msr &= mask; -+ oldmsr |= msr; -+ -+ wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); -+ return 0; -+} -+ -+static int dpm_centrino_startup(void) -+{ -+ struct cpuinfo_x86 *cpu = cpu_data; -+ unsigned l, h; -+ -+ if (!cpu_has(cpu, X86_FEATURE_EST)) -+ return -ENODEV; -+ -+ /* Check to see if Enhanced SpeedStep is enabled, and try to -+ enable it if not. */ -+ rdmsr(MSR_IA32_MISC_ENABLE, l, h); -+ -+ if (!(l & (1<<16))) { -+ l |= (1<<16); -+ wrmsr(MSR_IA32_MISC_ENABLE, l, h); -+ -+ /* check to see if it stuck */ -+ rdmsr(MSR_IA32_MISC_ENABLE, l, h); -+ if (!(l & (1<<16))) { -+ printk(KERN_INFO "DPM: Couldn't enable Enhanced SpeedStep\n"); -+ return -ENODEV; -+ } -+ } -+ -+ return 0; -+} -+ -+int __init dpm_centrino_init(void) -+{ -+ printk("Dynamic Power Management for Intel Centrino Enhanced SpeedStep.\n"); -+ -+ dpm_bd.startup = dpm_centrino_startup; -+ dpm_bd.init_opt = dpm_centrino_init_opt; -+ dpm_bd.get_opt = dpm_centrino_get_opt; -+ dpm_bd.set_opt = dpm_centrino_set_opt; -+ return 0; -+} -+ -+__initcall(dpm_centrino_init); -Index: linux-2.6.16/arch/i386/kernel/cpu/dpm/x86_dpm.c -=================================================================== ---- linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/x86_dpm.c 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16/arch/i386/kernel/cpu/dpm/x86_dpm.c 2006-04-11 06:34:10.000000000 +0000 -@@ -0,0 +1,133 @@ -+/* -+ * 2003 (c) 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/config.h> -+#include <linux/dpm.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+ -+#include <asm/page.h> -+#include <asm/uaccess.h> -+ -+struct dpm_bd dpm_bd; -+ -+static int -+dpm_x86_init_opt(struct dpm_opt *opt) -+{ -+ return dpm_bd.init_opt ? dpm_bd.init_opt(opt) : -1; -+} -+ -+/* Fully determine the current machine-dependent operating point, and fill in a -+ structure presented by the caller. This should only be called when the -+ dpm_sem is held. This call can return an error if the system is currently at -+ an operating point that could not be constructed by dpm_md_init_opt(). */ -+ -+static unsigned long loops_per_jiffy_ref = 0; -+ -+static int -+dpm_x86_get_opt(struct dpm_opt *opt) -+{ -+ return dpm_bd.get_opt ? dpm_bd.get_opt(opt) : -1; -+} -+ -+int -+dpm_x86_set_opt(struct dpm_opt *cur, struct dpm_opt *new) -+{ -+ struct cpuinfo_x86 *cpu = cpu_data; -+ -+ if (! new->md_opt.cpu) { -+#ifdef CONFIG_PM -+ pm_suspend(PM_SUSPEND_STANDBY); -+ -+ /* Here when we wake up. Recursive call to switch back to -+ * to task state. -+ */ -+ -+ dpm_set_os(DPM_TASK_STATE); -+#endif -+ return 0; -+ } -+ -+ if (dpm_bd.set_opt){ -+ dpm_bd.set_opt(&new->md_opt); -+ -+ }else{ -+ return -1; -+ } -+ -+ if (cur->md_opt.cpu && new->md_opt.cpu){ -+ loops_per_jiffy_ref = cpu->loops_per_jiffy; -+ cpu->loops_per_jiffy = -+ dpm_compute_lpj(loops_per_jiffy_ref , -+ cur->md_opt.cpu, -+ new->md_opt.cpu); -+ -+ loops_per_jiffy = cpu->loops_per_jiffy; -+ if (cpu_khz) -+ cpu_khz = dpm_compute_lpj(cpu_khz, -+ cur->md_opt.cpu, -+ new->md_opt.cpu); -+ } -+ return 0; -+} -+ -+/* -+ * idle loop -+ */ -+ -+static void (*orig_idle)(void); -+ -+void dpm_x86_idle(void) -+{ -+ extern void default_idle(void); -+ -+ if (orig_idle) -+ orig_idle(); -+ else -+ default_idle(); -+} -+ -+/**************************************************************************** -+ * Initialization/Exit -+ ****************************************************************************/ -+ -+void -+dpm_x86_startup(void) -+{ -+ orig_idle = pm_idle; -+ pm_idle = dpm_idle; -+ -+ if (dpm_bd.startup) -+ dpm_bd.startup(); -+} -+ -+void -+dpm_x86_cleanup(void) -+{ -+ pm_idle = orig_idle; -+ -+ if (dpm_bd.cleanup) -+ dpm_bd.cleanup(); -+} -+ -+int __init -+dpm_x86_init(void) -+{ -+ printk("Dynamic Power Management for x86.\n"); -+ -+ dpm_md.init_opt = dpm_x86_init_opt; -+ dpm_md.set_opt = dpm_x86_set_opt; -+ dpm_md.get_opt = dpm_x86_get_opt; -+ dpm_md.idle = dpm_x86_idle; -+ dpm_md.startup = dpm_x86_startup; -+ dpm_md.cleanup = dpm_x86_cleanup; -+ return 0; -+} -+__initcall(dpm_x86_init); -Index: linux-2.6.16/arch/i386/kernel/process.c -=================================================================== ---- linux-2.6.16.orig/arch/i386/kernel/process.c 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/arch/i386/kernel/process.c 2006-04-11 06:34:10.000000000 +0000 -@@ -58,6 +58,8 @@ - #include <asm/tlbflush.h> - #include <asm/cpu.h> - -+#include <linux/dpm.h> -+ - asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); - - static int hlt_counter; -@@ -697,6 +699,7 @@ - - disable_tsc(prev_p, next_p); - -+ dpm_set_os(next_p->dpm_state); - return prev_p; - } - -Index: linux-2.6.16/drivers/Makefile -=================================================================== ---- linux-2.6.16.orig/drivers/Makefile 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/drivers/Makefile 2006-04-11 06:34:10.000000000 +0000 -@@ -67,6 +67,7 @@ - obj-$(CONFIG_MCA) += mca/ - obj-$(CONFIG_EISA) += eisa/ - obj-$(CONFIG_CPU_FREQ) += cpufreq/ -+obj-$(CONFIG_DPM) += dpm/ - obj-$(CONFIG_MMC) += mmc/ - obj-$(CONFIG_INFINIBAND) += infiniband/ - obj-$(CONFIG_SGI_SN) += sn/ -Index: linux-2.6.16/drivers/base/core.c -=================================================================== ---- linux-2.6.16.orig/drivers/base/core.c 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/drivers/base/core.c 2006-04-11 06:34:10.000000000 +0000 -@@ -282,6 +282,8 @@ - if (parent) - klist_add_tail(&dev->knode_parent, &parent->klist_children); - -+ assert_constraints(dev->constraints); -+ - /* notify platform of device entry */ - if (platform_notify) - platform_notify(dev); -@@ -367,6 +369,8 @@ - klist_del(&dev->knode_parent); - device_remove_file(dev, &dev->uevent_attr); - -+ deassert_constraints(dev->constraints); -+ - /* Notify the platform of the removal, in case they - * need to do anything... - */ -Index: linux-2.6.16/drivers/base/power/Makefile -=================================================================== ---- linux-2.6.16.orig/drivers/base/power/Makefile 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/drivers/base/power/Makefile 2006-04-11 06:34:10.000000000 +0000 -@@ -1,4 +1,4 @@ --obj-y := shutdown.o -+obj-y := shutdown.o power-dpm.o - obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o - - ifeq ($(CONFIG_DEBUG_DRIVER),y) -Index: linux-2.6.16/drivers/base/power/power-dpm.c -=================================================================== ---- linux-2.6.16.orig/drivers/base/power/power-dpm.c 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16/drivers/base/power/power-dpm.c 2006-04-11 06:35:28.000000000 +0000 -@@ -0,0 +1,473 @@ -+/* -+ * power-dpm.c -- Dynamic Power Management LDM power hooks -+ * -+ * (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/device.h> -+#include <linux/pm.h> -+#include <linux/dpm.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <linux/mm.h> -+#include <linux/slab.h> -+ -+#include "power.h" -+ -+/* -+ * power hotplug events -+ */ -+ -+#define BUFFER_SIZE 1024 /* should be enough memory for the env */ -+#define NUM_ENVP 32 /* number of env pointers */ -+static unsigned long sequence_num; -+static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED; -+ -+void power_event(char *eventstr) -+{ -+ char *argv [3]; -+ char **envp = NULL; -+ char *buffer = NULL; -+ char *scratch; -+ int i = 0; -+ int retval; -+ unsigned long seq; -+ -+ if (!uevent_helper[0]) -+ return; -+ -+ envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); -+ if (!envp) -+ return; -+ memset (envp, 0x00, NUM_ENVP * sizeof (char *)); -+ -+ buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); -+ if (!buffer) -+ goto exit; -+ -+ argv [0] = uevent_helper; -+ argv [1] = "power"; -+ argv [2] = 0; -+ -+ /* minimal command environment */ -+ envp [i++] = "HOME=/"; -+ envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; -+ -+ scratch = buffer; -+ -+ envp [i++] = scratch; -+ scratch += sprintf(scratch, "ACTION=event") + 1; -+ -+ spin_lock(&sequence_lock); -+ seq = sequence_num++; -+ spin_unlock(&sequence_lock); -+ -+ envp [i++] = scratch; -+ scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1; -+ envp [i++] = scratch; -+ scratch += sprintf(scratch, "EVENT=%s", eventstr) + 1; -+ -+ pr_debug ("%s: %s %s %s %s %s %s %s\n", __FUNCTION__, argv[0], argv[1], -+ envp[0], envp[1], envp[2], envp[3], envp[4]); -+ retval = call_usermodehelper (argv[0], argv, envp, 0); -+ if (retval) -+ pr_debug ("%s - call_usermodehelper returned %d\n", -+ __FUNCTION__, retval); -+ -+exit: -+ kfree(buffer); -+ kfree(envp); -+ return; -+} -+ -+void device_power_event(struct device * dev, char *eventstr) -+{ -+ char *argv [3]; -+ char **envp = NULL; -+ char *buffer = NULL; -+ char *scratch; -+ int i = 0; -+ int retval; -+ unsigned long seq; -+ -+ if (!uevent_helper[0]) -+ return; -+ -+ envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); -+ if (!envp) -+ return; -+ memset (envp, 0x00, NUM_ENVP * sizeof (char *)); -+ -+ buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); -+ if (!buffer) -+ goto exit; -+ -+ argv [0] = uevent_helper; -+ argv [1] = "power"; -+ argv [2] = 0; -+ -+ /* minimal command environment */ -+ envp [i++] = "HOME=/"; -+ envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; -+ -+ scratch = buffer; -+ -+ envp [i++] = scratch; -+ scratch += sprintf(scratch, "ACTION=device-event") + 1; -+ -+ spin_lock(&sequence_lock); -+ seq = sequence_num++; -+ spin_unlock(&sequence_lock); -+ -+ envp [i++] = scratch; -+ scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1; -+ envp [i++] = scratch; -+ scratch += sprintf(scratch, "DEVICE=%s", dev->bus_id) + 1; -+ envp [i++] = scratch; -+ scratch += sprintf(scratch, "EVENT=%s", eventstr) + 1; -+ envp [i++] = scratch; -+ scratch += sprintf(scratch, "SUBSYSTEM=power") + 1; -+ -+ pr_debug ("%s: %s %s %s %s %s %s %s %s %2\n", __FUNCTION__, argv[0], argv[1], -+ envp[0], envp[1], envp[2], envp[3], envp[4], envp[5], -+ envp[6]); -+ retval = call_usermodehelper (argv[0], argv, envp, 0); -+ if (retval) -+ pr_debug ("%s - call_usermodehelper returned %d\n", -+ __FUNCTION__, retval); -+ -+exit: -+ kfree(buffer); -+ kfree(envp); -+ return; -+} -+ -+/* -+ * Device constraints -+ */ -+ -+#ifdef CONFIG_DPM -+LIST_HEAD(dpm_constraints); -+DECLARE_MUTEX(dpm_constraints_sem); -+ -+void assert_constraints(struct constraints *constraints) -+{ -+ if (! constraints || constraints->asserted) -+ return; -+ -+ down(&dpm_constraints_sem); -+ constraints->asserted = 1; -+ list_add_tail(&constraints->entry, &dpm_constraints); -+ up(&dpm_constraints_sem); -+ -+ /* DPM-PM-TODO: Check against DPM state. */ -+ -+} -+ -+ -+void deassert_constraints(struct constraints *constraints) -+{ -+ if (! constraints || ! constraints->asserted) -+ return; -+ -+ down(&dpm_constraints_sem); -+ constraints->asserted = 0; -+ list_del_init(&constraints->entry); -+ up(&dpm_constraints_sem); -+} -+ -+ -+EXPORT_SYMBOL(assert_constraints); -+EXPORT_SYMBOL(deassert_constraints); -+ -+static ssize_t -+constraints_show(struct device * dev, struct device_attribute *attr, -+ char * buf) -+{ -+ int i, cnt = 0; -+ -+ if (dev->constraints) { -+ for (i = 0; i < dev->constraints->count; i++) { -+ cnt += sprintf(buf + cnt,"%s: min=%d max=%d\n", -+ dpm_param_names[dev->constraints->param[i].id], -+ dev->constraints->param[i].min, -+ dev->constraints->param[i].max); -+ } -+ -+ cnt += sprintf(buf + cnt,"asserted=%s violations=%d\n", -+ dev->constraints->asserted ? -+ "yes" : "no", dev->constraints->violations); -+ } else { -+ cnt += sprintf(buf + cnt,"none\n"); -+ } -+ -+ return cnt; -+} -+ -+static ssize_t -+constraints_store(struct device * dev, struct device_attribute *attr, -+ const char * buf, size_t count) -+{ -+ int num_args, paramid, min, max; -+ int cidx; -+ const char *cp, *paramname; -+ int paramnamelen; -+ int provisional = 0; -+ int ret = 0; -+ -+ if (!dev->constraints) { -+ if (! (dev->constraints = kmalloc(sizeof(struct constraints), -+ GFP_KERNEL))) -+ return -EINVAL; -+ -+ memset(dev->constraints, 0, -+ sizeof(struct constraints)); -+ provisional = 1; -+ } -+ -+ cp = buf; -+ while((cp - buf < count) && *cp && (*cp == ' ')) -+ cp++; -+ -+ paramname = cp; -+ -+ while((cp - buf < count) && *cp && (*cp != ' ')) -+ cp++; -+ -+ paramnamelen = cp - paramname; -+ num_args = sscanf(cp, "%d %d", &min, &max); -+ -+ if (num_args != 2) { -+ printk("DPM: Need 2 integer parameters for constraint min/max.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ for (paramid = 0; paramid < DPM_PP_NBR; paramid++) { -+ if (strncmp(paramname, dpm_param_names[paramid], paramnamelen) == 0) -+ break; -+ } -+ -+ if (paramid >= DPM_PP_NBR) { -+ printk("DPM: Unknown power parameter name in device constraints\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ for (cidx = 0; cidx < dev->constraints->count; cidx++) -+ /* -+ * If the new range overlaps an existing range, -+ * modify the existing one. -+ */ -+ -+ if ((dev->constraints->param[cidx].id == paramid) && -+ ((max == -1) || -+ (max >= dev->constraints->param[cidx].min)) && -+ ((min == -1) || -+ (min <= dev->constraints->param[cidx].max))) -+ break; -+ -+ if (cidx >= DPM_CONSTRAINT_PARAMS_MAX) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* Error if max is less than min */ -+ if (max < min) { -+ printk("DPM: Max value of the constraint should not be less than min\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ dev->constraints->param[cidx].id = paramid; -+ dev->constraints->param[cidx].max = max; -+ dev->constraints->param[cidx].min = min; -+ -+ if (cidx == dev->constraints->count) -+ dev->constraints->count++; -+ -+ /* New constraints should start off with same state as power -+ state */ -+ if (provisional && (dev->power.power_state.event == PM_EVENT_ON)) -+ assert_constraints(dev->constraints); -+ -+out: -+ -+ if (provisional && (ret < 0)) { -+ kfree(dev->constraints); -+ dev->constraints = NULL; -+ } -+ -+ return ret < 0 ? ret : count; -+} -+ -+DEVICE_ATTR(constraints,S_IWUSR | S_IRUGO, -+ constraints_show,constraints_store); -+ -+#else /* CONFIG_DPM */ -+void assert_constraints(struct constraints *constraints) -+{ -+} -+ -+void deassert_constraints(struct constraints *constraints) -+{ -+} -+#endif /* CONFIG_DPM */ -+ -+#ifdef CONFIG_DPM -+ -+/* -+ * Driver scale callbacks -+ */ -+ -+static struct notifier_block *dpm_scale_notifier_list[SCALE_MAX]; -+static DECLARE_MUTEX(dpm_scale_sem); -+ -+/* This function may be called by the platform frequency scaler before -+ or after a frequency change, in order to let drivers adjust any -+ clocks or calculations for the new frequency. */ -+ -+void dpm_driver_scale(int level, struct dpm_opt *newop) -+{ -+ if (down_trylock(&dpm_scale_sem)) -+ return; -+ -+ notifier_call_chain(&dpm_scale_notifier_list[level], level, newop); -+ up(&dpm_scale_sem); -+} -+ -+void dpm_register_scale(struct notifier_block *nb, int level) -+{ -+ down(&dpm_scale_sem); -+ notifier_chain_register(&dpm_scale_notifier_list[level], nb); -+ up(&dpm_scale_sem); -+} -+ -+void dpm_unregister_scale(struct notifier_block *nb, int level) -+{ -+ down(&dpm_scale_sem); -+ notifier_chain_unregister(&dpm_scale_notifier_list[level], nb); -+ up(&dpm_scale_sem); -+} -+ -+int dpm_constraint_rejects = 0; -+ -+ -+int -+dpm_default_check_constraint(struct constraint_param *param, -+ struct dpm_opt *opt) -+{ -+ return (opt->pp[param->id] == -1) || -+ ((param->min == -1 || opt->pp[param->id] >= param->min) && -+ (param->max == -1 || opt->pp[param->id] <= param->max)); -+} -+ -+static int -+dpm_check_a_constraint(struct constraints *constraints, struct dpm_opt *opt) -+{ -+ int i; -+ int failid = -1; -+ int ppconstraint[DPM_PP_NBR]; -+ -+ -+ if (! constraints || !constraints->asserted) -+ return 1; -+ -+ /* -+ * ppconstraint[ppid] == 0 means power param has not been checked -+ * for a constraint -+ * == -1 means power param has matched a constraint -+ * > 0 means constraint #n-1 mismatched -+ * -+ * failid == pp id of (a) failed constraint -+ */ -+ -+ memset(ppconstraint, 0, sizeof(ppconstraint)); -+ -+ for (i = 0; i < constraints->count; i++) { -+ struct constraint_param *param = &constraints->param[i]; -+ -+ if (! dpm_md_check_constraint(param, opt)) { -+ if (ppconstraint[param->id] == 0) { -+ failid = param->id; -+ ppconstraint[failid] = i+1; -+ } -+ } else -+ ppconstraint[param->id] = -1; -+ } -+ -+ if ((failid >= 0) && (ppconstraint[failid] > 0)) { -+#ifdef CONFIG_DPM_TRACE -+ struct constraint_param *param = -+ &constraints->param[ppconstraint[failid]-1]; -+ -+ dpm_trace(DPM_TRACE_CONSTRAINT_ASSERTED, -+ param->id, param->min, param->max, -+ opt); -+#endif -+ return 0; -+ } -+ -+ return 1; -+} -+ -+int dpm_check_constraints(struct dpm_opt *opt) -+{ -+ struct list_head * entry; -+ int valid = 1; -+ -+ list_for_each(entry,&dpm_constraints) { -+ struct constraints *constraints = -+ list_entry(entry, struct constraints, entry); -+ if (!dpm_check_a_constraint(constraints, opt)) { -+ constraints->violations++; -+ dpm_constraint_rejects++; -+ valid = 0; -+ } -+ } -+ -+ return valid; -+} -+ -+int dpm_show_opconstraints(struct dpm_opt *opt, char * buf) -+{ -+#ifdef CONFIG_PM -+ struct list_head * entry; -+ int len = 0; -+ -+ list_for_each_prev(entry,&dpm_active) { -+ struct device * dev = to_device(entry); -+ -+ if (!dpm_check_a_constraint(dev->constraints, opt)) { -+ len += sprintf(buf + len, "%s/%s\n", dev->bus->name, -+ dev->bus_id); -+ } -+ } -+ -+ return len; -+#else /* CONFIG_PM */ -+ return 0; -+#endif /* CONFIG_PM */ -+} -+ -+void dpm_force_off_constrainers(struct dpm_opt *opt) -+{ -+#ifdef CONFIG_PM -+ struct list_head * entry; -+ -+ list_for_each_prev(entry,&dpm_active) { -+ struct device * dev = to_device(entry); -+ -+ if (!dpm_check_a_constraint(dev->constraints, opt)) { -+ suspend_device(dev, PMSG_SUSPEND); -+ } -+ } -+#endif -+} -+ -+EXPORT_SYMBOL(dpm_force_off_constrainers); -+#endif /* CONFIG_DPM */ -+ -Index: linux-2.6.16/drivers/base/power/resume.c -=================================================================== ---- linux-2.6.16.orig/drivers/base/power/resume.c 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/drivers/base/power/resume.c 2006-04-11 06:34:10.000000000 +0000 -@@ -34,6 +34,8 @@ - if (dev->bus && dev->bus->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->bus->resume(dev); -+ if (!error) -+ assert_constraints(dev->constraints); - } - up(&dev->sem); - return error; -Index: linux-2.6.16/drivers/base/power/suspend.c -=================================================================== ---- linux-2.6.16.orig/drivers/base/power/suspend.c 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/drivers/base/power/suspend.c 2006-04-11 06:34:10.000000000 +0000 -@@ -57,6 +57,9 @@ - if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { - dev_dbg(dev, "suspending\n"); - error = dev->bus->suspend(dev, state); -+ -+ if (! error) -+ deassert_constraints(dev->constraints); - } - up(&dev->sem); - return error; -Index: linux-2.6.16/drivers/base/power/sysfs.c -=================================================================== ---- linux-2.6.16.orig/drivers/base/power/sysfs.c 2006-03-20 05:53:29.000000000 +0000 -+++ linux-2.6.16/drivers/base/power/sysfs.c 2006-04-11 06:34:10.000000000 +0000 -@@ -56,7 +56,6 @@ - - static DEVICE_ATTR(state, 0644, state_show, state_store); - -- - /* - * wakeup - Report/change current wakeup option for device - * -@@ -128,10 +127,14 @@ - - static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); - -+extern struct device_attribute dev_attr_constraints; - - static struct attribute * power_attrs[] = { - &dev_attr_state.attr, - &dev_attr_wakeup.attr, -+#ifdef CONFIG_DPM -+ &dev_attr_constraints.attr, -+#endif - NULL, - }; - static struct attribute_group pm_attr_group = { -Index: linux-2.6.16/drivers/dpm/Kconfig -=================================================================== ---- linux-2.6.16.orig/drivers/dpm/Kconfig 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16/drivers/dpm/Kconfig 2006-04-11 06:34:10.000000000 +0000 -@@ -0,0 +1,43 @@ -+# -+# Dynamic Power Management -+# -+ -+menu "Dynamic Power Management" -+ -+config DPM -+ bool "Dynamic Power Management" -+ help -+ Enable Dynamic Power Management, if implemented for your platform. -+ DPM conserves power by adjusting power parameters according to -+ system state (such as idle, running a high-power-usage task, etc.) -+ and enables associated power management features such as device -+ constraints on power parameters. DPM relies on power policy and -+ machine-dependent power operating points and such to be configured -+ from userspace after boot. -+ -+ If in doubt, say N. -+ -+config DPM_STATS -+ bool " Enable DPM Statistics Gathering" -+ depends on DPM -+ help -+ This enables gathering and reporting statistics for DPM. -+ This can be useful during development of DPM platform code or -+ in other situations where information on the operation of DPM is -+ needed. -+ -+ If in doubt, say N. -+ -+ -+config DPM_PROCFS -+ bool " Enable old DPM /proc interface (deprecated)" -+ depends on DPM && PROC_FS -+ help -+ This enables the /proc/driver/dpm interface for controlling -+ DPM. Please note that it is recommended to use the sysfs -+ interface instead (which is built automatically). -+ -+ If in doubt, say N. -+ -+endmenu -+ -Index: linux-2.6.16/drivers/dpm/Makefile -=================================================================== ---- linux-2.6.16.orig/drivers/dpm/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16/drivers/dpm/Makefile 2006-04-11 06:34:10.000000000 +0000 -@@ -0,0 +1,7 @@ -+# -+# Makefile for the kernel DPM driver. -+# -+ -+obj-$(CONFIG_DPM) += dpm.o dpm-idle.o dpm-ui.o -+obj-$(CONFIG_DPM_PROCFS) += proc.o -+ -Index: linux-2.6.16/drivers/dpm/dpm-idle.c -=================================================================== ---- linux-2.6.16.orig/drivers/dpm/dpm-idle.c 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16/drivers/dpm/dpm-idle.c 2006-04-11 06:34:10.000000000 +0000 -@@ -0,0 +1,167 @@ -+/* -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * 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); |
