Suspend/hibernation patches for 2.6.25
Subsystems (5)
cover Suspend/hibernation patches for 2.6.25
Hi Len,
I've already sent all of the following patches to you, but you haven't picked them up yet, so here they go again in one pack (with missing ACKs added here and there).
I'm considering all of them as 2.6.25 material, so please add them to the suspend branch.
Thanks,
Rafael
PATCH 1/8 ACPI: Fix mismerge in acpi_hibernation_finish
From: Rafael J. Wysocki <[email protected]>
Some code in acpi_hibernation_finish() was moved to acpi_hibernation_leave(), but the old copy had been left (it's harmless, but also useless). Remove it.
--- drivers/acpi/sleep/main.c | 5 ----- 1 file changed, 5 deletions(-)
drivers/acpi/sleep/main.c +0 -5
@@ -267,11 +267,6 @@ static void acpi_hibernation_leave(void)static void acpi_hibernation_finish (void ) { -/* -* If ACPI is not enabled by the BIOS and the boot kernel, we need to -* enable it here. -*/ -acpi_enable ();acpi_disable_wakeup_device (ACPI_STATE_S4 );acpi_leave_sleep_state (ACPI_STATE_S4 );
PATCH 1/8 ACPI: Fix mismerge in acpi_hibernation_finish
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Some code in acpi_hibernation_finish() was moved to acpi_hibernation_leave(), but the old copy had been left (it's harmless, but also useless). Remove it.
--- drivers/acpi/sleep/main.c | 5 ----- 1 file changed, 5 deletions(-)
drivers/acpi/sleep/main.c +0 -5
@@ -267,11 +267,6 @@ static void acpi_hibernation_leave(void)static void acpi_hibernation_finish (void ) { -/* -* If ACPI is not enabled by the BIOS and the boot kernel, we need to -* enable it here. -*/ -acpi_enable ();acpi_disable_wakeup_device (ACPI_STATE_S4 );acpi_leave_sleep_state (ACPI_STATE_S4 );
PATCH 2/8 Hibernation: Move function prototypes to header
In reply to Rafael J. WysockiFrom: Adrian Bunk <[email protected]>
This patch moves the prototypes of count_highmem_pages() and restore_highmem() to kernel/power/power.h
--- kernel/power/power.h | 8 ++++++++ kernel/power/snapshot.c | 1 - kernel/power/swsusp.c | 8 -------- 3 files changed, 8 insertions(+), 9 deletions(-)
20af06052a0203d9e60b4937282793900c756182
kernel/power/power.h +8 -0
@@ -211,3 +211,11 @@ static inline int pm_notifier_call_chain(unsigned long val)return (blocking_notifier_call_chain (&pm_chain_head, val,NULL ) ==NOTIFY_BAD ) ? -EINVAL :0 ; } + +#ifdef CONFIG_HIGHMEM +unsigned int count_highmem_pages (void ); +int restore_highmem (void ); +#else +static inline unsigned int count_highmem_pages (void ) {return 0 ; } +static inline int restore_highmem (void ) {return 0 ; } +#endif
kernel/power/snapshot.c +0 -1
@@ -872,7 +872,6 @@ unsigned int count_highmem_pages(void) }#else static inline void *saveable_highmem_page (unsigned long pfn) {return NULL ; } -static inline unsigned int count_highmem_pages (void ) {return 0 ; }#endif /* CONFIG_HIGHMEM */ /**
kernel/power/swsusp.c +0 -8
@@ -64,14 +64,6 @@ unsigned long image_size = 500 * 1024 * 1024; int in_suspend __nosavedata = 0; -#ifdef CONFIG_HIGHMEM -unsigned int count_highmem_pages (void ); -int restore_highmem (void ); -#else -static inline int restore_highmem (void ) {return 0 ; } -static inline unsigned int count_highmem_pages (void ) {return 0 ; } -#endif -/** * The following functions are used for tracing the allocated * swap pages, so that they can be freed in case of an error.
PATCH 2/8 Hibernation: Move function prototypes to header
In reply to Rafael J. WysockiFrom: Adrian Bunk <[email protected]>
This patch moves the prototypes of count_highmem_pages() and restore_highmem() to kernel/power/power.h
--- kernel/power/power.h | 8 ++++++++ kernel/power/snapshot.c | 1 - kernel/power/swsusp.c | 8 -------- 3 files changed, 8 insertions(+), 9 deletions(-)
20af06052a0203d9e60b4937282793900c756182
kernel/power/power.h +8 -0
@@ -211,3 +211,11 @@ static inline int pm_notifier_call_chain(unsigned long val)return (blocking_notifier_call_chain (&pm_chain_head, val,NULL ) ==NOTIFY_BAD ) ? -EINVAL :0 ; } + +#ifdef CONFIG_HIGHMEM +unsigned int count_highmem_pages (void ); +int restore_highmem (void ); +#else +static inline unsigned int count_highmem_pages (void ) {return 0 ; } +static inline int restore_highmem (void ) {return 0 ; } +#endif
kernel/power/snapshot.c +0 -1
@@ -872,7 +872,6 @@ unsigned int count_highmem_pages(void) }#else static inline void *saveable_highmem_page (unsigned long pfn) {return NULL ; } -static inline unsigned int count_highmem_pages (void ) {return 0 ; }#endif /* CONFIG_HIGHMEM */ /**
kernel/power/swsusp.c +0 -8
@@ -64,14 +64,6 @@ unsigned long image_size = 500 * 1024 * 1024; int in_suspend __nosavedata = 0; -#ifdef CONFIG_HIGHMEM -unsigned int count_highmem_pages (void ); -int restore_highmem (void ); -#else -static inline int restore_highmem (void ) {return 0 ; } -static inline unsigned int count_highmem_pages (void ) {return 0 ; } -#endif -/** * The following functions are used for tracing the allocated * swap pages, so that they can be freed in case of an error.
PATCH 3/8 Hibernation: Add PM_RESTORE_PREPARE and PM_POST_RESTORE notifiers (rev. 2)
In reply to Rafael J. WysockiFrom: Alan Stern <[email protected]>
Add PM_RESTORE_PREPARE and PM_POST_RESTORE notifiers to the PM core, to be used in analogy with the existing PM_HIBERNATION_PREPARE and PM_POST_HIBERNATION notifiers.
--- Documentation/power/notifiers.txt | 8 ++++++++ include/linux/notifier.h | 2 ++ kernel/power/disk.c | 5 +++++ kernel/power/user.c | 31 +++++++++++++++++++------------ 4 files changed, 34 insertions(+), 12 deletions(-)
Documentation/power/notifiers.txt +8 -0
@@ -28,6 +28,14 @@ PM_POST_HIBERNATION The system memory st hibernation. Device drivers' .resume() callbacks have been executed and tasks have been thawed. +PM_RESTORE_PREPARE The system is going to restore a hibernation image. + If all goes well the restored kernel will issue a + PM_POST_HIBERNATION notification. + +PM_POST_RESTORE An error occurred during the hibernation restore. + Device drivers' .resume() callbacks have been executed + and tasks have been thawed. + PM_SUSPEND_PREPARE The system is preparing for a suspend. PM_POST_SUSPEND The system has just resumed or an error occured during
include/linux/notifier.h +2 -0
@@ -230,6 +230,8 @@ static inline int notifier_to_errno(int#define PM_POST_HIBERNATION 0x0002/* Hibernation finished */ #define PM_SUSPEND_PREPARE 0x0003/* Going to suspend the system */ #define PM_POST_SUSPEND 0x0004/* Suspend finished */ +#define PM_RESTORE_PREPARE 0x0005/* Going to restore a saved image */ +#define PM_POST_RESTORE 0x0006/* Restore failed */ /* Console keyboard events. * Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and
kernel/power/disk.c +5 -0
@@ -499,6 +499,10 @@ static int software_resume(void) goto Unlock; } + error =pm_notifier_call_chain (PM_RESTORE_PREPARE ); +if (error) + goto Finish; + error =create_basic_memory_bitmaps ();if (error) goto Finish;
@@ -522,6 +526,7 @@ static int software_resume(void) Done:free_basic_memory_bitmaps (); Finish: +pm_notifier_call_chain (PM_POST_RESTORE );atomic_inc (&snapshot_device_available);/* For success case, the suspend path will release the lock */ Unlock:
kernel/power/user.c +19 -12
@@ -67,6 +67,7 @@ atomic_t snapshot_device_available = ATOstatic int snapshot_open (struct inode *inode,struct file *filp) {struct snapshot_data *data; +int error;if (!atomic_add_unless (&snapshot_device_available,-1 ,0 ))return -EBUSY ;
@@ -87,9 +88,19 @@ static int snapshot_open(struct inode *i data->swap = swsusp_resume_device ?swap_type_of (swsusp_resume_device,0 ,NULL ) :-1 ; data->mode =O_RDONLY ; + error =pm_notifier_call_chain (PM_RESTORE_PREPARE ); +if (error) +pm_notifier_call_chain (PM_POST_RESTORE ); }else { data->swap =-1 ; data->mode =O_WRONLY ; + error =pm_notifier_call_chain (PM_HIBERNATION_PREPARE ); +if (error) +pm_notifier_call_chain (PM_POST_HIBERNATION ); + } +if (error) { +atomic_inc (&snapshot_device_available); +return error; } data->frozen =0 ; data->ready =0 ;
@@ -111,6 +122,8 @@ static int snapshot_release(struct inodethaw_processes ();mutex_unlock (&pm_mutex); } +pm_notifier_call_chain (data->mode ==O_WRONLY ? +PM_POST_HIBERNATION :PM_POST_RESTORE );atomic_inc (&snapshot_device_available);return 0 ; }
@@ -174,18 +187,13 @@ static int snapshot_ioctl(struct inode *if (data->frozen)break ;mutex_lock (&pm_mutex); - error =pm_notifier_call_chain (PM_HIBERNATION_PREPARE ); -if (!error) { -printk ("Syncing filesystems ... " ); -sys_sync (); -printk ("done.\n" ); - - error =freeze_processes (); -if (error) -thaw_processes (); - } +printk ("Syncing filesystems ... " ); +sys_sync (); +printk ("done.\n" ); + + error =freeze_processes ();if (error) -pm_notifier_call_chain (PM_POST_HIBERNATION ); +thaw_processes ();mutex_unlock (&pm_mutex);if (!error) data->frozen =1 ;
@@ -196,7 +204,6 @@ static int snapshot_ioctl(struct inode *break ;mutex_lock (&pm_mutex);thaw_processes (); -pm_notifier_call_chain (PM_POST_HIBERNATION );mutex_unlock (&pm_mutex); data->frozen =0 ;break ;
PATCH 3/8 Hibernation: Add PM_RESTORE_PREPARE and PM_POST_RESTORE notifiers (rev. 2)
In reply to Rafael J. WysockiFrom: Alan Stern <[email protected]>
Add PM_RESTORE_PREPARE and PM_POST_RESTORE notifiers to the PM core, to be used in analogy with the existing PM_HIBERNATION_PREPARE and PM_POST_HIBERNATION notifiers.
--- Documentation/power/notifiers.txt | 8 ++++++++ include/linux/notifier.h | 2 ++ kernel/power/disk.c | 5 +++++ kernel/power/user.c | 31 +++++++++++++++++++------------ 4 files changed, 34 insertions(+), 12 deletions(-)
Documentation/power/notifiers.txt +8 -0
@@ -28,6 +28,14 @@ PM_POST_HIBERNATION The system memory st hibernation. Device drivers' .resume() callbacks have been executed and tasks have been thawed. +PM_RESTORE_PREPARE The system is going to restore a hibernation image. + If all goes well the restored kernel will issue a + PM_POST_HIBERNATION notification. + +PM_POST_RESTORE An error occurred during the hibernation restore. + Device drivers' .resume() callbacks have been executed + and tasks have been thawed. + PM_SUSPEND_PREPARE The system is preparing for a suspend. PM_POST_SUSPEND The system has just resumed or an error occured during
include/linux/notifier.h +2 -0
@@ -230,6 +230,8 @@ static inline int notifier_to_errno(int#define PM_POST_HIBERNATION 0x0002/* Hibernation finished */ #define PM_SUSPEND_PREPARE 0x0003/* Going to suspend the system */ #define PM_POST_SUSPEND 0x0004/* Suspend finished */ +#define PM_RESTORE_PREPARE 0x0005/* Going to restore a saved image */ +#define PM_POST_RESTORE 0x0006/* Restore failed */ /* Console keyboard events. * Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and
kernel/power/disk.c +5 -0
@@ -499,6 +499,10 @@ static int software_resume(void) goto Unlock; } + error =pm_notifier_call_chain (PM_RESTORE_PREPARE ); +if (error) + goto Finish; + error =create_basic_memory_bitmaps ();if (error) goto Finish;
@@ -522,6 +526,7 @@ static int software_resume(void) Done:free_basic_memory_bitmaps (); Finish: +pm_notifier_call_chain (PM_POST_RESTORE );atomic_inc (&snapshot_device_available);/* For success case, the suspend path will release the lock */ Unlock:
kernel/power/user.c +19 -12
@@ -67,6 +67,7 @@ atomic_t snapshot_device_available = ATOstatic int snapshot_open (struct inode *inode,struct file *filp) {struct snapshot_data *data; +int error;if (!atomic_add_unless (&snapshot_device_available,-1 ,0 ))return -EBUSY ;
@@ -87,9 +88,19 @@ static int snapshot_open(struct inode *i data->swap = swsusp_resume_device ?swap_type_of (swsusp_resume_device,0 ,NULL ) :-1 ; data->mode =O_RDONLY ; + error =pm_notifier_call_chain (PM_RESTORE_PREPARE ); +if (error) +pm_notifier_call_chain (PM_POST_RESTORE ); }else { data->swap =-1 ; data->mode =O_WRONLY ; + error =pm_notifier_call_chain (PM_HIBERNATION_PREPARE ); +if (error) +pm_notifier_call_chain (PM_POST_HIBERNATION ); + } +if (error) { +atomic_inc (&snapshot_device_available); +return error; } data->frozen =0 ; data->ready =0 ;
@@ -111,6 +122,8 @@ static int snapshot_release(struct inodethaw_processes ();mutex_unlock (&pm_mutex); } +pm_notifier_call_chain (data->mode ==O_WRONLY ? +PM_POST_HIBERNATION :PM_POST_RESTORE );atomic_inc (&snapshot_device_available);return 0 ; }
@@ -174,18 +187,13 @@ static int snapshot_ioctl(struct inode *if (data->frozen)break ;mutex_lock (&pm_mutex); - error =pm_notifier_call_chain (PM_HIBERNATION_PREPARE ); -if (!error) { -printk ("Syncing filesystems ... " ); -sys_sync (); -printk ("done.\n" ); - - error =freeze_processes (); -if (error) -thaw_processes (); - } +printk ("Syncing filesystems ... " ); +sys_sync (); +printk ("done.\n" ); + + error =freeze_processes ();if (error) -pm_notifier_call_chain (PM_POST_HIBERNATION ); +thaw_processes ();mutex_unlock (&pm_mutex);if (!error) data->frozen =1 ;
@@ -196,7 +204,6 @@ static int snapshot_ioctl(struct inode *break ;mutex_lock (&pm_mutex);thaw_processes (); -pm_notifier_call_chain (PM_POST_HIBERNATION );mutex_unlock (&pm_mutex); data->frozen =0 ;break ;
PATCH 4/8 Suspend: Testing facility (rev. 2)
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Introduce sysfs attribute /sys/power/pm_test allowing one to test the suspend core code. Namely, writing one of the strings:
freezer
devices
platform
processors
core
to this file causes the suspend code to work in one of the test modes defined as follows:
freezer
- test the freezing of processes
devices
- test the freezing of processes and suspending of devices
platform
- test the freezing of processes, suspending of devices and platform global control methods(*)
processors
- test the freezing of processes, suspending of devices, platform global control methods and the disabling of nonboot CPUs
core
- test the freezing of processes, suspending of devices, platform global control methods, the disabling of nonboot CPUs and suspending of platform/system devices
(*) These are ACPI global control methods on ACPI systems
Then, if a suspend is started by normal means, the suspend core will perform its normal operations up to the point indicated by given test level. Next, it will wait for 5 seconds and carry out the resume operations needed to transition the system back to the fully functional state.
Writing "none" to /sys/power/pm_test turns the testing off.
When open for reading, /sys/power/pm_test contains a space-separated list of all available tests (including "none" that represents the normal functionality) in which the current test level is indicated by square brackets.
--- kernel/power/main.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++----- kernel/power/power.h | 18 ++++++++ 2 files changed, 118 insertions(+), 9 deletions(-)
kernel/power/main.c +100 -9
@@ -28,6 +28,80 @@ BLOCKING_NOTIFIER_HEAD(pm_chain_head);DEFINE_MUTEX (pm_mutex); +#ifdef CONFIG_PM_DEBUG +int pm_test_level =TEST_NONE ; + +static int suspend_test (int level) +{ +if (pm_test_level == level) { +printk (KERN_INFO "suspend debug: Waiting for 5 seconds.\n" ); +mdelay (5000 ); +return 1 ; + } +return 0 ; +} + +static const char *const pm_tests[__TEST_AFTER_LAST] = { + [TEST_NONE ] ="none" , + [TEST_CORE ] ="core" , + [TEST_CPUS ] ="processors" , + [TEST_PLATFORM ] ="platform" , + [TEST_DEVICES ] ="devices" , + [TEST_FREEZER ] ="freezer" , +}; + +static ssize_t pm_test_show (struct kset *kset,char *buf) +{ +char *s = buf; +int level; + +for (level =TEST_FIRST ; level <=TEST_MAX ; level++) +if (pm_tests[level]) { +if (level == pm_test_level) + s +=sprintf (s,"[%s] " , pm_tests[level]); +else + s +=sprintf (s,"%s " , pm_tests[level]); + } + +if (s != buf) +/* convert the last space to a newline */ + *(s-1 ) ='\n' ; + +return (s - buf); +} + +static ssize_t pm_test_store (struct kset *kset,const char *buf,size_t n) +{ +const char *const *s; +int level; +char *p; +int len; +int error = -EINVAL ; + + p =memchr (buf,'\n' , n); + len = p ? p - buf : n; + +mutex_lock (&pm_mutex); + + level =TEST_FIRST ; +for (s = &pm_tests[level]; level <=TEST_MAX ; s++, level++) +if (*s && len ==strlen (*s) && !strncmp (buf, *s, len)) { + pm_test_level = level; + error =0 ; +break ; + } + +mutex_unlock (&pm_mutex); + +return error ? error : n; +} + +power_attr (pm_test); +#else /* !CONFIG_PM_DEBUG */ +static inline int suspend_test (int level) {return 0 ; } +#endif /* !CONFIG_PM_DEBUG */ + +#ifdef CONFIG_SUSPEND /* This is just an arbitrary number */
@@ -133,7 +207,10 @@ static int suspend_enter(suspend_state_tprintk (KERN_ERR "Some devices failed to power down\n" ); goto Done; } - error = suspend_ops->enter (state); + +if (!suspend_test (TEST_CORE )) + error = suspend_ops->enter (state); +device_power_up (); Done:arch_suspend_enable_irqs ();
@@ -164,16 +241,25 @@ int suspend_devices_and_enter(suspend_stprintk (KERN_ERR "Some devices failed to suspend\n" ); goto Resume_console; } + +if (suspend_test (TEST_DEVICES )) + goto Resume_devices; +if (suspend_ops->prepare) { error = suspend_ops->prepare ();if (error) goto Resume_devices; } + +if (suspend_test (TEST_PLATFORM )) + goto Finish; + error =disable_nonboot_cpus (); -if (!error) +if (!error && !suspend_test (TEST_CPUS ))suspend_enter (state);enable_nonboot_cpus (); + Finish:if (suspend_ops->finish) suspend_ops->finish (); Resume_devices:
@@ -240,12 +326,17 @@ static int enter_state(suspend_state_t sprintk ("done.\n" );pr_debug ("PM: Preparing system for %s sleep\n" , pm_states[state]); -if ((error =suspend_prepare ())) + error =suspend_prepare (); +if (error) goto Unlock; +if (suspend_test (TEST_FREEZER )) + goto Finish; +pr_debug ("PM: Entering %s sleep\n" , pm_states[state]); error =suspend_devices_and_enter (state); + Finish:pr_debug ("PM: Finishing wakeup.\n" );suspend_finish (); Unlock:
@@ -363,18 +454,18 @@ pm_trace_store(struct kset *kset, const }power_attr (pm_trace); +#endif /* CONFIG_PM_TRACE */ static struct attribute * g[] = { &state_attr.attr, +#ifdef CONFIG_PM_TRACE &pm_trace_attr.attr, +#endif +#ifdef CONFIG_PM_DEBUG + &pm_test_attr.attr, +#endifNULL , }; -#else -static struct attribute * g[] = { - &state_attr.attr, -NULL , -}; -#endif /* CONFIG_PM_TRACE */ static struct attribute_group attr_group = { .attrs = g,
kernel/power/power.h +18 -0
@@ -190,3 +190,21 @@ int restore_highmem(void);static inline unsigned int count_highmem_pages (void ) {return 0 ; }static inline int restore_highmem (void ) {return 0 ; }#endif + +/* +* Suspend test levels +*/ +enum { +/* keep first */ +TEST_NONE , +TEST_CORE , +TEST_CPUS , +TEST_PLATFORM , +TEST_DEVICES , +TEST_FREEZER , +/* keep last */ + __TEST_AFTER_LAST +}; + +#define TEST_FIRST TEST_NONE +#define TEST_MAX (__TEST_AFTER_LAST - 1)
-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 4/8 Suspend: Testing facility (rev. 2)
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Introduce sysfs attribute /sys/power/pm_test allowing one to test the suspend core code. Namely, writing one of the strings:
freezer
devices
platform
processors
core
to this file causes the suspend code to work in one of the test modes defined as follows:
freezer
- test the freezing of processes
devices
- test the freezing of processes and suspending of devices
platform
- test the freezing of processes, suspending of devices and platform global control methods(*)
processors
- test the freezing of processes, suspending of devices, platform global control methods and the disabling of nonboot CPUs
core
- test the freezing of processes, suspending of devices, platform global control methods, the disabling of nonboot CPUs and suspending of platform/system devices
(*) These are ACPI global control methods on ACPI systems
Then, if a suspend is started by normal means, the suspend core will perform its normal operations up to the point indicated by given test level. Next, it will wait for 5 seconds and carry out the resume operations needed to transition the system back to the fully functional state.
Writing "none" to /sys/power/pm_test turns the testing off.
When open for reading, /sys/power/pm_test contains a space-separated list of all available tests (including "none" that represents the normal functionality) in which the current test level is indicated by square brackets.
--- kernel/power/main.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++----- kernel/power/power.h | 18 ++++++++ 2 files changed, 118 insertions(+), 9 deletions(-)
kernel/power/main.c +100 -9
@@ -28,6 +28,80 @@ BLOCKING_NOTIFIER_HEAD(pm_chain_head);DEFINE_MUTEX (pm_mutex); +#ifdef CONFIG_PM_DEBUG +int pm_test_level =TEST_NONE ; + +static int suspend_test (int level) +{ +if (pm_test_level == level) { +printk (KERN_INFO "suspend debug: Waiting for 5 seconds.\n" ); +mdelay (5000 ); +return 1 ; + } +return 0 ; +} + +static const char *const pm_tests[__TEST_AFTER_LAST] = { + [TEST_NONE ] ="none" , + [TEST_CORE ] ="core" , + [TEST_CPUS ] ="processors" , + [TEST_PLATFORM ] ="platform" , + [TEST_DEVICES ] ="devices" , + [TEST_FREEZER ] ="freezer" , +}; + +static ssize_t pm_test_show (struct kset *kset,char *buf) +{ +char *s = buf; +int level; + +for (level =TEST_FIRST ; level <=TEST_MAX ; level++) +if (pm_tests[level]) { +if (level == pm_test_level) + s +=sprintf (s,"[%s] " , pm_tests[level]); +else + s +=sprintf (s,"%s " , pm_tests[level]); + } + +if (s != buf) +/* convert the last space to a newline */ + *(s-1 ) ='\n' ; + +return (s - buf); +} + +static ssize_t pm_test_store (struct kset *kset,const char *buf,size_t n) +{ +const char *const *s; +int level; +char *p; +int len; +int error = -EINVAL ; + + p =memchr (buf,'\n' , n); + len = p ? p - buf : n; + +mutex_lock (&pm_mutex); + + level =TEST_FIRST ; +for (s = &pm_tests[level]; level <=TEST_MAX ; s++, level++) +if (*s && len ==strlen (*s) && !strncmp (buf, *s, len)) { + pm_test_level = level; + error =0 ; +break ; + } + +mutex_unlock (&pm_mutex); + +return error ? error : n; +} + +power_attr (pm_test); +#else /* !CONFIG_PM_DEBUG */ +static inline int suspend_test (int level) {return 0 ; } +#endif /* !CONFIG_PM_DEBUG */ + +#ifdef CONFIG_SUSPEND /* This is just an arbitrary number */
@@ -133,7 +207,10 @@ static int suspend_enter(suspend_state_tprintk (KERN_ERR "Some devices failed to power down\n" ); goto Done; } - error = suspend_ops->enter (state); + +if (!suspend_test (TEST_CORE )) + error = suspend_ops->enter (state); +device_power_up (); Done:arch_suspend_enable_irqs ();
@@ -164,16 +241,25 @@ int suspend_devices_and_enter(suspend_stprintk (KERN_ERR "Some devices failed to suspend\n" ); goto Resume_console; } + +if (suspend_test (TEST_DEVICES )) + goto Resume_devices; +if (suspend_ops->prepare) { error = suspend_ops->prepare ();if (error) goto Resume_devices; } + +if (suspend_test (TEST_PLATFORM )) + goto Finish; + error =disable_nonboot_cpus (); -if (!error) +if (!error && !suspend_test (TEST_CPUS ))suspend_enter (state);enable_nonboot_cpus (); + Finish:if (suspend_ops->finish) suspend_ops->finish (); Resume_devices:
@@ -240,12 +326,17 @@ static int enter_state(suspend_state_t sprintk ("done.\n" );pr_debug ("PM: Preparing system for %s sleep\n" , pm_states[state]); -if ((error =suspend_prepare ())) + error =suspend_prepare (); +if (error) goto Unlock; +if (suspend_test (TEST_FREEZER )) + goto Finish; +pr_debug ("PM: Entering %s sleep\n" , pm_states[state]); error =suspend_devices_and_enter (state); + Finish:pr_debug ("PM: Finishing wakeup.\n" );suspend_finish (); Unlock:
@@ -363,18 +454,18 @@ pm_trace_store(struct kset *kset, const }power_attr (pm_trace); +#endif /* CONFIG_PM_TRACE */ static struct attribute * g[] = { &state_attr.attr, +#ifdef CONFIG_PM_TRACE &pm_trace_attr.attr, +#endif +#ifdef CONFIG_PM_DEBUG + &pm_test_attr.attr, +#endifNULL , }; -#else -static struct attribute * g[] = { - &state_attr.attr, -NULL , -}; -#endif /* CONFIG_PM_TRACE */ static struct attribute_group attr_group = { .attrs = g,
kernel/power/power.h +18 -0
@@ -190,3 +190,21 @@ int restore_highmem(void);static inline unsigned int count_highmem_pages (void ) {return 0 ; }static inline int restore_highmem (void ) {return 0 ; }#endif + +/* +* Suspend test levels +*/ +enum { +/* keep first */ +TEST_NONE , +TEST_CORE , +TEST_CPUS , +TEST_PLATFORM , +TEST_DEVICES , +TEST_FREEZER , +/* keep last */ + __TEST_AFTER_LAST +}; + +#define TEST_FIRST TEST_NONE +#define TEST_MAX (__TEST_AFTER_LAST - 1)
PATCH 5/8 Hibernation: New testing facility (rev. 2)
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Make it possible to test the hibernation core code with the help of the /sys/power/pm_test attribute introduced for suspend testing in the previous patch.
Writing an appropriate string to this file causes the hibernation code to work in one of the test modes defined as follows:
freezer
- test the freezing of processes
devices
- test the freezing of processes and suspending of devices
platform
- test the freezing of processes, suspending of devices and platform global control methods(*)
processors
- test the freezing of processes, suspending of devices, platform global control methods(*) and the disabling of nonboot CPUs
core
- test the freezing of processes, suspending of devices, platform global control methods(*), the disabling of nonboot CPUs and suspending of platform/system devices
(*) - the platform global control methods are only available on ACPI systems and are only tested if the hibernation mode is set to "platform"
Then, if a hibernation is started by normal means, the hibernation core will perform its normal operations up to the point indicated by given test level. Next, it will wait for 5 seconds and carry out the resume operations needed to transition the system back to the fully functional state.
--- kernel/power/disk.c | 70 ++++++++++++++++++++++++++++++++++++++++----------- kernel/power/power.h | 2 + 2 files changed, 57 insertions(+), 15 deletions(-)
kernel/power/disk.c +55 -15
@@ -70,6 +70,35 @@ void hibernation_set_ops(struct platformmutex_unlock (&pm_mutex); } +#ifdef CONFIG_PM_DEBUG +static void hibernation_debug_sleep (void ) +{ +printk (KERN_INFO "hibernation debug: Waiting for 5 seconds.\n" ); +mdelay (5000 ); +} + +static int hibernation_testmode (int mode) +{ +if (hibernation_mode == mode) { +hibernation_debug_sleep (); +return 1 ; + } +return 0 ; +} + +static int hibernation_test (int level) +{ +if (pm_test_level == level) { +hibernation_debug_sleep (); +return 1 ; + } +return 0 ; +} +#else /* !CONFIG_PM_DEBUG */ +static int hibernation_testmode (int mode) {return 0 ; } +static int hibernation_test (int level) {return 0 ; } +#endif /* !CONFIG_PM_DEBUG */ +/** * platform_start - tell the platform driver that we're starting * hibernation
@@ -167,6 +196,10 @@ int create_image(int platform_mode) goto Enable_irqs; } +if (hibernation_test (TEST_CORE )) + goto Power_up; + + in_suspend =1 ;save_processor_state (); error =swsusp_arch_suspend ();if (error)
@@ -175,6 +208,7 @@ int create_image(int platform_mode)restore_processor_state ();if (!in_suspend)platform_leave (platform_mode); + Power_up:/* NOTE: device_power_up() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */
@@ -211,24 +245,29 @@ int hibernation_snapshot(int platform_moif (error) goto Resume_console; - error =platform_pre_snapshot (platform_mode); -if (error) +if (hibernation_test (TEST_DEVICES )) goto Resume_devices; + error =platform_pre_snapshot (platform_mode); +if (error ||hibernation_test (TEST_PLATFORM )) + goto Finish; + error =disable_nonboot_cpus ();if (!error) { -if (hibernation_mode !=HIBERNATION_TEST ) { - in_suspend =1 ; - error =create_image (platform_mode); -/* Control returns here after successful restore */ - }else { -printk ("swsusp debug: Waiting for 5 seconds.\n" ); -mdelay (5000 ); - } +if (hibernation_test (TEST_CPUS )) + goto Enable_cpus; + +if (hibernation_testmode (HIBERNATION_TEST )) + goto Enable_cpus; + + error =create_image (platform_mode); +/* Control returns here after successful restore */ } + Enable_cpus:enable_nonboot_cpus (); - Resume_devices: + Finish:platform_finish (platform_mode); + Resume_devices:device_resume (); Resume_console:resume_console ();
@@ -406,11 +445,12 @@ int hibernate(void)if (error) goto Finish; -if (hibernation_mode ==HIBERNATION_TESTPROC ) { -printk ("swsusp debug: Waiting for 5 seconds.\n" ); -mdelay (5000 ); +if (hibernation_test (TEST_FREEZER )) goto Thaw; - } + +if (hibernation_testmode (HIBERNATION_TESTPROC )) + goto Thaw; + error =hibernation_snapshot (hibernation_mode ==HIBERNATION_PLATFORM );if (in_suspend && !error) {unsigned int flags =0 ;
kernel/power/power.h +2 -0
@@ -208,3 +208,5 @@ enum {#define TEST_FIRST TEST_NONE#define TEST_MAX (__TEST_AFTER_LAST - 1) + +extern int pm_test_level;
-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 5/8 Hibernation: New testing facility (rev. 2)
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Make it possible to test the hibernation core code with the help of the /sys/power/pm_test attribute introduced for suspend testing in the previous patch.
Writing an appropriate string to this file causes the hibernation code to work in one of the test modes defined as follows:
freezer
- test the freezing of processes
devices
- test the freezing of processes and suspending of devices
platform
- test the freezing of processes, suspending of devices and platform global control methods(*)
processors
- test the freezing of processes, suspending of devices, platform global control methods(*) and the disabling of nonboot CPUs
core
- test the freezing of processes, suspending of devices, platform global control methods(*), the disabling of nonboot CPUs and suspending of platform/system devices
(*) - the platform global control methods are only available on ACPI systems and are only tested if the hibernation mode is set to "platform"
Then, if a hibernation is started by normal means, the hibernation core will perform its normal operations up to the point indicated by given test level. Next, it will wait for 5 seconds and carry out the resume operations needed to transition the system back to the fully functional state.
--- kernel/power/disk.c | 70 ++++++++++++++++++++++++++++++++++++++++----------- kernel/power/power.h | 2 + 2 files changed, 57 insertions(+), 15 deletions(-)
kernel/power/disk.c +55 -15
@@ -70,6 +70,35 @@ void hibernation_set_ops(struct platformmutex_unlock (&pm_mutex); } +#ifdef CONFIG_PM_DEBUG +static void hibernation_debug_sleep (void ) +{ +printk (KERN_INFO "hibernation debug: Waiting for 5 seconds.\n" ); +mdelay (5000 ); +} + +static int hibernation_testmode (int mode) +{ +if (hibernation_mode == mode) { +hibernation_debug_sleep (); +return 1 ; + } +return 0 ; +} + +static int hibernation_test (int level) +{ +if (pm_test_level == level) { +hibernation_debug_sleep (); +return 1 ; + } +return 0 ; +} +#else /* !CONFIG_PM_DEBUG */ +static int hibernation_testmode (int mode) {return 0 ; } +static int hibernation_test (int level) {return 0 ; } +#endif /* !CONFIG_PM_DEBUG */ +/** * platform_start - tell the platform driver that we're starting * hibernation
@@ -167,6 +196,10 @@ int create_image(int platform_mode) goto Enable_irqs; } +if (hibernation_test (TEST_CORE )) + goto Power_up; + + in_suspend =1 ;save_processor_state (); error =swsusp_arch_suspend ();if (error)
@@ -175,6 +208,7 @@ int create_image(int platform_mode)restore_processor_state ();if (!in_suspend)platform_leave (platform_mode); + Power_up:/* NOTE: device_power_up() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */
@@ -211,24 +245,29 @@ int hibernation_snapshot(int platform_moif (error) goto Resume_console; - error =platform_pre_snapshot (platform_mode); -if (error) +if (hibernation_test (TEST_DEVICES )) goto Resume_devices; + error =platform_pre_snapshot (platform_mode); +if (error ||hibernation_test (TEST_PLATFORM )) + goto Finish; + error =disable_nonboot_cpus ();if (!error) { -if (hibernation_mode !=HIBERNATION_TEST ) { - in_suspend =1 ; - error =create_image (platform_mode); -/* Control returns here after successful restore */ - }else { -printk ("swsusp debug: Waiting for 5 seconds.\n" ); -mdelay (5000 ); - } +if (hibernation_test (TEST_CPUS )) + goto Enable_cpus; + +if (hibernation_testmode (HIBERNATION_TEST )) + goto Enable_cpus; + + error =create_image (platform_mode); +/* Control returns here after successful restore */ } + Enable_cpus:enable_nonboot_cpus (); - Resume_devices: + Finish:platform_finish (platform_mode); + Resume_devices:device_resume (); Resume_console:resume_console ();
@@ -406,11 +445,12 @@ int hibernate(void)if (error) goto Finish; -if (hibernation_mode ==HIBERNATION_TESTPROC ) { -printk ("swsusp debug: Waiting for 5 seconds.\n" ); -mdelay (5000 ); +if (hibernation_test (TEST_FREEZER )) goto Thaw; - } + +if (hibernation_testmode (HIBERNATION_TESTPROC )) + goto Thaw; + error =hibernation_snapshot (hibernation_mode ==HIBERNATION_PLATFORM );if (in_suspend && !error) {unsigned int flags =0 ;
kernel/power/power.h +2 -0
@@ -208,3 +208,5 @@ enum {#define TEST_FIRST TEST_NONE#define TEST_MAX (__TEST_AFTER_LAST - 1) + +extern int pm_test_level;
PATCH 6/8 PM: Suspend/hibernation debug documentation update (rev. 2)
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Update the suspend/hibernation debugging and testing documentation to describe the newly introduced testing facilities.
--- Documentation/power/basic-pm-debugging.txt | 212 +++++++++++++++++++++-------- Documentation/power/drivers-testing.txt | 30 ++-- 2 files changed, 172 insertions(+), 70 deletions(-)
Documentation/power/drivers-testing.txt +17 -13
@@ -6,9 +6,9 @@ Testing suspend and resume support in de Unfortunately, to effectively test the support for the system-wide suspend and resume transitions in a driver, it is necessary to suspend and resume a fully functional system with this driver loaded. Moreover, that should be done -several times, preferably several times in a row, and separately for the suspend -to disk (STD) and the suspend to RAM (STR) transitions, because each of these -cases involves different ordering of operations and different interactions with +several times, preferably several times in a row, and separately for hibernation +(aka suspend to disk or STD) and suspend to RAM (STR), because each of these +cases involves slightly different operations and different interactions with the machine's BIOS. Of course, for this purpose the test system has to be known to suspend and
@@ -22,20 +22,24 @@ for more information about the debugging Once you have resolved the suspend/resume-related problems with your test system without the new driver, you are ready to test it: -a) Build the driver as a module, load it and try the STD in the test mode (see: -Documents/power/basic-pm-debugging.txt, 1a)). +a) Build the driver as a module, load it and try the test modes of hibernation + (see: Documents/power/basic-pm-debugging.txt, 1). -b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown" -and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1). +b) Load the driver and attempt to hibernate in the "reboot", "shutdown" and + "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1). -c) Compile the driver directly into the kernel and try the STD in the test mode. +c) Compile the driver directly into the kernel and try the test modes of + hibernation. -d) Attempt to suspend to disk with the driver compiled directly into the kernel -in the "reboot", "shutdown" and "platform" modes. +d) Attempt to hibernate with the driver compiled directly into the kernel + in the "reboot", "shutdown" and "platform" modes. -e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see: -Documents/power/basic-pm-debugging.txt, 2). As far as the STR tests are -concerned, it should not matter whether or not the driver is built as a module. +e) Try the test modes of suspend (see: Documents/power/basic-pm-debugging.txt, + 2). [As far as the STR tests are concerned, it should not matter whether or + not the driver is built as a module.] + +f) Attempt to suspend to RAM using the s2ram tool with the driver loaded + (see: Documents/power/basic-pm-debugging.txt, 2). Each of the above tests should be repeated several times and the STD tests should be mixed with the STR tests. If any of them fails, the driver cannot be
Documentation/power/basic-pm-debugging.txt +155 -57
258 lines not on this page · raw message
PATCH 6/8 PM: Suspend/hibernation debug documentation update (rev. 2)
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Update the suspend/hibernation debugging and testing documentation to describe the newly introduced testing facilities.
--- Documentation/power/basic-pm-debugging.txt | 212 +++++++++++++++++++++-------- Documentation/power/drivers-testing.txt | 30 ++-- 2 files changed, 172 insertions(+), 70 deletions(-)
Documentation/power/drivers-testing.txt +17 -13
@@ -6,9 +6,9 @@ Testing suspend and resume support in de Unfortunately, to effectively test the support for the system-wide suspend and resume transitions in a driver, it is necessary to suspend and resume a fully functional system with this driver loaded. Moreover, that should be done -several times, preferably several times in a row, and separately for the suspend -to disk (STD) and the suspend to RAM (STR) transitions, because each of these -cases involves different ordering of operations and different interactions with +several times, preferably several times in a row, and separately for hibernation +(aka suspend to disk or STD) and suspend to RAM (STR), because each of these +cases involves slightly different operations and different interactions with the machine's BIOS. Of course, for this purpose the test system has to be known to suspend and
@@ -22,20 +22,24 @@ for more information about the debugging Once you have resolved the suspend/resume-related problems with your test system without the new driver, you are ready to test it: -a) Build the driver as a module, load it and try the STD in the test mode (see: -Documents/power/basic-pm-debugging.txt, 1a)). +a) Build the driver as a module, load it and try the test modes of hibernation + (see: Documents/power/basic-pm-debugging.txt, 1). -b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown" -and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1). +b) Load the driver and attempt to hibernate in the "reboot", "shutdown" and + "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1). -c) Compile the driver directly into the kernel and try the STD in the test mode. +c) Compile the driver directly into the kernel and try the test modes of + hibernation. -d) Attempt to suspend to disk with the driver compiled directly into the kernel -in the "reboot", "shutdown" and "platform" modes. +d) Attempt to hibernate with the driver compiled directly into the kernel + in the "reboot", "shutdown" and "platform" modes. -e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see: -Documents/power/basic-pm-debugging.txt, 2). As far as the STR tests are -concerned, it should not matter whether or not the driver is built as a module. +e) Try the test modes of suspend (see: Documents/power/basic-pm-debugging.txt, + 2). [As far as the STR tests are concerned, it should not matter whether or + not the driver is built as a module.] + +f) Attempt to suspend to RAM using the s2ram tool with the driver loaded + (see: Documents/power/basic-pm-debugging.txt, 2). Each of the above tests should be repeated several times and the STD tests should be mixed with the STR tests. If any of them fails, the driver cannot be
Documentation/power/basic-pm-debugging.txt +155 -57
258 lines not on this page · raw message
PATCH 7/8 PM: Make PM_TRACE more architecture independent
In reply to Rafael J. WysockiFrom: Johannes Berg <[email protected]>
When trying to debug a suspend failure I started implementing PM_TRACE for powerpc. I then noticed that I'm debugging a suspend failure and so PM_TRACE isn't useful at all, but thought that nonetheless this could be useful in the future.
Basically, to support PM_TRACE, you add a Kconfig option that selects PM_TRACE and provides the infrastructure as per the help text of PM_TRACE.
--- drivers/base/power/Makefile | 2 +- kernel/power/Kconfig | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-)
drivers/base/power/Makefile +1 -1
@@ -1,7 +1,7 @@ obj-y := shutdown.o obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o -obj-$(CONFIG_PM_TRACE) += trace.o +obj-$(CONFIG_PM_TRACE_RTC) += trace.o ifeq ($(CONFIG_DEBUG_DRIVER),y) EXTRA_CFLAGS += -DDEBUG
kernel/power/Kconfig +22 -1
@@ -44,9 +44,30 @@ config PM_VERBOSE ---help--- This option enables verbose messages from the Power Management code. +config CAN_PM_TRACE + def_bool y + depends on PM_DEBUG && PM_SLEEP && EXPERIMENTAL + config PM_TRACE + bool + help + This enables code to save the last PM event point across + reboot. The architecture needs to support this, x86 for + example does by saving things in the RTC, see below. + + The architecture specific code must provide the extern + functions from <linux/resume-trace.h> as well as the + <asm/resume-trace.h> header with a TRACE_RESUME() macro. + + The way the information is presented is architecture- + dependent, x86 will print the information during a + late_initcall. + +config PM_TRACE_RTC bool "Suspend/resume event tracing" - depends on PM_DEBUG && X86 && PM_SLEEP && EXPERIMENTAL + depends on CAN_PM_TRACE + depends on X86 + select PM_TRACE default n ---help--- This enables some cheesy code to save the last PM event point in the
PATCH 7/8 PM: Make PM_TRACE more architecture independent
In reply to Rafael J. WysockiFrom: Johannes Berg <[email protected]>
When trying to debug a suspend failure I started implementing PM_TRACE for powerpc. I then noticed that I'm debugging a suspend failure and so PM_TRACE isn't useful at all, but thought that nonetheless this could be useful in the future.
Basically, to support PM_TRACE, you add a Kconfig option that selects PM_TRACE and provides the infrastructure as per the help text of PM_TRACE.
--- drivers/base/power/Makefile | 2 +- kernel/power/Kconfig | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-)
drivers/base/power/Makefile +1 -1
@@ -1,7 +1,7 @@ obj-y := shutdown.o obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o -obj-$(CONFIG_PM_TRACE) += trace.o +obj-$(CONFIG_PM_TRACE_RTC) += trace.o ifeq ($(CONFIG_DEBUG_DRIVER),y) EXTRA_CFLAGS += -DDEBUG
kernel/power/Kconfig +22 -1
@@ -44,9 +44,30 @@ config PM_VERBOSE ---help--- This option enables verbose messages from the Power Management code. +config CAN_PM_TRACE + def_bool y + depends on PM_DEBUG && PM_SLEEP && EXPERIMENTAL + config PM_TRACE + bool + help + This enables code to save the last PM event point across + reboot. The architecture needs to support this, x86 for + example does by saving things in the RTC, see below. + + The architecture specific code must provide the extern + functions from <linux/resume-trace.h> as well as the + <asm/resume-trace.h> header with a TRACE_RESUME() macro. + + The way the information is presented is architecture- + dependent, x86 will print the information during a + late_initcall. + +config PM_TRACE_RTC bool "Suspend/resume event tracing" - depends on PM_DEBUG && X86 && PM_SLEEP && EXPERIMENTAL + depends on CAN_PM_TRACE + depends on X86 + select PM_TRACE default n ---help--- This enables some cheesy code to save the last PM event point in the
PATCH 8/8 PM: Convert PM notifiers to out-of-line code
In reply to Rafael J. WysockiFrom: Alan Stern <[email protected]>
This patch (as1008b) converts the PM notifier routines from inline calls to out-of-line code. It also prevents pm_chain_head from being created when CONFIG_PM_SLEEP isn't enabled, and EXPORTs the notifier registration and unregistration routines.
--- include/linux/suspend.h | 13 ++----------- kernel/power/main.c | 28 ++++++++++++++++++++++++++-- kernel/power/power.h | 12 ++++-------- 3 files changed, 32 insertions(+), 21 deletions(-)
include/linux/suspend.h +2 -11
@@ -216,17 +216,8 @@ void __save_processor_state(struct savedvoid __restore_processor_state (struct saved_context *ctxt);/* kernel/power/main.c */ -extern struct blocking_notifier_head pm_chain_head; - -static inline int register_pm_notifier (struct notifier_block *nb) -{ -return blocking_notifier_chain_register (&pm_chain_head, nb); -} - -static inline int unregister_pm_notifier (struct notifier_block *nb) -{ -return blocking_notifier_chain_unregister (&pm_chain_head, nb); -} +extern int register_pm_notifier (struct notifier_block *nb); +extern int unregister_pm_notifier (struct notifier_block *nb);#define pm_notifier (fn, pri) { \ static struct notifier_block fn##_nb = \
kernel/power/main.c +26 -2
@@ -24,10 +24,34 @@#include "power.h" -BLOCKING_NOTIFIER_HEAD (pm_chain_head); -DEFINE_MUTEX (pm_mutex); +#ifdef CONFIG_PM_SLEEP + +/* Routines for PM-transition notifications */ + +static BLOCKING_NOTIFIER_HEAD (pm_chain_head); + +int register_pm_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_register (&pm_chain_head, nb); +} +EXPORT_SYMBOL_GPL (register_pm_notifier); + +int unregister_pm_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_unregister (&pm_chain_head, nb); +} +EXPORT_SYMBOL_GPL (unregister_pm_notifier); + +int pm_notifier_call_chain (unsigned long val) +{ +return (blocking_notifier_call_chain (&pm_chain_head, val,NULL ) + ==NOTIFY_BAD ) ? -EINVAL :0 ; +} + +#endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM_DEBUG int pm_test_level =TEST_NONE ;
kernel/power/power.h +4 -8
@@ -174,14 +174,10 @@ static inline int suspend_devices_and_en }#endif /* !CONFIG_SUSPEND */ -/* kernel/power/common.c */ -extern struct blocking_notifier_head pm_chain_head; - -static inline int pm_notifier_call_chain (unsigned long val) -{ -return (blocking_notifier_call_chain (&pm_chain_head, val,NULL ) - ==NOTIFY_BAD ) ? -EINVAL :0 ; -} +#ifdef CONFIG_PM_SLEEP +/* kernel/power/main.c */ +extern int pm_notifier_call_chain (unsigned long val); +#endif #ifdef CONFIG_HIGHMEM unsigned int count_highmem_pages (void );
PATCH 8/8 PM: Convert PM notifiers to out-of-line code
In reply to Rafael J. WysockiFrom: Alan Stern <[email protected]>
This patch (as1008b) converts the PM notifier routines from inline calls to out-of-line code. It also prevents pm_chain_head from being created when CONFIG_PM_SLEEP isn't enabled, and EXPORTs the notifier registration and unregistration routines.
--- include/linux/suspend.h | 13 ++----------- kernel/power/main.c | 28 ++++++++++++++++++++++++++-- kernel/power/power.h | 12 ++++-------- 3 files changed, 32 insertions(+), 21 deletions(-)
include/linux/suspend.h +2 -11
@@ -216,17 +216,8 @@ void __save_processor_state(struct savedvoid __restore_processor_state (struct saved_context *ctxt);/* kernel/power/main.c */ -extern struct blocking_notifier_head pm_chain_head; - -static inline int register_pm_notifier (struct notifier_block *nb) -{ -return blocking_notifier_chain_register (&pm_chain_head, nb); -} - -static inline int unregister_pm_notifier (struct notifier_block *nb) -{ -return blocking_notifier_chain_unregister (&pm_chain_head, nb); -} +extern int register_pm_notifier (struct notifier_block *nb); +extern int unregister_pm_notifier (struct notifier_block *nb);#define pm_notifier (fn, pri) { \ static struct notifier_block fn##_nb = \
kernel/power/main.c +26 -2
@@ -24,10 +24,34 @@#include "power.h" -BLOCKING_NOTIFIER_HEAD (pm_chain_head); -DEFINE_MUTEX (pm_mutex); +#ifdef CONFIG_PM_SLEEP + +/* Routines for PM-transition notifications */ + +static BLOCKING_NOTIFIER_HEAD (pm_chain_head); + +int register_pm_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_register (&pm_chain_head, nb); +} +EXPORT_SYMBOL_GPL (register_pm_notifier); + +int unregister_pm_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_unregister (&pm_chain_head, nb); +} +EXPORT_SYMBOL_GPL (unregister_pm_notifier); + +int pm_notifier_call_chain (unsigned long val) +{ +return (blocking_notifier_call_chain (&pm_chain_head, val,NULL ) + ==NOTIFY_BAD ) ? -EINVAL :0 ; +} + +#endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM_DEBUG int pm_test_level =TEST_NONE ;
kernel/power/power.h +4 -8
@@ -174,14 +174,10 @@ static inline int suspend_devices_and_en }#endif /* !CONFIG_SUSPEND */ -/* kernel/power/common.c */ -extern struct blocking_notifier_head pm_chain_head; - -static inline int pm_notifier_call_chain (unsigned long val) -{ -return (blocking_notifier_call_chain (&pm_chain_head, val,NULL ) - ==NOTIFY_BAD ) ? -EINVAL :0 ; -} +#ifdef CONFIG_PM_SLEEP +/* kernel/power/main.c */ +extern int pm_notifier_call_chain (unsigned long val); +#endif #ifdef CONFIG_HIGHMEM unsigned int count_highmem_pages (void );
Len Brown
reviewerthanks for re-sending, Rafael.
I've created a new "suspend" branch -- currently rooted on Linus' latest.
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git suspend
I've re-based the older hibernate patches onto the new branch, and added the batch you just sent.
Note that the suspend branch is included in my test branch, which akpm pulls into -mm.
-Len
Quoted 12 lines · Rafael J. Wysocki
Hi Len,
I've already sent all of the following patches to you, but you haven't picked them up yet, so here they go again in one pack (with missing ACKs added here and there).
I'm considering all of them as 2.6.25 material, so please add them to the suspend branch.
Thanks,
Rafael
Len Brown
reviewerthanks for re-sending, Rafael.
I've created a new "suspend" branch -- currently rooted on Linus' latest.
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git suspend
I've re-based the older hibernate patches onto the new branch, and added the batch you just sent.
Note that the suspend branch is included in my test branch, which akpm pulls into -mm.
-Len
Quoted 12 lines · Rafael J. Wysocki
Hi Len,
I've already sent all of the following patches to you, but you haven't picked them up yet, so here they go again in one pack (with missing ACKs added here and there).
I'm considering all of them as 2.6.25 material, so please add them to the suspend branch.
Thanks,
Rafael
Quoted 5 lines · Len Brown
thanks for re-sending, Rafael.
I've created a new "suspend" branch -- currently rooted on Linus' latest.
Quoted 7 lines
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.gitsuspendI've re-based the older hibernate patches onto the new branch, and added the batch you just sent.
Note that the suspend branch is included in my test branch, which akpm pulls into -mm.
Thanks for all that!
I'm now seeing the suspend branch on gitweb, but when I do
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
I get a repository with only one branch which is "test" and indeed .git/refs/heads contains this one only. What should I do to get the suspend branch (and the others) too with git clone (or git fetch)?
Rafael
Len Brown
reviewerQuoted 16 lines · Rafael J. Wysocki
Quoted 5 lines · Len Brown
thanks for re-sending, Rafael.
I've created a new "suspend" branch -- currently rooted on Linus' latest.
Quoted 7 lines
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.gitsuspendI've re-based the older hibernate patches onto the new branch, and added the batch you just sent.
Note that the suspend branch is included in my test branch, which akpm pulls into -mm.
Thanks for all that!
Quoted 7 lines
I'm now seeing the suspend branch on gitweb, but when I do
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6I get a repository with only one branch which is "test" and indeed .git/refs/heads contains this one only. What should I do to get the suspend branch (and the others) too with git clone (or git fetch)?
per http://www.lesswatts.org/projects/acpi/git.php
$ git branch -r
to see the branches
$ git checkout -b origin/suspend
to get onto that particular branch.
cheers,
-Len
Len Brown
reviewerQuoted 16 lines · Rafael J. Wysocki
Quoted 5 lines · Len Brown
thanks for re-sending, Rafael.
I've created a new "suspend" branch -- currently rooted on Linus' latest.
Quoted 7 lines
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.gitsuspendI've re-based the older hibernate patches onto the new branch, and added the batch you just sent.
Note that the suspend branch is included in my test branch, which akpm pulls into -mm.
Thanks for all that!
Quoted 7 lines
I'm now seeing the suspend branch on gitweb, but when I do
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6I get a repository with only one branch which is "test" and indeed .git/refs/heads contains this one only. What should I do to get the suspend branch (and the others) too with git clone (or git fetch)?
per http://www.lesswatts.org/projects/acpi/git.php
$ git branch -r
to see the branches
$ git checkout -b origin/suspend
to get onto that particular branch.
cheers,
-Len
Quoted 5 lines · Len Brown
thanks for re-sending, Rafael.
I've created a new "suspend" branch -- currently rooted on Linus' latest.
Quoted 7 lines
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.gitsuspendI've re-based the older hibernate patches onto the new branch, and added the batch you just sent.
Note that the suspend branch is included in my test branch, which akpm pulls into -mm.
Thanks for all that!
I'm now seeing the suspend branch on gitweb, but when I do
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
I get a repository with only one branch which is "test" and indeed .git/refs/heads contains this one only. What should I do to get the suspend branch (and the others) too with git clone (or git fetch)?
Rafael