소스 검색

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>
Rafael J. Wysocki 18 년 전
부모
커밋
296699de6b

+ 8 - 0
drivers/acpi/Kconfig

@@ -63,6 +63,14 @@ config ACPI_PROCFS
 
 
 	  Say N to delete /proc/acpi/ files that have moved to /sys/
 	  Say N to delete /proc/acpi/ files that have moved to /sys/
 
 
+config ACPI_PROCFS_SLEEP
+	bool "/proc/acpi/sleep (deprecated)"
+	depends on PM_SLEEP && ACPI_PROCFS
+	default n
+	---help---
+	  Create /proc/acpi/sleep
+	  Deprecated by /sys/power/state
+
 config ACPI_AC
 config ACPI_AC
 	tristate "AC Adapter"
 	tristate "AC Adapter"
 	depends on X86
 	depends on X86

+ 1 - 1
drivers/acpi/sleep/Makefile

@@ -1,5 +1,5 @@
 obj-y					:= poweroff.o wakeup.o
 obj-y					:= poweroff.o wakeup.o
-obj-y					+= main.o
+obj-$(CONFIG_PM_SLEEP)			+= main.o
 obj-$(CONFIG_X86)			+= proc.o
 obj-$(CONFIG_X86)			+= proc.o
 
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
 EXTRA_CFLAGS += $(ACPI_CFLAGS)

+ 50 - 44
drivers/acpi/sleep/main.c

@@ -21,6 +21,9 @@
 
 
 u8 sleep_states[ACPI_S_STATE_COUNT];
 u8 sleep_states[ACPI_S_STATE_COUNT];
 
 
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+
+#ifdef CONFIG_SUSPEND
 static struct pm_ops acpi_pm_ops;
 static struct pm_ops acpi_pm_ops;
 
 
 extern void do_suspend_lowlevel(void);
 extern void do_suspend_lowlevel(void);
@@ -34,11 +37,6 @@ static u32 acpi_suspend_states[] = {
 
 
 static int init_8259A_after_S1;
 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
  *	acpi_pm_set_target - Set the target system sleep state to the state
  *		associated with given @pm_state, if supported.
  *		associated with given @pm_state, if supported.
@@ -163,21 +161,6 @@ static int acpi_pm_finish(suspend_state_t pm_state)
 	return 0;
 	return 0;
 }
 }
 
 
