diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2007-07-29 17:27:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-29 19:45:38 -0400 |
commit | 296699de6bdc717189a331ab6bbe90e05c94db06 (patch) | |
tree | 53c847ecc8cce11952502921844052e44ca60d5e /drivers/acpi/sleep | |
parent | b0cb1a19d05b8ea8611a9ef48a17fe417f1832e6 (diff) |
Introduce CONFIG_SUSPEND for suspend-to-Ram and standby
Introduce CONFIG_SUSPEND representing the ability to enter system sleep
states, such as the ACPI S3 state, and allow the user to choose SUSPEND
and HIBERNATION independently of each other.
Make HOTPLUG_CPU be selected automatically if SUSPEND or HIBERNATION has
been chosen and the kernel is intended for SMP systems.
Also, introduce CONFIG_PM_SLEEP which is automatically selected if
CONFIG_SUSPEND or CONFIG_HIBERNATION is set and use it to select the
code needed for both suspend and hibernation.
The top-level power management headers and the ACPI code related to
suspend and hibernation are modified to use the new definitions (the
changes in drivers/acpi/sleep/main.c are, mostly, moving code to reduce
the number of ifdefs).
There are many other files in which CONFIG_PM can be replaced with
CONFIG_PM_SLEEP or even with CONFIG_SUSPEND, but they can be updated in
the future.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/acpi/sleep')
-rw-r--r-- | drivers/acpi/sleep/Makefile | 2 | ||||
-rw-r--r-- | drivers/acpi/sleep/main.c | 94 | ||||
-rw-r--r-- | drivers/acpi/sleep/proc.c | 10 | ||||
-rw-r--r-- | drivers/acpi/sleep/sleep.h | 2 |
4 files changed, 58 insertions, 50 deletions
diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile index 01a993a1d086..2bec897ab1eb 100644 --- a/drivers/acpi/sleep/Makefile +++ b/drivers/acpi/sleep/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-y := poweroff.o wakeup.o | 1 | obj-y := poweroff.o wakeup.o |
2 | obj-y += main.o | 2 | obj-$(CONFIG_PM_SLEEP) += main.o |
3 | obj-$(CONFIG_X86) += proc.o | 3 | obj-$(CONFIG_X86) += proc.o |
4 | 4 | ||
5 | EXTRA_CFLAGS += $(ACPI_CFLAGS) | 5 | EXTRA_CFLAGS += $(ACPI_CFLAGS) |
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index b4e94c893c81..e8cff5dd4cbc 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c | |||
@@ -21,6 +21,9 @@ | |||
21 | 21 | ||
22 | u8 sleep_states[ACPI_S_STATE_COUNT]; | 22 | u8 sleep_states[ACPI_S_STATE_COUNT]; |
23 | 23 | ||
24 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | ||
25 | |||
26 | #ifdef CONFIG_SUSPEND | ||
24 | static struct pm_ops acpi_pm_ops; | 27 | static struct pm_ops acpi_pm_ops; |
25 | 28 | ||
26 | extern void do_suspend_lowlevel(void); | 29 | extern void do_suspend_lowlevel(void); |
@@ -34,11 +37,6 @@ static u32 acpi_suspend_states[] = { | |||
34 | 37 | ||
35 | static int init_8259A_after_S1; | 38 | static int init_8259A_after_S1; |
36 | 39 | ||
37 | extern int acpi_sleep_prepare(u32 acpi_state); | ||
38 | extern void acpi_power_off(void); | ||
39 | |||
40 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | ||
41 | |||
42 | /** | 40 | /** |
43 | * acpi_pm_set_target - Set the target system sleep state to the state | 41 | * acpi_pm_set_target - Set the target system sleep state to the state |
44 | * associated with given @pm_state, if supported. | 42 | * associated with given @pm_state, if supported. |
@@ -163,21 +161,6 @@ static int acpi_pm_finish(suspend_state_t pm_state) | |||
163 | return 0; | 161 | return 0; |
164 | } | 162 | } |
165 | 163 | ||
166 | int acpi_suspend(u32 acpi_state) | ||
167 | { | ||
168 | suspend_state_t states[] = { | ||
169 | [1] = PM_SUSPEND_STANDBY, | ||
170 | [3] = PM_SUSPEND_MEM, | ||
171 | [5] = PM_SUSPEND_MAX | ||
172 | }; | ||
173 | |||
174 | if (acpi_state < 6 && states[acpi_state]) | ||
175 | return pm_suspend(states[acpi_state]); | ||
176 | if (acpi_state == 4) | ||
177 | return hibernate(); | ||
178 | return -EINVAL; | ||
179 | } | ||
180 | |||
181 | static int acpi_pm_state_valid(suspend_state_t pm_state) | 164 | static int acpi_pm_state_valid(suspend_state_t pm_state) |
182 | { | 165 | { |
183 | u32 acpi_state; | 166 | u32 acpi_state; |
@@ -202,6 +185,27 @@ static struct pm_ops acpi_pm_ops = { | |||
202 | .finish = acpi_pm_finish, | 185 | .finish = acpi_pm_finish, |
203 | }; | 186 | }; |
204 | 187 | ||
188 | /* | ||
189 | * Toshiba fails to preserve interrupts over S1, reinitialization | ||
190 | * of 8259 is needed after S1 resume. | ||
191 | */ | ||
192 | static int __init init_ints_after_s1(struct dmi_system_id *d) | ||
193 | { | ||
194 | printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident); | ||
195 | init_8259A_after_S1 = 1; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static struct dmi_system_id __initdata acpisleep_dmi_table[] = { | ||
200 | { | ||
201 | .callback = init_ints_after_s1, | ||
202 | .ident = "Toshiba Satellite 4030cdt", | ||
203 | .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),}, | ||
204 | }, | ||
205 | {}, | ||
206 | }; | ||
207 | #endif /* CONFIG_SUSPEND */ | ||
208 | |||
205 | #ifdef CONFIG_HIBERNATION | 209 | #ifdef CONFIG_HIBERNATION |
206 | static int acpi_hibernation_prepare(void) | 210 | static int acpi_hibernation_prepare(void) |
207 | { | 211 | { |
@@ -256,6 +260,21 @@ static struct hibernation_ops acpi_hibernation_ops = { | |||
256 | }; | 260 | }; |
257 | #endif /* CONFIG_HIBERNATION */ | 261 | #endif /* CONFIG_HIBERNATION */ |
258 | 262 | ||
263 | int acpi_suspend(u32 acpi_state) | ||
264 | { | ||
265 | suspend_state_t states[] = { | ||
266 | [1] = PM_SUSPEND_STANDBY, | ||
267 | [3] = PM_SUSPEND_MEM, | ||
268 | [5] = PM_SUSPEND_MAX | ||
269 | }; | ||
270 | |||
271 | if (acpi_state < 6 && states[acpi_state]) | ||
272 | return pm_suspend(states[acpi_state]); | ||
273 | if (acpi_state == 4) | ||
274 | return hibernate(); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | |||
259 | /** | 278 | /** |
260 | * acpi_pm_device_sleep_state - return preferred power state of ACPI device | 279 | * acpi_pm_device_sleep_state - return preferred power state of ACPI device |
261 | * in the system sleep state given by %acpi_target_sleep_state | 280 | * in the system sleep state given by %acpi_target_sleep_state |
@@ -331,39 +350,22 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p) | |||
331 | return d_max; | 350 | return d_max; |
332 | } | 351 | } |
333 | 352 | ||
334 | /* | ||
335 | * Toshiba fails to preserve interrupts over S1, reinitialization | ||
336 | * of 8259 is needed after S1 resume. | ||
337 | */ | ||
338 | static int __init init_ints_after_s1(struct dmi_system_id *d) | ||
339 | { | ||
340 | printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident); | ||
341 | init_8259A_after_S1 = 1; | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static struct dmi_system_id __initdata acpisleep_dmi_table[] = { | ||
346 | { | ||
347 | .callback = init_ints_after_s1, | ||
348 | .ident = "Toshiba Satellite 4030cdt", | ||
349 | .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),}, | ||
350 | }, | ||
351 | {}, | ||
352 | }; | ||
353 | |||
354 | int __init acpi_sleep_init(void) | 353 | int __init acpi_sleep_init(void) |
355 | { | 354 | { |
355 | acpi_status status; | ||
356 | u8 type_a, type_b; | ||
357 | #ifdef CONFIG_SUSPEND | ||
356 | int i = 0; | 358 | int i = 0; |
357 | 359 | ||
358 | dmi_check_system(acpisleep_dmi_table); | 360 | dmi_check_system(acpisleep_dmi_table); |
361 | #endif | ||
359 | 362 | ||
360 | if (acpi_disabled) | 363 | if (acpi_disabled) |
361 | return 0; | 364 | return 0; |
362 | 365 | ||
366 | #ifdef CONFIG_SUSPEND | ||
363 | printk(KERN_INFO PREFIX "(supports"); | 367 | printk(KERN_INFO PREFIX "(supports"); |
364 | for (i = 0; i < ACPI_S_STATE_COUNT; i++) { | 368 | for (i = ACPI_STATE_S0; i < ACPI_STATE_S4; i++) { |
365 | acpi_status status; | ||
366 | u8 type_a, type_b; | ||
367 | status = acpi_get_sleep_type_data(i, &type_a, &type_b); | 369 | status = acpi_get_sleep_type_data(i, &type_a, &type_b); |
368 | if (ACPI_SUCCESS(status)) { | 370 | if (ACPI_SUCCESS(status)) { |
369 | sleep_states[i] = 1; | 371 | sleep_states[i] = 1; |
@@ -373,10 +375,14 @@ int __init acpi_sleep_init(void) | |||
373 | printk(")\n"); | 375 | printk(")\n"); |
374 | 376 | ||
375 | pm_set_ops(&acpi_pm_ops); | 377 | pm_set_ops(&acpi_pm_ops); |
378 | #endif | ||
376 | 379 | ||
377 | #ifdef CONFIG_HIBERNATION | 380 | #ifdef CONFIG_HIBERNATION |
378 | if (sleep_states[ACPI_STATE_S4]) | 381 | status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b); |
382 | if (ACPI_SUCCESS(status)) { | ||
379 | hibernation_set_ops(&acpi_hibernation_ops); | 383 | hibernation_set_ops(&acpi_hibernation_ops); |
384 | sleep_states[ACPI_STATE_S4] = 1; | ||
385 | } | ||
380 | #else | 386 | #else |
381 | sleep_states[ACPI_STATE_S4] = 0; | 387 | sleep_states[ACPI_STATE_S4] = 0; |
382 | #endif | 388 | #endif |
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 1b7bbb5ba623..5dfe8b789633 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c | |||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | ACPI_MODULE_NAME("sleep") | 25 | ACPI_MODULE_NAME("sleep") |
26 | #ifdef CONFIG_ACPI_PROCFS | 26 | #ifdef CONFIG_ACPI_PROCFS_SLEEP |
27 | static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) | 27 | static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) |
28 | { | 28 | { |
29 | int i; | 29 | int i; |
@@ -76,7 +76,7 @@ acpi_system_write_sleep(struct file *file, | |||
76 | Done: | 76 | Done: |
77 | return error ? error : count; | 77 | return error ? error : count; |
78 | } | 78 | } |
79 | #endif /* CONFIG_ACPI_PROCFS */ | 79 | #endif /* CONFIG_ACPI_PROCFS_SLEEP */ |
80 | 80 | ||
81 | #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) | 81 | #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) |
82 | /* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */ | 82 | /* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */ |
@@ -471,7 +471,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = { | |||
471 | .release = single_release, | 471 | .release = single_release, |
472 | }; | 472 | }; |
473 | 473 | ||
474 | #ifdef CONFIG_ACPI_PROCFS | 474 | #ifdef CONFIG_ACPI_PROCFS_SLEEP |
475 | static const struct file_operations acpi_system_sleep_fops = { | 475 | static const struct file_operations acpi_system_sleep_fops = { |
476 | .open = acpi_system_sleep_open_fs, | 476 | .open = acpi_system_sleep_open_fs, |
477 | .read = seq_read, | 477 | .read = seq_read, |
@@ -479,7 +479,7 @@ static const struct file_operations acpi_system_sleep_fops = { | |||
479 | .llseek = seq_lseek, | 479 | .llseek = seq_lseek, |
480 | .release = single_release, | 480 | .release = single_release, |
481 | }; | 481 | }; |
482 | #endif /* CONFIG_ACPI_PROCFS */ | 482 | #endif /* CONFIG_ACPI_PROCFS_SLEEP */ |
483 | 483 | ||
484 | #ifdef HAVE_ACPI_LEGACY_ALARM | 484 | #ifdef HAVE_ACPI_LEGACY_ALARM |
485 | static const struct file_operations acpi_system_alarm_fops = { | 485 | static const struct file_operations acpi_system_alarm_fops = { |
@@ -506,7 +506,7 @@ static int __init acpi_sleep_proc_init(void) | |||
506 | if (acpi_disabled) | 506 | if (acpi_disabled) |
507 | return 0; | 507 | return 0; |
508 | 508 | ||
509 | #ifdef CONFIG_ACPI_PROCFS | 509 | #ifdef CONFIG_ACPI_PROCFS_SLEEP |
510 | /* 'sleep' [R/W] */ | 510 | /* 'sleep' [R/W] */ |
511 | entry = | 511 | entry = |
512 | create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, | 512 | create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, |
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h index f3e70397a7d6..ff1f8504f497 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep/sleep.h | |||
@@ -6,3 +6,5 @@ extern void acpi_enable_wakeup_device_prep(u8 sleep_state); | |||
6 | extern void acpi_enable_wakeup_device(u8 sleep_state); | 6 | extern void acpi_enable_wakeup_device(u8 sleep_state); |
7 | extern void acpi_disable_wakeup_device(u8 sleep_state); | 7 | extern void acpi_disable_wakeup_device(u8 sleep_state); |
8 | extern void acpi_gpe_sleep_prepare(u32 sleep_state); | 8 | extern void acpi_gpe_sleep_prepare(u32 sleep_state); |
9 | |||
10 | extern int acpi_sleep_prepare(u32 acpi_state); | ||