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/main.c | |
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/main.c')
-rw-r--r-- | drivers/acpi/sleep/main.c | 94 |
1 files changed, 50 insertions, 44 deletions
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 |