Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Rafael J. Wysocki and committed by
Linus Torvalds
296699de b0cb1a19

+164 -86
+8
drivers/acpi/Kconfig
··· 63 63 64 64 Say N to delete /proc/acpi/ files that have moved to /sys/ 65 65 66 + config ACPI_PROCFS_SLEEP 67 + bool "/proc/acpi/sleep (deprecated)" 68 + depends on PM_SLEEP && ACPI_PROCFS 69 + default n 70 + ---help--- 71 + Create /proc/acpi/sleep 72 + Deprecated by /sys/power/state 73 + 66 74 config ACPI_AC 67 75 tristate "AC Adapter" 68 76 depends on X86
+1 -1
drivers/acpi/sleep/Makefile
··· 1 1 obj-y := poweroff.o wakeup.o 2 - obj-y += main.o 2 + obj-$(CONFIG_PM_SLEEP) += main.o 3 3 obj-$(CONFIG_X86) += proc.o 4 4 5 5 EXTRA_CFLAGS += $(ACPI_CFLAGS)
+50 -44
drivers/acpi/sleep/main.c
··· 21 21 22 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 27 static struct pm_ops acpi_pm_ops; 25 28 26 29 extern void do_suspend_lowlevel(void); ··· 36 33 }; 37 34 38 35 static int init_8259A_after_S1; 39 - 40 - extern int acpi_sleep_prepare(u32 acpi_state); 41 - extern void acpi_power_off(void); 42 - 43 - static u32 acpi_target_sleep_state = ACPI_STATE_S0; 44 36 45 37 /** 46 38 * acpi_pm_set_target - Set the target system sleep state to the state ··· 161 163 return 0; 162 164 } 163 165 164 - int acpi_suspend(u32 acpi_state) 165 - { 166 - suspend_state_t states[] = { 167 - [1] = PM_SUSPEND_STANDBY, 168 - [3] = PM_SUSPEND_MEM, 169 - [5] = PM_SUSPEND_MAX 170 - }; 171 - 172 - if (acpi_state < 6 && states[acpi_state]) 173 - return pm_suspend(states[acpi_state]); 174 - if (acpi_state == 4) 175 - return hibernate(); 176 - return -EINVAL; 177 - } 178 - 179 166 static int acpi_pm_state_valid(suspend_state_t pm_state) 180 167 { 181 168 u32 acpi_state; ··· 184 201 .enter = acpi_pm_enter, 185 202 .finish = acpi_pm_finish, 186 203 }; 204 + 205 + /* 206 + * Toshiba fails to preserve interrupts over S1, reinitialization 207 + * of 8259 is needed after S1 resume. 208 + */ 209 + static int __init init_ints_after_s1(struct dmi_system_id *d) 210 + { 211 + printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident); 212 + init_8259A_after_S1 = 1; 213 + return 0; 214 + } 215 + 216 + static struct dmi_system_id __initdata acpisleep_dmi_table[] = { 217 + { 218 + .callback = init_ints_after_s1, 219 + .ident = "Toshiba Satellite 4030cdt", 220 + .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),}, 221 + }, 222 + {}, 223 + }; 224 + #endif /* CONFIG_SUSPEND */ 187 225 188 226 #ifdef CONFIG_HIBERNATION 189 227 static int acpi_hibernation_prepare(void) ··· 259 255 .restore_cleanup = acpi_hibernation_restore_cleanup, 260 256 }; 261 257 #endif /* CONFIG_HIBERNATION */ 258 + 259 + int acpi_suspend(u32 acpi_state) 260 + { 261 + suspend_state_t states[] = { 262 + [1] = PM_SUSPEND_STANDBY, 263 + [3] = PM_SUSPEND_MEM, 264 + [5] = PM_SUSPEND_MAX 265 + }; 266 + 267 + if (acpi_state < 6 && states[acpi_state]) 268 + return pm_suspend(states[acpi_state]); 269 + if (acpi_state == 4) 270 + return hibernate(); 271 + return -EINVAL; 272 + } 262 273 263 274 /** 264 275 * acpi_pm_device_sleep_state - return preferred power state of ACPI device ··· 350 331 return d_max; 351 332 } 352 333 353 - /* 354 - * Toshiba fails to preserve interrupts over S1, reinitialization 355 - * of 8259 is needed after S1 resume. 356 - */ 357 - static int __init init_ints_after_s1(struct dmi_system_id *d) 358 - { 359 - printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident); 360 - init_8259A_after_S1 = 1; 361 - return 0; 362 - } 363 - 364 - static struct dmi_system_id __initdata acpisleep_dmi_table[] = { 365 - { 366 - .callback = init_ints_after_s1, 367 - .ident = "Toshiba Satellite 4030cdt", 368 - .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),}, 369 - }, 370 - {}, 371 - }; 372 - 373 334 int __init acpi_sleep_init(void) 374 335 { 336 + acpi_status status; 337 + u8 type_a, type_b; 338 + #ifdef CONFIG_SUSPEND 375 339 int i = 0; 376 340 377 341 dmi_check_system(acpisleep_dmi_table); 342 + #endif 378 343 379 344 if (acpi_disabled) 380 345 return 0; 381 346 347 + #ifdef CONFIG_SUSPEND 382 348 printk(KERN_INFO PREFIX "(supports"); 383 - for (i = 0; i < ACPI_S_STATE_COUNT; i++) { 384 - acpi_status status; 385 - u8 type_a, type_b; 349 + for (i = ACPI_STATE_S0; i < ACPI_STATE_S4; i++) { 386 350 status = acpi_get_sleep_type_data(i, &type_a, &type_b); 387 351 if (ACPI_SUCCESS(status)) { 388 352 sleep_states[i] = 1; ··· 375 373 printk(")\n"); 376 374 377 375 pm_set_ops(&acpi_pm_ops); 376 + #endif 378 377 379 378 #ifdef CONFIG_HIBERNATION 380 - if (sleep_states[ACPI_STATE_S4]) 379 + status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b); 380 + if (ACPI_SUCCESS(status)) { 381 381 hibernation_set_ops(&acpi_hibernation_ops); 382 + sleep_states[ACPI_STATE_S4] = 1; 383 + } 382 384 #else 383 385 sleep_states[ACPI_STATE_S4] = 0; 384 386 #endif
+5 -5
drivers/acpi/sleep/proc.c
··· 23 23 */ 24 24 25 25 ACPI_MODULE_NAME("sleep") 26 - #ifdef CONFIG_ACPI_PROCFS 26 + #ifdef CONFIG_ACPI_PROCFS_SLEEP 27 27 static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) 28 28 { 29 29 int i; ··· 76 76 Done: 77 77 return error ? error : count; 78 78 } 79 - #endif /* CONFIG_ACPI_PROCFS */ 79 + #endif /* CONFIG_ACPI_PROCFS_SLEEP */ 80 80 81 81 #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) 82 82 /* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */ ··· 471 471 .release = single_release, 472 472 }; 473 473 474 - #ifdef CONFIG_ACPI_PROCFS 474 + #ifdef CONFIG_ACPI_PROCFS_SLEEP 475 475 static const struct file_operations acpi_system_sleep_fops = { 476 476 .open = acpi_system_sleep_open_fs, 477 477 .read = seq_read, ··· 479 479 .llseek = seq_lseek, 480 480 .release = single_release, 481 481 }; 482 - #endif /* CONFIG_ACPI_PROCFS */ 482 + #endif /* CONFIG_ACPI_PROCFS_SLEEP */ 483 483 484 484 #ifdef HAVE_ACPI_LEGACY_ALARM 485 485 static const struct file_operations acpi_system_alarm_fops = { ··· 506 506 if (acpi_disabled) 507 507 return 0; 508 508 509 - #ifdef CONFIG_ACPI_PROCFS 509 + #ifdef CONFIG_ACPI_PROCFS_SLEEP 510 510 /* 'sleep' [R/W] */ 511 511 entry = 512 512 create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
+2
drivers/acpi/sleep/sleep.h
··· 6 6 extern void acpi_enable_wakeup_device(u8 sleep_state); 7 7 extern void acpi_disable_wakeup_device(u8 sleep_state); 8 8 extern void acpi_gpe_sleep_prepare(u32 sleep_state); 9 + 10 + extern int acpi_sleep_prepare(u32 acpi_state);
+1 -1
drivers/base/power/Makefile
··· 1 1 obj-y := shutdown.o 2 - obj-$(CONFIG_PM) += main.o suspend.o resume.o sysfs.o 2 + obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o 3 3 obj-$(CONFIG_PM_TRACE) += trace.o 4 4 5 5 ifeq ($(CONFIG_DEBUG_DRIVER),y)
+2 -2
drivers/base/power/power.h
··· 5 5 extern void device_shutdown(void); 6 6 7 7 8 - #ifdef CONFIG_PM 8 + #ifdef CONFIG_PM_SLEEP 9 9 10 10 /* 11 11 * main.c ··· 62 62 */ 63 63 extern int suspend_device(struct device *, pm_message_t); 64 64 65 - #else /* CONFIG_PM */ 65 + #else /* CONFIG_PM_SLEEP */ 66 66 67 67 68 68 static inline int device_pm_add(struct device * dev)
+9
include/acpi/acpi_bus.h
··· 366 366 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); 367 367 #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) 368 368 369 + #ifdef CONFIG_PM_SLEEP 369 370 int acpi_pm_device_sleep_state(struct device *, int, int *); 371 + #else /* !CONFIG_PM_SLEEP */ 372 + static inline int acpi_pm_device_sleep_state(struct device *d, int w, int *p) 373 + { 374 + if (p) 375 + *p = ACPI_STATE_D0; 376 + return ACPI_STATE_D3; 377 + } 378 + #endif /* !CONFIG_PM_SLEEP */ 370 379 371 380 #endif /* CONFIG_ACPI */ 372 381
+4
include/acpi/acpi_drivers.h
··· 147 147 /*-------------------------------------------------------------------------- 148 148 Suspend/Resume 149 149 -------------------------------------------------------------------------- */ 150 + #ifdef CONFIG_PM_SLEEP 150 151 extern int acpi_sleep_init(void); 152 + #else 153 + static inline int acpi_sleep_init(void) { return 0; } 154 + #endif 151 155 152 156 #endif /*__ACPI_DRIVERS_H__*/
+3 -3
include/linux/freezer.h
··· 5 5 6 6 #include <linux/sched.h> 7 7 8 - #ifdef CONFIG_PM 8 + #ifdef CONFIG_PM_SLEEP 9 9 /* 10 10 * Check if a process has been frozen 11 11 */ ··· 126 126 current->flags &= ~PF_NOFREEZE; 127 127 } 128 128 129 - #else 129 + #else /* !CONFIG_PM_SLEEP */ 130 130 static inline int frozen(struct task_struct *p) { return 0; } 131 131 static inline int freezing(struct task_struct *p) { return 0; } 132 132 static inline void set_freeze_flag(struct task_struct *p) {} ··· 143 143 static inline void freezer_count(void) {} 144 144 static inline int freezer_should_skip(struct task_struct *p) { return 0; } 145 145 static inline void set_freezable(void) {} 146 - #endif 146 + #endif /* !CONFIG_PM_SLEEP */ 147 147 148 148 #endif /* FREEZER_H_INCLUDED */
+11 -4
include/linux/pm.h
··· 165 165 int (*finish)(suspend_state_t state); 166 166 }; 167 167 168 + #ifdef CONFIG_SUSPEND 168 169 extern struct pm_ops *pm_ops; 169 170 170 171 /** ··· 194 193 extern void arch_suspend_enable_irqs(void); 195 194 196 195 extern int pm_suspend(suspend_state_t state); 196 + #else /* !CONFIG_SUSPEND */ 197 + #define suspend_valid_only_mem NULL 198 + 199 + static inline void pm_set_ops(struct pm_ops *pm_ops) {} 200 + static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } 201 + #endif /* !CONFIG_SUSPEND */ 197 202 198 203 /* 199 204 * Device power management ··· 273 266 struct dev_pm_info { 274 267 pm_message_t power_state; 275 268 unsigned can_wakeup:1; 276 - #ifdef CONFIG_PM 269 + #ifdef CONFIG_PM_SLEEP 277 270 unsigned should_wakeup:1; 278 271 struct list_head entry; 279 272 #endif ··· 283 276 extern void device_power_up(void); 284 277 extern void device_resume(void); 285 278 286 - #ifdef CONFIG_PM 279 + #ifdef CONFIG_PM_SLEEP 287 280 extern int device_suspend(pm_message_t state); 288 281 extern int device_prepare_suspend(pm_message_t state); 289 282 ··· 313 306 return 0; 314 307 } 315 308 316 - #else /* !CONFIG_PM */ 309 + #else /* !CONFIG_PM_SLEEP */ 317 310 318 311 static inline int device_suspend(pm_message_t state) 319 312 { ··· 330 323 return 0; 331 324 } 332 325 333 - #endif 326 + #endif /* !CONFIG_PM_SLEEP */ 334 327 335 328 /* changes to device_may_wakeup take effect on the next pm state change. 336 329 * by default, devices should wakeup if they can.
+5 -5
include/linux/suspend.h
··· 24 24 extern void drain_local_pages(void); 25 25 extern void mark_free_pages(struct zone *zone); 26 26 27 - #if defined(CONFIG_PM) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) 27 + #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) 28 28 extern int pm_prepare_console(void); 29 29 extern void pm_restore_console(void); 30 30 #else ··· 54 54 void (*restore_cleanup)(void); 55 55 }; 56 56 57 - #ifdef CONFIG_PM 58 57 #ifdef CONFIG_HIBERNATION 59 58 /* kernel/power/snapshot.c */ 60 59 extern void __register_nosave_region(unsigned long b, unsigned long e, int km); ··· 81 82 static inline int hibernate(void) { return -ENOSYS; } 82 83 #endif /* CONFIG_HIBERNATION */ 83 84 85 + #ifdef CONFIG_PM_SLEEP 84 86 void save_processor_state(void); 85 87 void restore_processor_state(void); 86 88 struct saved_context; ··· 106 106 { .notifier_call = fn, .priority = pri }; \ 107 107 register_pm_notifier(&fn##_nb); \ 108 108 } 109 - #else /* CONFIG_PM */ 109 + #else /* !CONFIG_PM_SLEEP */ 110 110 111 111 static inline int register_pm_notifier(struct notifier_block *nb) 112 112 { ··· 119 119 } 120 120 121 121 #define pm_notifier(fn, pri) do { (void)(fn); } while (0) 122 - #endif /* CONFIG_PM */ 122 + #endif /* !CONFIG_PM_SLEEP */ 123 123 124 - #if !defined CONFIG_HIBERNATION || !defined(CONFIG_PM) 124 + #ifndef CONFIG_HIBERNATION 125 125 static inline void register_nosave_region(unsigned long b, unsigned long e) 126 126 { 127 127 }
+32 -9
kernel/power/Kconfig
··· 46 46 47 47 config DISABLE_CONSOLE_SUSPEND 48 48 bool "Keep console(s) enabled during suspend/resume (DANGEROUS)" 49 - depends on PM_DEBUG 49 + depends on PM_DEBUG && PM_SLEEP 50 50 default n 51 51 ---help--- 52 52 This option turns off the console suspend mechanism that prevents ··· 57 57 58 58 config PM_TRACE 59 59 bool "Suspend/resume event tracing" 60 - depends on PM_DEBUG && X86 && EXPERIMENTAL 60 + depends on PM_DEBUG && X86 && PM_SLEEP && EXPERIMENTAL 61 61 default n 62 62 ---help--- 63 63 This enables some cheesy code to save the last PM event point in the ··· 72 72 CAUTION: this option will cause your machine's real-time clock to be 73 73 set to an invalid time after a resume. 74 74 75 + config SUSPEND_SMP_POSSIBLE 76 + bool 77 + depends on (X86 && !X86_VOYAGER) || (PPC64 && (PPC_PSERIES || PPC_PMAC)) 78 + depends on SMP 79 + default y 80 + 81 + config SUSPEND_SMP 82 + bool 83 + depends on SUSPEND_SMP_POSSIBLE && PM_SLEEP 84 + select HOTPLUG_CPU 85 + default y 86 + 87 + config PM_SLEEP 88 + bool 89 + depends on SUSPEND || HIBERNATION 90 + default y 91 + 92 + config SUSPEND 93 + bool "Suspend to RAM and standby" 94 + depends on PM 95 + depends on !SMP || SUSPEND_SMP_POSSIBLE 96 + default y 97 + ---help--- 98 + Allow the system to enter sleep states in which main memory is 99 + powered and thus its contents are preserved, such as the 100 + suspend-to-RAM state (i.e. the ACPI S3 state). 101 + 75 102 config HIBERNATION 76 - bool "Hibernation" 77 - depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)) 103 + bool "Hibernation (aka 'suspend to disk')" 104 + depends on PM && SWAP 105 + depends on ((X86 || PPC64_SWSUSP || FRV || PPC32) && !SMP) || SUSPEND_SMP_POSSIBLE 78 106 ---help--- 79 107 Enable the suspend to disk (STD) functionality, which is usually 80 108 called "hibernation" in user interfaces. STD checkpoints the ··· 159 131 Note there is currently not a way to specify which device to save the 160 132 suspended image to. It will simply pick the first available swap 161 133 device. 162 - 163 - config SUSPEND_SMP 164 - bool 165 - depends on HOTPLUG_CPU && (X86 || PPC64) && PM 166 - default y 167 134 168 135 config APM_EMULATION 169 136 tristate "Advanced Power Management Emulation"
+2 -1
kernel/power/Makefile
··· 3 3 EXTRA_CFLAGS += -DDEBUG 4 4 endif 5 5 6 - obj-y := main.o process.o console.o 6 + obj-y := main.o 7 7 obj-$(CONFIG_PM_LEGACY) += pm.o 8 + obj-$(CONFIG_PM_SLEEP) += process.o console.o 8 9 obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o 9 10 10 11 obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
+18 -8
kernel/power/main.c
··· 25 25 26 26 BLOCKING_NOTIFIER_HEAD(pm_chain_head); 27 27 28 - /*This is just an arbitrary number */ 29 - #define FREE_PAGE_NUMBER (100) 30 - 31 28 DEFINE_MUTEX(pm_mutex); 29 + 30 + #ifdef CONFIG_SUSPEND 31 + 32 + /* This is just an arbitrary number */ 33 + #define FREE_PAGE_NUMBER (100) 32 34 33 35 struct pm_ops *pm_ops; 34 36 ··· 271 269 272 270 EXPORT_SYMBOL(pm_suspend); 273 271 272 + #endif /* CONFIG_SUSPEND */ 273 + 274 274 decl_subsys(power,NULL,NULL); 275 275 276 276 ··· 289 285 290 286 static ssize_t state_show(struct kset *kset, char *buf) 291 287 { 288 + char *s = buf; 289 + #ifdef CONFIG_SUSPEND 292 290 int i; 293 - char * s = buf; 294 291 295 292 for (i = 0; i < PM_SUSPEND_MAX; i++) { 296 293 if (pm_states[i] && valid_state(i)) 297 294 s += sprintf(s,"%s ", pm_states[i]); 298 295 } 296 + #endif 299 297 #ifdef CONFIG_HIBERNATION 300 298 s += sprintf(s, "%s\n", "disk"); 301 299 #else ··· 310 304 311 305 static ssize_t state_store(struct kset *kset, const char *buf, size_t n) 312 306 { 307 + #ifdef CONFIG_SUSPEND 313 308 suspend_state_t state = PM_SUSPEND_STANDBY; 314 309 const char * const *s; 310 + #endif 315 311 char *p; 316 - int error; 317 312 int len; 313 + int error = -EINVAL; 318 314 319 315 p = memchr(buf, '\n', n); 320 316 len = p ? p - buf : n; ··· 324 316 /* First, check if we are requested to hibernate */ 325 317 if (len == 4 && !strncmp(buf, "disk", len)) { 326 318 error = hibernate(); 327 - return error ? error : n; 319 + goto Exit; 328 320 } 329 321 322 + #ifdef CONFIG_SUSPEND 330 323 for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { 331 324 if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) 332 325 break; 333 326 } 334 327 if (state < PM_SUSPEND_MAX && *s) 335 328 error = enter_state(state); 336 - else 337 - error = -EINVAL; 329 + #endif 330 + 331 + Exit: 338 332 return error ? error : n; 339 333 } 340 334
+9 -1
kernel/power/power.h
··· 176 176 extern void swsusp_show_speed(struct timeval *, struct timeval *, 177 177 unsigned int, char *); 178 178 179 + #ifdef CONFIG_SUSPEND 179 180 /* kernel/power/main.c */ 180 - extern int suspend_enter(suspend_state_t state); 181 181 extern int suspend_devices_and_enter(suspend_state_t state); 182 + #else /* !CONFIG_SUSPEND */ 183 + static inline int suspend_devices_and_enter(suspend_state_t state) 184 + { 185 + return -ENOSYS; 186 + } 187 + #endif /* !CONFIG_SUSPEND */ 188 + 189 + /* kernel/power/common.c */ 182 190 extern struct blocking_notifier_head pm_chain_head; 183 191 184 192 static inline int pm_notifier_call_chain(unsigned long val)
+2 -2
mm/page_alloc.c
··· 726 726 } 727 727 } 728 728 729 - #ifdef CONFIG_PM 729 + #ifdef CONFIG_HIBERNATION 730 730 731 731 void mark_free_pages(struct zone *zone) 732 732 { ··· 772 772 __drain_pages(smp_processor_id()); 773 773 local_irq_restore(flags); 774 774 } 775 - #endif /* CONFIG_PM */ 775 + #endif /* CONFIG_HIBERNATION */ 776 776 777 777 /* 778 778 * Free a 0-order page