* ACPI patches in test for Linux-2.6.22
@ 2007-03-10 4:00 Len Brown
[not found] ` <941b1971a405f95537bc6f9a738e737eb2186e45.1173498647.git.len.brown@intel.com>
2007-03-16 17:58 ` ACPI patches in test for Linux-2.6.22 Sergio Monteiro Basto
0 siblings, 2 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi
These patches are in test for Linux-2.6.22.
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git test
thanks,
-Len
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure
[not found] ` <941b1971a405f95537bc6f9a738e737eb2186e45.1173498647.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
2007-03-15 12:31 ` Andi Kleen
2007-03-15 13:13 ` Richard Hughes
[not found] ` <92648781fb5f44cee584da36eb569e88dddc4b8f.1173498651.git.len.brown@intel.com>
` (19 subsequent siblings)
20 siblings, 2 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Venkatesh Pallipadi, Adam Belay, Shaohua Li, Len Brown
From: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Announcing 'cpuidle', a new CPU power management infrastructure to manage
idle CPUs in a clean and efficient manner.
cpuidle separates out the drivers that can provide support for multiple types
of idle states and policy governors that decide on what idle state to use
at run time.
A cpuidle driver can support multiple idle states based on parameters like
varying power consumption, wakeup latency, etc (ACPI C-states for example).
A cpuidle governor can be usage model specific (laptop, server,
laptop on battery etc).
Main advantage of the infrastructure being, it allows independent development
of drivers and governors and allows for better CPU power management.
A huge thanks to Adam Belay and Shaohua Li who were part of this mini-project
since its beginning and are greatly responsible for this patchset.
This patch:
Core cpuidle infrastructure.
Introduces a new abstraction layer for cpuidle:
* which manages drivers that can support multiple idles states. Drivers
can be generic or particular to specific hardware/platform
* allows pluging in multiple policy governors that can take idle state policy
decision
* The core also has a set of sysfs interfaces with which administrato can know
about supported drivers and governors and switch them at run time.
Signed-off-by: Adam Belay <abelay@novell.com>
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
arch/i386/Kconfig | 2 +
arch/x86_64/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/cpuidle/Kconfig | 28 +++
drivers/cpuidle/Makefile | 5 +
drivers/cpuidle/cpuidle.c | 287 ++++++++++++++++++++++++++++++
drivers/cpuidle/cpuidle.h | 52 ++++++
drivers/cpuidle/driver.c | 219 +++++++++++++++++++++++
drivers/cpuidle/governor.c | 160 +++++++++++++++++
drivers/cpuidle/governors/Makefile | 5 +
drivers/cpuidle/governors/ladder.c | 229 ++++++++++++++++++++++++
drivers/cpuidle/sysfs.c | 340 ++++++++++++++++++++++++++++++++++++
include/linux/cpuidle.h | 160 +++++++++++++++++
13 files changed, 1490 insertions(+), 0 deletions(-)
create mode 100644 drivers/cpuidle/Kconfig
create mode 100644 drivers/cpuidle/Makefile
create mode 100644 drivers/cpuidle/cpuidle.c
create mode 100644 drivers/cpuidle/cpuidle.h
create mode 100644 drivers/cpuidle/driver.c
create mode 100644 drivers/cpuidle/governor.c
create mode 100644 drivers/cpuidle/governors/Makefile
create mode 100644 drivers/cpuidle/governors/ladder.c
create mode 100644 drivers/cpuidle/sysfs.c
create mode 100644 include/linux/cpuidle.h
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 2f76725..bf68fc2 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -1066,6 +1066,8 @@ endmenu
source "arch/i386/kernel/cpu/cpufreq/Kconfig"
+source "drivers/cpuidle/Kconfig"
+
endmenu
menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 56eb14c..fd01428 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -670,6 +670,8 @@ source "drivers/acpi/Kconfig"
source "arch/x86_64/kernel/cpufreq/Kconfig"
+source "drivers/cpuidle/Kconfig"
+
endmenu
menu "Bus options (PCI etc.)"
diff --git a/drivers/Makefile b/drivers/Makefile
index 3a718f5..7acd123 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_EDAC) += edac/
obj-$(CONFIG_MCA) += mca/
obj-$(CONFIG_EISA) += eisa/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
+obj-$(CONFIG_CPU_IDLE) += cpuidle/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_NEW_LEDS) += leds/
obj-$(CONFIG_INFINIBAND) += infiniband/
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
new file mode 100644
index 0000000..b9ac217
--- /dev/null
+++ b/drivers/cpuidle/Kconfig
@@ -0,0 +1,28 @@
+menu "CPU idle PM support"
+
+config CPU_IDLE
+ bool "CPU idle PM support"
+ help
+ CPU idle is a generic framework for supporting software-controlled
+ idle processor power management. It includes modular cross-platform
+ governors that can be swapped during runtime.
+
+ If you're using a mobile platform that supports CPU idle PM (e.g.
+ an ACPI-capable notebook), you should say Y here.
+
+if CPU_IDLE
+
+comment "Governors"
+
+config CPU_IDLE_GOV_LADDER
+ tristate "'ladder' governor"
+ depends on CPU_IDLE
+ default y
+ help
+ This cpuidle governor promotes and demotes through the supported idle
+ states using residency time and bus master activity as metrics. This
+ algorithm was originally introduced in the old ACPI processor driver.
+
+endif # CPU_IDLE
+
+endmenu
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
new file mode 100644
index 0000000..5634f88
--- /dev/null
+++ b/drivers/cpuidle/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for cpuidle.
+#
+
+obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
new file mode 100644
index 0000000..dc626d9
--- /dev/null
+++ b/drivers/cpuidle/cpuidle.c
@@ -0,0 +1,287 @@
+/*
+ * cpuidle.c - core cpuidle infrastructure
+ *
+ * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ * Shaohua Li <shaohua.li@intel.com>
+ * Adam Belay <abelay@novell.com>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/latency.h>
+#include <linux/cpuidle.h>
+
+#include "cpuidle.h"
+
+DEFINE_PER_CPU(struct cpuidle_device, cpuidle_devices);
+EXPORT_PER_CPU_SYMBOL_GPL(cpuidle_devices);
+
+DEFINE_MUTEX(cpuidle_lock);
+LIST_HEAD(cpuidle_detected_devices);
+static void (*pm_idle_old)(void);
+
+
+/**
+ * cpuidle_idle_call - the main idle loop
+ *
+ * NOTE: no locks or semaphores should be used here
+ * FIXME: DYNTICKS handling
+ */
+static void cpuidle_idle_call(void)
+{
+ struct cpuidle_device *dev = &__get_cpu_var(cpuidle_devices);
+
+ struct cpuidle_state *target_state;
+ int next_state;
+
+ /* check if the device is ready */
+ if (dev->status != CPUIDLE_STATUS_DOIDLE) {
+ if (pm_idle_old)
+ pm_idle_old();
+ return;
+ }
+
+ if (cpuidle_curr_governor->prepare_idle)
+ cpuidle_curr_governor->prepare_idle(dev);
+
+ while(!need_resched()) {
+ next_state = cpuidle_curr_governor->select_state(dev);
+ if (need_resched())
+ break;
+
+ target_state = &dev->states[next_state];
+
+ dev->last_residency = target_state->enter(dev, target_state);
+ dev->last_state = target_state;
+ target_state->time += dev->last_residency;
+ target_state->usage++;
+
+ if (dev->status != CPUIDLE_STATUS_DOIDLE)
+ break;
+ }
+}
+
+/**
+ * cpuidle_install_idle_handler - installs the cpuidle idle loop handler
+ */
+void cpuidle_install_idle_handler(void)
+{
+ if (pm_idle != cpuidle_idle_call) {
+ /* Make sure all changes finished before we switch to new idle */
+ smp_wmb();
+ pm_idle = cpuidle_idle_call;
+ }
+}
+
+/**
+ * cpuidle_uninstall_idle_handler - uninstalls the cpuidle idle loop handler
+ */
+void cpuidle_uninstall_idle_handler(void)
+{
+ if (pm_idle != pm_idle_old) {
+ pm_idle = pm_idle_old;
+ cpu_idle_wait();
+ }
+}
+
+/**
+ * cpuidle_rescan_device - prepares for a new state configuration
+ * @dev: the target device
+ *
+ * Must be called with cpuidle_lock aquired.
+ */
+void cpuidle_rescan_device(struct cpuidle_device *dev)
+{
+ int i;
+
+ if (cpuidle_curr_governor->scan)
+ cpuidle_curr_governor->scan(dev);
+
+ for (i = 0; i < dev->state_count; i++) {
+ dev->states[i].usage = 0;
+ dev->states[i].time = 0;
+ }
+}
+
+/**
+ * cpuidle_add_device - attaches the driver to a CPU instance
+ * @sys_dev: the system device (driver model CPU representation)
+ */
+static int cpuidle_add_device(struct sys_device *sys_dev)
+{
+ int cpu = sys_dev->id;
+ struct cpuidle_device *dev;
+
+ dev = &per_cpu(cpuidle_devices, cpu);
+
+ mutex_lock(&cpuidle_lock);
+ if (cpu_is_offline(cpu)) {
+ mutex_unlock(&cpuidle_lock);
+ return 0;
+ }
+
+ if (dev->status & CPUIDLE_STATUS_DETECTED) {
+ mutex_unlock(&cpuidle_lock);
+ return 0;
+ }
+ dev->status |= CPUIDLE_STATUS_DETECTED;
+ list_add(&dev->device_list, &cpuidle_detected_devices);
+ cpuidle_add_sysfs(sys_dev);
+ if (cpuidle_curr_driver)
+ cpuidle_attach_driver(dev);
+ if (cpuidle_curr_governor)
+ cpuidle_attach_governor(dev);
+ if (cpuidle_device_can_idle(dev))
+ cpuidle_install_idle_handler();
+ mutex_unlock(&cpuidle_lock);
+
+ return 0;
+}
+
+/**
+ * __cpuidle_remove_device - detaches the driver from a CPU instance
+ * @sys_dev: the system device (driver model CPU representation)
+ *
+ * Must be called with cpuidle_lock aquired.
+ */
+static int __cpuidle_remove_device(struct sys_device *sys_dev)
+{
+ struct cpuidle_device *dev;
+
+ dev = &per_cpu(cpuidle_devices, sys_dev->id);
+
+ if (!(dev->status & CPUIDLE_STATUS_DETECTED)) {
+ return 0;
+ }
+ dev->status &= ~CPUIDLE_STATUS_DETECTED;
+ /* NOTE: we don't wait because the cpu is already offline */
+ if (cpuidle_curr_governor)
+ cpuidle_detach_governor(dev);
+ if (cpuidle_curr_driver)
+ cpuidle_detach_driver(dev);
+ cpuidle_remove_sysfs(sys_dev);
+ list_del(&dev->device_list);
+
+ return 0;
+}
+
+/**
+ * cpuidle_remove_device - detaches the driver from a CPU instance
+ * @sys_dev: the system device (driver model CPU representation)
+ */
+static int cpuidle_remove_device(struct sys_device *sys_dev)
+{
+ int ret;
+ mutex_lock(&cpuidle_lock);
+ ret = __cpuidle_remove_device(sys_dev);
+ mutex_unlock(&cpuidle_lock);
+
+ return ret;
+}
+
+static struct sysdev_driver cpuidle_sysdev_driver = {
+ .add = cpuidle_add_device,
+ .remove = cpuidle_remove_device,
+};
+
+#ifdef CONFIG_SMP
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int cpuidle_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ struct sys_device *sys_dev;
+
+ sys_dev = get_cpu_sysdev((unsigned long)hcpu);
+
+ switch (action) {
+ case CPU_ONLINE:
+ cpuidle_add_device(sys_dev);
+ break;
+ case CPU_DOWN_PREPARE:
+ mutex_lock(&cpuidle_lock);
+ break;
+ case CPU_DEAD:
+ __cpuidle_remove_device(sys_dev);
+ mutex_unlock(&cpuidle_lock);
+ break;
+ case CPU_DOWN_FAILED:
+ mutex_unlock(&cpuidle_lock);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata cpuidle_cpu_notifier =
+{
+ .notifier_call = cpuidle_cpu_callback,
+};
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
+static void smp_callback(void *v)
+{
+ /* we already woke the CPU up, nothing more to do */
+}
+
+/*
+ * This function gets called when a part of the kernel has a new latency
+ * requirement. This means we need to get all processors out of their C-state,
+ * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
+ * wakes them all right up.
+ */
+static int cpuidle_latency_notify(struct notifier_block *b,
+ unsigned long l, void *v)
+{
+ smp_call_function(smp_callback, NULL, 0, 1);
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cpuidle_latency_notifier = {
+ .notifier_call = cpuidle_latency_notify,
+};
+
+#define latency_notifier_init(x) do { register_latency_notifier(x); } while (0)
+
+#else /* CONFIG_SMP */
+
+#define latency_notifier_init(x) do { } while (0)
+
+#endif /* CONFIG_SMP */
+
+/**
+ * cpuidle_init - core initializer
+ */
+static int __init cpuidle_init(void)
+{
+ int ret;
+
+ pm_idle_old = pm_idle;
+
+ ret = cpuidle_add_class_sysfs(&cpu_sysdev_class);
+ if (ret)
+ return ret;
+
+ register_hotcpu_notifier(&cpuidle_cpu_notifier);
+
+ ret = sysdev_driver_register(&cpu_sysdev_class, &cpuidle_sysdev_driver);
+
+ if (ret) {
+ cpuidle_remove_class_sysfs(&cpu_sysdev_class);
+ printk(KERN_ERR "cpuidle: failed to initialize\n");
+ return ret;
+ }
+
+ latency_notifier_init(&cpuidle_latency_notifier);
+
+ return 0;
+}
+
+core_initcall(cpuidle_init);
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
new file mode 100644
index 0000000..2defa39
--- /dev/null
+++ b/drivers/cpuidle/cpuidle.h
@@ -0,0 +1,52 @@
+/*
+ * cpuidle.h - The internal header file
+ */
+
+#ifndef __DRIVER_CPUIDLE_H
+#define __DRIVER_CPUIDLE_H
+
+#include <linux/sysdev.h>
+
+/* For internal use only */
+extern struct cpuidle_governor *cpuidle_curr_governor;
+extern struct cpuidle_driver *cpuidle_curr_driver;
+extern struct list_head cpuidle_drivers;
+extern struct list_head cpuidle_governors;
+extern struct list_head cpuidle_detected_devices;
+extern struct mutex cpuidle_lock;
+
+/* idle loop */
+extern void cpuidle_install_idle_handler(void);
+extern void cpuidle_uninstall_idle_handler(void);
+extern void cpuidle_rescan_device(struct cpuidle_device *dev);
+
+/* drivers */
+extern int cpuidle_attach_driver(struct cpuidle_device *dev);
+extern void cpuidle_detach_driver(struct cpuidle_device *dev);
+extern struct cpuidle_driver * __cpuidle_find_driver(const char *str);
+extern int cpuidle_switch_driver(struct cpuidle_driver *drv);
+
+/* governors */
+extern int cpuidle_attach_governor(struct cpuidle_device *dev);
+extern void cpuidle_detach_governor(struct cpuidle_device *dev);
+extern struct cpuidle_governor * __cpuidle_find_governor(const char *str);
+extern int cpuidle_switch_governor(struct cpuidle_governor *gov);
+
+/* sysfs */
+extern int cpuidle_add_class_sysfs(struct sysdev_class *cls);
+extern void cpuidle_remove_class_sysfs(struct sysdev_class *cls);
+extern int cpuidle_add_driver_sysfs(struct cpuidle_device *device);
+extern void cpuidle_remove_driver_sysfs(struct cpuidle_device *device);
+extern int cpuidle_add_sysfs(struct sys_device *sysdev);
+extern void cpuidle_remove_sysfs(struct sys_device *sysdev);
+
+/**
+ * cpuidle_device_can_idle - determines if a CPU can utilize the idle loop
+ * @dev: the target CPU
+ */
+static inline int cpuidle_device_can_idle(struct cpuidle_device *dev)
+{
+ return (dev->status == CPUIDLE_STATUS_DOIDLE);
+}
+
+#endif /* __DRIVER_CPUIDLE_H */
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
new file mode 100644
index 0000000..1111279
--- /dev/null
+++ b/drivers/cpuidle/driver.c
@@ -0,0 +1,219 @@
+/*
+ * driver.c - driver support
+ *
+ * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ * Shaohua Li <shaohua.li@intel.com>
+ * Adam Belay <abelay@novell.com>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/cpuidle.h>
+
+#include "cpuidle.h"
+
+LIST_HEAD(cpuidle_drivers);
+struct cpuidle_driver *cpuidle_curr_driver;
+
+
+/**
+ * cpuidle_attach_driver - attaches a driver to a CPU
+ * @dev: the target CPU
+ *
+ * Must be called with cpuidle_lock aquired.
+ */
+int cpuidle_attach_driver(struct cpuidle_device *dev)
+{
+ int ret;
+
+ if (dev->status & CPUIDLE_STATUS_DRIVER_ATTACHED)
+ return -EIO;
+
+ if (!try_module_get(cpuidle_curr_driver->owner))
+ return -EINVAL;
+
+ ret = cpuidle_curr_driver->init(dev);
+ if (ret) {
+ module_put(cpuidle_curr_driver->owner);
+ printk(KERN_ERR "cpuidle: driver %s failed to attach to cpu %d\n",
+ cpuidle_curr_driver->name, dev->cpu);
+ } else {
+ if (dev->status & CPUIDLE_STATUS_GOVERNOR_ATTACHED)
+ cpuidle_rescan_device(dev);
+ smp_wmb();
+ dev->status |= CPUIDLE_STATUS_DRIVER_ATTACHED;
+ cpuidle_add_driver_sysfs(dev);
+ }
+
+ return ret;
+}
+
+/**
+ * cpuidle_detach_govenor - detaches a driver from a CPU
+ * @dev: the target CPU
+ *
+ * Must be called with cpuidle_lock aquired.
+ */
+void cpuidle_detach_driver(struct cpuidle_device *dev)
+{
+ if (dev->status & CPUIDLE_STATUS_DRIVER_ATTACHED) {
+ cpuidle_remove_driver_sysfs(dev);
+ dev->status &= ~CPUIDLE_STATUS_DRIVER_ATTACHED;
+ if (cpuidle_curr_driver->exit)
+ cpuidle_curr_driver->exit(dev);
+ module_put(cpuidle_curr_driver->owner);
+ }
+}
+
+/**
+ * __cpuidle_find_driver - finds a driver of the specified name
+ * @str: the name
+ *
+ * Must be called with cpuidle_lock aquired.
+ */
+struct cpuidle_driver * __cpuidle_find_driver(const char *str)
+{
+ struct cpuidle_driver *drv;
+
+ list_for_each_entry(drv, &cpuidle_drivers, driver_list)
+ if (!strnicmp(str, drv->name, CPUIDLE_NAME_LEN))
+ return drv;
+
+ return NULL;
+}
+
+/**
+ * cpuidle_switch_driver - changes the driver
+ * @drv: the new target driver
+ *
+ * NOTE: "drv" can be NULL to specify disabled
+ * Must be called with cpuidle_lock aquired.
+ */
+int cpuidle_switch_driver(struct cpuidle_driver *drv)
+{
+ struct cpuidle_device *dev;
+
+ if (drv == cpuidle_curr_driver)
+ return -EINVAL;
+
+ cpuidle_uninstall_idle_handler();
+
+ if (cpuidle_curr_driver)
+ list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
+ cpuidle_detach_driver(dev);
+
+ cpuidle_curr_driver = drv;
+
+ if (drv) {
+ list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
+ cpuidle_attach_driver(dev);
+ if (cpuidle_curr_governor)
+ cpuidle_install_idle_handler();
+ printk(KERN_INFO "cpuidle: using driver %s\n", drv->name);
+ }
+
+ return 0;
+}
+
+/**
+ * cpuidle_register_driver - registers a driver
+ * @drv: the driver
+ */
+int cpuidle_register_driver(struct cpuidle_driver *drv)
+{
+ int ret = -EEXIST;
+
+ if (!drv || !drv->init)
+ return -EINVAL;
+
+ mutex_lock(&cpuidle_lock);
+ if (__cpuidle_find_driver(drv->name) == NULL) {
+ ret = 0;
+ list_add_tail(&drv->driver_list, &cpuidle_drivers);
+ if (!cpuidle_curr_driver)
+ cpuidle_switch_driver(drv);
+ }
+ mutex_unlock(&cpuidle_lock);
+
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(cpuidle_register_driver);
+
+/**
+ * cpuidle_unregister_driver - unregisters a driver
+ * @drv: the driver
+ */
+void cpuidle_unregister_driver(struct cpuidle_driver *drv)
+{
+ if (!drv)
+ return;
+
+ mutex_lock(&cpuidle_lock);
+ if (drv == cpuidle_curr_driver)
+ cpuidle_switch_driver(NULL);
+ list_del(&drv->driver_list);
+ mutex_unlock(&cpuidle_lock);
+}
+
+EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
+
+/**
+ * cpuidle_force_redetect - redetects the idle states of a CPU
+ *
+ * @dev: the CPU to redetect
+ *
+ * Generally, the driver will call this when the supported states set has
+ * changed. (e.g. as the result of an ACPI transition to battery power)
+ */
+int cpuidle_force_redetect(struct cpuidle_device *dev)
+{
+ int uninstalled = 0;
+
+ mutex_lock(&cpuidle_lock);
+
+ if (!(dev->status & CPUIDLE_STATUS_DRIVER_ATTACHED) ||
+ !cpuidle_curr_driver->redetect) {
+ mutex_unlock(&cpuidle_lock);
+ return -EIO;
+ }
+
+ if (cpuidle_device_can_idle(dev)) {
+ uninstalled = 1;
+ cpuidle_uninstall_idle_handler();
+ }
+
+ cpuidle_remove_driver_sysfs(dev);
+ cpuidle_curr_driver->redetect(dev);
+ cpuidle_add_driver_sysfs(dev);
+
+ if (cpuidle_device_can_idle(dev)) {
+ cpuidle_rescan_device(dev);
+ cpuidle_install_idle_handler();
+ }
+
+ /* other devices are still ok */
+ if (uninstalled)
+ cpuidle_install_idle_handler();
+
+ mutex_unlock(&cpuidle_lock);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(cpuidle_force_redetect);
+
+/**
+ * cpuidle_get_bm_activity - determines if BM activity has occured
+ */
+int cpuidle_get_bm_activity(void)
+{
+ if (cpuidle_curr_driver->bm_check)
+ return cpuidle_curr_driver->bm_check();
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpuidle_get_bm_activity);
+
diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c
new file mode 100644
index 0000000..b2d6a69
--- /dev/null
+++ b/drivers/cpuidle/governor.c
@@ -0,0 +1,160 @@
+/*
+ * governor.c - governor support
+ *
+ * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ * Shaohua Li <shaohua.li@intel.com>
+ * Adam Belay <abelay@novell.com>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/cpuidle.h>
+
+#include "cpuidle.h"
+
+LIST_HEAD(cpuidle_governors);
+struct cpuidle_governor *cpuidle_curr_governor;
+
+
+/**
+ * cpuidle_attach_governor - attaches a governor to a CPU
+ * @dev: the target CPU
+ *
+ * Must be called with cpuidle_lock aquired.
+ */
+int cpuidle_attach_governor(struct cpuidle_device *dev)
+{
+ int ret = 0;
+
+ if(dev->status & CPUIDLE_STATUS_GOVERNOR_ATTACHED)
+ return -EIO;
+
+ if (!try_module_get(cpuidle_curr_governor->owner))
+ return -EINVAL;
+
+ if (cpuidle_curr_governor->init)
+ ret = cpuidle_curr_governor->init(dev);
+ if (ret) {
+ module_put(cpuidle_curr_governor->owner);
+ printk(KERN_ERR "cpuidle: governor %s failed to attach to cpu %d\n",
+ cpuidle_curr_governor->name, dev->cpu);
+ } else {
+ if (dev->status & CPUIDLE_STATUS_DRIVER_ATTACHED)
+ cpuidle_rescan_device(dev);
+ smp_wmb();
+ dev->status |= CPUIDLE_STATUS_GOVERNOR_ATTACHED;
+ }
+
+ return ret;
+}
+
+/**
+ * cpuidle_detach_govenor - detaches a governor from a CPU
+ * @dev: the target CPU
+ *
+ * Must be called with cpuidle_lock aquired.
+ */
+void cpuidle_detach_governor(struct cpuidle_device *dev)
+{
+ if (dev->status & CPUIDLE_STATUS_GOVERNOR_ATTACHED) {
+ dev->status &= ~CPUIDLE_STATUS_GOVERNOR_ATTACHED;
+ if (cpuidle_curr_governor->exit)
+ cpuidle_curr_governor->exit(dev);
+ module_put(cpuidle_curr_governor->owner);
+ }
+}
+
+/**
+ * __cpuidle_find_governor - finds a governor of the specified name
+ * @str: the name
+ *
+ * Must be called with cpuidle_lock aquired.
+ */
+struct cpuidle_governor * __cpuidle_find_governor(const char *str)
+{
+ struct cpuidle_governor *gov;
+
+ list_for_each_entry(gov, &cpuidle_governors, governor_list)
+ if (!strnicmp(str, gov->name, CPUIDLE_NAME_LEN))
+ return gov;
+
+ return NULL;
+}
+
+/**
+ * cpuidle_switch_governor - changes the governor
+ * @gov: the new target governor
+ *
+ * NOTE: "gov" can be NULL to specify disabled
+ * Must be called with cpuidle_lock aquired.
+ */
+int cpuidle_switch_governor(struct cpuidle_governor *gov)
+{
+ struct cpuidle_device *dev;
+
+ if (gov == cpuidle_curr_governor)
+ return -EINVAL;
+
+ cpuidle_uninstall_idle_handler();
+
+ if (cpuidle_curr_governor)
+ list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
+ cpuidle_detach_governor(dev);
+
+ cpuidle_curr_governor = gov;
+
+ if (gov) {
+ list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
+ cpuidle_attach_governor(dev);
+ if (cpuidle_curr_driver)
+ cpuidle_install_idle_handler();
+ printk(KERN_INFO "cpuidle: using governor %s\n", gov->name);
+ }
+
+ return 0;
+}
+
+/**
+ * cpuidle_register_governor - registers a governor
+ * @gov: the governor
+ */
+int cpuidle_register_governor(struct cpuidle_governor *gov)
+{
+ int ret = -EEXIST;
+
+ if (!gov || !gov->select_state)
+ return -EINVAL;
+
+ mutex_lock(&cpuidle_lock);
+ if (__cpuidle_find_governor(gov->name) == NULL) {
+ ret = 0;
+ list_add_tail(&gov->governor_list, &cpuidle_governors);
+ if (!cpuidle_curr_governor)
+ cpuidle_switch_governor(gov);
+ }
+ mutex_unlock(&cpuidle_lock);
+
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(cpuidle_register_governor);
+
+/**
+ * cpuidle_unregister_governor - unregisters a governor
+ * @gov: the governor
+ */
+void cpuidle_unregister_governor(struct cpuidle_governor *gov)
+{
+ if (!gov)
+ return;
+
+ mutex_lock(&cpuidle_lock);
+ if (gov == cpuidle_curr_governor)
+ cpuidle_switch_governor(NULL);
+ list_del(&gov->governor_list);
+ mutex_unlock(&cpuidle_lock);
+}
+
+EXPORT_SYMBOL_GPL(cpuidle_unregister_governor);
diff --git a/drivers/cpuidle/governors/Makefile b/drivers/cpuidle/governors/Makefile
new file mode 100644
index 0000000..becf470
--- /dev/null
+++ b/drivers/cpuidle/governors/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for cpuidle governors.
+#
+
+obj-$(CONFIG_CPU_IDLE_GOV_LADDER) += ladder.o
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
new file mode 100644
index 0000000..d999393
--- /dev/null
+++ b/drivers/cpuidle/governors/ladder.c
@@ -0,0 +1,229 @@
+/*
+ * ladder.c - the residency ladder algorithm
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004, 2005 Dominik Brodowski <linux@brodo.de>
+ *
+ * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ * Shaohua Li <shaohua.li@intel.com>
+ * Adam Belay <abelay@novell.com>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpuidle.h>
+#include <linux/acpi.h>
+#include <linux/latency.h>
+#include <linux/moduleparam.h>
+#include <linux/jiffies.h>
+#include <acpi/processor.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define PROMOTION_COUNT 4
+#define DEMOTION_COUNT 1
+
+/*
+ * bm_history -- bit-mask with a bit per jiffy of bus-master activity
+ * 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms
+ * 800 HZ: 0xFFFFFFFF: 32 jiffies = 40ms
+ * 100 HZ: 0x0000000F: 4 jiffies = 40ms
+ * reduce history for more aggressive entry into C3
+ */
+static unsigned int bm_history __read_mostly =
+ (HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1));
+module_param(bm_history, uint, 0644);
+
+struct ladder_device_state {
+ struct {
+ u32 promotion_count;
+ u32 demotion_count;
+ u32 promotion_time;
+ u32 demotion_time;
+ u32 bm;
+ } threshold;
+ struct {
+ int promotion_count;
+ int demotion_count;
+ } stats;
+};
+
+struct ladder_device {
+ struct ladder_device_state states[CPUIDLE_STATE_MAX];
+ int bm_check:1;
+ unsigned long bm_check_timestamp;
+ unsigned long bm_activity; /* FIXME: bm activity should be global */
+ int last_state_idx;
+};
+
+/**
+ * ladder_do_selection - prepares private data for a state change
+ * @ldev: the ladder device
+ * @old_idx: the current state index
+ * @new_idx: the new target state index
+ */
+static inline void ladder_do_selection(struct ladder_device *ldev,
+ int old_idx, int new_idx)
+{
+ ldev->states[old_idx].stats.promotion_count = 0;
+ ldev->states[old_idx].stats.demotion_count = 0;
+ ldev->last_state_idx = new_idx;
+}
+
+/**
+ * ladder_select_state - selects the next state to enter
+ * @dev: the CPU
+ */
+static int ladder_select_state(struct cpuidle_device *dev)
+{
+ struct ladder_device *ldev = dev->governor_data;
+ struct ladder_device_state *last_state;
+ int last_residency, last_idx = ldev->last_state_idx;
+
+ if (unlikely(!ldev))
+ return 0;
+
+ last_state = &ldev->states[last_idx];
+
+ /* demote if within BM threshold */
+ if (ldev->bm_check) {
+ unsigned long diff;
+
+ diff = jiffies - ldev->bm_check_timestamp;
+ if (diff > 31)
+ diff = 31;
+
+ ldev->bm_activity <<= diff;
+ if (cpuidle_get_bm_activity())
+ ldev->bm_activity |= ((1 << diff) - 1);
+
+ ldev->bm_check_timestamp = jiffies;
+ if ((last_idx > 0) &&
+ (last_state->threshold.bm & ldev->bm_activity)) {
+ ladder_do_selection(ldev, last_idx, last_idx - 1);
+ return last_idx - 1;
+ }
+ }
+
+ if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID)
+ last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency;
+ else
+ last_residency = last_state->threshold.promotion_time + 1;
+
+ /* consider promotion */
+ if (last_idx < dev->state_count - 1 &&
+ last_residency > last_state->threshold.promotion_time &&
+ dev->states[last_idx + 1].exit_latency <= system_latency_constraint()) {
+ last_state->stats.promotion_count++;
+ last_state->stats.demotion_count = 0;
+ if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
+ ladder_do_selection(ldev, last_idx, last_idx + 1);
+ return last_idx + 1;
+ }
+ }
+
+ /* consider demotion */
+ if (last_idx > 0 &&
+ last_residency < last_state->threshold.demotion_time) {
+ last_state->stats.demotion_count++;
+ last_state->stats.promotion_count = 0;
+ if (last_state->stats.demotion_count >= last_state->threshold.demotion_count) {
+ ladder_do_selection(ldev, last_idx, last_idx - 1);
+ return last_idx - 1;
+ }
+ }
+
+ /* otherwise remain at the current state */
+ return last_idx;
+}
+
+/**
+ * ladder_scan_device - scans a CPU's states and does setup
+ * @dev: the CPU
+ */
+static void ladder_scan_device(struct cpuidle_device *dev)
+{
+ int i, bm_check = 0;
+ struct ladder_device *ldev = dev->governor_data;
+ struct ladder_device_state *lstate;
+ struct cpuidle_state *state;
+
+ ldev->last_state_idx = 0;
+ ldev->bm_check_timestamp = 0;
+ ldev->bm_activity = 0;
+
+ for (i = 0; i < dev->state_count; i++) {
+ state = &dev->states[i];
+ lstate = &ldev->states[i];
+
+ lstate->stats.promotion_count = 0;
+ lstate->stats.demotion_count = 0;
+
+ lstate->threshold.promotion_count = PROMOTION_COUNT;
+ lstate->threshold.demotion_count = DEMOTION_COUNT;
+
+ if (i < dev->state_count - 1)
+ lstate->threshold.promotion_time = state->exit_latency;
+ if (i > 0)
+ lstate->threshold.demotion_time = state->exit_latency;
+ if (state->flags & CPUIDLE_FLAG_CHECK_BM) {
+ lstate->threshold.bm = bm_history;
+ bm_check = 1;
+ } else
+ lstate->threshold.bm = 0;
+ }
+
+ ldev->bm_check = bm_check;
+}
+
+/**
+ * ladder_init_device - initializes a CPU-instance
+ * @dev: the CPU
+ */
+static int ladder_init_device(struct cpuidle_device *dev)
+{
+ dev->governor_data = kmalloc(sizeof(struct ladder_device), GFP_KERNEL);
+
+ return !dev->governor_data;
+}
+
+/**
+ * ladder_exit_device - exits a CPU-instance
+ * @dev: the CPU
+ */
+static void ladder_exit_device(struct cpuidle_device *dev)
+{
+ kfree(dev->governor_data);
+}
+
+struct cpuidle_governor ladder_governor = {
+ .name = "ladder",
+ .init = ladder_init_device,
+ .exit = ladder_exit_device,
+ .scan = ladder_scan_device,
+ .select_state = ladder_select_state,
+ .owner = THIS_MODULE,
+};
+
+/**
+ * init_ladder - initializes the governor
+ */
+static int __init init_ladder(void)
+{
+ return cpuidle_register_governor(&ladder_governor);
+}
+
+/**
+ * exit_ladder - exits the governor
+ */
+static void __exit exit_ladder(void)
+{
+ cpuidle_unregister_governor(&ladder_governor);
+}
+
+MODULE_LICENSE("GPL");
+module_init(init_ladder);
+module_exit(exit_ladder);
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
new file mode 100644
index 0000000..8822d0d
--- /dev/null
+++ b/drivers/cpuidle/sysfs.c
@@ -0,0 +1,340 @@
+/*
+ * sysfs.c - sysfs support
+ *
+ * (C) 2006-2007 Shaohua Li <shaohua.li@intel.com>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpuidle.h>
+#include <linux/sysfs.h>
+#include <linux/cpu.h>
+
+#include "cpuidle.h"
+
+static ssize_t show_available_drivers(struct sys_device *dev, char *buf)
+{
+ ssize_t i = 0;
+ struct cpuidle_driver *tmp;
+
+ mutex_lock(&cpuidle_lock);
+ list_for_each_entry(tmp, &cpuidle_drivers, driver_list) {
+ if (i >= (ssize_t)((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2))
+ goto out;
+ i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name);
+ }
+out:
+ i+= sprintf(&buf[i], "\n");
+ mutex_unlock(&cpuidle_lock);
+ return i;
+}
+
+static ssize_t show_available_governors(struct sys_device *dev, char *buf)
+{
+ ssize_t i = 0;
+ struct cpuidle_governor *tmp;
+
+ mutex_lock(&cpuidle_lock);
+ list_for_each_entry(tmp, &cpuidle_governors, governor_list) {
+ if (i >= (ssize_t)((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2))
+ goto out;
+ i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name);
+ }
+ if (list_empty(&cpuidle_governors))
+ i+= sprintf(&buf[i], "no governors");
+out:
+ i+= sprintf(&buf[i], "\n");
+ mutex_unlock(&cpuidle_lock);
+ return i;
+}
+
+static ssize_t show_current_driver(struct sys_device *dev, char *buf)
+{
+ ssize_t ret;
+
+ mutex_lock(&cpuidle_lock);
+ ret = sprintf(buf, "%s\n", cpuidle_curr_driver->name);
+ mutex_unlock(&cpuidle_lock);
+ return ret;
+}
+
+static ssize_t store_current_driver(struct sys_device *dev,
+ const char *buf, size_t count)
+{
+ char str[CPUIDLE_NAME_LEN];
+ int len = count;
+ struct cpuidle_driver *tmp, *found = NULL;
+
+ if (len > CPUIDLE_NAME_LEN)
+ len = CPUIDLE_NAME_LEN;
+
+ if (sscanf(buf, "%s", str) != 1)
+ return -EINVAL;
+
+ mutex_lock(&cpuidle_lock);
+ list_for_each_entry(tmp, &cpuidle_drivers, driver_list) {
+ if (strncmp(tmp->name, str, CPUIDLE_NAME_LEN) == 0) {
+ found = tmp;
+ break;
+ }
+ }
+ if (found)
+ cpuidle_switch_driver(found);
+ mutex_unlock(&cpuidle_lock);
+
+ return count;
+}
+
+static ssize_t show_current_governor(struct sys_device *dev, char *buf)
+{
+ ssize_t i;
+
+ mutex_lock(&cpuidle_lock);
+ if (cpuidle_curr_governor)
+ i = sprintf(buf, "%s\n", cpuidle_curr_governor->name);
+ else
+ i = sprintf(buf, "no governor\n");
+ mutex_unlock(&cpuidle_lock);
+
+ return i;
+}
+
+static ssize_t store_current_governor(struct sys_device *dev,
+ const char *buf, size_t count)
+{
+ char str[CPUIDLE_NAME_LEN];
+ int len = count;
+ struct cpuidle_governor *tmp, *found = NULL;
+
+ if (len > CPUIDLE_NAME_LEN)
+ len = CPUIDLE_NAME_LEN;
+
+ if (sscanf(buf, "%s", str) != 1)
+ return -EINVAL;
+
+ mutex_lock(&cpuidle_lock);
+ list_for_each_entry(tmp, &cpuidle_governors, governor_list) {
+ if (strncmp(tmp->name, str, CPUIDLE_NAME_LEN) == 0) {
+ found = tmp;
+ break;
+ }
+ }
+ if (found)
+ cpuidle_switch_governor(found);
+ mutex_unlock(&cpuidle_lock);
+
+ return count;
+}
+
+static SYSDEV_ATTR(available_drivers, 0444, show_available_drivers, NULL);
+static SYSDEV_ATTR(available_governors, 0444, show_available_governors, NULL);
+static SYSDEV_ATTR(current_driver, 0644, show_current_driver,
+ store_current_driver);
+static SYSDEV_ATTR(current_governor, 0644, show_current_governor,
+ store_current_governor);
+
+static struct attribute *cpuclass_default_attrs[] = {
+ &attr_available_drivers.attr,
+ &attr_available_governors.attr,
+ &attr_current_driver.attr,
+ &attr_current_governor.attr,
+ NULL
+};
+
+static struct attribute_group cpuclass_attr_group = {
+ .attrs = cpuclass_default_attrs,
+ .name = "cpuidle",
+};
+
+/**
+ * cpuidle_add_class_sysfs - add CPU global sysfs attributes
+ */
+int cpuidle_add_class_sysfs(struct sysdev_class *cls)
+{
+ return sysfs_create_group(&cls->kset.kobj, &cpuclass_attr_group);
+}
+
+/**
+ * cpuidle_remove_class_sysfs - remove CPU global sysfs attributes
+ */
+void cpuidle_remove_class_sysfs(struct sysdev_class *cls)
+{
+ sysfs_remove_group(&cls->kset.kobj, &cpuclass_attr_group);
+}
+
+struct cpuidle_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct cpuidle_device *, char *);
+ ssize_t (*store)(struct cpuidle_device *, const char *, size_t count);
+};
+
+#define define_one_ro(_name, show) \
+ static struct cpuidle_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
+#define define_one_rw(_name, show, store) \
+ static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
+
+#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
+#define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
+static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
+{
+ int ret = -EIO;
+ struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
+ struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
+
+ if (cattr->show) {
+ mutex_lock(&cpuidle_lock);
+ ret = cattr->show(dev, buf);
+ mutex_unlock(&cpuidle_lock);
+ }
+ return ret;
+}
+
+static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
+ const char * buf, size_t count)
+{
+ int ret = -EIO;
+ struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
+ struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
+
+ if (cattr->store) {
+ mutex_lock(&cpuidle_lock);
+ ret = cattr->store(dev, buf, count);
+ mutex_unlock(&cpuidle_lock);
+ }
+ return ret;
+}
+
+static struct sysfs_ops cpuidle_sysfs_ops = {
+ .show = cpuidle_show,
+ .store = cpuidle_store,
+};
+
+static struct kobj_type ktype_cpuidle = {
+ .sysfs_ops = &cpuidle_sysfs_ops,
+};
+
+struct cpuidle_state_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct cpuidle_state *, char *);
+ ssize_t (*store)(struct cpuidle_state *, const char *, size_t);
+};
+
+#define define_one_state_ro(_name, show) \
+static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
+
+#define define_show_state_function(_name) \
+static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \
+{ \
+ return sprintf(buf, "%d\n", state->_name);\
+}
+
+define_show_state_function(exit_latency)
+define_show_state_function(power_usage)
+define_show_state_function(usage)
+define_show_state_function(time)
+define_one_state_ro(latency, show_state_exit_latency);
+define_one_state_ro(power, show_state_power_usage);
+define_one_state_ro(usage, show_state_usage);
+define_one_state_ro(time, show_state_time);
+
+static struct attribute *cpuidle_state_default_attrs[] = {
+ &attr_latency.attr,
+ &attr_power.attr,
+ &attr_usage.attr,
+ &attr_time.attr,
+ NULL
+};
+
+#define kobj_to_state(k) container_of(k, struct cpuidle_state, kobj)
+#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
+static ssize_t cpuidle_state_show(struct kobject * kobj,
+ struct attribute * attr ,char * buf)
+{
+ int ret = -EIO;
+ struct cpuidle_state *state = kobj_to_state(kobj);
+ struct cpuidle_state_attr * cattr = attr_to_stateattr(attr);
+
+ if (cattr->show)
+ ret = cattr->show(state, buf);
+
+ return ret;
+}
+
+static struct sysfs_ops cpuidle_state_sysfs_ops = {
+ .show = cpuidle_state_show,
+};
+
+static struct kobj_type ktype_state_cpuidle = {
+ .sysfs_ops = &cpuidle_state_sysfs_ops,
+ .default_attrs = cpuidle_state_default_attrs,
+};
+
+/**
+ * cpuidle_add_driver_sysfs - adds driver-specific sysfs attributes
+ * @device: the target device
+ */
+int cpuidle_add_driver_sysfs(struct cpuidle_device *device)
+{
+ int i, ret;
+ struct cpuidle_state *state;
+
+ /* state statistics */
+ for (i = 0; i < device->state_count; i++) {
+ state = &device->states[i];
+ state->kobj.parent = &device->kobj;
+ state->kobj.ktype = &ktype_state_cpuidle;
+ kobject_set_name(&state->kobj, "state%d", i);
+ ret = kobject_register(&state->kobj);
+ if (ret)
+ goto error_state;
+ }
+
+ return 0;
+
+error_state:
+ for (i = i - 1; i >= 0; i--)
+ kobject_unregister(&device->states[i].kobj);
+ return ret;
+}
+
+/**
+ * cpuidle_remove_driver_sysfs - removes driver-specific sysfs attributes
+ * @device: the target device
+ */
+void cpuidle_remove_driver_sysfs(struct cpuidle_device *device)
+{
+ int i;
+
+ for (i = 0; i < device->state_count; i++)
+ kobject_unregister(&device->states[i].kobj);
+}
+
+/**
+ * cpuidle_add_sysfs - creates a sysfs instance for the target device
+ * @sysdev: the target device
+ */
+int cpuidle_add_sysfs(struct sys_device *sysdev)
+{
+ int cpu = sysdev->id;
+ struct cpuidle_device *dev;
+
+ dev = &per_cpu(cpuidle_devices, cpu);
+ dev->kobj.parent = &sysdev->kobj;
+ dev->kobj.ktype = &ktype_cpuidle;
+ kobject_set_name(&dev->kobj, "%s", "cpuidle");
+ return kobject_register(&dev->kobj);
+}
+
+/**
+ * cpuidle_remove_sysfs - deletes a sysfs instance on the target device
+ * @sysdev: the target device
+ */
+void cpuidle_remove_sysfs(struct sys_device *sysdev)
+{
+ int cpu = sysdev->id;
+ struct cpuidle_device *dev;
+
+ dev = &per_cpu(cpuidle_devices, cpu);
+ kobject_unregister(&dev->kobj);
+}
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
new file mode 100644
index 0000000..d26a82e
--- /dev/null
+++ b/include/linux/cpuidle.h
@@ -0,0 +1,160 @@
+/*
+ * cpuidle.h - a generic framework for CPU idle power management
+ *
+ * (C) 2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ * Shaohua Li <shaohua.li@intel.com>
+ * Adam Belay <abelay@novell.com>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#ifndef _LINUX_CPUIDLE_H
+#define _LINUX_CPUIDLE_H
+
+#include <linux/percpu.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/completion.h>
+
+#define CPUIDLE_STATE_MAX 8
+#define CPUIDLE_NAME_LEN 16
+
+struct cpuidle_device;
+
+
+/****************************
+ * CPUIDLE DEVICE INTERFACE *
+ ****************************/
+
+struct cpuidle_state {
+ char name[CPUIDLE_NAME_LEN];
+ void *driver_data;
+
+ unsigned int flags;
+ unsigned int exit_latency; /* in US */
+ unsigned int power_usage; /* in mW */
+ unsigned int target_residency; /* in US */
+
+ unsigned int usage;
+ unsigned int time; /* in US */
+
+ int (*enter) (struct cpuidle_device *dev,
+ struct cpuidle_state *state);
+
+ struct kobject kobj;
+};
+
+/* Idle State Flags */
+#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
+#define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */
+#define CPUIDLE_FLAG_SHALLOW (0x10) /* low latency, minimal savings */
+#define CPUIDLE_FLAG_BALANCED (0x20) /* medium latency, moderate savings */
+#define CPUIDLE_FLAG_DEEP (0x40) /* high latency, large savings */
+
+#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
+
+/**
+ * cpuidle_get_statedata - retrieves private driver state data
+ * @state: the state
+ */
+static inline void * cpuidle_get_statedata(struct cpuidle_state *state)
+{
+ return state->driver_data;
+}
+
+/**
+ * cpuidle_set_statedata - stores private driver state data
+ * @state: the state
+ * @data: the private data
+ */
+static inline void
+cpuidle_set_statedata(struct cpuidle_state *state, void *data)
+{
+ state->driver_data = data;
+}
+
+struct cpuidle_device {
+ unsigned int status;
+ int cpu;
+
+ int last_residency;
+ int state_count;
+ struct cpuidle_state states[CPUIDLE_STATE_MAX];
+ struct cpuidle_state *last_state;
+
+ struct list_head device_list;
+ struct kobject kobj;
+ struct completion kobj_unregister;
+ void *governor_data;
+};
+
+#define to_cpuidle_device(n) container_of(n, struct cpuidle_device, kobj);
+
+DECLARE_PER_CPU(struct cpuidle_device, cpuidle_devices);
+
+/* Device Status Flags */
+#define CPUIDLE_STATUS_DETECTED (0x1)
+#define CPUIDLE_STATUS_DRIVER_ATTACHED (0x2)
+#define CPUIDLE_STATUS_GOVERNOR_ATTACHED (0x4)
+#define CPUIDLE_STATUS_DOIDLE (CPUIDLE_STATUS_DETECTED | \
+ CPUIDLE_STATUS_DRIVER_ATTACHED | \
+ CPUIDLE_STATUS_GOVERNOR_ATTACHED)
+
+/**
+ * cpuidle_get_last_residency - retrieves the last state's residency time
+ * @dev: the target CPU
+ *
+ * NOTE: this value is invalid if CPUIDLE_FLAG_TIME_VALID isn't set
+ */
+static inline int cpuidle_get_last_residency(struct cpuidle_device *dev)
+{
+ return dev->last_residency;
+}
+
+
+/****************************
+ * CPUIDLE DRIVER INTERFACE *
+ ****************************/
+
+struct cpuidle_driver {
+ char name[CPUIDLE_NAME_LEN];
+ struct list_head driver_list;
+
+ int (*init) (struct cpuidle_device *dev);
+ void (*exit) (struct cpuidle_device *dev);
+ int (*redetect) (struct cpuidle_device *dev);
+
+ int (*bm_check) (void);
+
+ struct module *owner;
+};
+
+extern int cpuidle_register_driver(struct cpuidle_driver *drv);
+extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
+extern int cpuidle_force_redetect(struct cpuidle_device *dev);
+
+
+/******************************
+ * CPUIDLE GOVERNOR INTERFACE *
+ ******************************/
+
+struct cpuidle_governor {
+ char name[CPUIDLE_NAME_LEN];
+ struct list_head governor_list;
+
+ int (*init) (struct cpuidle_device *dev);
+ void (*exit) (struct cpuidle_device *dev);
+ void (*scan) (struct cpuidle_device *dev);
+
+ void (*prepare_idle) (struct cpuidle_device *dev);
+ int (*select_state) (struct cpuidle_device *dev);
+
+ struct module *owner;
+};
+
+extern int cpuidle_register_governor(struct cpuidle_governor *gov);
+extern void cpuidle_unregister_governor(struct cpuidle_governor *gov);
+extern int cpuidle_get_bm_activity(void);
+
+#endif /* _LINUX_CPUIDLE_H */
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 02/22] cpuidle take2: Hookup ACPI C-states driver with cpuidle
[not found] ` <92648781fb5f44cee584da36eb569e88dddc4b8f.1173498651.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Venkatesh Pallipadi, Shaohua Li, Adam Belay, Len Brown
From: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Hookup ACPI C-states onto generic cpuidle infrastructure.
drivers/acpi/procesor_idle.c is now a ACPI C-states driver that registers as
a driver in cpuidle infrastructure and the policy part is removed from
drivers/acpi/processor_idle.c. We use governor in cpuidle instead.
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Adam Belay <abelay@novell.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/processor_core.c | 3 +
drivers/acpi/processor_idle.c | 868 ++++++++++++++++-------------------------
include/acpi/processor.h | 2 +
3 files changed, 337 insertions(+), 536 deletions(-)
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 99d1516..ddc9e20 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -44,6 +44,7 @@
#include <linux/seq_file.h>
#include <linux/dmi.h>
#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -1024,11 +1025,13 @@ static int __init acpi_processor_init(void)
acpi_processor_ppc_init();
+ cpuidle_register_driver(&acpi_idle_driver);
return 0;
}
static void __exit acpi_processor_exit(void)
{
+ cpuidle_unregister_driver(&acpi_idle_driver);
acpi_processor_ppc_exit();
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 6077300..eba8bed 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -40,6 +40,7 @@
#include <linux/sched.h> /* need_resched() */
#include <linux/latency.h>
#include <linux/clockchips.h>
+#include <linux/cpuidle.h>
/*
* Include the apic definitions for x86 to have the APIC timer related defines
@@ -70,25 +71,15 @@
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_idle");
#define ACPI_PROCESSOR_FILE_POWER "power"
-#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
-#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
-#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
-static void (*pm_idle_save) (void) __read_mostly;
+#define PM_TIMER_TICKS_TO_US(p) (((p) * 1000)/(PM_TIMER_FREQUENCY/1000))
+#define C2_OVERHEAD 1 /* 1us */
+#define C3_OVERHEAD 1 /* 1us */
+
module_param(max_cstate, uint, 0644);
static unsigned int nocst __read_mostly;
module_param(nocst, uint, 0000);
-/*
- * bm_history -- bit-mask with a bit per jiffy of bus-master activity
- * 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms
- * 800 HZ: 0xFFFFFFFF: 32 jiffies = 40ms
- * 100 HZ: 0x0000000F: 4 jiffies = 40ms
- * reduce history for more aggressive entry into C3
- */
-static unsigned int bm_history __read_mostly =
- (HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1));
-module_param(bm_history, uint, 0644);
/* --------------------------------------------------------------------------
Power Management
-------------------------------------------------------------------------- */
@@ -174,88 +165,6 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
{},
};
-static inline u32 ticks_elapsed(u32 t1, u32 t2)
-{
- if (t2 >= t1)
- return (t2 - t1);
- else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
- return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
- else
- return ((0xFFFFFFFF - t1) + t2);
-}
-
-static void
-acpi_processor_power_activate(struct acpi_processor *pr,
- struct acpi_processor_cx *new)
-{
- struct acpi_processor_cx *old;
-
- if (!pr || !new)
- return;
-
- old = pr->power.state;
-
- if (old)
- old->promotion.count = 0;
- new->demotion.count = 0;
-
- /* Cleanup from old state. */
- if (old) {
- switch (old->type) {
- case ACPI_STATE_C3:
- /* Disable bus master reload */
- if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
- break;
- }
- }
-
- /* Prepare to use new state. */
- switch (new->type) {
- case ACPI_STATE_C3:
- /* Enable bus master reload */
- if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
- break;
- }
-
- pr->power.state = new;
-
- return;
-}
-
-static void acpi_safe_halt(void)
-{
- current_thread_info()->status &= ~TS_POLLING;
- /*
- * TS_POLLING-cleared state must be visible before we
- * test NEED_RESCHED:
- */
- smp_mb();
- if (!need_resched())
- safe_halt();
- current_thread_info()->status |= TS_POLLING;
-}
-
-static atomic_t c3_cpu_count;
-
-/* Common C-state entry for C2, C3, .. */
-static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
-{
- if (cstate->space_id == ACPI_CSTATE_FFH) {
- /* Call into architectural FFH based C-state */
- acpi_processor_ffh_cstate_enter(cstate);
- } else {
- int unused;
- /* IO port based C-state */
- inb(cstate->address);
- /* Dummy wait op - must do something useless after P_LVL2 read
- because chipsets cannot guarantee that STPCLK# signal
- gets asserted in time to freeze execution properly. */
- unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
- }
-}
-
#ifdef ARCH_APICTIMER_STOPS_ON_C3
/*
@@ -330,376 +239,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
}
#endif
-
-static void acpi_processor_idle(void)
-{
- struct acpi_processor *pr = NULL;
- struct acpi_processor_cx *cx = NULL;
- struct acpi_processor_cx *next_state = NULL;
- int sleep_ticks = 0;
- u32 t1, t2 = 0;
-
- pr = processors[smp_processor_id()];
- if (!pr)
- return;
-
- /*
- * Interrupts must be disabled during bus mastering calculations and
- * for C2/C3 transitions.
- */
- local_irq_disable();
-
- /*
- * Check whether we truly need to go idle, or should
- * reschedule:
- */
- if (unlikely(need_resched())) {
- local_irq_enable();
- return;
- }
-
- cx = pr->power.state;
- if (!cx) {
- if (pm_idle_save)
- pm_idle_save();
- else
- acpi_safe_halt();
- return;
- }
-
- /*
- * Check BM Activity
- * -----------------
- * Check for bus mastering activity (if required), record, and check
- * for demotion.
- */
- if (pr->flags.bm_check) {
- u32 bm_status = 0;
- unsigned long diff = jiffies - pr->power.bm_check_timestamp;
-
- if (diff > 31)
- diff = 31;
-
- pr->power.bm_activity <<= diff;
-
- acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
- if (bm_status) {
- pr->power.bm_activity |= 0x1;
- acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
- }
- /*
- * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
- * the true state of bus mastering activity; forcing us to
- * manually check the BMIDEA bit of each IDE channel.
- */
- else if (errata.piix4.bmisx) {
- if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
- || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
- pr->power.bm_activity |= 0x1;
- }
-
- pr->power.bm_check_timestamp = jiffies;
-
- /*
- * If bus mastering is or was active this jiffy, demote
- * to avoid a faulty transition. Note that the processor
- * won't enter a low-power state during this call (to this
- * function) but should upon the next.
- *
- * TBD: A better policy might be to fallback to the demotion
- * state (use it for this quantum only) istead of
- * demoting -- and rely on duration as our sole demotion
- * qualification. This may, however, introduce DMA
- * issues (e.g. floppy DMA transfer overrun/underrun).
- */
- if ((pr->power.bm_activity & 0x1) &&
- cx->demotion.threshold.bm) {
- local_irq_enable();
- next_state = cx->demotion.state;
- goto end;
- }
- }
-
-#ifdef CONFIG_HOTPLUG_CPU
- /*
- * Check for P_LVL2_UP flag before entering C2 and above on
- * an SMP system. We do it here instead of doing it at _CST/P_LVL
- * detection phase, to work cleanly with logical CPU hotplug.
- */
- if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
- cx = &pr->power.states[ACPI_STATE_C1];
-#endif
-
- /*
- * Sleep:
- * ------
- * Invoke the current Cx state to put the processor to sleep.
- */
- if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) {
- current_thread_info()->status &= ~TS_POLLING;
- /*
- * TS_POLLING-cleared state must be visible before we
- * test NEED_RESCHED:
- */
- smp_mb();
- if (need_resched()) {
- current_thread_info()->status |= TS_POLLING;
- local_irq_enable();
- return;
- }
- }
-
- switch (cx->type) {
-
- case ACPI_STATE_C1:
- /*
- * Invoke C1.
- * Use the appropriate idle routine, the one that would
- * be used without acpi C-states.
- */
- if (pm_idle_save)
- pm_idle_save();
- else
- acpi_safe_halt();
-
- /*
- * TBD: Can't get time duration while in C1, as resumes
- * go to an ISR rather than here. Need to instrument
- * base interrupt handler.
- */
- sleep_ticks = 0xFFFFFFFF;
- break;
-
- case ACPI_STATE_C2:
- /* Get start time (ticks) */
- t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
- /* Invoke C2 */
- acpi_state_timer_broadcast(pr, cx, 1);
- acpi_cstate_enter(cx);
- /* Get end time (ticks) */
- t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-
-#ifdef CONFIG_GENERIC_TIME
- /* TSC halts in C2, so notify users */
- mark_tsc_unstable();
-#endif
- /* Re-enable interrupts */
- local_irq_enable();
- current_thread_info()->status |= TS_POLLING;
- /* Compute time (ticks) that we were actually asleep */
- sleep_ticks =
- ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
- acpi_state_timer_broadcast(pr, cx, 0);
- break;
-
- case ACPI_STATE_C3:
-
- if (pr->flags.bm_check) {
- if (atomic_inc_return(&c3_cpu_count) ==
- num_online_cpus()) {
- /*
- * All CPUs are trying to go to C3
- * Disable bus master arbitration
- */
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
- }
- } else {
- /* SMP with no shared cache... Invalidate cache */
- ACPI_FLUSH_CPU_CACHE();
- }
-
- /* Get start time (ticks) */
- t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
- /* Invoke C3 */
- acpi_state_timer_broadcast(pr, cx, 1);
- acpi_cstate_enter(cx);
- /* Get end time (ticks) */
- t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
- if (pr->flags.bm_check) {
- /* Enable bus master arbitration */
- atomic_dec(&c3_cpu_count);
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
- }
-
-#ifdef CONFIG_GENERIC_TIME
- /* TSC halts in C3, so notify users */
- mark_tsc_unstable();
-#endif
- /* Re-enable interrupts */
- local_irq_enable();
- current_thread_info()->status |= TS_POLLING;
- /* Compute time (ticks) that we were actually asleep */
- sleep_ticks =
- ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;
- acpi_state_timer_broadcast(pr, cx, 0);
- break;
-
- default:
- local_irq_enable();
- return;
- }
- cx->usage++;
- if ((cx->type != ACPI_STATE_C1) && (sleep_ticks > 0))
- cx->time += sleep_ticks;
-
- next_state = pr->power.state;
-
-#ifdef CONFIG_HOTPLUG_CPU
- /* Don't do promotion/demotion */
- if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) {
- next_state = cx;
- goto end;
- }
-#endif
-
- /*
- * Promotion?
- * ----------
- * Track the number of longs (time asleep is greater than threshold)
- * and promote when the count threshold is reached. Note that bus
- * mastering activity may prevent promotions.
- * Do not promote above max_cstate.
- */
- if (cx->promotion.state &&
- ((cx->promotion.state - pr->power.states) <= max_cstate)) {
- if (sleep_ticks > cx->promotion.threshold.ticks &&
- cx->promotion.state->latency <= system_latency_constraint()) {
- cx->promotion.count++;
- cx->demotion.count = 0;
- if (cx->promotion.count >=
- cx->promotion.threshold.count) {
- if (pr->flags.bm_check) {
- if (!
- (pr->power.bm_activity & cx->
- promotion.threshold.bm)) {
- next_state =
- cx->promotion.state;
- goto end;
- }
- } else {
- next_state = cx->promotion.state;
- goto end;
- }
- }
- }
- }
-
- /*
- * Demotion?
- * ---------
- * Track the number of shorts (time asleep is less than time threshold)
- * and demote when the usage threshold is reached.
- */
- if (cx->demotion.state) {
- if (sleep_ticks < cx->demotion.threshold.ticks) {
- cx->demotion.count++;
- cx->promotion.count = 0;
- if (cx->demotion.count >= cx->demotion.threshold.count) {
- next_state = cx->demotion.state;
- goto end;
- }
- }
- }
-
- end:
- /*
- * Demote if current state exceeds max_cstate
- * or if the latency of the current state is unacceptable
- */
- if ((pr->power.state - pr->power.states) > max_cstate ||
- pr->power.state->latency > system_latency_constraint()) {
- if (cx->demotion.state)
- next_state = cx->demotion.state;
- }
-
- /*
- * New Cx State?
- * -------------
- * If we're going to start using a new Cx state we must clean up
- * from the previous and prepare to use the new.
- */
- if (next_state != pr->power.state)
- acpi_processor_power_activate(pr, next_state);
-}
-
-static int acpi_processor_set_power_policy(struct acpi_processor *pr)
-{
- unsigned int i;
- unsigned int state_is_set = 0;
- struct acpi_processor_cx *lower = NULL;
- struct acpi_processor_cx *higher = NULL;
- struct acpi_processor_cx *cx;
-
-
- if (!pr)
- return -EINVAL;
-
- /*
- * This function sets the default Cx state policy (OS idle handler).
- * Our scheme is to promote quickly to C2 but more conservatively
- * to C3. We're favoring C2 for its characteristics of low latency
- * (quick response), good power savings, and ability to allow bus
- * mastering activity. Note that the Cx state policy is completely
- * customizable and can be altered dynamically.
- */
-
- /* startup state */
- for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
- cx = &pr->power.states[i];
- if (!cx->valid)
- continue;
-
- if (!state_is_set)
- pr->power.state = cx;
- state_is_set++;
- break;
- }
-
- if (!state_is_set)
- return -ENODEV;
-
- /* demotion */
- for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
- cx = &pr->power.states[i];
- if (!cx->valid)
- continue;
-
- if (lower) {
- cx->demotion.state = lower;
- cx->demotion.threshold.ticks = cx->latency_ticks;
- cx->demotion.threshold.count = 1;
- if (cx->type == ACPI_STATE_C3)
- cx->demotion.threshold.bm = bm_history;
- }
-
- lower = cx;
- }
-
- /* promotion */
- for (i = (ACPI_PROCESSOR_MAX_POWER - 1); i > 0; i--) {
- cx = &pr->power.states[i];
- if (!cx->valid)
- continue;
-
- if (higher) {
- cx->promotion.state = higher;
- cx->promotion.threshold.ticks = cx->latency_ticks;
- if (cx->type >= ACPI_STATE_C2)
- cx->promotion.threshold.count = 4;
- else
- cx->promotion.threshold.count = 10;
- if (higher->type == ACPI_STATE_C3)
- cx->promotion.threshold.bm = bm_history;
- }
-
- higher = cx;
- }
-
- return 0;
-}
-
static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
{
@@ -917,7 +456,7 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
* Normalize the C2 latency to expidite policy
*/
cx->valid = 1;
- cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+ cx->latency_ticks = cx->latency;
return;
}
@@ -991,7 +530,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
* use this in our C3 policy
*/
cx->valid = 1;
- cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+ cx->latency_ticks = cx->latency;
return;
}
@@ -1057,18 +596,6 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
pr->power.count = acpi_processor_power_verify(pr);
/*
- * Set Default Policy
- * ------------------
- * Now that we know which states are supported, set the default
- * policy. Note that this policy can be changed dynamically
- * (e.g. encourage deeper sleeps to conserve battery life when
- * not on AC).
- */
- result = acpi_processor_set_power_policy(pr);
- if (result)
- return result;
-
- /*
* if one state of type C2 or C3 is available, mark this
* CPU as being "idle manageable"
*/
@@ -1085,9 +612,6 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
- int result = 0;
-
-
if (!pr)
return -EINVAL;
@@ -1098,16 +622,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
if (!pr->flags.power_setup_done)
return -ENODEV;
- /* Fall back to the default idle loop */
- pm_idle = pm_idle_save;
- synchronize_sched(); /* Relies on interrupts forcing exit from idle. */
-
- pr->flags.power = 0;
- result = acpi_processor_get_power_info(pr);
- if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
- pm_idle = acpi_processor_idle;
-
- return result;
+ acpi_processor_get_power_info(pr);
+ return cpuidle_force_redetect(&per_cpu(cpuidle_devices, pr->id));
}
/* proc interface */
@@ -1193,30 +709,6 @@ static const struct file_operations acpi_processor_power_fops = {
.release = single_release,
};
-#ifdef CONFIG_SMP
-static void smp_callback(void *v)
-{
- /* we already woke the CPU up, nothing more to do */
-}
-
-/*
- * This function gets called when a part of the kernel has a new latency
- * requirement. This means we need to get all processors out of their C-state,
- * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
- * wakes them all right up.
- */
-static int acpi_processor_latency_notify(struct notifier_block *b,
- unsigned long l, void *v)
-{
- smp_call_function(smp_callback, NULL, 0, 1);
- return NOTIFY_OK;
-}
-
-static struct notifier_block acpi_processor_latency_notifier = {
- .notifier_call = acpi_processor_latency_notify,
-};
-#endif
-
int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device)
{
@@ -1233,9 +725,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
"ACPI: processor limited to max C-state %d\n",
max_cstate);
first_run++;
-#ifdef CONFIG_SMP
- register_latency_notifier(&acpi_processor_latency_notifier);
-#endif
}
if (!pr)
@@ -1252,6 +741,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
acpi_processor_get_power_info(pr);
+
/*
* Install the idle handler if processor power management is supported.
* Note that we use previously set idle handler will be used on
@@ -1264,11 +754,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
printk(" C%d[C%d]", i,
pr->power.states[i].type);
printk(")\n");
-
- if (pr->id == 0) {
- pm_idle_save = pm_idle;
- pm_idle = acpi_processor_idle;
- }
}
/* 'power' [R] */
@@ -1296,21 +781,332 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
if (acpi_device_dir(device))
remove_proc_entry(ACPI_PROCESSOR_FILE_POWER,
acpi_device_dir(device));
+ return 0;
+}
+
+/**
+ * ticks_elapsed - a helper function that determines how many ticks (in US)
+ * have elapsed between two PM Timer timestamps
+ * @t1: the start time
+ * @t2: the end time
+ */
+static inline u32 ticks_elapsed(u32 t1, u32 t2)
+{
+ if (t2 >= t1)
+ return PM_TIMER_TICKS_TO_US(t2 - t1);
+ else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
+ return PM_TIMER_TICKS_TO_US(((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
+ else
+ return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
+}
- /* Unregister the idle handler when processor #0 is removed. */
- if (pr->id == 0) {
- pm_idle = pm_idle_save;
+/**
+ * acpi_idle_update_bm_rld - updates the BM_RLD bit depending on target state
+ * @pr: the processor
+ * @target: the new target state
+ */
+static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
+ struct acpi_processor_cx *target)
+{
+ if (pr->flags.bm_rld_set && target->type != ACPI_STATE_C3) {
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
+ pr->flags.bm_rld_set = 0;
+ }
- /*
- * We are about to unload the current idle thread pm callback
- * (pm_idle), Wait for all processors to update cached/local
- * copies of pm_idle before proceeding.
- */
- cpu_idle_wait();
-#ifdef CONFIG_SMP
- unregister_latency_notifier(&acpi_processor_latency_notifier);
+ if (!pr->flags.bm_rld_set && target->type == ACPI_STATE_C3) {
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
+ pr->flags.bm_rld_set = 1;
+ }
+}
+
+/**
+ * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
+ * @cx: cstate data
+ */
+static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
+{
+ if (cx->space_id == ACPI_CSTATE_FFH) {
+ /* Call into architectural FFH based C-state */
+ acpi_processor_ffh_cstate_enter(cx);
+ } else {
+ int unused;
+ /* IO port based C-state */
+ inb(cx->address);
+ /* Dummy wait op - must do something useless after P_LVL2 read
+ because chipsets cannot guarantee that STPCLK# signal
+ gets asserted in time to freeze execution properly. */
+ unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ }
+}
+
+/**
+ * acpi_idle_enter_c1 - enters an ACPI C1 state-type
+ * @dev: the target CPU
+ * @state: the state data
+ *
+ * This is equivalent to the HALT instruction.
+ */
+static int acpi_idle_enter_c1(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ struct acpi_processor *pr;
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ pr = processors[smp_processor_id()];
+
+ if (unlikely(!pr))
+ return 0;
+
+ if (pr->flags.bm_check)
+ acpi_idle_update_bm_rld(pr, cx);
+
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+ if (!need_resched())
+ safe_halt();
+ current_thread_info()->status |= TS_POLLING;
+
+ cx->usage++;
+
+ return 0;
+}
+
+/**
+ * acpi_idle_enter_c2 - enters an ACPI C2 state-type
+ * @dev: the target CPU
+ * @state: the state data
+ */
+static int acpi_idle_enter_c2(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ struct acpi_processor *pr;
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ u32 t1, t2;
+ pr = processors[smp_processor_id()];
+
+ if (unlikely(!pr))
+ return 0;
+
+ if (pr->flags.bm_check)
+ acpi_idle_update_bm_rld(pr, cx);
+
+ local_irq_disable();
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+
+ if (unlikely(need_resched())) {
+ current_thread_info()->status |= TS_POLLING;
+ local_irq_enable();
+ return 0;
+ }
+
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ acpi_state_timer_broadcast(pr, cx, 1);
+ acpi_idle_do_entry(cx);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+
+#ifdef CONFIG_GENERIC_TIME
+ /* TSC halts in C2, so notify users */
+ mark_tsc_unstable();
#endif
+
+ local_irq_enable();
+ current_thread_info()->status |= TS_POLLING;
+
+ cx->usage++;
+
+ acpi_state_timer_broadcast(pr, cx, 0);
+ return ticks_elapsed(t1, t2);
+}
+
+static int c3_cpu_count;
+static DEFINE_SPINLOCK(c3_lock);
+
+/**
+ * acpi_idle_enter_c3 - enters an ACPI C3 state-type
+ * @dev: the target CPU
+ * @state: the state data
+ *
+ * Similar to C2 entry, except special bus master handling is needed.
+ */
+static int acpi_idle_enter_c3(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ struct acpi_processor *pr;
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ u32 t1, t2;
+ pr = processors[smp_processor_id()];
+
+ if (unlikely(!pr))
+ return 0;
+
+ if (pr->flags.bm_check)
+ acpi_idle_update_bm_rld(pr, cx);
+
+ local_irq_disable();
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+
+ if (unlikely(need_resched())) {
+ current_thread_info()->status |= TS_POLLING;
+ local_irq_enable();
+ return 0;
+ }
+
+ /* disable bus master */
+ if (pr->flags.bm_check) {
+ spin_lock(&c3_lock);
+ c3_cpu_count++;
+ if (c3_cpu_count == num_online_cpus()) {
+ /*
+ * All CPUs are trying to go to C3
+ * Disable bus master arbitration
+ */
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
+ }
+ spin_unlock(&c3_lock);
+ } else {
+ /* SMP with no shared cache... Invalidate cache */
+ ACPI_FLUSH_CPU_CACHE();
+ }
+
+ /* Get start time (ticks) */
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ acpi_state_timer_broadcast(pr, cx, 1);
+ acpi_idle_do_entry(cx);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+
+ if (pr->flags.bm_check) {
+ spin_lock(&c3_lock);
+ /* Enable bus master arbitration */
+ if (c3_cpu_count == num_online_cpus())
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
+ c3_cpu_count--;
+ spin_unlock(&c3_lock);
}
+#ifdef CONFIG_GENERIC_TIME
+ /* TSC halts in C3, so notify users */
+ mark_tsc_unstable();
+#endif
+
+ local_irq_enable();
+ current_thread_info()->status |= TS_POLLING;
+
+ cx->usage++;
+
+ acpi_state_timer_broadcast(pr, cx, 0);
+ return ticks_elapsed(t1, t2);
+}
+
+/**
+ * acpi_idle_bm_check - checks if bus master activity was detected
+ */
+static int acpi_idle_bm_check(void)
+{
+ u32 bm_status = 0;
+
+ acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
+ if (bm_status)
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
+ /*
+ * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
+ * the true state of bus mastering activity; forcing us to
+ * manually check the BMIDEA bit of each IDE channel.
+ */
+ else if (errata.piix4.bmisx) {
+ if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
+ || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
+ bm_status = 1;
+ }
+ return bm_status;
+}
+
+/**
+ * acpi_idle_init - attaches the driver to a CPU
+ * @dev: the CPU
+ */
+static int acpi_idle_init(struct cpuidle_device *dev)
+{
+ int cpu = dev->cpu;
+ int i, count = 0;
+ struct acpi_processor_cx *cx;
+ struct cpuidle_state *state;
+
+ struct acpi_processor *pr = processors[cpu];
+
+ if (!pr->flags.power_setup_done)
+ return -EINVAL;
+
+ if (pr->flags.power == 0) {
+ return -EINVAL;
+ }
+
+ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ cx = &pr->power.states[i];
+ state = &dev->states[count];
+
+ if (!cx->valid)
+ continue;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
+ !pr->flags.has_cst &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
+ continue;
+#endif
+ cpuidle_set_statedata(state, cx);
+
+ state->exit_latency = cx->latency;
+ state->target_residency = cx->latency * 6;
+ state->power_usage = cx->power;
+
+ state->flags = 0;
+ switch (cx->type) {
+ case ACPI_STATE_C1:
+ state->flags |= CPUIDLE_FLAG_SHALLOW;
+ state->enter = acpi_idle_enter_c1;
+ break;
+
+ case ACPI_STATE_C2:
+ state->flags |= CPUIDLE_FLAG_BALANCED;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ state->enter = acpi_idle_enter_c2;
+ break;
+
+ case ACPI_STATE_C3:
+ state->flags |= CPUIDLE_FLAG_DEEP;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ state->flags |= CPUIDLE_FLAG_CHECK_BM;
+ state->enter = acpi_idle_enter_c3;
+ break;
+ }
+
+ count++;
+ }
+
+ if (!count)
+ return -EINVAL;
+
+ dev->state_count = count;
return 0;
}
+
+struct cpuidle_driver acpi_idle_driver = {
+ .name = "acpi_idle",
+ .init = acpi_idle_init,
+ .redetect = acpi_idle_init,
+ .bm_check = acpi_idle_bm_check,
+ .owner = THIS_MODULE,
+};
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 916c010..e375570 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -161,6 +161,7 @@ struct acpi_processor_flags {
u8 bm_check:1;
u8 has_cst:1;
u8 power_setup_done:1;
+ u8 bm_rld_set:1;
};
struct acpi_processor {
@@ -275,6 +276,7 @@ int acpi_processor_power_init(struct acpi_processor *pr,
int acpi_processor_cst_has_changed(struct acpi_processor *pr);
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device);
+extern struct cpuidle_driver acpi_idle_driver;
/* in processor_thermal.c */
int acpi_processor_get_limit_info(struct acpi_processor *pr);
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 03/22] cpuidle take2: Basic documentation for cpuidle
[not found] ` <c5bb38e598e68202e0d6f08b3fe0f30f12999357.1173498651.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Venkatesh Pallipadi, Adam Belay, Shaohua Li, Len Brown
From: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Documentation for cpuidle infrastructure
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Adam Belay <abelay@novell.com>
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
Documentation/cpuidle/core.txt | 17 +++++++++++++++++
Documentation/cpuidle/driver.txt | 24 ++++++++++++++++++++++++
Documentation/cpuidle/governor.txt | 24 ++++++++++++++++++++++++
Documentation/cpuidle/sysfs.txt | 27 +++++++++++++++++++++++++++
4 files changed, 92 insertions(+), 0 deletions(-)
create mode 100644 Documentation/cpuidle/core.txt
create mode 100644 Documentation/cpuidle/driver.txt
create mode 100644 Documentation/cpuidle/governor.txt
create mode 100644 Documentation/cpuidle/sysfs.txt
diff --git a/Documentation/cpuidle/core.txt b/Documentation/cpuidle/core.txt
new file mode 100644
index 0000000..e686cfc
--- /dev/null
+++ b/Documentation/cpuidle/core.txt
@@ -0,0 +1,17 @@
+
+ Supporting multiple CPU idle levels in kernel
+
+ cpuidle
+
+General Information:
+
+Various CPUs today support multiple idle levels that are differentiated
+by varying exit latencies and power consumption during idle.
+cpuidle is a generic in-kernel infrastructure that separates
+idle policy (governor) from idle mechanism (driver) and provides a
+standardized infrastructure to support independent development of
+governors and drivers.
+
+cpuidle resides under /drivers/cpuidle.
+
+
diff --git a/Documentation/cpuidle/driver.txt b/Documentation/cpuidle/driver.txt
new file mode 100644
index 0000000..2dbee4b
--- /dev/null
+++ b/Documentation/cpuidle/driver.txt
@@ -0,0 +1,24 @@
+
+
+ Supporting multiple CPU idle levels in kernel
+
+ cpuidle drivers
+
+
+
+
+cpuidle driver supports capability detection for a particular system. The
+init and exit routines will be called for each online CPU, with a percpu
+cpuidle_driver object and driver should fill in cpuidle_states inside
+cpuidle_driver depending on the CPU capability.
+
+Driver can handle dynamic state changes (like battery<->AC), by calling
+force_redetect interface.
+
+It is possible to have more than one driver registered at the same time and
+user can switch between drivers using /sysfs interface.
+
+Interfaces:
+int cpuidle_register_driver(struct cpuidle_driver *drv);
+void cpuidle_unregister_driver(struct cpuidle_driver *drv);
+int cpuidle_force_redetect(struct cpuidle_device *dev);
diff --git a/Documentation/cpuidle/governor.txt b/Documentation/cpuidle/governor.txt
new file mode 100644
index 0000000..a0fc3e5
--- /dev/null
+++ b/Documentation/cpuidle/governor.txt
@@ -0,0 +1,24 @@
+
+
+
+ Supporting multiple CPU idle levels in kernel
+
+ cpuidle governors
+
+
+
+
+cpuidle governor is policy routine that decides what idle state to enter at
+any given time. cpuidle core uses different callbacks to governor while
+handling idle entry.
+* select_state callback where governor can determine next idle state to enter
+* prepare_idle callback is called before entering an idle state
+* scan callback is called after a driver forces redetection of the states
+
+More than one governor can be registered at the same time and
+user can switch between drivers using /sysfs interface.
+
+Interfaces:
+int cpuidle_register_governor(struct cpuidle_governor *gov);
+void cpuidle_unregister_governor(struct cpuidle_governor *gov);
+
diff --git a/Documentation/cpuidle/sysfs.txt b/Documentation/cpuidle/sysfs.txt
new file mode 100644
index 0000000..7fbf644
--- /dev/null
+++ b/Documentation/cpuidle/sysfs.txt
@@ -0,0 +1,27 @@
+
+
+ Supporting multiple CPU idle levels in kernel
+
+ cpuidle sysfs
+
+System global cpuidle information are under
+/sys/devices/system/cpu/cpuidle
+
+The current interfaces in this directory has self-explanatory names:
+* available_drivers
+* available_governors
+* current_driver
+* current_governor
+
+Per logical CPU specific cpuidle information are under
+/sys/devices/system/cpu/cpuX/cpuidle
+for each online cpu X
+
+Under this percpu directory, there is a directory for each idle state supported
+by the driver, which in turn has
+* latency
+* power
+* time
+* usage
+
+
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 04/22] ACPI: battery: make internal names consistent with battery "state"
[not found] ` <a1f0eff21edac1bd87e397f56c4258b9611b5a50.1173498652.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Vladimir Lebedev, Len Brown
From: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Cleanup -- No functional changes.
Battery state is currently exported in a proc "state" file.
Update associated #defines and routines to be consistent.
Signed-off-by: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/battery.c | 18 +++++++++---------
1 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index e64c76c..df04f87 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -44,7 +44,7 @@
#define ACPI_BATTERY_HID "PNP0C0A"
#define ACPI_BATTERY_DEVICE_NAME "Battery"
#define ACPI_BATTERY_FILE_INFO "info"
-#define ACPI_BATTERY_FILE_STATUS "state"
+#define ACPI_BATTERY_FILE_STATE "state"
#define ACPI_BATTERY_FILE_ALARM "alarm"
#define ACPI_BATTERY_NOTIFY_STATUS 0x80
#define ACPI_BATTERY_NOTIFY_INFO 0x81
@@ -76,7 +76,7 @@ static struct acpi_driver acpi_battery_driver = {
},
};
-struct acpi_battery_status {
+struct acpi_battery_state {
acpi_integer state;
acpi_integer present_rate;
acpi_integer remaining_capacity;
@@ -183,8 +183,8 @@ acpi_battery_get_info(struct acpi_battery *battery,
}
static int
-acpi_battery_get_status(struct acpi_battery *battery,
- struct acpi_battery_status **bst)
+acpi_battery_get_state(struct acpi_battery *battery,
+ struct acpi_battery_state **bst)
{
int result = 0;
acpi_status status = 0;
@@ -425,7 +425,7 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
{
int result = 0;
struct acpi_battery *battery = seq->private;
- struct acpi_battery_status *bst = NULL;
+ struct acpi_battery_state *bst = NULL;
char *units = "?";
@@ -449,9 +449,9 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
/* Battery Status (_BST) */
- result = acpi_battery_get_status(battery, &bst);
+ result = acpi_battery_get_state(battery, &bst);
if (result || !bst) {
- seq_printf(seq, "ERROR: Unable to read battery status\n");
+ seq_printf(seq, "ERROR: Unable to read battery state\n");
goto end;
}
@@ -621,7 +621,7 @@ static int acpi_battery_add_fs(struct acpi_device *device)
}
/* 'status' [R] */
- entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
+ entry = create_proc_entry(ACPI_BATTERY_FILE_STATE,
S_IRUGO, acpi_device_dir(device));
if (!entry)
return -ENODEV;
@@ -652,7 +652,7 @@ static int acpi_battery_remove_fs(struct acpi_device *device)
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
acpi_device_dir(device));
- remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
+ remove_proc_entry(ACPI_BATTERY_FILE_STATE,
acpi_device_dir(device));
remove_proc_entry(ACPI_BATTERY_FILE_INFO,
acpi_device_dir(device));
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 05/22] ACPI: Cache battery status instead of re-evaluating AML
[not found] ` <b6ce4083ed8e2a01a3a59301eabe0fc1e68a8a84.1173498652.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
2007-04-19 18:23 ` Andrew Morton
0 siblings, 1 reply; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Vladimir Lebedev, Len Brown
From: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
/proc exports _BST in a single file, and _BST is re-evaulated
whenever that file is read.
Sometimes user-space reads this file frequently, and on some
systems _BST takes a long time to evaluate due to a slow EC.
Further, when we move to sysfs, the values returned from _BST
will be in multiple files, and evaluating _BST for each
file read would make matters worse.
Here code is added to support caching the results of _BST.
A new module parameter "update_time" tells how many seconds the
cached _BST should be used before it is re-evaluated.
Currently, update_time defaults to 0, and so the
existing behaviour of re-evaluating on each read retained.
Signed-off-by: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/battery.c | 613 ++++++++++++++++++++++++++++++++++--------------
1 files changed, 441 insertions(+), 172 deletions(-)
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index df04f87..f3b0024 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -52,12 +52,24 @@
#define ACPI_BATTERY_UNITS_AMPS "mA"
#define _COMPONENT ACPI_BATTERY_COMPONENT
+
+#define ACPI_BATTERY_UPDATE_TIME 0
+
+#define ACPI_BATTERY_NONE_UPDATE 0
+#define ACPI_BATTERY_EASY_UPDATE 1
+#define ACPI_BATTERY_INIT_UPDATE 2
+
ACPI_MODULE_NAME("battery");
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL");
+static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME;
+
+/* 0 - every time, > 0 - by update_time */
+module_param(update_time, uint, 0644);
+
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
@@ -100,32 +112,117 @@ struct acpi_battery_info {
};
struct acpi_battery_flags {
- u8 present:1; /* Bay occupied? */
- u8 power_unit:1; /* 0=watts, 1=apms */
- u8 alarm:1; /* _BTP present? */
- u8 reserved:5;
-};
-
-struct acpi_battery_trips {
- unsigned long warning;
- unsigned long low;
+ u8 battery_present_prev;
+ u8 alarm_present;
+ u8 init_update;
+ u8 info_update;
+ u8 state_update;
+ u8 alarm_update;
+ u8 power_unit;
};
struct acpi_battery {
+ struct mutex mutex;
struct acpi_device * device;
struct acpi_battery_flags flags;
- struct acpi_battery_trips trips;
+ struct acpi_buffer bif_data;
+ struct acpi_buffer bst_data;
unsigned long alarm;
- struct acpi_battery_info *info;
+ unsigned long info_update_time;
+ unsigned long state_update_time;
+ unsigned long alarm_update_time;
};
+#define acpi_battery_present(battery) battery->device->status.battery_present
+#define acpi_battery_present_prev(battery) battery->flags.battery_present_prev
+#define acpi_battery_alarm_present(battery) battery->flags.alarm_present
+#define acpi_battery_init_update_flag(battery) battery->flags.init_update
+#define acpi_battery_info_update_flag(battery) battery->flags.info_update
+#define acpi_battery_state_update_flag(battery) battery->flags.state_update
+#define acpi_battery_alarm_update_flag(battery) battery->flags.alarm_update
+#define acpi_battery_power_units(battery) battery->flags.power_unit ? \
+ ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS
+#define acpi_battery_handle(battery) battery->device->handle
+#define acpi_battery_inserted(battery) (!acpi_battery_present_prev(battery) & acpi_battery_present(battery))
+#define acpi_battery_removed(battery) (acpi_battery_present_prev(battery) & !acpi_battery_present(battery))
+#define acpi_battery_bid(battery) acpi_device_bid(battery->device)
+#define acpi_battery_status_str(battery) acpi_battery_present(battery) ? "present" : "absent"
+
/* --------------------------------------------------------------------------
Battery Management
-------------------------------------------------------------------------- */
-static int
-acpi_battery_get_info(struct acpi_battery *battery,
- struct acpi_battery_info **bif)
+static void acpi_battery_mutex_lock(struct acpi_battery *battery)
+{
+ mutex_lock(&battery->mutex);
+}
+
+static void acpi_battery_mutex_unlock(struct acpi_battery *battery)
+{
+ mutex_unlock(&battery->mutex);
+}
+
+static void acpi_battery_check_result(struct acpi_battery *battery, int result)
+{
+ if (!battery)
+ return;
+
+ if (result) {
+ acpi_battery_init_update_flag(battery) = 1;
+ }
+}
+
+static int acpi_battery_extract_package(struct acpi_battery *battery,
+ union acpi_object *package,
+ struct acpi_buffer *format,
+ struct acpi_buffer *data,
+ char *package_name)
+{
+ acpi_status status = AE_OK;
+ struct acpi_buffer data_null = { 0, NULL };
+
+ status = acpi_extract_package(package, format, &data_null);
+ if (status != AE_BUFFER_OVERFLOW) {
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
+ package_name));
+ return -ENODEV;
+ }
+
+ if (data_null.length != data->length) {
+ if (data->pointer) {
+ kfree(data->pointer);
+ }
+ data->pointer = kzalloc(data_null.length, GFP_KERNEL);
+ if (!data->pointer) {
+ ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
+ return -ENOMEM;
+ }
+ data->length = data_null.length;
+ }
+
+ status = acpi_extract_package(package, format, data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
+ package_name));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int acpi_battery_get_status(struct acpi_battery *battery)
+{
+ int result = 0;
+
+ result = acpi_bus_get_status(battery->device);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
+ return -ENODEV;
+ }
+ return result;
+}
+
+static int acpi_battery_get_info(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = 0;
@@ -133,16 +230,18 @@ acpi_battery_get_info(struct acpi_battery *battery,
struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
ACPI_BATTERY_FORMAT_BIF
};
- struct acpi_buffer data = { 0, NULL };
union acpi_object *package = NULL;
+ struct acpi_buffer *data = NULL;
+ struct acpi_battery_info *bif = NULL;
+ battery->info_update_time = get_seconds();
- if (!battery || !bif)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return 0;
/* Evalute _BIF */
- status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
+ status = acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
return -ENODEV;
@@ -150,41 +249,29 @@ acpi_battery_get_info(struct acpi_battery *battery,
package = buffer.pointer;
+ data = &battery->bif_data;
+
/* Extract Package Data */
- status = acpi_extract_package(package, &format, &data);
- if (status != AE_BUFFER_OVERFLOW) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
- result = -ENODEV;
+ result = acpi_battery_extract_package(battery, package, &format, data, "_BIF");
+ if (result)
goto end;
- }
- data.pointer = kzalloc(data.length, GFP_KERNEL);
- if (!data.pointer) {
- result = -ENOMEM;
- goto end;
- }
+ end:
- status = acpi_extract_package(package, &format, &data);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
- kfree(data.pointer);
- result = -ENODEV;
- goto end;
+ if (buffer.pointer) {
+ kfree(buffer.pointer);
}
- end:
- kfree(buffer.pointer);
-
- if (!result)
- (*bif) = data.pointer;
+ if (!result) {
+ bif = data->pointer;
+ battery->flags.power_unit = bif->power_unit;
+ }
return result;
}
-static int
-acpi_battery_get_state(struct acpi_battery *battery,
- struct acpi_battery_state **bst)
+static int acpi_battery_get_state(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = 0;
@@ -192,16 +279,17 @@ acpi_battery_get_state(struct acpi_battery *battery,
struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
ACPI_BATTERY_FORMAT_BST
};
- struct acpi_buffer data = { 0, NULL };
union acpi_object *package = NULL;
+ struct acpi_buffer *data = NULL;
+ battery->state_update_time = get_seconds();
- if (!battery || !bst)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return 0;
/* Evalute _BST */
- status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
+ status = acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
return -ENODEV;
@@ -209,55 +297,46 @@ acpi_battery_get_state(struct acpi_battery *battery,
package = buffer.pointer;
- /* Extract Package Data */
+ data = &battery->bst_data;
- status = acpi_extract_package(package, &format, &data);
- if (status != AE_BUFFER_OVERFLOW) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
- result = -ENODEV;
- goto end;
- }
+ /* Extract Package Data */
- data.pointer = kzalloc(data.length, GFP_KERNEL);
- if (!data.pointer) {
- result = -ENOMEM;
+ result = acpi_battery_extract_package(battery, package, &format, data, "_BST");
+ if (result)
goto end;
- }
- status = acpi_extract_package(package, &format, &data);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
- kfree(data.pointer);
- result = -ENODEV;
- goto end;
+ end:
+ if (buffer.pointer) {
+ kfree(buffer.pointer);
}
- end:
- kfree(buffer.pointer);
+ return result;
+}
- if (!result)
- (*bst) = data.pointer;
+static int acpi_battery_get_alarm(struct acpi_battery *battery)
+{
+ battery->alarm_update_time = get_seconds();
- return result;
+ return 0;
}
-static int
-acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
+static int acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
{
acpi_status status = 0;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list arg_list = { 1, &arg0 };
+ battery->alarm_update_time = get_seconds();
- if (!battery)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return -ENODEV;
- if (!battery->flags.alarm)
+ if (!acpi_battery_alarm_present(battery))
return -ENODEV;
arg0.integer.value = alarm;
- status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
+ status = acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", &arg_list, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -268,65 +347,110 @@ acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
return 0;
}
-static int acpi_battery_check(struct acpi_battery *battery)
+static int acpi_battery_init_alarm(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = AE_OK;
acpi_handle handle = NULL;
- struct acpi_device *device = NULL;
- struct acpi_battery_info *bif = NULL;
-
+ struct acpi_battery_info *bif = battery->bif_data.pointer;
+ unsigned long alarm = battery->alarm;
- if (!battery)
- return -EINVAL;
+ /* See if alarms are supported, and if so, set default */
- device = battery->device;
+ status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle);
+ if (ACPI_SUCCESS(status)) {
+ acpi_battery_alarm_present(battery) = 1;
+ if (!alarm && bif) {
+ alarm = bif->design_capacity_warning;
+ }
+ result = acpi_battery_set_alarm(battery, alarm);
+ if (result)
+ goto end;
+ } else {
+ acpi_battery_alarm_present(battery) = 0;
+ }
- result = acpi_bus_get_status(device);
- if (result)
- return result;
+ end:
- /* Insertion? */
+ return result;
+}
- if (!battery->flags.present && device->status.battery_present) {
+static int acpi_battery_init_update(struct acpi_battery *battery)
+{
+ int result = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
+ result = acpi_battery_get_status(battery);
+ if (result)
+ return result;
- /* Evalute _BIF to get certain static information */
+ acpi_battery_present_prev(battery) = acpi_battery_present(battery);
- result = acpi_battery_get_info(battery, &bif);
+ if (acpi_battery_present(battery)) {
+ result = acpi_battery_get_info(battery);
+ if (result)
+ return result;
+ result = acpi_battery_get_state(battery);
if (result)
return result;
- battery->flags.power_unit = bif->power_unit;
- battery->trips.warning = bif->design_capacity_warning;
- battery->trips.low = bif->design_capacity_low;
- kfree(bif);
+ acpi_battery_init_alarm(battery);
+ }
+
+ return result;
+}
+
+static int acpi_battery_update(struct acpi_battery *battery,
+ int update, int *update_result_ptr)
+{
+ int result = 0;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
- /* See if alarms are supported, and if so, set default */
+ if (!acpi_battery_present(battery)) {
+ update = 1;
+ }
- status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
- if (ACPI_SUCCESS(status)) {
- battery->flags.alarm = 1;
- acpi_battery_set_alarm(battery, battery->trips.warning);
+ if (acpi_battery_init_update_flag(battery)) {
+ result = acpi_battery_init_update(battery);
+ if (result)
+ goto end;;
+ update_result = ACPI_BATTERY_INIT_UPDATE;
+ } else if (update) {
+ result = acpi_battery_get_status(battery);
+ if (result)
+ goto end;;
+ if (acpi_battery_inserted(battery) || acpi_battery_removed(battery)) {
+ result = acpi_battery_init_update(battery);
+ if (result)
+ goto end;;
+ update_result = ACPI_BATTERY_INIT_UPDATE;
+ } else {
+ update_result = ACPI_BATTERY_EASY_UPDATE;
}
}
- /* Removal? */
+ end:
- else if (battery->flags.present && !device->status.battery_present) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
- }
+ acpi_battery_init_update_flag(battery) = (result != 0);
- battery->flags.present = device->status.battery_present;
+ *update_result_ptr = update_result;
return result;
}
-static void acpi_battery_check_present(struct acpi_battery *battery)
+static void acpi_battery_notify_update(struct acpi_battery *battery)
{
- if (!battery->flags.present) {
- acpi_battery_check(battery);
+ acpi_battery_get_status(battery);
+
+ if (acpi_battery_init_update_flag(battery)) {
+ return;
+ }
+
+ if (acpi_battery_inserted(battery) || acpi_battery_removed(battery)) {
+ acpi_battery_init_update_flag(battery) = 1;
+ } else {
+ acpi_battery_info_update_flag(battery) = 1;
+ acpi_battery_state_update_flag(battery) = 1;
+ acpi_battery_alarm_update_flag(battery) = 1;
}
}
@@ -335,37 +459,33 @@ static void acpi_battery_check_present(struct acpi_battery *battery)
-------------------------------------------------------------------------- */
static struct proc_dir_entry *acpi_battery_dir;
-static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+
+static int acpi_battery_read_info_print(struct seq_file *seq, int result)
{
- int result = 0;
struct acpi_battery *battery = seq->private;
struct acpi_battery_info *bif = NULL;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (battery->flags.present)
+ if (acpi_battery_present(battery))
seq_printf(seq, "present: yes\n");
else {
seq_printf(seq, "present: no\n");
goto end;
}
- /* Battery Info (_BIF) */
-
- result = acpi_battery_get_info(battery, &bif);
- if (result || !bif) {
- seq_printf(seq, "ERROR: Unable to read battery information\n");
+ bif = battery->bif_data.pointer;
+ if (!bif) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL"));
+ result = -ENODEV;
goto end;
}
- units =
- bif->
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+ /* Battery Units */
+
+ units = acpi_battery_power_units(battery);
if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "design capacity: unknown\n");
@@ -396,7 +516,6 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
else
seq_printf(seq, "design voltage: %d mV\n",
(u32) bif->design_voltage);
-
seq_printf(seq, "design capacity warning: %d %sh\n",
(u32) bif->design_capacity_warning, units);
seq_printf(seq, "design capacity low: %d %sh\n",
@@ -411,9 +530,48 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
seq_printf(seq, "OEM info: %s\n", bif->oem_info);
end:
- kfree(bif);
- return 0;
+ if (result)
+ seq_printf(seq, "ERROR: Unable to read battery info\n");
+
+ return result;
+}
+
+static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+{
+ struct acpi_battery *battery = seq->private;
+ int result = 0;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
+ int update = 0;
+
+ acpi_battery_mutex_lock(battery);
+
+ update = (get_seconds() - battery->info_update_time >= update_time);
+ update = (update | acpi_battery_info_update_flag(battery));
+
+ result = acpi_battery_update(battery, update, &update_result);
+ if (result)
+ goto end;
+
+ /* Battery Info (_BIF) */
+
+ if (update_result == ACPI_BATTERY_EASY_UPDATE) {
+ result = acpi_battery_get_info(battery);
+ if (result)
+ goto end;
+ }
+
+ end:
+
+ result = acpi_battery_read_info_print(seq, result);
+
+ acpi_battery_check_result(battery, result);
+
+ acpi_battery_info_update_flag(battery) = result;
+
+ acpi_battery_mutex_unlock(battery);
+
+ return result;
}
static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
@@ -421,40 +579,33 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_battery_read_info, PDE(inode)->data);
}
-static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+static int acpi_battery_read_state_print(struct seq_file *seq, int result)
{
- int result = 0;
struct acpi_battery *battery = seq->private;
struct acpi_battery_state *bst = NULL;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (battery->flags.present)
+ if (acpi_battery_present(battery))
seq_printf(seq, "present: yes\n");
else {
seq_printf(seq, "present: no\n");
goto end;
}
- /* Battery Units */
-
- units =
- battery->flags.
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
- /* Battery Status (_BST) */
-
- result = acpi_battery_get_state(battery, &bst);
- if (result || !bst) {
- seq_printf(seq, "ERROR: Unable to read battery state\n");
+ bst = battery->bst_data.pointer;
+ if (!bst) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL"));
+ result = -ENODEV;
goto end;
}
+ /* Battery Units */
+
+ units = acpi_battery_power_units(battery);
+
if (!(bst->state & 0x04))
seq_printf(seq, "capacity state: ok\n");
else
@@ -490,9 +641,49 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
(u32) bst->present_voltage);
end:
- kfree(bst);
- return 0;
+ if (result) {
+ seq_printf(seq, "ERROR: Unable to read battery state\n");
+ }
+
+ return result;
+}
+
+static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+{
+ struct acpi_battery *battery = seq->private;
+ int result = 0;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
+ int update = 0;
+
+ acpi_battery_mutex_lock(battery);
+
+ update = (get_seconds() - battery->state_update_time >= update_time);
+ update = (update | acpi_battery_state_update_flag(battery));
+
+ result = acpi_battery_update(battery, update, &update_result);
+ if (result)
+ goto end;
+
+ /* Battery State (_BST) */
+
+ if (update_result == ACPI_BATTERY_EASY_UPDATE) {
+ result = acpi_battery_get_state(battery);
+ if (result)
+ goto end;
+ }
+
+ end:
+
+ result = acpi_battery_read_state_print(seq, result);
+
+ acpi_battery_check_result(battery, result);
+
+ acpi_battery_state_update_flag(battery) = result;
+
+ acpi_battery_mutex_unlock(battery);
+
+ return result;
}
static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
@@ -500,38 +691,72 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_battery_read_state, PDE(inode)->data);
}
-static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+static int acpi_battery_read_alarm_print(struct seq_file *seq, int result)
{
struct acpi_battery *battery = seq->private;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (!battery->flags.present) {
+ if (!acpi_battery_present(battery)) {
seq_printf(seq, "present: no\n");
goto end;
}
/* Battery Units */
- units =
- battery->flags.
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
- /* Battery Alarm */
+ units = acpi_battery_power_units(battery);
seq_printf(seq, "alarm: ");
if (!battery->alarm)
seq_printf(seq, "unsupported\n");
else
- seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
+ seq_printf(seq, "%lu %sh\n", battery->alarm, units);
end:
- return 0;
+
+ if (result)
+ seq_printf(seq, "ERROR: Unable to read battery alarm\n");
+
+ return result;
+}
+
+static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+{
+ struct acpi_battery *battery = seq->private;
+ int result = 0;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
+ int update = 0;
+
+ acpi_battery_mutex_lock(battery);
+
+ update = (get_seconds() - battery->alarm_update_time >= update_time);
+ update = (update | acpi_battery_alarm_update_flag(battery));
+
+ result = acpi_battery_update(battery, update, &update_result);
+ if (result)
+ goto end;
+
+ /* Battery Alarm */
+
+ if (update_result == ACPI_BATTERY_EASY_UPDATE) {
+ result = acpi_battery_get_alarm(battery);
+ if (result)
+ goto end;
+ }
+
+ end:
+
+ result = acpi_battery_read_alarm_print(seq, result);
+
+ acpi_battery_check_result(battery, result);
+
+ acpi_battery_alarm_update_flag(battery) = result;
+
+ acpi_battery_mutex_unlock(battery);
+
+ return result;
}
static ssize_t
@@ -543,27 +768,47 @@ acpi_battery_write_alarm(struct file *file,
char alarm_string[12] = { '\0' };
struct seq_file *m = file->private_data;
struct acpi_battery *battery = m->private;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
if (!battery || (count > sizeof(alarm_string) - 1))
return -EINVAL;
- acpi_battery_check_present(battery);
+ acpi_battery_mutex_lock(battery);
- if (!battery->flags.present)
- return -ENODEV;
+ result = acpi_battery_update(battery, 1, &update_result);
+ if (result) {
+ result = -ENODEV;
+ goto end;
+ }
- if (copy_from_user(alarm_string, buffer, count))
- return -EFAULT;
+ if (!acpi_battery_present(battery)) {
+ result = -ENODEV;
+ goto end;
+ }
+
+ if (copy_from_user(alarm_string, buffer, count)) {
+ result = -EFAULT;
+ goto end;
+ }
alarm_string[count] = '\0';
result = acpi_battery_set_alarm(battery,
simple_strtoul(alarm_string, NULL, 0));
if (result)
- return result;
+ goto end;
+
+ end:
+
+ acpi_battery_check_result(battery, result);
- return count;
+ if (!result)
+ result = count;
+
+ acpi_battery_mutex_unlock(battery);
+
+ return result;
}
static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
@@ -648,7 +893,6 @@ static int acpi_battery_add_fs(struct acpi_device *device)
static int acpi_battery_remove_fs(struct acpi_device *device)
{
-
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
acpi_device_dir(device));
@@ -684,8 +928,11 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
case ACPI_BATTERY_NOTIFY_INFO:
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
- acpi_battery_check(battery);
- acpi_bus_generate_event(device, event, battery->flags.present);
+ acpi_battery_mutex_lock(battery);
+ device = battery->device;
+ acpi_battery_notify_update(battery);
+ acpi_battery_mutex_unlock(battery);
+ acpi_bus_generate_event(device, event, acpi_battery_present(battery));
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -702,7 +949,6 @@ static int acpi_battery_add(struct acpi_device *device)
acpi_status status = 0;
struct acpi_battery *battery = NULL;
-
if (!device)
return -EINVAL;
@@ -710,15 +956,21 @@ static int acpi_battery_add(struct acpi_device *device)
if (!battery)
return -ENOMEM;
+ mutex_init(&battery->mutex);
+
+ acpi_battery_mutex_lock(battery);
+
battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
acpi_driver_data(device) = battery;
- result = acpi_battery_check(battery);
+ result = acpi_battery_get_status(battery);
if (result)
goto end;
+ acpi_battery_init_update_flag(battery) = 1;
+
result = acpi_battery_add_fs(device);
if (result)
goto end;
@@ -727,6 +979,7 @@ static int acpi_battery_add(struct acpi_device *device)
ACPI_ALL_NOTIFY,
acpi_battery_notify, battery);
if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
result = -ENODEV;
goto end;
}
@@ -736,11 +989,14 @@ static int acpi_battery_add(struct acpi_device *device)
device->status.battery_present ? "present" : "absent");
end:
+
if (result) {
acpi_battery_remove_fs(device);
kfree(battery);
}
+ acpi_battery_mutex_unlock(battery);
+
return result;
}
@@ -749,18 +1005,29 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
acpi_status status = 0;
struct acpi_battery *battery = NULL;
-
if (!device || !acpi_driver_data(device))
return -EINVAL;
battery = acpi_driver_data(device);
+ acpi_battery_mutex_lock(battery);
+
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify);
acpi_battery_remove_fs(device);
+ if (battery->bif_data.pointer)
+ kfree(battery->bif_data.pointer);
+
+ if (battery->bst_data.pointer)
+ kfree(battery->bst_data.pointer);
+
+ acpi_battery_mutex_unlock(battery);
+
+ mutex_destroy(&battery->mutex);
+
kfree(battery);
return 0;
@@ -775,7 +1042,10 @@ static int acpi_battery_resume(struct acpi_device *device)
return -EINVAL;
battery = device->driver_data;
- return acpi_battery_check(battery);
+
+ acpi_battery_init_update_flag(battery) = 1;
+
+ return 0;
}
static int __init acpi_battery_init(void)
@@ -800,7 +1070,6 @@ static int __init acpi_battery_init(void)
static void __exit acpi_battery_exit(void)
{
-
acpi_bus_unregister_driver(&acpi_battery_driver);
acpi_unlock_battery_dir(acpi_battery_dir);
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 06/22] ACPI: battery: Lindent
[not found] ` <9ea7d57576f40c6af03c8c9fa7a069f2222b498b.1173498653.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Vladimir Lebedev, Len Brown
From: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Signed-off-by: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/battery.c | 36 +++++++++++++++++++++++-------------
1 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index f3b0024..fc9c50a 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -123,7 +123,7 @@ struct acpi_battery_flags {
struct acpi_battery {
struct mutex mutex;
- struct acpi_device * device;
+ struct acpi_device *device;
struct acpi_battery_flags flags;
struct acpi_buffer bif_data;
struct acpi_buffer bst_data;
@@ -241,7 +241,9 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
/* Evalute _BIF */
- status = acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, &buffer);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
+ &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
return -ENODEV;
@@ -253,7 +255,9 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
/* Extract Package Data */
- result = acpi_battery_extract_package(battery, package, &format, data, "_BIF");
+ result =
+ acpi_battery_extract_package(battery, package, &format, data,
+ "_BIF");
if (result)
goto end;
@@ -289,7 +293,9 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
/* Evalute _BST */
- status = acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, &buffer);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
+ &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
return -ENODEV;
@@ -301,7 +307,9 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
/* Extract Package Data */
- result = acpi_battery_extract_package(battery, package, &format, data, "_BST");
+ result =
+ acpi_battery_extract_package(battery, package, &format, data,
+ "_BST");
if (result)
goto end;
@@ -320,7 +328,8 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery)
return 0;
}
-static int acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
+static int acpi_battery_set_alarm(struct acpi_battery *battery,
+ unsigned long alarm)
{
acpi_status status = 0;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
@@ -336,7 +345,9 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long al
arg0.integer.value = alarm;
- status = acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", &arg_list, NULL);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
+ &arg_list, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -400,7 +411,7 @@ static int acpi_battery_init_update(struct acpi_battery *battery)
}
static int acpi_battery_update(struct acpi_battery *battery,
- int update, int *update_result_ptr)
+ int update, int *update_result_ptr)
{
int result = 0;
int update_result = ACPI_BATTERY_NONE_UPDATE;
@@ -418,7 +429,8 @@ static int acpi_battery_update(struct acpi_battery *battery,
result = acpi_battery_get_status(battery);
if (result)
goto end;;
- if (acpi_battery_inserted(battery) || acpi_battery_removed(battery)) {
+ if (acpi_battery_inserted(battery)
+ || acpi_battery_removed(battery)) {
result = acpi_battery_init_update(battery);
if (result)
goto end;;
@@ -770,7 +782,6 @@ acpi_battery_write_alarm(struct file *file,
struct acpi_battery *battery = m->private;
int update_result = ACPI_BATTERY_NONE_UPDATE;
-
if (!battery || (count > sizeof(alarm_string) - 1))
return -EINVAL;
@@ -845,7 +856,6 @@ static int acpi_battery_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
-
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_battery_dir);
@@ -917,7 +927,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
struct acpi_battery *battery = data;
struct acpi_device *device = NULL;
-
if (!battery)
return;
@@ -932,7 +941,8 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
device = battery->device;
acpi_battery_notify_update(battery);
acpi_battery_mutex_unlock(battery);
- acpi_bus_generate_event(device, event, acpi_battery_present(battery));
+ acpi_bus_generate_event(device, event,
+ acpi_battery_present(battery));
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 07/22] cpuidle: build fix for !CPU_IDLE
[not found] ` <d98b2065c5ac31a35cbdfe9b47d421352f96fc3f.1173498653.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Venkatesh Pallipadi, Andrew Morton, Len Brown
From: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Fix the compile issues when CPU_IDLE is not configured.
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Cc: Adam Belay <abelay@novell.com>
Cc: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Len Brown <len.brown@intel.com>
---
include/linux/cpuidle.h | 23 +++++++++++++++++++++++
1 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index d26a82e..4a41f42 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -130,10 +130,21 @@ struct cpuidle_driver {
struct module *owner;
};
+#ifdef CONFIG_CPU_IDLE
+
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
extern int cpuidle_force_redetect(struct cpuidle_device *dev);
+#else
+
+static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
+{return 0;}
+static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
+static inline int cpuidle_force_redetect(struct cpuidle_device *dev)
+{return 0;}
+
+#endif
/******************************
* CPUIDLE GOVERNOR INTERFACE *
@@ -153,8 +164,20 @@ struct cpuidle_governor {
struct module *owner;
};
+#ifdef CONFIG_CPU_IDLE
+
extern int cpuidle_register_governor(struct cpuidle_governor *gov);
extern void cpuidle_unregister_governor(struct cpuidle_governor *gov);
extern int cpuidle_get_bm_activity(void);
+#else
+
+static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
+{return 0;}
+static inline void cpuidle_unregister_governor(struct cpuidle_governor *gov) { }
+static inline int cpuidle_get_bm_activity(void)
+{return 0;}
+
+#endif
+
#endif /* _LINUX_CPUIDLE_H */
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 08/22] cpu_idle: fix build break
[not found] ` <bc17374e69a621c9b7f6f9624c9248f3b8e8503d.1173498653.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Venkatesh Pallipadi, Adrian Bunk, Andrew Morton, Len Brown
From: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
This patch fixes a build breakage with !CONFIG_HOTPLUG_CPU and
CONFIG_CPU_IDLE.
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/cpuidle/cpuidle.c | 6 +-----
1 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index dc626d9..4d2071e 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -189,10 +189,6 @@ static struct sysdev_driver cpuidle_sysdev_driver = {
.remove = cpuidle_remove_device,
};
-#ifdef CONFIG_SMP
-
-#ifdef CONFIG_HOTPLUG_CPU
-
static int cpuidle_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
@@ -224,7 +220,7 @@ static struct notifier_block __cpuinitdata cpuidle_cpu_notifier =
.notifier_call = cpuidle_cpu_callback,
};
-#endif /* CONFIG_HOTPLUG_CPU */
+#ifdef CONFIG_SMP
static void smp_callback(void *v)
{
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 09/22] cpuidle: make code static
[not found] ` <3d869f55bda8b0b6f0cb55f9a85a6f855a016092.1173498654.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Adrian Bunk, Andrew Morton, Len Brown
From: Adrian Bunk <bunk@stusta.de>
This patch makes the following needlessly global code static:
- driver.c: __cpuidle_find_driver()
- governor.c: __cpuidle_find_governor()
- ladder.c: struct ladder_governor
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Cc: Adam Belay <abelay@novell.com>
Cc: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/cpuidle/cpuidle.h | 2 --
drivers/cpuidle/driver.c | 2 +-
drivers/cpuidle/governor.c | 2 +-
drivers/cpuidle/governors/ladder.c | 2 +-
4 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
index 2defa39..8bbc090 100644
--- a/drivers/cpuidle/cpuidle.h
+++ b/drivers/cpuidle/cpuidle.h
@@ -23,13 +23,11 @@ extern void cpuidle_rescan_device(struct cpuidle_device *dev);
/* drivers */
extern int cpuidle_attach_driver(struct cpuidle_device *dev);
extern void cpuidle_detach_driver(struct cpuidle_device *dev);
-extern struct cpuidle_driver * __cpuidle_find_driver(const char *str);
extern int cpuidle_switch_driver(struct cpuidle_driver *drv);
/* governors */
extern int cpuidle_attach_governor(struct cpuidle_device *dev);
extern void cpuidle_detach_governor(struct cpuidle_device *dev);
-extern struct cpuidle_governor * __cpuidle_find_governor(const char *str);
extern int cpuidle_switch_governor(struct cpuidle_governor *gov);
/* sysfs */
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 1111279..de8c627 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -73,7 +73,7 @@ void cpuidle_detach_driver(struct cpuidle_device *dev)
*
* Must be called with cpuidle_lock aquired.
*/
-struct cpuidle_driver * __cpuidle_find_driver(const char *str)
+static struct cpuidle_driver * __cpuidle_find_driver(const char *str)
{
struct cpuidle_driver *drv;
diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c
index b2d6a69..fa637fa 100644
--- a/drivers/cpuidle/governor.c
+++ b/drivers/cpuidle/governor.c
@@ -72,7 +72,7 @@ void cpuidle_detach_governor(struct cpuidle_device *dev)
*
* Must be called with cpuidle_lock aquired.
*/
-struct cpuidle_governor * __cpuidle_find_governor(const char *str)
+static struct cpuidle_governor * __cpuidle_find_governor(const char *str)
{
struct cpuidle_governor *gov;
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index d999393..87d2e54 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -199,7 +199,7 @@ static void ladder_exit_device(struct cpuidle_device *dev)
kfree(dev->governor_data);
}
-struct cpuidle_governor ladder_governor = {
+static struct cpuidle_governor ladder_governor = {
.name = "ladder",
.init = ladder_init_device,
.exit = ladder_exit_device,
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 10/22] cpuidle: ladder does not depend on ACPI
[not found] ` <b51f201f9a9af932c723492551f9e688d34cc468.1173498654.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Len Brown
From: Len Brown <len.brown@intel.com>
build fix for CONFIG_ACPI=n
In file included from drivers/cpuidle/governors/ladder.c:21:
include/acpi/processor.h:88: error: expected specifier-qualifier-list before âacpi_integerâ
include/acpi/processor.h:106: error: expected specifier-qualifier-list before âacpi_integerâ
include/acpi/processor.h:168: error: expected specifier-qualifier-list before âacpi_handleâ
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/cpuidle/governors/ladder.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 87d2e54..cf5a7a7 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -14,11 +14,9 @@
#include <linux/kernel.h>
#include <linux/cpuidle.h>
-#include <linux/acpi.h>
#include <linux/latency.h>
#include <linux/moduleparam.h>
#include <linux/jiffies.h>
-#include <acpi/processor.h>
#include <asm/io.h>
#include <asm/uaccess.h>
--
1.5.0.3.310.g05ef5
-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 11/22] ACPI: EC: Don't use Global Lock if not asked to do so
[not found] ` <705ff592931e6738926fd6d596461010a1e8977d.1173498654.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
2007-03-10 14:12 ` Sanjoy Mahajan
1 sibling, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 1e525dd..0e06ba8 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -827,7 +827,6 @@ acpi_fake_ecdt_callback(acpi_handle handle,
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->global_lock = TRUE;
ec_ecdt->handle = handle;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
@@ -901,8 +900,6 @@ static int __init acpi_ec_get_real_ecdt(void)
ec_ecdt->command_addr = ecdt_ptr->control.address;
ec_ecdt->data_addr = ecdt_ptr->data.address;
ec_ecdt->gpe = ecdt_ptr->gpe;
- /* use the GL just to be safe */
- ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid;
status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 12/22] ACPI: EC: Make EC to initialize first in ACPI
[not found] ` <e4382a15d138ea6c0d4277967e646216ce57040f.1173498654.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/Makefile | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 5956e9f..9623aac 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for the Linux ACPI interpreter
-#
+#
export ACPI_CFLAGS
@@ -32,16 +32,17 @@ obj-y += osl.o utils.o \
processor-objs += processor_core.o processor_throttling.o \
processor_idle.o processor_thermal.o
ifdef CONFIG_CPU_FREQ
-processor-objs += processor_perflib.o
+processor-objs += processor_perflib.o
endif
obj-y += sleep/
obj-y += bus.o glue.o
obj-y += scan.o
+# Keep EC driver first. Initialization of others depend on it.
+obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
-obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o
obj-$(CONFIG_ACPI_BAY) += bay.o
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 13/22] ACPI: EC: "Fake ECDT" workaround is not needed any longer.
[not found] ` <94418415a62ec4c88109385d8663e56aac54dfd6.1173498656.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 81 -----------------------------------------------------
1 files changed, 0 insertions(+), 81 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 0e06ba8..5999abd 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -805,74 +805,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
return 0;
}
-static acpi_status __init
-acpi_fake_ecdt_callback(acpi_handle handle,
- u32 Level, void *context, void **retval)
-{
- acpi_status status;
-
- mutex_init(&ec_ecdt->lock);
- atomic_set(&ec->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- init_waitqueue_head(&ec_ecdt->wait);
- }
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- acpi_ec_io_ports, ec_ecdt);
- if (ACPI_FAILURE(status))
- return status;
-
- ec_ecdt->uid = -1;
- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
-
- status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
- if (ACPI_FAILURE(status))
- return status;
- ec_ecdt->handle = handle;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
- ec_ecdt->gpe, ec_ecdt->command_addr,
- ec_ecdt->data_addr));
-
- return AE_CTRL_TERMINATE;
-}
-
-/*
- * Some BIOS (such as some from Gateway laptops) access EC region very early
- * such as in BAT0._INI or EC._INI before an EC device is found and
- * do not provide an ECDT. According to ACPI spec, ECDT isn't mandatorily
- * required, but if EC regison is accessed early, it is required.
- * The routine tries to workaround the BIOS bug by pre-scan EC device
- * It assumes that _CRS, _HID, _GPE, _UID methods of EC don't touch any
- * op region (since _REG isn't invoked yet). The assumption is true for
- * all systems found.
- */
-static int __init acpi_ec_fake_ecdt(void)
-{
- acpi_status status;
- int ret = 0;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
-
- ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
- if (!ec_ecdt) {
- ret = -ENOMEM;
- goto error;
- }
-
- status = acpi_get_devices(ACPI_EC_HID,
- acpi_fake_ecdt_callback, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- kfree(ec_ecdt);
- ec_ecdt = NULL;
- ret = -ENODEV;
- ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
- goto error;
- }
- return 0;
- error:
- return ret;
-}
-
static int __init acpi_ec_get_real_ecdt(void)
{
acpi_status status;
@@ -916,18 +848,12 @@ static int __init acpi_ec_get_real_ecdt(void)
return -ENODEV;
}
-static int __initdata acpi_fake_ecdt_enabled;
int __init acpi_ec_ecdt_probe(void)
{
acpi_status status;
int ret;
ret = acpi_ec_get_real_ecdt();
- /* Try to make a fake ECDT */
- if (ret && acpi_fake_ecdt_enabled) {
- ret = acpi_ec_fake_ecdt();
- }
-
if (ret)
return 0;
@@ -1000,13 +926,6 @@ static void __exit acpi_ec_exit(void)
}
#endif /* 0 */
-static int __init acpi_fake_ecdt_setup(char *str)
-{
- acpi_fake_ecdt_enabled = 1;
- return 1;
-}
-
-__setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
static int __init acpi_ec_set_intr_mode(char *str)
{
int intr;
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 14/22] ACPI: EC: enable burst functionality in EC.
[not found] ` <50a76c6beb6e41664f44239d866240952f56de78.1173498656.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 89 ++++++++++++++++++++++-------------------------------
1 files changed, 37 insertions(+), 52 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5999abd..e7ce6e4 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -101,7 +101,6 @@ static struct acpi_ec {
struct mutex lock;
atomic_t query_pending;
atomic_t event_count;
- atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
wait_queue_head_t wait;
} *ec_ecdt;
@@ -173,56 +172,6 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
return -ETIME;
}
-#ifdef ACPI_FUTURE_USAGE
-/*
- * Note: samsung nv5000 doesn't work with ec burst mode.
- * http://bugzilla.kernel.org/show_bug.cgi?id=4980
- */
-int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
-{
- u8 tmp = 0;
- u8 status = 0;
-
- status = acpi_ec_read_status(ec);
- if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if (status)
- goto end;
- acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
- tmp = acpi_ec_read_data(ec);
- if (tmp != 0x90) { /* Burst ACK byte */
- return -EINVAL;
- }
- }
-
- atomic_set(&ec->leaving_burst, 0);
- return 0;
- end:
- ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
- return -1;
-}
-
-int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
-{
- u8 status = 0;
-
- status = acpi_ec_read_status(ec);
- if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) {
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if (status)
- goto end;
- acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
- acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- }
- atomic_set(&ec->leaving_burst, 1);
- return 0;
- end:
- ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
- return -1;
-}
-#endif /* ACPI_FUTURE_USAGE */
-
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
const u8 * wdata, unsigned wdata_len,
u8 * rdata, unsigned rdata_len)
@@ -312,6 +261,21 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
return status;
}
+/*
+ * Note: samsung nv5000 doesn't work with ec burst mode.
+ * http://bugzilla.kernel.org/show_bug.cgi?id=4980
+ */
+int acpi_ec_burst_enable(struct acpi_ec *ec)
+{
+ u8 d;
+ return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1);
+}
+
+int acpi_ec_burst_disable(struct acpi_ec *ec)
+{
+ return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0);
+}
+
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
{
int result;
@@ -333,6 +297,28 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
/*
* Externally callable EC access functions. For now, assume 1 EC only
*/
+int ec_burst_enable(void)
+{
+ struct acpi_ec *ec;
+ if (!first_ec)
+ return -ENODEV;
+ ec = acpi_driver_data(first_ec);
+ return acpi_ec_burst_enable(ec);
+}
+
+EXPORT_SYMBOL(ec_burst_enable);
+
+int ec_burst_disable(void)
+{
+ struct acpi_ec *ec;
+ if (!first_ec)
+ return -ENODEV;
+ ec = acpi_driver_data(first_ec);
+ return acpi_ec_burst_disable(ec);
+}
+
+EXPORT_SYMBOL(ec_burst_disable);
+
int ec_read(u8 addr, u8 * val)
{
struct acpi_ec *ec;
@@ -639,7 +625,6 @@ static int acpi_ec_add(struct acpi_device *device)
atomic_set(&ec->query_pending, 0);
atomic_set(&ec->event_count, 1);
if (acpi_ec_mode == EC_INTR) {
- atomic_set(&ec->leaving_burst, 1);
init_waitqueue_head(&ec->wait);
}
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 15/22] ACPI: EC: Remove casts to/from void* from ec.c
[not found] ` <388ea1ea778138553bc42b8d4aa26b9221faee23.1173498656.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 13 ++++++-------
1 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e7ce6e4..1989631 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -406,7 +406,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
static void acpi_ec_gpe_query(void *ec_cxt)
{
- struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+ struct acpi_ec *ec = ec_cxt;
u8 value = 0;
char object_name[8];
@@ -424,8 +424,9 @@ static u32 acpi_ec_gpe_handler(void *data)
{
acpi_status status = AE_OK;
u8 value;
- struct acpi_ec *ec = (struct acpi_ec *)data;
+ struct acpi_ec *ec = data;
atomic_inc(&ec->event_count);
+
if (acpi_ec_mode == EC_INTR) {
wake_up(&ec->wait);
}
@@ -468,7 +469,7 @@ acpi_ec_space_handler(u32 function,
void *handler_context, void *region_context)
{
int result = 0;
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec = handler_context;
u64 temp = *value;
acpi_integer f_v = 0;
int i = 0;
@@ -480,8 +481,6 @@ acpi_ec_space_handler(u32 function,
return AE_BAD_PARAMETER;
}
- ec = (struct acpi_ec *)handler_context;
-
next_byte:
switch (function) {
case ACPI_READ:
@@ -537,7 +536,7 @@ static struct proc_dir_entry *acpi_ec_dir;
static int acpi_ec_read_info(struct seq_file *seq, void *offset)
{
- struct acpi_ec *ec = (struct acpi_ec *)seq->private;
+ struct acpi_ec *ec = seq->private;
if (!ec)
goto end;
@@ -694,7 +693,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
static acpi_status
acpi_ec_io_ports(struct acpi_resource *resource, void *context)
{
- struct acpi_ec *ec = (struct acpi_ec *)context;
+ struct acpi_ec *ec = context;
if (resource->type != ACPI_RESOURCE_TYPE_IO) {
return AE_OK;
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 16/22] ACPI: EC: Put install handlers into separate function.
[not found] ` <87340f2d12cb87a5a1e6cebe714cf61cc501b588.1173498656.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 87 ++++++++++++++++------------------------------------
1 files changed, 27 insertions(+), 60 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 1989631..399cedf 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -715,6 +715,28 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context)
return AE_OK;
}
+static int ec_install_handlers(struct acpi_ec *ec)
+{
+ acpi_status status = acpi_install_gpe_handler(NULL, ec->gpe,
+ ACPI_GPE_EDGE_TRIGGERED,
+ &acpi_ec_gpe_handler, ec);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+
+ status = acpi_install_address_space_handler(ec->handle,
+ ACPI_ADR_SPACE_EC,
+ &acpi_ec_space_handler,
+ &acpi_ec_space_setup, ec);
+ if (ACPI_FAILURE(status)) {
+ acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static int acpi_ec_start(struct acpi_device *device)
{
acpi_status status = AE_OK;
@@ -742,28 +764,7 @@ static int acpi_ec_start(struct acpi_device *device)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
ec->gpe, ec->command_addr, ec->data_addr));
- /*
- * Install GPE handler
- */
- status = acpi_install_gpe_handler(NULL, ec->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler, ec);
- if (ACPI_FAILURE(status)) {
- return -ENODEV;
- }
- acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
-
- status = acpi_install_address_space_handler(ec->handle,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler,
- &acpi_ec_space_setup, ec);
- if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
- return -ENODEV;
- }
-
- return AE_OK;
+ return ec_install_handlers(ec);
}
static int acpi_ec_stop(struct acpi_device *device, int type)
@@ -818,56 +819,22 @@ static int __init acpi_ec_get_real_ecdt(void)
ec_ecdt->gpe = ecdt_ptr->gpe;
ec_ecdt->uid = ecdt_ptr->uid;
- status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
- if (ACPI_FAILURE(status)) {
- goto error;
- }
-
+ ec_ecdt->handle = ACPI_ROOT_OBJECT;
return 0;
- error:
- ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
- kfree(ec_ecdt);
- ec_ecdt = NULL;
-
- return -ENODEV;
}
int __init acpi_ec_ecdt_probe(void)
{
- acpi_status status;
int ret;
ret = acpi_ec_get_real_ecdt();
if (ret)
return 0;
- /*
- * Install GPE handler
- */
- status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler, ec_ecdt);
- if (ACPI_FAILURE(status)) {
- goto error;
- }
- acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR);
-
- status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler,
- &acpi_ec_space_setup,
- ec_ecdt);
- if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
- &acpi_ec_gpe_handler);
- goto error;
- }
-
- return 0;
+ ret = ec_install_handlers(ec_ecdt);
+ if (!ret)
+ return 0;
- error:
- ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
kfree(ec_ecdt);
ec_ecdt = NULL;
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 17/22] ACPI: EC: Clean ECDT and namespace parsing.
[not found] ` <fb7d8f568d5bbb28d535bb68c0f287246d6a5fbf.1173498657.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 205 ++++++++++++++++++++++++++++-------------------------
1 files changed, 109 insertions(+), 96 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 399cedf..c9dcf9a 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -604,74 +604,73 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
+static acpi_status
+ec_parse_io_ports(struct acpi_resource *resource, void *context);
+
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
+
+static struct acpi_ec *make_acpi_ec(void)
+{
+ struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec)
+ return NULL;
+
+ atomic_set(&ec->query_pending, 0);
+ atomic_set(&ec->event_count, 1);
+ mutex_init(&ec->lock);
+ init_waitqueue_head(&ec->wait);
+
+ return ec;
+}
static int acpi_ec_add(struct acpi_device *device)
{
- int result = 0;
acpi_status status = AE_OK;
struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
- ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_EC_CLASS);
+
+ ec = make_acpi_ec();
if (!ec)
return -ENOMEM;
- ec->handle = device->handle;
- ec->uid = -1;
- mutex_init(&ec->lock);
- atomic_set(&ec->query_pending, 0);
- atomic_set(&ec->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- init_waitqueue_head(&ec->wait);
+ status = ec_parse_device(device->handle, 0, ec, NULL);
+ if (status != AE_CTRL_TERMINATE) {
+ kfree(ec);
+ return -EINVAL;
}
- strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_EC_CLASS);
- acpi_driver_data(device) = ec;
- /* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
-
- /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
- http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+ /* Check if we found the boot EC */
if (ec_ecdt) {
- acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler);
+ if (ec_ecdt->gpe == ec->gpe) {
+ /* We might have incorrect info for GL at boot time */
+ mutex_lock(&ec_ecdt->lock);
+ ec_ecdt->global_lock = ec->global_lock;
+ mutex_unlock(&ec_ecdt->lock);
+ kfree(ec);
+ ec = ec_ecdt;
+ }
+ }
- acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
- &acpi_ec_gpe_handler);
+ ec->handle = device->handle;
- kfree(ec_ecdt);
- }
+ acpi_driver_data(device) = ec;
- /* Get GPE bit assignment (EC events). */
- /* TODO: Add support for _GPE returning a package */
- status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Obtaining GPE bit assignment"));
- result = -ENODEV;
- goto end;
- }
+ if (!first_ec)
+ first_ec = device;
- result = acpi_ec_add_fs(device);
- if (result)
- goto end;
+ acpi_ec_add_fs(device);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
acpi_device_name(device), acpi_device_bid(device),
(u32) ec->gpe));
- if (!first_ec)
- first_ec = device;
-
- end:
- if (result)
- kfree(ec);
-
- return result;
+ return 0;
}
static int acpi_ec_remove(struct acpi_device *device, int type)
@@ -685,13 +684,19 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
acpi_ec_remove_fs(device);
- kfree(ec);
+ acpi_driver_data(device) = NULL;
+ if (device == first_ec)
+ first_ec = NULL;
+
+ /* Don't touch boot EC */
+ if (ec_ecdt != ec)
+ kfree(ec);
return 0;
}
static acpi_status
-acpi_ec_io_ports(struct acpi_resource *resource, void *context)
+ec_parse_io_ports(struct acpi_resource *resource, void *context)
{
struct acpi_ec *ec = context;
@@ -717,9 +722,10 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context)
static int ec_install_handlers(struct acpi_ec *ec)
{
- acpi_status status = acpi_install_gpe_handler(NULL, ec->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler, ec);
+ acpi_status status;
+ status = acpi_install_gpe_handler(NULL, ec->gpe,
+ ACPI_GPE_EDGE_TRIGGERED,
+ &acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status))
return -ENODEV;
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
@@ -739,8 +745,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
static int acpi_ec_start(struct acpi_device *device)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec;
if (!device)
return -EINVAL;
@@ -750,32 +755,31 @@ static int acpi_ec_start(struct acpi_device *device)
if (!ec)
return -EINVAL;
- /*
- * Get I/O port addresses. Convert to GAS format.
- */
- status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
- acpi_ec_io_ports, ec);
- if (ACPI_FAILURE(status) || ec->command_addr == 0) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Error getting I/O port addresses"));
- return -ENODEV;
- }
-
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
ec->gpe, ec->command_addr, ec->data_addr));
+ /* Boot EC is already working */
+ if (ec == ec_ecdt)
+ return 0;
+
return ec_install_handlers(ec);
}
static int acpi_ec_stop(struct acpi_device *device, int type)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
+ if (!ec)
+ return -EINVAL;
+
+ /* Don't touch boot EC */
+ if (ec == ec_ecdt)
+ return 0;
status = acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
@@ -790,51 +794,64 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
return 0;
}
-static int __init acpi_ec_get_real_ecdt(void)
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
{
acpi_status status;
+
+ struct acpi_ec *ec = context;
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ ec_parse_io_ports, ec);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ /* Get GPE bit assignment (EC events). */
+ /* TODO: Add support for _GPE returning a package */
+ status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ /* Use the global lock for all EC transactions? */
+ acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
+
+ ec->handle = handle;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+ ec->gpe, ec->command_addr, ec->data_addr));
+
+ return AE_CTRL_TERMINATE;
+}
+
+int __init acpi_ec_ecdt_probe(void)
+{
+ int ret;
+ acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
+ ec_ecdt = make_acpi_ec();
+ if (!ec_ecdt)
+ return -ENOMEM;
+ /*
+ * Generate a boot ec context
+ */
+
status = acpi_get_table(ACPI_SIG_ECDT, 1,
(struct acpi_table_header **)&ecdt_ptr);
if (ACPI_FAILURE(status))
- return -ENODEV;
+ goto error;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
- /*
- * Generate a temporary ec context to use until the namespace is scanned
- */
- ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
- if (!ec_ecdt)
- return -ENOMEM;
-
- mutex_init(&ec_ecdt->lock);
- atomic_set(&ec_ecdt->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- init_waitqueue_head(&ec_ecdt->wait);
- }
ec_ecdt->command_addr = ecdt_ptr->control.address;
ec_ecdt->data_addr = ecdt_ptr->data.address;
ec_ecdt->gpe = ecdt_ptr->gpe;
ec_ecdt->uid = ecdt_ptr->uid;
-
ec_ecdt->handle = ACPI_ROOT_OBJECT;
- return 0;
-}
-
-int __init acpi_ec_ecdt_probe(void)
-{
- int ret;
-
- ret = acpi_ec_get_real_ecdt();
- if (ret)
- return 0;
ret = ec_install_handlers(ec_ecdt);
if (!ret)
return 0;
-
+ error:
kfree(ec_ecdt);
ec_ecdt = NULL;
@@ -884,12 +901,8 @@ static int __init acpi_ec_set_intr_mode(char *str)
if (!get_option(&str, &intr))
return 0;
- if (intr) {
- acpi_ec_mode = EC_INTR;
- } else {
- acpi_ec_mode = EC_POLL;
- }
- acpi_ec_driver.ops.add = acpi_ec_add;
+ acpi_ec_mode = (intr) ? EC_INTR : EC_POLL;
+
printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
return 1;
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 18/22] ACPI: EC: Rename ec_ecdt to more informative boot_ec
[not found] ` <105cfb8936ce350c426b9b2a42e52cd3a625d102.1173498657.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 43 ++++++++++++++++++++-----------------------
1 files changed, 20 insertions(+), 23 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c9dcf9a..1250468 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -102,7 +102,7 @@ static struct acpi_ec {
atomic_t query_pending;
atomic_t event_count;
wait_queue_head_t wait;
-} *ec_ecdt;
+} *boot_ec;
/* External interfaces use first EC only, so remember */
static struct acpi_device *first_ec;
@@ -646,21 +646,18 @@ static int acpi_ec_add(struct acpi_device *device)
}
/* Check if we found the boot EC */
- if (ec_ecdt) {
- if (ec_ecdt->gpe == ec->gpe) {
+ if (boot_ec) {
+ if (boot_ec->gpe == ec->gpe) {
/* We might have incorrect info for GL at boot time */
- mutex_lock(&ec_ecdt->lock);
- ec_ecdt->global_lock = ec->global_lock;
- mutex_unlock(&ec_ecdt->lock);
+ mutex_lock(&boot_ec->lock);
+ boot_ec->global_lock = ec->global_lock;
+ mutex_unlock(&boot_ec->lock);
kfree(ec);
- ec = ec_ecdt;
+ ec = boot_ec;
}
}
-
ec->handle = device->handle;
-
acpi_driver_data(device) = ec;
-
if (!first_ec)
first_ec = device;
@@ -689,7 +686,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
first_ec = NULL;
/* Don't touch boot EC */
- if (ec_ecdt != ec)
+ if (boot_ec != ec)
kfree(ec);
return 0;
@@ -759,7 +756,7 @@ static int acpi_ec_start(struct acpi_device *device)
ec->gpe, ec->command_addr, ec->data_addr));
/* Boot EC is already working */
- if (ec == ec_ecdt)
+ if (ec == boot_ec)
return 0;
return ec_install_handlers(ec);
@@ -778,7 +775,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
return -EINVAL;
/* Don't touch boot EC */
- if (ec == ec_ecdt)
+ if (ec == boot_ec)
return 0;
status = acpi_remove_address_space_handler(ec->handle,
@@ -828,8 +825,8 @@ int __init acpi_ec_ecdt_probe(void)
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
- ec_ecdt = make_acpi_ec();
- if (!ec_ecdt)
+ boot_ec = make_acpi_ec();
+ if (!boot_ec)
return -ENOMEM;
/*
* Generate a boot ec context
@@ -842,18 +839,18 @@ int __init acpi_ec_ecdt_probe(void)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
- ec_ecdt->command_addr = ecdt_ptr->control.address;
- ec_ecdt->data_addr = ecdt_ptr->data.address;
- ec_ecdt->gpe = ecdt_ptr->gpe;
- ec_ecdt->uid = ecdt_ptr->uid;
- ec_ecdt->handle = ACPI_ROOT_OBJECT;
+ boot_ec->command_addr = ecdt_ptr->control.address;
+ boot_ec->data_addr = ecdt_ptr->data.address;
+ boot_ec->gpe = ecdt_ptr->gpe;
+ boot_ec->uid = ecdt_ptr->uid;
+ boot_ec->handle = ACPI_ROOT_OBJECT;
- ret = ec_install_handlers(ec_ecdt);
+ ret = ec_install_handlers(boot_ec);
if (!ret)
return 0;
error:
- kfree(ec_ecdt);
- ec_ecdt = NULL;
+ kfree(boot_ec);
+ boot_ec = NULL;
return -ENODEV;
}
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 19/22] ACPI: EC: first_ec is better to be acpi_ec than acpi_device.
[not found] ` <4f53bd846f964c9c3c590b3bc8eb2bfe1d392b5d.1173498657.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 41 +++++++++++++----------------------------
1 files changed, 13 insertions(+), 28 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 1250468..187981a 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -91,6 +91,7 @@ static struct acpi_driver acpi_ec_driver = {
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
+/* External interfaces use first EC only, so remember */
static struct acpi_ec {
acpi_handle handle;
unsigned long uid;
@@ -102,10 +103,7 @@ static struct acpi_ec {
atomic_t query_pending;
atomic_t event_count;
wait_queue_head_t wait;
-} *boot_ec;
-
-/* External interfaces use first EC only, so remember */
-static struct acpi_device *first_ec;
+} *boot_ec, *first_ec;
/* --------------------------------------------------------------------------
Transaction Management
@@ -299,38 +297,31 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
*/
int ec_burst_enable(void)
{
- struct acpi_ec *ec;
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
- return acpi_ec_burst_enable(ec);
+ return acpi_ec_burst_enable(first_ec);
}
EXPORT_SYMBOL(ec_burst_enable);
int ec_burst_disable(void)
{
- struct acpi_ec *ec;
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
- return acpi_ec_burst_disable(ec);
+ return acpi_ec_burst_disable(first_ec);
}
EXPORT_SYMBOL(ec_burst_disable);
int ec_read(u8 addr, u8 * val)
{
- struct acpi_ec *ec;
int err;
u8 temp_data;
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- err = acpi_ec_read(ec, addr, &temp_data);
+ err = acpi_ec_read(first_ec, addr, &temp_data);
if (!err) {
*val = temp_data;
@@ -343,15 +334,12 @@ EXPORT_SYMBOL(ec_read);
int ec_write(u8 addr, u8 val)
{
- struct acpi_ec *ec;
int err;
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- err = acpi_ec_write(ec, addr, val);
+ err = acpi_ec_write(first_ec, addr, val);
return err;
}
@@ -362,14 +350,10 @@ int ec_transaction(u8 command,
const u8 * wdata, unsigned wdata_len,
u8 * rdata, unsigned rdata_len)
{
- struct acpi_ec *ec;
-
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- return acpi_ec_transaction(ec, command, wdata,
+ return acpi_ec_transaction(first_ec, command, wdata,
wdata_len, rdata, rdata_len);
}
@@ -655,11 +639,10 @@ static int acpi_ec_add(struct acpi_device *device)
kfree(ec);
ec = boot_ec;
}
- }
+ } else
+ first_ec = ec;
ec->handle = device->handle;
acpi_driver_data(device) = ec;
- if (!first_ec)
- first_ec = device;
acpi_ec_add_fs(device);
@@ -682,7 +665,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
acpi_ec_remove_fs(device);
acpi_driver_data(device) = NULL;
- if (device == first_ec)
+ if (ec == first_ec)
first_ec = NULL;
/* Don't touch boot EC */
@@ -846,8 +829,10 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->handle = ACPI_ROOT_OBJECT;
ret = ec_install_handlers(boot_ec);
- if (!ret)
+ if (!ret) {
+ first_ec = boot_ec;
return 0;
+ }
error:
kfree(boot_ec);
boot_ec = NULL;
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 20/22] ACPI: EC: Cleanup of EC initialization
[not found] ` <2f11ffb10877e93e24ae042649666b78dd9985e6.1173498657.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 32 +++++++++++++-------------------
1 files changed, 13 insertions(+), 19 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 187981a..2a17229 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1,6 +1,8 @@
/*
- * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $)
+ * ec.c - ACPI Embedded Controller Driver (v2.0)
*
+ * Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
+ * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -94,7 +96,6 @@ static struct acpi_driver acpi_ec_driver = {
/* External interfaces use first EC only, so remember */
static struct acpi_ec {
acpi_handle handle;
- unsigned long uid;
unsigned long gpe;
unsigned long command_addr;
unsigned long data_addr;
@@ -525,13 +526,11 @@ static int acpi_ec_read_info(struct seq_file *seq, void *offset)
if (!ec)
goto end;
- seq_printf(seq, "gpe: 0x%02x\n", (u32) ec->gpe);
- seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
- (u32) ec->command_addr, (u32) ec->data_addr);
- seq_printf(seq, "use global lock: %s\n",
+ seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
+ seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
+ (unsigned)ec->command_addr, (unsigned)ec->data_addr);
+ seq_printf(seq, "use global lock:\t%s\n",
ec->global_lock ? "yes" : "no");
- acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
-
end:
return 0;
}
@@ -655,15 +654,13 @@ static int acpi_ec_add(struct acpi_device *device)
static int acpi_ec_remove(struct acpi_device *device, int type)
{
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
-
acpi_ec_remove_fs(device);
-
acpi_driver_data(device) = NULL;
if (ec == first_ec)
first_ec = NULL;
@@ -671,7 +668,6 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
/* Don't touch boot EC */
if (boot_ec != ec)
kfree(ec);
-
return 0;
}
@@ -680,22 +676,20 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
{
struct acpi_ec *ec = context;
- if (resource->type != ACPI_RESOURCE_TYPE_IO) {
+ if (resource->type != ACPI_RESOURCE_TYPE_IO)
return AE_OK;
- }
/*
* The first address region returned is the data port, and
* the second address region returned is the status/command
* port.
*/
- if (ec->data_addr == 0) {
+ if (ec->data_addr == 0)
ec->data_addr = resource->data.io.minimum;
- } else if (ec->command_addr == 0) {
+ else if (ec->command_addr == 0)
ec->command_addr = resource->data.io.minimum;
- } else {
+ else
return AE_CTRL_TERMINATE;
- }
return AE_OK;
}
@@ -708,6 +702,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
&acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status))
return -ENODEV;
+
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
@@ -825,7 +820,6 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->command_addr = ecdt_ptr->control.address;
boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe;
- boot_ec->uid = ecdt_ptr->uid;
boot_ec->handle = ACPI_ROOT_OBJECT;
ret = ec_install_handlers(boot_ec);
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 21/22] ACPI: EC: Block queries until EC is fully initialized
[not found] ` <5923a5eb97e66a7678742b84352b82597673c766.1173498658.git.len.brown@intel.com>
@ 2007-03-10 4:00 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-10 4:00 UTC (permalink / raw)
To: linux-acpi; +Cc: Alexey Starikovskiy, Len Brown
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 2a17229..e08cf98 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -599,7 +599,7 @@ static struct acpi_ec *make_acpi_ec(void)
if (!ec)
return NULL;
- atomic_set(&ec->query_pending, 0);
+ atomic_set(&ec->query_pending, 1);
atomic_set(&ec->event_count, 1);
mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait);
@@ -715,6 +715,9 @@ static int ec_install_handlers(struct acpi_ec *ec)
return -ENODEV;
}
+ /* EC is fully operational, allow queries */
+ atomic_set(&ec->query_pending, 0);
+
return 0;
}
--
1.5.0.3.310.g05ef5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH 11/22] ACPI: EC: Don't use Global Lock if not asked to do so
[not found] ` <705ff592931e6738926fd6d596461010a1e8977d.1173498654.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 11/22] ACPI: EC: Don't use Global Lock if not asked to do so Len Brown
@ 2007-03-10 14:12 ` Sanjoy Mahajan
1 sibling, 0 replies; 31+ messages in thread
From: Sanjoy Mahajan @ 2007-03-10 14:12 UTC (permalink / raw)
To: Len Brown; +Cc: linux-acpi, Alexey Starikovskiy, Len Brown
Does this patch obsolete the patch to "release global lock in
acpi_ec_wait"? It's part of bugzilla 6749 "Thinkpad A21m freeze after
second supedn to RAM"
<http://bugzilla.kernel.org/show_bug.cgi?id=6749> and its direct url
is <http://bugzilla.kernel.org/attachment.cgi?id=8481&action=view>.
Or did that patch get integrated via some other flow of code? It
fixed the S3 suspend hangs on my TP 600X. It might also help the T60:
Once in a long while it would hang on suspend and it reminded me of
the 600X's behavior (though the T60 has an ancient kernel, 2.6.17-10
from ubuntu, which is why I never filed a report). I work around the
problem by unloading the fan and thermal modules before suspending.
It also hangs once in a while on resume, but those problems will
hopefully be resolved by a more recent kernel.
-Sanjoy
`Not all those who wander are lost.' (J.R.R. Tolkien)
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure
2007-03-10 4:00 ` [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure Len Brown
@ 2007-03-15 12:31 ` Andi Kleen
2007-03-15 16:47 ` Len Brown
2007-03-15 13:13 ` Richard Hughes
1 sibling, 1 reply; 31+ messages in thread
From: Andi Kleen @ 2007-03-15 12:31 UTC (permalink / raw)
To: Len Brown; +Cc: venkatesh.pallipadi, linux-acpi
Len Brown <lenb@kernel.org> writes:
> +
> +/**
> + * cpuidle_idle_call - the main idle loop
> + *
> + * NOTE: no locks or semaphores should be used here
> + * FIXME: DYNTICKS handling
I don't think you can merge anything anymore with such a FIXME.
Besides cpuidle is a pretty radical change outside ACPI and I would recommend to
make a few review cycles over linux-kernel and likely linux-arch.
For me it's not clear it has enough advantages for its amount of code
-Andi
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure
2007-03-10 4:00 ` [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure Len Brown
2007-03-15 12:31 ` Andi Kleen
@ 2007-03-15 13:13 ` Richard Hughes
2007-03-15 16:38 ` Len Brown
1 sibling, 1 reply; 31+ messages in thread
From: Richard Hughes @ 2007-03-15 13:13 UTC (permalink / raw)
To: Len Brown
Cc: linux-acpi, Venkatesh Pallipadi, Adam Belay, Shaohua Li,
Len Brown
On 10/03/07, Len Brown <lenb@kernel.org> wrote:
> arch/i386/Kconfig | 2 +
> arch/x86_64/Kconfig | 2 +
> drivers/Makefile | 1 +
> drivers/cpuidle/Kconfig | 28 +++
> drivers/cpuidle/Makefile | 5 +
> drivers/cpuidle/cpuidle.c | 287 ++++++++++++++++++++++++++++++
> drivers/cpuidle/cpuidle.h | 52 ++++++
> drivers/cpuidle/driver.c | 219 +++++++++++++++++++++++
> drivers/cpuidle/governor.c | 160 +++++++++++++++++
> drivers/cpuidle/governors/Makefile | 5 +
> drivers/cpuidle/governors/ladder.c | 229 ++++++++++++++++++++++++
> drivers/cpuidle/sysfs.c | 340 ++++++++++++++++++++++++++++++++++++
> include/linux/cpuidle.h | 160 +++++++++++++++++
What about some documentation so that userspace knows what to do with
this new framework?
Richard.
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure
2007-03-15 13:13 ` Richard Hughes
@ 2007-03-15 16:38 ` Len Brown
2007-03-15 16:42 ` Richard Hughes
0 siblings, 1 reply; 31+ messages in thread
From: Len Brown @ 2007-03-15 16:38 UTC (permalink / raw)
To: Richard Hughes
Cc: linux-acpi, Venkatesh Pallipadi, Adam Belay, Shaohua Li,
Len Brown
On Thursday 15 March 2007 09:13, Richard Hughes wrote:
> What about some documentation so that userspace knows what to do with
> this new framework?
What does userspace need to know in addition to what is in Documentation/cpuidle/?
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure
2007-03-15 16:38 ` Len Brown
@ 2007-03-15 16:42 ` Richard Hughes
0 siblings, 0 replies; 31+ messages in thread
From: Richard Hughes @ 2007-03-15 16:42 UTC (permalink / raw)
To: Len Brown
Cc: linux-acpi, Venkatesh Pallipadi, Adam Belay, Shaohua Li,
Len Brown
On 15/03/07, Len Brown <lenb@kernel.org> wrote:
> On Thursday 15 March 2007 09:13, Richard Hughes wrote:
>
> > What about some documentation so that userspace knows what to do with
> > this new framework?
>
> What does userspace need to know in addition to what is in Documentation/cpuidle/?
I didn't see that file in the patch, apologies.
Richard.
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure
2007-03-15 12:31 ` Andi Kleen
@ 2007-03-15 16:47 ` Len Brown
0 siblings, 0 replies; 31+ messages in thread
From: Len Brown @ 2007-03-15 16:47 UTC (permalink / raw)
To: Andi Kleen; +Cc: venkatesh.pallipadi, linux-acpi, Adam Belay, Shaohua Li
On Thursday 15 March 2007 08:31, Andi Kleen wrote:
> Len Brown <lenb@kernel.org> writes:
> > +
> > +/**
> > + * cpuidle_idle_call - the main idle loop
> > + *
> > + * NOTE: no locks or semaphores should be used here
> > + * FIXME: DYNTICKS handling
>
> I don't think you can merge anything anymore with such a FIXME.
Certainly it need to work well with NOHZ before it can go upstream.
Indeed, NOHZ is one of the reasons for doing cpuidle in the first place.
But then NOHZ is probably going to take some time to mature also,
certainly it can't be considered mature until it is also in the 64-bit kernel.
The question becomes if NOHZ matures w/o cpuidle -- do we need
to modify the existing tick-based ACPI idle code before cpuidle?
> Besides cpuidle is a pretty radical change outside ACPI and I would recommend to
> make a few review cycles over linux-kernel and likely linux-arch.
I agree. acpi-test and -mm would not be sufficient exposure for generic code.
> For me it's not clear it has enough advantages for its amount of code
Understood. Measurements will tell.
This is the very reason we created tools which can simultaneously
measure performance and battery life: http://sourceforge.net/projects/bltk
I think that for cpuidle to go upstream, its default should not require any user-space changes
to work as well as the old code. If some sysfs hooks are available to get added
value, such as useful statistics or modifying policy, that is something that
user-space can safely ignore and not break.
-Len
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: ACPI patches in test for Linux-2.6.22
2007-03-10 4:00 ACPI patches in test for Linux-2.6.22 Len Brown
[not found] ` <941b1971a405f95537bc6f9a738e737eb2186e45.1173498647.git.len.brown@intel.com>
@ 2007-03-16 17:58 ` Sergio Monteiro Basto
2007-03-16 18:03 ` Alexey Starikovskiy
1 sibling, 1 reply; 31+ messages in thread
From: Sergio Monteiro Basto @ 2007-03-16 17:58 UTC (permalink / raw)
To: Len Brown; +Cc: linux-acpi
[-- Attachment #1: Type: text/plain, Size: 267 bytes --]
On Fri, 2007-03-09 at 23:00 -0500, Len Brown wrote:
> These patches are in test for Linux-2.6.22.
>
Since we have big changes on ACPI for 2.6.21 , why we don't test all at
once (why we don't also include this on 6.21) ?
Best regards,
--
Sérgio M. B.
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 2192 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: ACPI patches in test for Linux-2.6.22
2007-03-16 17:58 ` ACPI patches in test for Linux-2.6.22 Sergio Monteiro Basto
@ 2007-03-16 18:03 ` Alexey Starikovskiy
0 siblings, 0 replies; 31+ messages in thread
From: Alexey Starikovskiy @ 2007-03-16 18:03 UTC (permalink / raw)
To: Sergio Monteiro Basto; +Cc: Len Brown, linux-acpi
Sergio Monteiro Basto wrote:
> On Fri, 2007-03-09 at 23:00 -0500, Len Brown wrote:
>
>> These patches are in test for Linux-2.6.22.
>>
>>
> Since we have big changes on ACPI for 2.6.21 , why we don't test all at
> once (why we don't also include this on 6.21) ?
>
> Best regards,
>
Because testing is expected to be done in Andrew Morton' -mm and not in
Linus' stable kernel.
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 05/22] ACPI: Cache battery status instead of re-evaluating AML
2007-03-10 4:00 ` [PATCH 05/22] ACPI: Cache battery status instead of re-evaluating AML Len Brown
@ 2007-04-19 18:23 ` Andrew Morton
0 siblings, 0 replies; 31+ messages in thread
From: Andrew Morton @ 2007-04-19 18:23 UTC (permalink / raw)
To: Len Brown; +Cc: linux-acpi, Vladimir Lebedev, Len Brown
On Fri, 9 Mar 2007 23:00:42 -0500
Len Brown <lenb@kernel.org> wrote:
> From: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
>
> /proc exports _BST in a single file, and _BST is re-evaulated
> whenever that file is read.
>
> Sometimes user-space reads this file frequently, and on some
> systems _BST takes a long time to evaluate due to a slow EC.
>
> Further, when we move to sysfs, the values returned from _BST
> will be in multiple files, and evaluating _BST for each
> file read would make matters worse.
>
> Here code is added to support caching the results of _BST.
> A new module parameter "update_time" tells how many seconds the
> cached _BST should be used before it is re-evaluated.
> Currently, update_time defaults to 0, and so the
> existing behaviour of re-evaluating on each read retained.
>
> ...
>
> +#define acpi_battery_present(battery) battery->device->status.battery_present
> +#define acpi_battery_present_prev(battery) battery->flags.battery_present_prev
> +#define acpi_battery_alarm_present(battery) battery->flags.alarm_present
> +#define acpi_battery_init_update_flag(battery) battery->flags.init_update
> +#define acpi_battery_info_update_flag(battery) battery->flags.info_update
> +#define acpi_battery_state_update_flag(battery) battery->flags.state_update
> +#define acpi_battery_alarm_update_flag(battery) battery->flags.alarm_update
> +#define acpi_battery_power_units(battery) battery->flags.power_unit ? \
> + ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS
> +#define acpi_battery_handle(battery) battery->device->handle
> +#define acpi_battery_inserted(battery) (!acpi_battery_present_prev(battery) & acpi_battery_present(battery))
> +#define acpi_battery_removed(battery) (acpi_battery_present_prev(battery) & !acpi_battery_present(battery))
> +#define acpi_battery_bid(battery) acpi_device_bid(battery->device)
> +#define acpi_battery_status_str(battery) acpi_battery_present(battery) ? "present" : "absent"
These macros are
a) insufficiently parenthesised: try evaluating
acpi_battery_present(battery + 1);
b) ugly. It's a real bad sign when we see
acpi_battery_init_update_flag(battery) = 1;
which simply isn't C.
If we really insist on this obfuscation layer then it would be much better
to do
static inline int acpi_battery_init_update_flag(struct acpi_battery *battery)
{
return battery->flags.init_update;
}
static inline void
acpi_battery_set_init_update_flag(struct acpi_battery *battery, int value)
{
battery->flags.init_update = value;
}
> +static void acpi_battery_mutex_lock(struct acpi_battery *battery)
> +{
> + mutex_lock(&battery->mutex);
> +}
> +
> +static void acpi_battery_mutex_unlock(struct acpi_battery *battery)
> +{
> + mutex_unlock(&battery->mutex);
> +}
These wrappers don't add any value and should be removed.
> +static void acpi_battery_check_result(struct acpi_battery *battery, int result)
> +{
> + if (!battery)
> + return;
> +
> + if (result) {
> + acpi_battery_init_update_flag(battery) = 1;
> + }
> +}
We prefer not to have braces around a single statement like this.
> +static int acpi_battery_extract_package(struct acpi_battery *battery,
> + union acpi_object *package,
> + struct acpi_buffer *format,
> + struct acpi_buffer *data,
> + char *package_name)
> +{
> + acpi_status status = AE_OK;
> + struct acpi_buffer data_null = { 0, NULL };
> +
> + status = acpi_extract_package(package, format, &data_null);
> + if (status != AE_BUFFER_OVERFLOW) {
> + ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
> + package_name));
> + return -ENODEV;
> + }
> +
> + if (data_null.length != data->length) {
> + if (data->pointer) {
> + kfree(data->pointer);
> + }
kfree(NULL) is legal and preferred kernel style is to not duplicate the
test fro NULL in the kfree() caller like this (there are multiple instances
of this in this patch).
> + data->pointer = kzalloc(data_null.length, GFP_KERNEL);
> + if (!data->pointer) {
> + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
> + return -ENOMEM;
> + }
> + data->length = data_null.length;
> + }
> +
> + status = acpi_extract_package(package, format, data);
> + if (ACPI_FAILURE(status)) {
> + ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
> + package_name));
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
>
> ...
>
> +static int acpi_battery_read_info(struct seq_file *seq, void *offset)
> +{
> + struct acpi_battery *battery = seq->private;
> + int result = 0;
> + int update_result = ACPI_BATTERY_NONE_UPDATE;
> + int update = 0;
> +
> + acpi_battery_mutex_lock(battery);
> +
> + update = (get_seconds() - battery->info_update_time >= update_time);
> + update = (update | acpi_battery_info_update_flag(battery));
> +
> + result = acpi_battery_update(battery, update, &update_result);
> + if (result)
> + goto end;
> +
> + /* Battery Info (_BIF) */
> +
> + if (update_result == ACPI_BATTERY_EASY_UPDATE) {
> + result = acpi_battery_get_info(battery);
> + if (result)
> + goto end;
> + }
> +
> + end:
> +
> + result = acpi_battery_read_info_print(seq, result);
> +
> + acpi_battery_check_result(battery, result);
> +
> + acpi_battery_info_update_flag(battery) = result;
> +
> + acpi_battery_mutex_unlock(battery);
> +
> + return result;
> }
We have several copies of this function, each with tiny variations:
> +static int acpi_battery_read_state(struct seq_file *seq, void *offset)
> +{
> + struct acpi_battery *battery = seq->private;
> + int result = 0;
> + int update_result = ACPI_BATTERY_NONE_UPDATE;
> + int update = 0;
> +
> + acpi_battery_mutex_lock(battery);
> +
> + update = (get_seconds() - battery->state_update_time >= update_time);
> + update = (update | acpi_battery_state_update_flag(battery));
> +
> + result = acpi_battery_update(battery, update, &update_result);
> + if (result)
> + goto end;
> +
> + /* Battery State (_BST) */
> +
> + if (update_result == ACPI_BATTERY_EASY_UPDATE) {
> + result = acpi_battery_get_state(battery);
> + if (result)
> + goto end;
> + }
> +
> + end:
> +
> + result = acpi_battery_read_state_print(seq, result);
> +
> + acpi_battery_check_result(battery, result);
> +
> + acpi_battery_state_update_flag(battery) = result;
> +
> + acpi_battery_mutex_unlock(battery);
> +
> + return result;
> }
Can we not find a way of consolidating all this duplication?
> +static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
> +{
> + struct acpi_battery *battery = seq->private;
> + int result = 0;
> + int update_result = ACPI_BATTERY_NONE_UPDATE;
> + int update = 0;
> +
> + acpi_battery_mutex_lock(battery);
> +
> + update = (get_seconds() - battery->alarm_update_time >= update_time);
> + update = (update | acpi_battery_alarm_update_flag(battery));
> +
> + result = acpi_battery_update(battery, update, &update_result);
> + if (result)
> + goto end;
> +
> + /* Battery Alarm */
> +
> + if (update_result == ACPI_BATTERY_EASY_UPDATE) {
> + result = acpi_battery_get_alarm(battery);
> + if (result)
> + goto end;
> + }
> +
> + end:
> +
> + result = acpi_battery_read_alarm_print(seq, result);
> +
> + acpi_battery_check_result(battery, result);
> +
> + acpi_battery_alarm_update_flag(battery) = result;
> +
> + acpi_battery_mutex_unlock(battery);
> +
> + return result;
> }
More here.
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2007-04-19 18:34 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-10 4:00 ACPI patches in test for Linux-2.6.22 Len Brown
[not found] ` <941b1971a405f95537bc6f9a738e737eb2186e45.1173498647.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 01/22] cpuidle take2: Core cpuidle infrastructure Len Brown
2007-03-15 12:31 ` Andi Kleen
2007-03-15 16:47 ` Len Brown
2007-03-15 13:13 ` Richard Hughes
2007-03-15 16:38 ` Len Brown
2007-03-15 16:42 ` Richard Hughes
[not found] ` <92648781fb5f44cee584da36eb569e88dddc4b8f.1173498651.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 02/22] cpuidle take2: Hookup ACPI C-states driver with cpuidle Len Brown
[not found] ` <c5bb38e598e68202e0d6f08b3fe0f30f12999357.1173498651.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 03/22] cpuidle take2: Basic documentation for cpuidle Len Brown
[not found] ` <a1f0eff21edac1bd87e397f56c4258b9611b5a50.1173498652.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 04/22] ACPI: battery: make internal names consistent with battery "state" Len Brown
[not found] ` <b6ce4083ed8e2a01a3a59301eabe0fc1e68a8a84.1173498652.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 05/22] ACPI: Cache battery status instead of re-evaluating AML Len Brown
2007-04-19 18:23 ` Andrew Morton
[not found] ` <9ea7d57576f40c6af03c8c9fa7a069f2222b498b.1173498653.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 06/22] ACPI: battery: Lindent Len Brown
[not found] ` <d98b2065c5ac31a35cbdfe9b47d421352f96fc3f.1173498653.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 07/22] cpuidle: build fix for !CPU_IDLE Len Brown
[not found] ` <bc17374e69a621c9b7f6f9624c9248f3b8e8503d.1173498653.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 08/22] cpu_idle: fix build break Len Brown
[not found] ` <3d869f55bda8b0b6f0cb55f9a85a6f855a016092.1173498654.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 09/22] cpuidle: make code static Len Brown
[not found] ` <b51f201f9a9af932c723492551f9e688d34cc468.1173498654.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 10/22] cpuidle: ladder does not depend on ACPI Len Brown
[not found] ` <705ff592931e6738926fd6d596461010a1e8977d.1173498654.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 11/22] ACPI: EC: Don't use Global Lock if not asked to do so Len Brown
2007-03-10 14:12 ` Sanjoy Mahajan
[not found] ` <e4382a15d138ea6c0d4277967e646216ce57040f.1173498654.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 12/22] ACPI: EC: Make EC to initialize first in ACPI Len Brown
[not found] ` <94418415a62ec4c88109385d8663e56aac54dfd6.1173498656.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 13/22] ACPI: EC: "Fake ECDT" workaround is not needed any longer Len Brown
[not found] ` <50a76c6beb6e41664f44239d866240952f56de78.1173498656.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 14/22] ACPI: EC: enable burst functionality in EC Len Brown
[not found] ` <388ea1ea778138553bc42b8d4aa26b9221faee23.1173498656.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 15/22] ACPI: EC: Remove casts to/from void* from ec.c Len Brown
[not found] ` <87340f2d12cb87a5a1e6cebe714cf61cc501b588.1173498656.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 16/22] ACPI: EC: Put install handlers into separate function Len Brown
[not found] ` <fb7d8f568d5bbb28d535bb68c0f287246d6a5fbf.1173498657.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 17/22] ACPI: EC: Clean ECDT and namespace parsing Len Brown
[not found] ` <105cfb8936ce350c426b9b2a42e52cd3a625d102.1173498657.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 18/22] ACPI: EC: Rename ec_ecdt to more informative boot_ec Len Brown
[not found] ` <4f53bd846f964c9c3c590b3bc8eb2bfe1d392b5d.1173498657.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 19/22] ACPI: EC: first_ec is better to be acpi_ec than acpi_device Len Brown
[not found] ` <2f11ffb10877e93e24ae042649666b78dd9985e6.1173498657.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 20/22] ACPI: EC: Cleanup of EC initialization Len Brown
[not found] ` <5923a5eb97e66a7678742b84352b82597673c766.1173498658.git.len.brown@intel.com>
2007-03-10 4:00 ` [PATCH 21/22] ACPI: EC: Block queries until EC is fully initialized Len Brown
2007-03-16 17:58 ` ACPI patches in test for Linux-2.6.22 Sergio Monteiro Basto
2007-03-16 18:03 ` Alexey Starikovskiy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).