aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/acpi/Makefile2
-rw-r--r--arch/i386/kernel/setup.c2
-rw-r--r--arch/i386/mm/init.c2
-rw-r--r--arch/ia64/kernel/acpi.c19
-rw-r--r--arch/x86_64/kernel/acpi/Makefile2
-rw-r--r--arch/x86_64/kernel/acpi/sleep.c4
-rw-r--r--arch/x86_64/kernel/head.S2
-rw-r--r--arch/x86_64/kernel/setup.c2
-rw-r--r--drivers/acpi/Kconfig64
-rw-r--r--drivers/acpi/processor_throttling.c59
-rw-r--r--drivers/acpi/sleep/Makefile4
-rw-r--r--drivers/acpi/sleep/main.c162
-rw-r--r--drivers/acpi/sleep/poweroff.c2
-rw-r--r--drivers/acpi/sleep/proc.c20
-rw-r--r--drivers/acpi/sleep/wakeup.c2
-rw-r--r--drivers/misc/asus-laptop.c32
-rw-r--r--drivers/pci/pci-acpi.c28
-rw-r--r--drivers/pci/pci.c8
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pnp/driver.c5
-rw-r--r--drivers/pnp/pnpacpi/core.c14
-rw-r--r--include/acpi/acpi_bus.h2
-rw-r--r--include/acpi/acpi_drivers.h4
-rw-r--r--include/asm-i386/acpi.h23
-rw-r--r--include/asm-i386/suspend.h2
-rw-r--r--include/asm-ia64/acpi.h5
-rw-r--r--include/asm-x86_64/acpi.h22
-rw-r--r--include/asm-x86_64/suspend.h2
-rw-r--r--include/linux/pnp.h4
-rw-r--r--kernel/sysctl.c2
30 files changed, 332 insertions, 171 deletions
diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile
index 7f7be01f44e..223f58fc9f4 100644
--- a/arch/i386/kernel/acpi/Makefile
+++ b/arch/i386/kernel/acpi/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_ACPI) += boot.o
ifneq ($(CONFIG_PCI),)
obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o
endif
-obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
+obj-$(CONFIG_ACPI) += sleep.o wakeup.o
ifneq ($(CONFIG_ACPI_PROCESSOR),)
obj-y += cstate.o processor.o
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index d474cd639bc..7fe5da3c932 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -422,7 +422,7 @@ void __init setup_bootmem_allocator(void)
*/
reserve_bootmem(PAGE_SIZE, PAGE_SIZE);
#endif
-#ifdef CONFIG_ACPI_SLEEP
+#ifdef CONFIG_ACPI
/*
* Reserve low memory region for sleep support.
*/
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index c3b9905af2d..1b1a1e66d09 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -432,7 +432,7 @@ static void __init pagetable_init (void)
paravirt_pagetable_setup_done(pgd_base);
}
-#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP)
+#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI)
/*
* Swap suspend & friends need this for resume because things like the intel-agp
* driver might have split up a kernel 4MB mapping.
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 103dd8edda7..c6ede8780de 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -67,6 +67,8 @@ EXPORT_SYMBOL(pm_power_off);
unsigned int acpi_cpei_override;
unsigned int acpi_cpei_phys_cpuid;
+unsigned long acpi_wakeup_address = 0;
+
const char __init *
acpi_get_sysname(void)
{
@@ -986,4 +988,21 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
EXPORT_SYMBOL(acpi_unregister_ioapic);
+/*
+ * acpi_save_state_mem() - save kernel state
+ *
+ * TBD when when IA64 starts to support suspend...
+ */
+int acpi_save_state_mem(void) { return 0; }
+
+/*
+ * acpi_restore_state()
+ */
+void acpi_restore_state_mem(void) {}
+
+/*
+ * do_suspend_lowlevel()
+ */
+void do_suspend_lowlevel(void) {}
+
#endif /* CONFIG_ACPI */
diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile
index 080b9963f1b..17595d23fee 100644
--- a/arch/x86_64/kernel/acpi/Makefile
+++ b/arch/x86_64/kernel/acpi/Makefile
@@ -1,6 +1,6 @@
obj-y := boot.o
boot-y := ../../../i386/kernel/acpi/boot.o
-obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
+obj-y += sleep.o wakeup.o
ifneq ($(CONFIG_ACPI_PROCESSOR),)
obj-y += processor.o
diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c
index 4277f2b27e6..79475d23707 100644
--- a/arch/x86_64/kernel/acpi/sleep.c
+++ b/arch/x86_64/kernel/acpi/sleep.c
@@ -51,8 +51,6 @@
Low-Level Sleep Support
-------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_SLEEP
-
/* address in low memory of the wakeup routine. */
unsigned long acpi_wakeup_address = 0;
unsigned long acpi_realmode_flags;
@@ -117,8 +115,6 @@ static int __init acpi_sleep_setup(char *str)
__setup("acpi_sleep=", acpi_sleep_setup);
-#endif /*CONFIG_ACPI_SLEEP */
-
void acpi_pci_link_exit(void)
{
}
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index e89abcdbdde..3a16e417dd8 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -120,7 +120,7 @@ ident_complete:
addq %rbp, trampoline_level4_pgt + 0(%rip)
addq %rbp, trampoline_level4_pgt + (511*8)(%rip)
#endif
-#ifdef CONFIG_ACPI_SLEEP
+#ifdef CONFIG_ACPI
addq %rbp, wakeup_level4_pgt + 0(%rip)
addq %rbp, wakeup_level4_pgt + (511*8)(%rip)
#endif
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index af838f6b0b7..0f400f3c469 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -333,7 +333,7 @@ void __init setup_arch(char **cmdline_p)
reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
#endif
-#ifdef CONFIG_ACPI_SLEEP
+#ifdef CONFIG_ACPI
/*
* Reserve low memory region for sleep support.
*/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 408b45168ab..251344cb29a 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -11,6 +11,9 @@ menuconfig ACPI
depends on PCI
depends on PM
select PNP
+ # for sleep
+ select HOTPLUG_CPU if X86 && SMP
+ select SUSPEND_SMP if X86 && SMP
default y
---help---
Advanced Configuration and Power Interface (ACPI) support for
@@ -42,51 +45,26 @@ menuconfig ACPI
if ACPI
-config ACPI_SLEEP
- bool "Sleep States"
- depends on X86 && (!SMP || SUSPEND_SMP)
- default y
- ---help---
- This option adds support for ACPI suspend states.
-
- With this option, you will be able to put the system "to sleep".
- Sleep states are low power states for the system and devices. All
- of the system operating state is saved to either memory or disk
- (depending on the state), to allow the system to resume operation
- quickly at your request.
-
- Although this option sounds really nifty, barely any of the device
- drivers have been converted to the new driver model and hence few
- have proper power management support.
-
- This option is not recommended for anyone except those doing driver
- power management development.
-
-config ACPI_SLEEP_PROC_FS
- bool
- depends on ACPI_SLEEP && PROC_FS
- default y
-
-config ACPI_SLEEP_PROC_SLEEP
- bool "/proc/acpi/sleep (deprecated)"
- depends on ACPI_SLEEP_PROC_FS
- default n
- ---help---
- Create /proc/acpi/sleep
- Deprecated by /sys/power/state
-
config ACPI_PROCFS
- bool "Procfs interface (deprecated)"
- default y
+ bool "Deprecated /proc/acpi files"
+ depends on PROC_FS
---help---
- The Procfs interface for ACPI is made optional for backward compatibility.
- As the same functions are duplicated in the sysfs interface
- and this proc interface will be removed some time later,
- it's marked as deprecated.
- ( /proc/acpi/debug_layer && debug_level are deprecated by
- /sys/module/acpi/parameters/debug_layer && debug_level.
- /proc/acpi/info is deprecated by
- /sys/module/acpi/parameters/acpica_version )
+ For backwards compatibility, this option allows
+ depricated /proc/acpi/ files to exist, even when
+ they have been replaced by functions in /sys.
+ The deprecated files (and their replacements) include:
+
+ /proc/acpi/sleep (/sys/power/state)
+ /proc/acpi/info (/sys/modules/acpi/parameters/acpica_version)
+ /proc/acpi/dsdt (/sys/firmware/acpi/tables/DSDT)
+ /proc/acpi/fadt (/sys/firmware/acpi/tables/FACP)
+ /proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer)
+ /proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level)
+
+ This option has no effect on /proc/acpi/ files
+ and functions which do not yet exist in /sys.
+
+ Say N to delete /proc/acpi/ files that have moved to /sys/
config ACPI_AC
tristate "AC Adapter"
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 3f55d1f90c1..0b8204e7082 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -47,6 +47,9 @@ ACPI_MODULE_NAME("processor_throttling");
static int acpi_processor_get_throttling(struct acpi_processor *pr);
int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+/*
+ * _TPC - Throttling Present Capabilities
+ */
static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
{
acpi_status status = 0;
@@ -55,8 +58,10 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
if (!pr)
return -EINVAL;
status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC"));
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC"));
+ }
return -ENODEV;
}
pr->throttling_platform_limit = (int)tpc;
@@ -68,9 +73,9 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
return acpi_processor_get_platform_limit(pr);
}
-/* --------------------------------------------------------------------------
- _PTC, _TSS, _TSD support
- -------------------------------------------------------------------------- */
+/*
+ * _PTC - Processor Throttling Control (and status) register location
+ */
static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
{
int result = 0;
@@ -81,7 +86,9 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC"));
+ if (status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC"));
+ }
return -ENODEV;
}
@@ -132,6 +139,10 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
return result;
}
+
+/*
+ * _TSS - Throttling Supported States
+ */
static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
{
int result = 0;
@@ -144,7 +155,9 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS"));
+ if (status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS"));
+ }
return -ENODEV;
}
@@ -201,6 +214,10 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
return result;
}
+
+/*
+ * _TSD - T-State Dependencies
+ */
static int acpi_processor_get_tsd(struct acpi_processor *pr)
{
int result = 0;
@@ -213,6 +230,9 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSD"));
+ }
return -ENODEV;
}
@@ -525,9 +545,6 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
int result = 0;
int step = 0;
int i = 0;
- int no_ptc = 0;
- int no_tss = 0;
- int no_tsd = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@@ -538,12 +555,14 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
if (!pr)
return -EINVAL;
- /* TBD: Support ACPI 2.0 objects */
- no_ptc = acpi_processor_get_throttling_control(pr);
- no_tss = acpi_processor_get_throttling_states(pr);
- no_tsd = acpi_processor_get_tsd(pr);
-
- if (no_ptc || no_tss) {
+ /*
+ * Evaluate _PTC, _TSS and _TPC
+ * They must all be present or none of them can be used.
+ */
+ if (acpi_processor_get_throttling_control(pr) ||
+ acpi_processor_get_throttling_states(pr) ||
+ acpi_processor_get_platform_limit(pr))
+ {
pr->throttling.acpi_processor_get_throttling =
&acpi_processor_get_throttling_fadt;
pr->throttling.acpi_processor_set_throttling =
@@ -555,6 +574,8 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
&acpi_processor_set_throttling_ptc;
}
+ acpi_processor_get_tsd(pr);
+
if (!pr->throttling.address) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
return 0;
@@ -658,18 +679,20 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
pr->throttling.state_count - 1);
seq_puts(seq, "states:\n");
- if (acpi_processor_get_throttling == acpi_processor_get_throttling_fadt)
+ if (pr->throttling.acpi_processor_get_throttling ==
+ acpi_processor_get_throttling_fadt) {
for (i = 0; i < pr->throttling.state_count; i++)
seq_printf(seq, " %cT%d: %02d%%\n",
(i == pr->throttling.state ? '*' : ' '), i,
(pr->throttling.states[i].performance ? pr->
throttling.states[i].performance / 10 : 0));
- else
+ } else {
for (i = 0; i < pr->throttling.state_count; i++)
seq_printf(seq, " %cT%d: %02d%%\n",
(i == pr->throttling.state ? '*' : ' '), i,
(int)pr->throttling.states_tss[i].
freqpercentage);
+ }
end:
return 0;
diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile
index d6c017709c8..01a993a1d08 100644
--- a/drivers/acpi/sleep/Makefile
+++ b/drivers/acpi/sleep/Makefile
@@ -1,5 +1,5 @@
obj-y := poweroff.o wakeup.o
-obj-$(CONFIG_ACPI_SLEEP) += main.o
-obj-$(CONFIG_ACPI_SLEEP_PROC_FS) += proc.o
+obj-y += main.o
+obj-$(CONFIG_X86) += proc.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 3279e72a94f..ab21357c5c7 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -34,35 +34,55 @@ static u32 acpi_suspend_states[] = {
static int init_8259A_after_S1;
+extern int acpi_sleep_prepare(u32 acpi_state);
+extern void acpi_power_off(void);
+
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+
+/**
+ * acpi_pm_set_target - Set the target system sleep state to the state
+ * associated with given @pm_state, if supported.
+ */
+
+static int acpi_pm_set_target(suspend_state_t pm_state)
+{
+ u32 acpi_state = acpi_suspend_states[pm_state];
+ int error = 0;
+
+ if (sleep_states[acpi_state]) {
+ acpi_target_sleep_state = acpi_state;
+ } else {
+ printk(KERN_ERR "ACPI does not support this state: %d\n",
+ pm_state);
+ error = -ENOSYS;
+ }
+ return error;
+}
+
/**
* acpi_pm_prepare - Do preliminary suspend work.
- * @pm_state: suspend state we're entering.
+ * @pm_state: ignored
*
- * Make sure we support the state. If we do, and we need it, set the
- * firmware waking vector and do arch-specific nastiness to get the
- * wakeup code to the waking vector.
+ * If necessary, set the firmware waking vector and do arch-specific
+ * nastiness to get the wakeup code to the waking vector.
*/
-extern int acpi_sleep_prepare(u32 acpi_state);
-extern void acpi_power_off(void);
-
static int acpi_pm_prepare(suspend_state_t pm_state)
{
- u32 acpi_state = acpi_suspend_states[pm_state];
+ int error = acpi_sleep_prepare(acpi_target_sleep_state);
- if (!sleep_states[acpi_state]) {
- printk("acpi_pm_prepare does not support %d \n", pm_state);
- return -EPERM;
- }
- return acpi_sleep_prepare(acpi_state);
+ if (error)
+ acpi_target_sleep_state = ACPI_STATE_S0;
+
+ return error;
}
/**
* acpi_pm_enter - Actually enter a sleep state.
- * @pm_state: State we're entering.
+ * @pm_state: ignored
*
- * Flush caches and go to sleep. For STR or STD, we have to call
- * arch-specific assembly, which in turn call acpi_enter_sleep_state().
+ * Flush caches and go to sleep. For STR we have to call arch-specific
+ * assembly, which in turn call acpi_enter_sleep_state().
* It's unfortunate, but it works. Please fix if you're feeling frisky.
*/
@@ -70,31 +90,31 @@ static int acpi_pm_enter(suspend_state_t pm_state)
{
acpi_status status = AE_OK;
unsigned long flags = 0;
- u32 acpi_state = acpi_suspend_states[pm_state];
+ u32 acpi_state = acpi_target_sleep_state;
ACPI_FLUSH_CPU_CACHE();
/* Do arch specific saving of state. */
- if (pm_state > PM_SUSPEND_STANDBY) {
+ if (acpi_state == ACPI_STATE_S3) {
int error = acpi_save_state_mem();
- if (error)
+
+ if (error) {
+ acpi_target_sleep_state = ACPI_STATE_S0;
return error;
+ }
}
local_irq_save(flags);
acpi_enable_wakeup_device(acpi_state);
- switch (pm_state) {
- case PM_SUSPEND_STANDBY:
+ switch (acpi_state) {
+ case ACPI_STATE_S1:
barrier();
status = acpi_enter_sleep_state(acpi_state);
break;
- case PM_SUSPEND_MEM:
+ case ACPI_STATE_S3:
do_suspend_lowlevel();
break;
-
- default:
- return -EINVAL;
}
/* ACPI 3.0 specs (P62) says that it's the responsabilty
@@ -107,12 +127,8 @@ static int acpi_pm_enter(suspend_state_t pm_state)
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");
- /* restore processor state
- * We should only be here if we're coming back from STR or STD.
- * And, in the case of the latter, the memory image should have already
- * been loaded from disk.
- */
- if (pm_state > PM_SUSPEND_STANDBY)
+ /* restore processor state */
+ if (acpi_state == ACPI_STATE_S3)
acpi_restore_state_mem();
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -120,7 +136,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
/**
* acpi_pm_finish - Finish up suspend sequence.
- * @pm_state: State we're coming out of.
+ * @pm_state: ignored
*
* This is called after we wake back up (or if entering the sleep state
* failed).
@@ -128,7 +144,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
static int acpi_pm_finish(suspend_state_t pm_state)
{
- u32 acpi_state = acpi_suspend_states[pm_state];
+ u32 acpi_state = acpi_target_sleep_state;
acpi_leave_sleep_state(acpi_state);
acpi_disable_wakeup_device(acpi_state);
@@ -136,10 +152,14 @@ static int acpi_pm_finish(suspend_state_t pm_state)
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+ acpi_target_sleep_state = ACPI_STATE_S0;
+
+#ifdef CONFIG_X86
if (init_8259A_after_S1) {
printk("Broken toshiba laptop -> kicking interrupts\n");
init_8259A(0);
}
+#endif
return 0;
}
@@ -176,6 +196,7 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
static struct pm_ops acpi_pm_ops = {
.valid = acpi_pm_state_valid,
+ .set_target = acpi_pm_set_target,
.prepare = acpi_pm_prepare,
.enter = acpi_pm_enter,
.finish = acpi_pm_finish,
@@ -235,6 +256,81 @@ static struct hibernation_ops acpi_hibernation_ops = {
};
#endif /* CONFIG_SOFTWARE_SUSPEND */
+/**
+ * acpi_pm_device_sleep_state - return preferred power state of ACPI device
+ * in the system sleep state given by %acpi_target_sleep_state
+ * @dev: device to examine
+ * @wake: if set, the device should be able to wake up the system
+ * @d_min_p: used to store the upper limit of allowed states range
+ * Return value: preferred power state of the device on success, -ENODEV on
+ * failure (ie. if there's no 'struct acpi_device' for @dev)
+ *
+ * Find the lowest power (highest number) ACPI device power state that
+ * device @dev can be in while the system is in the sleep state represented
+ * by %acpi_target_sleep_state. If @wake is nonzero, the device should be
+ * able to wake up the system from this sleep state. If @d_min_p is set,
+ * the highest power (lowest number) device power state of @dev allowed
+ * in this system sleep state is stored at the location pointed to by it.
+ *
+ * The caller must ensure that @dev is valid before using this function.
+ * The caller is also responsible for figuring out if the device is
+ * supposed to be able to wake up the system and passing this information
+ * via @wake.
+ */
+
+int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
+{
+ acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
+ struct acpi_device *adev;
+ char acpi_method[] = "_SxD";
+ unsigned long d_min, d_max;
+
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+ printk(KERN_ERR "ACPI handle has no context!\n");
+ return -ENODEV;
+ }
+
+ acpi_method[2] = '0' + acpi_target_sleep_state;
+ /*
+ * If the sleep state is S0, we will return D3, but if the device has
+ * _S0W, we will use the value from _S0W
+ */
+ d_min = ACPI_STATE_D0;
+ d_max = ACPI_STATE_D3;
+
+ /*
+ * If present, _SxD methods return the minimum D-state (highest power
+ * state) we can use for the corresponding S-states. Otherwise, the
+ * minimum D-state is D0 (ACPI 3.x).
+ *
+ * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer
+ * provided -- that's our fault recovery, we ignore retval.
+ */
+ if (acpi_target_sleep_state > ACPI_STATE_S0)
+ acpi_evaluate_integer(handle, acpi_method, NULL, &d_min);
+
+ /*
+ * If _PRW says we can wake up the system from the target sleep state,
+ * the D-state returned by _SxD is sufficient for that (we assume a
+ * wakeup-aware driver if wake is set). Still, if _SxW exists
+ * (ACPI 3.x), it should return the maximum (lowest power) D-state that
+ * can wake the system. _S0W may be valid, too.
+ */
+ if (acpi_target_sleep_state == ACPI_STATE_S0 ||
+ (wake && adev->wakeup.state.enabled &&
+ adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
+ acpi_method[3] = 'W';
+ acpi_evaluate_integer(handle, acpi_method, NULL, &d_max);
+ /* Sanity check */
+ if (d_max < d_min)
+ d_min = d_max;
+ }
+
+ if (d_min_p)
+ *d_min_p = d_min;
+ return d_max;
+}
+
/*
* Toshiba fails to preserve interrupts over S1, reinitialization
* of 8259 is needed after S1 resume.
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
index 39e40d56b03..b3f68ef0669 100644
--- a/drivers/acpi/sleep/poweroff.c
+++ b/drivers/acpi/sleep/poweroff.c
@@ -18,7 +18,6 @@
int acpi_sleep_prepare(u32 acpi_state)
{
-#ifdef CONFIG_ACPI_SLEEP
/* do we have a wakeup address for S2 and S3? */
if (acpi_state == ACPI_STATE_S3) {
if (!acpi_wakeup_address) {
@@ -31,7 +30,6 @@ int acpi_sleep_prepare(u32 acpi_state)
}
ACPI_FLUSH_CPU_CACHE();
acpi_enable_wakeup_device_prep(acpi_state);
-#endif
acpi_gpe_sleep_prepare(acpi_state);
acpi_enter_sleep_state_prep(acpi_state);
return 0;
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 61f1822cc35..ed58e1168ae 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -14,8 +14,16 @@
#include "sleep.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
+
+/*
+ * this file provides support for:
+ * /proc/acpi/sleep
+ * /proc/acpi/alarm
+ * /proc/acpi/wakeup
+ */
+
ACPI_MODULE_NAME("sleep")
-#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
{
int i;
@@ -68,7 +76,7 @@ acpi_system_write_sleep(struct file *file,
Done:
return error ? error : count;
}
-#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
+#endif /* CONFIG_ACPI_PROCFS */
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
/* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
@@ -463,7 +471,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = {
.release = single_release,
};
-#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
+#ifdef CONFIG_ACPI_PROCFS
static const struct file_operations acpi_system_sleep_fops = {
.open = acpi_system_sleep_open_fs,
.read = seq_read,
@@ -471,7 +479,7 @@ static const struct file_operations acpi_system_sleep_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
+#endif /* CONFIG_ACPI_PROCFS */
#ifdef HAVE_ACPI_LEGACY_ALARM
static const struct file_operations acpi_system_alarm_fops = {
@@ -498,14 +506,14 @@ static int __init acpi_sleep_proc_init(void)
if (acpi_disabled)
return 0;
-#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
+#ifdef CONFIG_ACPI_PROCFS
/* 'sleep' [R/W] */
entry =
create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
acpi_root_dir);
if (entry)
entry->proc_fops = &acpi_system_sleep_fops;
-#endif
+#endif /* CONFIG_ACPI_PROCFS */
#ifdef HAVE_ACPI_LEGACY_ALARM
/* 'alarm' [R/W] */
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
index fab8f2694f0..97c27ddb144 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/sleep/wakeup.c
@@ -17,7 +17,6 @@ ACPI_MODULE_NAME("wakeup_devices")
extern struct list_head acpi_wakeup_device_list;
extern spinlock_t acpi_device_lock;
-#ifdef CONFIG_ACPI_SLEEP
/**
* acpi_enable_wakeup_device_prep - prepare wakeup devices
* @sleep_state: ACPI state
@@ -180,7 +179,6 @@ static int __init acpi_wakeup_device_init(void)
}
late_initcall(acpi_wakeup_device_init);
-#endif
/*
* Disable all wakeup GPEs before entering requested sleep state.
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 63953fe0332..d0fc4fd212e 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -1072,19 +1072,16 @@ static void asus_backlight_exit(void)
}
#define ASUS_LED_UNREGISTER(object) \
- if(object##_led.class_dev \
- && !IS_ERR(object##_led.class_dev)) \
- led_classdev_unregister(&object##_led)
+ led_classdev_unregister(&object##_led)
static void asus_led_exit(void)
{
+ destroy_workqueue(led_workqueue);
ASUS_LED_UNREGISTER(mled);
ASUS_LED_UNREGISTER(tled);
ASUS_LED_UNREGISTER(pled);
ASUS_LED_UNREGISTER(rled);
ASUS_LED_UNREGISTER(gled);
-
- destroy_workqueue(led_workqueue);
}
static void __exit asus_laptop_exit(void)
@@ -1140,29 +1137,42 @@ static int asus_led_init(struct device *dev)
rv = ASUS_LED_REGISTER(mled, dev);
if (rv)
- return rv;
+ goto out;
rv = ASUS_LED_REGISTER(tled, dev);
if (rv)
- return rv;
+ goto out1;
rv = ASUS_LED_REGISTER(rled, dev);
if (rv)
- return rv;
+ goto out2;
rv = ASUS_LED_REGISTER(pled, dev);
if (rv)
- return rv;
+ goto out3;
rv = ASUS_LED_REGISTER(gled, dev);
if (rv)
- return rv;
+ goto out4;
led_workqueue = create_singlethread_workqueue("led_workqueue");
if (!led_workqueue)
- return -ENOMEM;
+ goto out5;
return 0;
+out5:
+ rv = -ENOMEM;
+ ASUS_LED_UNREGISTER(gled);
+out4:
+ ASUS_LED_UNREGISTER(pled);
+out3:
+ ASUS_LED_UNREGISTER(rled);
+out2:
+ ASUS_LED_UNREGISTER(tled);
+out1:
+ ASUS_LED_UNREGISTER(mled);
+out:
+ return rv;
}
static int __init asus_laptop_init(void)
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index c8062494009..67c63d1f158 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -245,16 +245,33 @@ EXPORT_SYMBOL(pci_osc_control_set);
* currently we simply return _SxD, if present.
*/
-static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state)
+static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev,
+ pm_message_t state)
{
- /* TBD */
-
- return -ENODEV;
+ int acpi_state;
+
+ acpi_state = acpi_pm_device_sleep_state(&pdev->dev,
+ device_may_wakeup(&pdev->dev), NULL);
+ if (acpi_state < 0)
+ return PCI_POWER_ERROR;
+
+ switch (acpi_state) {
+ case ACPI_STATE_D0:
+ return PCI_D0;
+ case ACPI_STATE_D1:
+ return PCI_D1;
+ case ACPI_STATE_D2:
+ return PCI_D2;
+ case ACPI_STATE_D3:
+ return PCI_D3hot;
+ }
+ return PCI_POWER_ERROR;
}
static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ acpi_handle tmp;
static int state_conv[] = {
[0] = 0,
[1] = 1,
@@ -266,6 +283,9 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
if (!handle)
return -ENODEV;
+ /* If the ACPI device has _EJ0, ignore the device */
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
+ return 0;
return acpi_bus_set_power(handle, acpi_state);
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 03fd59e80fe..1458fd69e67 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -499,7 +499,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
return 0;
}
-int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
/**
* pci_choose_state - Choose the power state of a PCI device
@@ -513,15 +513,15 @@ int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
{
- int ret;
+ pci_power_t ret;
if (!pci_find_capability(dev, PCI_CAP_ID_PM))
return PCI_D0;
if (platform_pci_choose_state) {
ret = platform_pci_choose_state(dev, state);
- if (ret >= 0)
- state.event = ret;
+ if (ret != PCI_POWER_ERROR)
+ return ret;
}
switch (state.event) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 3fec13d3add..c293ba1f274 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -13,7 +13,7 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
resource_size_t, resource_size_t),
void *alignf_data);
/* Firmware callbacks */
-extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state);
extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index e161423b430..1432806451c 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -167,6 +167,8 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state)
return error;
}
+ if (pnp_dev->protocol && pnp_dev->protocol->suspend)
+ pnp_dev->protocol->suspend(pnp_dev, state);
return 0;
}
@@ -179,6 +181,9 @@ static int pnp_bus_resume(struct device *dev)
if (!pnp_drv)
return 0;
+ if (pnp_dev->protocol && pnp_dev->protocol->resume)
+ pnp_dev->protocol->resume(pnp_dev);
+
if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
error = pnp_start_dev(pnp_dev);
if (error)
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 0bc889144e6..fcd32ac575c 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -124,11 +124,25 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
return ACPI_FAILURE(status) ? -ENODEV : 0;
}
+static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+ return acpi_bus_set_power((acpi_handle)dev->data,
+ acpi_pm_device_sleep_state(&dev->dev,
+ device_may_wakeup(&dev->dev), NULL));
+}
+
+static int pnpacpi_resume(struct pnp_dev *dev)
+{
+ return acpi_bus_set_power((acpi_handle)dev->data, ACPI_STATE_D0);
+}
+
static struct pnp_protocol pnpacpi_protocol = {
.name = "Plug and Play ACPI",
.get = pnpacpi_get_resources,
.set = pnpacpi_set_resources,
.disable = pnpacpi_disable_resources,
+ .suspend = pnpacpi_suspend,
+ .resume = pnpacpi_resume,
};
static int __init pnpacpi_add_device(struct acpi_device *device)
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 3f2a22b5dc6..533ef40f7cc 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -366,6 +366,8 @@ acpi_handle acpi_get_child(acpi_handle, acpi_integer);
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
+int acpi_pm_device_sleep_state(struct device *, int, int *);
+
#endif /* CONFIG_ACPI */
#endif /*__ACPI_BUS_H__*/
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index c348ff48e66..f85f77a538a 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -147,10 +147,6 @@ static inline void unregister_hotplug_dock_device(acpi_handle handle)
/*--------------------------------------------------------------------------
Suspend/Resume
-------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_SLEEP
extern int acpi_sleep_init(void);
-#else
-#define acpi_sleep_init() do {} while (0)
-#endif
#endif /*__ACPI_DRIVERS_H__*/
diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h
index 449f3f272e0..125179adf04 100644
--- a/include/asm-i386/acpi.h
+++ b/include/asm-i386/acpi.h
@@ -121,19 +121,6 @@ static inline void acpi_disable_pci(void)
}
extern int acpi_irq_balance_set(char *str);
-#else /* !CONFIG_ACPI */
-
-#define acpi_lapic 0
-#define acpi_ioapic 0
-static inline void acpi_noirq_set(void) { }
-static inline void acpi_disable_pci(void) { }
-static inline void disable_acpi(void) { }
-
-#endif /* !CONFIG_ACPI */
-
-
-#ifdef CONFIG_ACPI_SLEEP
-
/* routines for saving/restoring kernel state */
extern int acpi_save_state_mem(void);
extern void acpi_restore_state_mem(void);
@@ -143,7 +130,15 @@ extern unsigned long acpi_wakeup_address;
/* early initialization routine */
extern void acpi_reserve_bootmem(void);
-#endif /*CONFIG_ACPI_SLEEP*/
+#else /* !CONFIG_ACPI */
+
+#define acpi_lapic 0
+#define acpi_ioapic 0
+static inline void acpi_noirq_set(void) { }
+static inline void acpi_disable_pci(void) { }
+static inline void disable_acpi(void) { }
+
+#endif /* !CONFIG_ACPI */
#define ARCH_HAS_POWER_INIT 1
diff --git a/include/asm-i386/suspend.h b/include/asm-i386/suspend.h
index 8dbaafe611f..a2520732ffd 100644
--- a/include/asm-i386/suspend.h
+++ b/include/asm-i386/suspend.h
@@ -21,7 +21,7 @@ struct saved_context {
unsigned long return_address;
} __attribute__((packed));
-#ifdef CONFIG_ACPI_SLEEP
+#ifdef CONFIG_ACPI
extern unsigned long saved_eip;
extern unsigned long saved_esp;
extern unsigned long saved_ebp;
diff --git a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
index 5b526357d17..49730ffbbae 100644
--- a/include/asm-ia64/acpi.h
+++ b/include/asm-ia64/acpi.h
@@ -100,6 +100,11 @@ const char *acpi_get_sysname (void);
int acpi_request_vector (u32 int_type);
int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
+/* routines for saving/restoring kernel state */
+extern int acpi_save_state_mem(void);
+extern void acpi_restore_state_mem(void);
+extern unsigned long acpi_wakeup_address;
+
/*
* Record the cpei override flag and current logical cpu. This is
* useful for CPU removal.
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index 1da8f49c0fe..98173357dd8 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -108,6 +108,15 @@ static inline void acpi_disable_pci(void)
}
extern int acpi_irq_balance_set(char *str);
+/* routines for saving/restoring kernel state */
+extern int acpi_save_state_mem(void);
+extern void acpi_restore_state_mem(void);
+
+extern unsigned long acpi_wakeup_address;
+
+/* early initialization routine */
+extern void acpi_reserve_bootmem(void);
+
#else /* !CONFIG_ACPI */
#define acpi_lapic 0
@@ -121,19 +130,6 @@ extern int acpi_numa;
extern int acpi_scan_nodes(unsigned long start, unsigned long end);
#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
-#ifdef CONFIG_ACPI_SLEEP
-
-/* routines for saving/restoring kernel state */
-extern int acpi_save_state_mem(void);
-extern void acpi_restore_state_mem(void);
-
-extern unsigned long acpi_wakeup_address;
-
-/* early initialization routine */
-extern void acpi_reserve_bootmem(void);
-
-#endif /*CONFIG_ACPI_SLEEP*/
-
extern int acpi_disabled;
extern int acpi_pci_disabled;
diff --git a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h
index 9c3f8de90d2..b897e8cb55f 100644
--- a/include/asm-x86_64/suspend.h
+++ b/include/asm-x86_64/suspend.h
@@ -44,7 +44,6 @@ extern unsigned long saved_context_eflags;
extern void fix_processor_context(void);
-#ifdef CONFIG_ACPI_SLEEP
extern unsigned long saved_rip;
extern unsigned long saved_rsp;
extern unsigned long saved_rbp;
@@ -54,4 +53,3 @@ extern unsigned long saved_rdi;
/* routines for saving/restoring kernel state */
extern int acpi_save_state_mem(void);
-#endif
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 2a1897e6f93..66edb229318 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -335,6 +335,10 @@ struct pnp_protocol {
int (*set)(struct pnp_dev *dev, struct pnp_resource_table *res);
int (*disable)(struct pnp_dev *dev);
+ /* protocol specific suspend/resume */
+ int (*suspend)(struct pnp_dev *dev, pm_message_t state);
+ int (*resume)(struct pnp_dev *dev);
+
/* used by pnp layer only (look but don't touch) */
unsigned char number; /* protocol number*/
struct device dev; /* link to driver model */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index ddebf3f2aff..eb26f2ba51e 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -689,7 +689,7 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
-#ifdef CONFIG_ACPI_SLEEP
+#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
{
.ctl_name = KERN_ACPI_VIDEO_FLAGS,
.procname = "acpi_video_flags",