-int acpi_suspend(u32 acpi_state)
-{
-	suspend_state_t states[] = {
-		[1] = PM_SUSPEND_STANDBY,
-		[3] = PM_SUSPEND_MEM,
-		[5] = PM_SUSPEND_MAX
-	};
-
-	if (acpi_state < 6 && states[acpi_state])
-		return pm_suspend(states[acpi_state]);
-	if (acpi_state == 4)
-		return hibernate();
-	return -EINVAL;
-}
-
 static int acpi_pm_state_valid(suspend_state_t pm_state)
 static int acpi_pm_state_valid(suspend_state_t pm_state)
 {
 {
 	u32 acpi_state;
 	u32 acpi_state;
@@ -202,6 +185,27 @@ static struct pm_ops acpi_pm_ops = {
 	.finish = acpi_pm_finish,
 	.finish = acpi_pm_finish,
 };
 };
 
 
+/*
+ * Toshiba fails to preserve interrupts over S1, reinitialization
+ * of 8259 is needed after S1 resume.
+ */
+static int __init init_ints_after_s1(struct dmi_system_id *d)
+{
+	printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
+	init_8259A_after_S1 = 1;
+	return 0;
+}
+
+static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+	{
+	 .callback = init_ints_after_s1,
+	 .ident = "Toshiba Satellite 4030cdt",
+	 .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
+	 },
+	{},
+};
+#endif /* CONFIG_SUSPEND */
+
 #ifdef CONFIG_HIBERNATION
 #ifdef CONFIG_HIBERNATION
 static int acpi_hibernation_prepare(void)
 static int acpi_hibernation_prepare(void)
 {
 {
@@ -256,6 +260,21 @@ static struct hibernation_ops acpi_hibernation_ops = {
 };
 };
 #endif				/* CONFIG_HIBERNATION */
 #endif				/* CONFIG_HIBERNATION */
 
 
+int acpi_suspend(u32 acpi_state)
+{
+	suspend_state_t states[] = {
+		[1] = PM_SUSPEND_STANDBY,
+		[3] = PM_SUSPEND_MEM,
+		[5] = PM_SUSPEND_MAX
+	};
+
+	if (acpi_state < 6 && states[acpi_state])
+		return pm_suspend(states[acpi_state]);
+	if (acpi_state == 4)
+		return hibernate();
+	return -EINVAL;
+}
+
 /**
 /**
  *	acpi_pm_device_sleep_state - return preferred power state of ACPI device
  *	acpi_pm_device_sleep_state - return preferred power state of ACPI device
  *		in the system sleep state given by %acpi_target_sleep_state
  *		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)
 	return d_max;
 	return d_max;
 }
 }
 
 
-/*
- * Toshiba fails to preserve interrupts over S1, reinitialization
- * of 8259 is needed after S1 resume.
- */
-static int __init init_ints_after_s1(struct dmi_system_id *d)
-{
-	printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
-	init_8259A_after_S1 = 1;
-	return 0;
-}
-
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
-	{
-	 .callback = init_ints_after_s1,
-	 .ident = "Toshiba Satellite 4030cdt",
-	 .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
-	 },
-	{},
-};
-
 int __init acpi_sleep_init(void)
 int __init acpi_sleep_init(void)
 {
 {
+	acpi_status status;
+	u8 type_a, type_b;
+#ifdef CONFIG_SUSPEND
 	int i = 0;
 	int i = 0;
 
 
 	dmi_check_system(acpisleep_dmi_table);
 	dmi_check_system(acpisleep_dmi_table);
+#endif
 
 
 	if (acpi_disabled)
 	if (acpi_disabled)
 		return 0;
 		return 0;
 
 
+#ifdef CONFIG_SUSPEND
 	printk(KERN_INFO PREFIX "(supports");
 	printk(KERN_INFO PREFIX "(supports");
-	for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
-		acpi_status status;
-		u8 type_a, type_b;
+	for (i = ACPI_STATE_S0; i < ACPI_STATE_S4; i++) {
 		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
 		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
 		if (ACPI_SUCCESS(status)) {
 		if (ACPI_SUCCESS(status)) {
 			sleep_states[i] = 1;
 			sleep_states[i] = 1;
@@ -373,10 +375,14 @@ int __init acpi_sleep_init(void)
 	printk(")\n");
 	printk(")\n");
 
 
 	pm_set_ops(&acpi_pm_ops);
 	pm_set_ops(&acpi_pm_ops);
+#endif
 
 
 #ifdef CONFIG_HIBERNATION
 #ifdef CONFIG_HIBERNATION
-	if (sleep_states[ACPI_STATE_S4])
+	status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
+	if (ACPI_SUCCESS(status)) {
 		hibernation_set_ops(&acpi_hibernation_ops);
 		hibernation_set_ops(&acpi_hibernation_ops);
+		sleep_states[ACPI_STATE_S4] = 1;
+	}
 #else
 #else
 	sleep_states[ACPI_STATE_S4] = 0;
 	sleep_states[ACPI_STATE_S4] = 0;
 #endif
 #endif

+ 5 - 5
drivers/acpi/sleep/proc.c

@@ -23,7 +23,7 @@
  */
  */
 
 
 ACPI_MODULE_NAME("sleep")
 ACPI_MODULE_NAME("sleep")
-#ifdef	CONFIG_ACPI_PROCFS
+#ifdef	CONFIG_ACPI_PROCFS_SLEEP
 static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
 static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
 {
 {
 	int i;
 	int i;
@@ -76,7 +76,7 @@ acpi_system_write_sleep(struct file *file,
       Done:
       Done:
 	return error ? error : count;
 	return error ? error : count;
 }
 }
-#endif				/* CONFIG_ACPI_PROCFS */
+#endif				/* CONFIG_ACPI_PROCFS_SLEEP */
 
 
 #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
 #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
 /* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
 /* 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 = {
 	.release = single_release,
 	.release = single_release,
 };
 };
 
 
-#ifdef	CONFIG_ACPI_PROCFS
+#ifdef	CONFIG_ACPI_PROCFS_SLEEP
 static const struct file_operations acpi_system_sleep_fops = {
 static const struct file_operations acpi_system_sleep_fops = {
 	.open = acpi_system_sleep_open_fs,
 	.open = acpi_system_sleep_open_fs,
 	.read = seq_read,
 	.read = seq_read,
@@ -479,7 +479,7 @@ static const struct file_operations acpi_system_sleep_fops = {
 	.llseek = seq_lseek,
 	.llseek = seq_lseek,
 	.release = single_release,
 	.release = single_release,
 };
 };
-#endif				/* CONFIG_ACPI_PROCFS */
+#endif				/* CONFIG_ACPI_PROCFS_SLEEP */
 
 
 #ifdef	HAVE_ACPI_LEGACY_ALARM
 #ifdef	HAVE_ACPI_LEGACY_ALARM
 static const struct file_operations acpi_system_alarm_fops = {
 static const struct file_operations acpi_system_alarm_fops = {
@@ -506,7 +506,7 @@ static int __init acpi_sleep_proc_init(void)
 	if (acpi_disabled)
 	if (acpi_disabled)
 		return 0;
 		return 0;
 
 
-#ifdef	CONFIG_ACPI_PROCFS
+#ifdef	CONFIG_ACPI_PROCFS_SLEEP
 	/* 'sleep' [R/W] */
 	/* 'sleep' [R/W] */
 	entry =
 	entry =
 	    create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
 	    create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,

+ 2 - 0
drivers/acpi/sleep/sleep.h

@@ -6,3 +6,5 @@ extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
 extern void acpi_enable_wakeup_device(u8 sleep_state);
 extern void acpi_enable_wakeup_device(u8 sleep_state);
 extern void acpi_disable_wakeup_device(u8 sleep_state);
 extern void acpi_disable_wakeup_device(u8 sleep_state);
 extern void acpi_gpe_sleep_prepare(u32 sleep_state);
 extern void acpi_gpe_sleep_prepare(u32 sleep_state);
+
+extern int acpi_sleep_prepare(u32 acpi_state);

+ 1 - 1
drivers/base/power/Makefile

@@ -1,5 +1,5 @@
 obj-y			:= shutdown.o
 obj-y			:= shutdown.o
-obj-$(CONFIG_PM)	+= main.o suspend.o resume.o sysfs.o
+obj-$(CONFIG_PM_SLEEP)	+= main.o suspend.o resume.o sysfs.o
 obj-$(CONFIG_PM_TRACE)	+= trace.o
 obj-$(CONFIG_PM_TRACE)	+= trace.o
 
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
 ifeq ($(CONFIG_DEBUG_DRIVER),y)

+ 2 - 2
drivers/base/power/power.h

@@ -5,7 +5,7 @@
 extern void device_shutdown(void);
 extern void device_shutdown(void);
 
 
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 
 /*
 /*
  * main.c
  * main.c
@@ -62,7 +62,7 @@ extern int resume_device(struct device *);
  */
  */
 extern int suspend_device(struct device *, pm_message_t);
 extern int suspend_device(struct device *, pm_message_t);
 
 
-#else /* CONFIG_PM */
+#else /* CONFIG_PM_SLEEP */
 
 
 
 
 static inline int device_pm_add(struct device * dev)
 static inline int device_pm_add(struct device * dev)

+ 9 - 0
include/acpi/acpi_bus.h

@@ -366,7 +366,16 @@ acpi_handle acpi_get_child(acpi_handle, acpi_integer);
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
 #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
 #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
 
 
+#ifdef CONFIG_PM_SLEEP
 int acpi_pm_device_sleep_state(struct device *, int, int *);
 int acpi_pm_device_sleep_state(struct device *, int, int *);
+#else /* !CONFIG_PM_SLEEP */
+static inline int acpi_pm_device_sleep_state(struct device *d, int w, int *p)
+{
+	if (p)
+		*p = ACPI_STATE_D0;
+	return ACPI_STATE_D3;
+}
+#endif /* !CONFIG_PM_SLEEP */
 
 
 #endif				/* CONFIG_ACPI */
 #endif				/* CONFIG_ACPI */
 
 

+ 4 - 0
include/acpi/acpi_drivers.h

@@ -147,6 +147,10 @@ static inline void unregister_hotplug_dock_device(acpi_handle handle)
 /*--------------------------------------------------------------------------
 /*--------------------------------------------------------------------------
                                   Suspend/Resume
                                   Suspend/Resume
   -------------------------------------------------------------------------- */
   -------------------------------------------------------------------------- */
+#ifdef CONFIG_PM_SLEEP
 extern int acpi_sleep_init(void);
 extern int acpi_sleep_init(void);
+#else
+static inline int acpi_sleep_init(void) { return 0; }
+#endif
 
 
 #endif /*__ACPI_DRIVERS_H__*/
 #endif /*__ACPI_DRIVERS_H__*/

+ 3 - 3
include/linux/freezer.h

@@ -5,7 +5,7 @@
 
 
 #include <linux/sched.h>
 #include <linux/sched.h>
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
 /*
  * Check if a process has been frozen
  * Check if a process has been frozen
  */
  */
@@ -126,7 +126,7 @@ static inline void set_freezable(void)
 	current->flags &= ~PF_NOFREEZE;
 	current->flags &= ~PF_NOFREEZE;
 }
 }
 
 
-#else
+#else /* !CONFIG_PM_SLEEP */
 static inline int frozen(struct task_struct *p) { return 0; }
 static inline int frozen(struct task_struct *p) { return 0; }
 static inline int freezing(struct task_struct *p) { return 0; }
 static inline int freezing(struct task_struct *p) { return 0; }
 static inline void set_freeze_flag(struct task_struct *p) {}
 static inline void set_freeze_flag(struct task_struct *p) {}
@@ -143,6 +143,6 @@ static inline void freezer_do_not_count(void) {}
 static inline void freezer_count(void) {}
 static inline void freezer_count(void) {}
 static inline int freezer_should_skip(struct task_struct *p) { return 0; }
 static inline int freezer_should_skip(struct task_struct *p) { return 0; }
 static inline void set_freezable(void) {}
 static inline void set_freezable(void) {}
-#endif
+#endif /* !CONFIG_PM_SLEEP */
 
 
 #endif	/* FREEZER_H_INCLUDED */
 #endif	/* FREEZER_H_INCLUDED */

+ 11 - 4
include/linux/pm.h

@@ -165,6 +165,7 @@ struct pm_ops {
 	int (*finish)(suspend_state_t state);
 	int (*finish)(suspend_state_t state);
 };
 };
 
 
+#ifdef CONFIG_SUSPEND
 extern struct pm_ops *pm_ops;
 extern struct pm_ops *pm_ops;
 
 
 /**
 /**
@@ -193,6 +194,12 @@ extern void arch_suspend_disable_irqs(void);
 extern void arch_suspend_enable_irqs(void);
 extern void arch_suspend_enable_irqs(void);
 
 
 extern int pm_suspend(suspend_state_t state);
 extern int pm_suspend(suspend_state_t state);
+#else /* !CONFIG_SUSPEND */
+#define suspend_valid_only_mem	NULL
+
+static inline void pm_set_ops(struct pm_ops *pm_ops) {}
+static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
+#endif /* !CONFIG_SUSPEND */
 
 
 /*
 /*
  * Device power management
  * Device power management
@@ -266,7 +273,7 @@ typedef struct pm_message {
 struct dev_pm_info {
 struct dev_pm_info {
 	pm_message_t		power_state;
 	pm_message_t		power_state;
 	unsigned		can_wakeup:1;
 	unsigned		can_wakeup:1;
-#ifdef	CONFIG_PM
+#ifdef	CONFIG_PM_SLEEP
 	unsigned		should_wakeup:1;
 	unsigned		should_wakeup:1;
 	struct list_head	entry;
 	struct list_head	entry;
 #endif
 #endif
@@ -276,7 +283,7 @@ extern int device_power_down(pm_message_t state);
 extern void device_power_up(void);
 extern void device_power_up(void);
 extern void device_resume(void);
 extern void device_resume(void);
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 extern int device_suspend(pm_message_t state);
 extern int device_suspend(pm_message_t state);
 extern int device_prepare_suspend(pm_message_t state);
 extern int device_prepare_suspend(pm_message_t state);
 
 
@@ -306,7 +313,7 @@ static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
-#else /* !CONFIG_PM */
+#else /* !CONFIG_PM_SLEEP */
 
 
 static inline int device_suspend(pm_message_t state)
 static inline int device_suspend(pm_message_t state)
 {
 {
@@ -323,7 +330,7 @@ static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
-#endif
+#endif /* !CONFIG_PM_SLEEP */
 
 
 /* changes to device_may_wakeup take effect on the next pm state change.
 /* changes to device_may_wakeup take effect on the next pm state change.
  * by default, devices should wakeup if they can.
  * by default, devices should wakeup if they can.

+ 5 - 5
include/linux/suspend.h

@@ -24,7 +24,7 @@ struct pbe {
 extern void drain_local_pages(void);
 extern void drain_local_pages(void);
 extern void mark_free_pages(struct zone *zone);
 extern void mark_free_pages(struct zone *zone);
 
 
-#if defined(CONFIG_PM) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
 extern int pm_prepare_console(void);
 extern int pm_prepare_console(void);
 extern void pm_restore_console(void);
 extern void pm_restore_console(void);
 #else
 #else
@@ -54,7 +54,6 @@ struct hibernation_ops {
 	void (*restore_cleanup)(void);
 	void (*restore_cleanup)(void);
 };
 };
 
 
-#ifdef CONFIG_PM
 #ifdef CONFIG_HIBERNATION
 #ifdef CONFIG_HIBERNATION
 /* kernel/power/snapshot.c */
 /* kernel/power/snapshot.c */
 extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
 extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
@@ -82,6 +81,7 @@ static inline void hibernation_set_ops(struct hibernation_ops *ops) {}
 static inline int hibernate(void) { return -ENOSYS; }
 static inline int hibernate(void) { return -ENOSYS; }
 #endif /* CONFIG_HIBERNATION */
 #endif /* CONFIG_HIBERNATION */
 
 
+#ifdef CONFIG_PM_SLEEP
 void save_processor_state(void);
 void save_processor_state(void);
 void restore_processor_state(void);
 void restore_processor_state(void);
 struct saved_context;
 struct saved_context;
@@ -106,7 +106,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
 		{ .notifier_call = fn, .priority = pri };	\
 		{ .notifier_call = fn, .priority = pri };	\
 	register_pm_notifier(&fn##_nb);			\
 	register_pm_notifier(&fn##_nb);			\
 }
 }
-#else /* CONFIG_PM */
+#else /* !CONFIG_PM_SLEEP */
 
 
 static inline int register_pm_notifier(struct notifier_block *nb)
 static inline int register_pm_notifier(struct notifier_block *nb)
 {
 {
@@ -119,9 +119,9 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
 }
 }
 
 
 #define pm_notifier(fn, pri)	do { (void)(fn); } while (0)
 #define pm_notifier(fn, pri)	do { (void)(fn); } while (0)
-#endif /* CONFIG_PM */
+#endif /* !CONFIG_PM_SLEEP */
 
 
-#if !defined CONFIG_HIBERNATION || !defined(CONFIG_PM)
+#ifndef CONFIG_HIBERNATION
 static inline void register_nosave_region(unsigned long b, unsigned long e)
 static inline void register_nosave_region(unsigned long b, unsigned long e)
 {
 {
 }
 }

+ 32 - 9
kernel/power/Kconfig

@@ -46,7 +46,7 @@ config PM_VERBOSE
 
 
 config DISABLE_CONSOLE_SUSPEND
 config DISABLE_CONSOLE_SUSPEND
 	bool "Keep console(s) enabled during suspend/resume (DANGEROUS)"
 	bool "Keep console(s) enabled during suspend/resume (DANGEROUS)"
-	depends on PM_DEBUG
+	depends on PM_DEBUG && PM_SLEEP
 	default n
 	default n
 	---help---
 	---help---
 	This option turns off the console suspend mechanism that prevents
 	This option turns off the console suspend mechanism that prevents
@@ -57,7 +57,7 @@ config DISABLE_CONSOLE_SUSPEND
 
 
 config PM_TRACE
 config PM_TRACE
 	bool "Suspend/resume event tracing"
 	bool "Suspend/resume event tracing"
-	depends on PM_DEBUG && X86 && EXPERIMENTAL
+	depends on PM_DEBUG && X86 && PM_SLEEP && EXPERIMENTAL
 	default n
 	default n
 	---help---
 	---help---
 	This enables some cheesy code to save the last PM event point in the
 	This enables some cheesy code to save the last PM event point in the
@@ -72,9 +72,37 @@ config PM_TRACE
 	CAUTION: this option will cause your machine's real-time clock to be
 	CAUTION: this option will cause your machine's real-time clock to be
 	set to an invalid time after a resume.
 	set to an invalid time after a resume.
 
 
+config SUSPEND_SMP_POSSIBLE
+	bool
+	depends on (X86 && !X86_VOYAGER) || (PPC64 && (PPC_PSERIES || PPC_PMAC))
+	depends on SMP
+	default y
+
+config SUSPEND_SMP
+	bool
+	depends on SUSPEND_SMP_POSSIBLE && PM_SLEEP
+	select HOTPLUG_CPU
+	default y
+
+config PM_SLEEP
+	bool
+	depends on SUSPEND || HIBERNATION
+	default y
+
+config SUSPEND
+	bool "Suspend to RAM and standby"
+	depends on PM
+	depends on !SMP || SUSPEND_SMP_POSSIBLE
+	default y
+	---help---
+	  Allow the system to enter sleep states in which main memory is
+	  powered and thus its contents are preserved, such as the
+	  suspend-to-RAM state (i.e. the ACPI S3 state).
+
 config HIBERNATION
 config HIBERNATION
-	bool "Hibernation"
-	depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
+	bool "Hibernation (aka 'suspend to disk')"
+	depends on PM && SWAP
+	depends on ((X86 || PPC64_SWSUSP || FRV || PPC32) && !SMP) || SUSPEND_SMP_POSSIBLE
 	---help---
 	---help---
 	  Enable the suspend to disk (STD) functionality, which is usually
 	  Enable the suspend to disk (STD) functionality, which is usually
 	  called "hibernation" in user interfaces.  STD checkpoints the
 	  called "hibernation" in user interfaces.  STD checkpoints the
@@ -132,11 +160,6 @@ config PM_STD_PARTITION
 	  suspended image to. It will simply pick the first available swap 
 	  suspended image to. It will simply pick the first available swap 
 	  device.
 	  device.
 
 
-config SUSPEND_SMP
-	bool
-	depends on HOTPLUG_CPU && (X86 || PPC64) && PM
-	default y
-
 config APM_EMULATION
 config APM_EMULATION
 	tristate "Advanced Power Management Emulation"
 	tristate "Advanced Power Management Emulation"
 	depends on PM && SYS_SUPPORTS_APM_EMULATION
 	depends on PM && SYS_SUPPORTS_APM_EMULATION

+ 2 - 1
kernel/power/Makefile

@@ -3,8 +3,9 @@ ifeq ($(CONFIG_PM_DEBUG),y)
 EXTRA_CFLAGS	+=	-DDEBUG
 EXTRA_CFLAGS	+=	-DDEBUG
 endif
 endif
 
 
-obj-y				:= main.o process.o console.o
+obj-y				:= main.o
 obj-$(CONFIG_PM_LEGACY)		+= pm.o
 obj-$(CONFIG_PM_LEGACY)		+= pm.o
+obj-$(CONFIG_PM_SLEEP)		+= process.o console.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
 
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o

+ 18 - 8
kernel/power/main.c

@@ -25,11 +25,13 @@
 
 
 BLOCKING_NOTIFIER_HEAD(pm_chain_head);
 BLOCKING_NOTIFIER_HEAD(pm_chain_head);
 
 
-/*This is just an arbitrary number */
-#define FREE_PAGE_NUMBER (100)
-
 DEFINE_MUTEX(pm_mutex);
 DEFINE_MUTEX(pm_mutex);
 
 
+#ifdef CONFIG_SUSPEND
+
+/* This is just an arbitrary number */
+#define FREE_PAGE_NUMBER (100)
+
 struct pm_ops *pm_ops;
 struct pm_ops *pm_ops;
 
 
 /**
 /**
@@ -269,6 +271,8 @@ int pm_suspend(suspend_state_t state)
 
 
 EXPORT_SYMBOL(pm_suspend);
 EXPORT_SYMBOL(pm_suspend);
 
 
+#endif /* CONFIG_SUSPEND */
+
 decl_subsys(power,NULL,NULL);
 decl_subsys(power,NULL,NULL);
 
 
 
 
@@ -285,13 +289,15 @@ decl_subsys(power,NULL,NULL);
 
 
 static ssize_t state_show(struct kset *kset, char *buf)
 static ssize_t state_show(struct kset *kset, char *buf)
 {
 {
+	char *s = buf;
+#ifdef CONFIG_SUSPEND
 	int i;
 	int i;
-	char * s = buf;
 
 
 	for (i = 0; i < PM_SUSPEND_MAX; i++) {
 	for (i = 0; i < PM_SUSPEND_MAX; i++) {
 		if (pm_states[i] && valid_state(i))
 		if (pm_states[i] && valid_state(i))
 			s += sprintf(s,"%s ", pm_states[i]);
 			s += sprintf(s,"%s ", pm_states[i]);
 	}
 	}
+#endif
 #ifdef CONFIG_HIBERNATION
 #ifdef CONFIG_HIBERNATION
 	s += sprintf(s, "%s\n", "disk");
 	s += sprintf(s, "%s\n", "disk");
 #else
 #else
@@ -304,11 +310,13 @@ static ssize_t state_show(struct kset *kset, char *buf)
 
 
 static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
 static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
 {
 {
+#ifdef CONFIG_SUSPEND
 	suspend_state_t state = PM_SUSPEND_STANDBY;
 	suspend_state_t state = PM_SUSPEND_STANDBY;
 	const char * const *s;
 	const char * const *s;
+#endif
 	char *p;
 	char *p;
-	int error;
 	int len;
 	int len;
+	int error = -EINVAL;
 
 
 	p = memchr(buf, '\n', n);
 	p = memchr(buf, '\n', n);
 	len = p ? p - buf : n;
 	len = p ? p - buf : n;
@@ -316,17 +324,19 @@ static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
 	/* First, check if we are requested to hibernate */
 	/* First, check if we are requested to hibernate */
 	if (len == 4 && !strncmp(buf, "disk", len)) {
 	if (len == 4 && !strncmp(buf, "disk", len)) {
 		error = hibernate();
 		error = hibernate();
-		return error ? error : n;
+  goto Exit;
 	}
 	}
 
 
+#ifdef CONFIG_SUSPEND
 	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
 	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
 		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
 		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
 			break;
 			break;
 	}
 	}
 	if (state < PM_SUSPEND_MAX && *s)
 	if (state < PM_SUSPEND_MAX && *s)
 		error = enter_state(state);
 		error = enter_state(state);
-	else
-		error = -EINVAL;
+#endif
+
+ Exit:
 	return error ? error : n;
 	return error ? error : n;
 }
 }
 
 

+ 9 - 1
kernel/power/power.h

@@ -176,9 +176,17 @@ struct timeval;
 extern void swsusp_show_speed(struct timeval *, struct timeval *,
 extern void swsusp_show_speed(struct timeval *, struct timeval *,
 				unsigned int, char *);
 				unsigned int, char *);
 
 
+#ifdef CONFIG_SUSPEND
 /* kernel/power/main.c */
 /* kernel/power/main.c */
-extern int suspend_enter(suspend_state_t state);
 extern int suspend_devices_and_enter(suspend_state_t state);
 extern int suspend_devices_and_enter(suspend_state_t state);
+#else /* !CONFIG_SUSPEND */
+static inline int suspend_devices_and_enter(suspend_state_t state)
+{
+	return -ENOSYS;
+}
+#endif /* !CONFIG_SUSPEND */
+
+/* kernel/power/common.c */
 extern struct blocking_notifier_head pm_chain_head;
 extern struct blocking_notifier_head pm_chain_head;
 
 
 static inline int pm_notifier_call_chain(unsigned long val)
 static inline int pm_notifier_call_chain(unsigned long val)

+ 2 - 2
mm/page_alloc.c

@@ -726,7 +726,7 @@ static void __drain_pages(unsigned int cpu)
 	}
 	}
 }
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_HIBERNATION
 
 
 void mark_free_pages(struct zone *zone)
 void mark_free_pages(struct zone *zone)
 {
 {
@@ -772,7 +772,7 @@ void drain_local_pages(void)
 	__drain_pages(smp_processor_id());
 	__drain_pages(smp_processor_id());
 	local_irq_restore(flags);	
 	local_irq_restore(flags);	
 }
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_HIBERNATION */
 
 
 /*
 /*
  * Free a 0-order page
  * Free a 0-order page