Hibernate: Handle ACPI NVS memory as required by the spec
Subsystems (5)
cover Hibernate: Handle ACPI NVS memory as required by the spec
Hi,
I have recently tried to rebase the Zhang Rui's patches making the Linux hibernation code handle the ACPI NVS memory as required by the spec, but I found that they didn't work on x86_64 boxes where the NVS region was located behind the last usable PFN. Also, I decided to put the memory management part into the hibernation core rather than into drivers/acpi/sleep/main.c .
As a result, I have obtained the following patch series. Please review and if it looks good, please queue in the 'suspend' branch as .29 material.
Thanks,
Rafael
PATCH 1/4 Hibernate: Call platform_begin before swsusp_shrink_memory
From: Zhang Rui <[email protected]>
Hibernate: Call platform_begin before swsusp_shrink_memory
Call platform_begin() before swsusp_shrink_memory() so that we can always allocate enough memory to save the ACPI NVS region from platform_begin().
--- kernel/power/disk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/power/disk.c +3 -3
@@ -267,12 +267,12 @@ int hibernation_snapshot(int platform_mo {int error, ftrace_save; -/* Free memory before shutting down devices. */ - error =swsusp_shrink_memory (); + error =platform_begin (platform_mode);if (error)return error; - error =platform_begin (platform_mode); +/* Free memory before shutting down devices. */ + error =swsusp_shrink_memory ();if (error) goto Close;
PATCH 1/4 Hibernate: Call platform_begin before swsusp_shrink_memory
In reply to Rafael J. WysockiFrom: Zhang Rui <[email protected]>
Hibernate: Call platform_begin before swsusp_shrink_memory
Call platform_begin() before swsusp_shrink_memory() so that we can always allocate enough memory to save the ACPI NVS region from platform_begin().
--- kernel/power/disk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/power/disk.c +3 -3
@@ -267,12 +267,12 @@ int hibernation_snapshot(int platform_mo {int error, ftrace_save; -/* Free memory before shutting down devices. */ - error =swsusp_shrink_memory (); + error =platform_begin (platform_mode);if (error)return error; - error =platform_begin (platform_mode); +/* Free memory before shutting down devices. */ + error =swsusp_shrink_memory ();if (error) goto Close;
Re: [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory
Hi.
Quoted 24 lines · Rafael J. Wysocki
From: Zhang Rui <[email protected]>
Hibernate: Call
platform_beginbeforeswsusp_shrink_memoryCall
platform_begin()beforeswsusp_shrink_memory()so that we can always allocate enough memory to save the ACPI NVS region fromplatform_begin().Signed-off-by Zhang Rui <[email protected]>Signed-off-by Rafael J. Wysocki <[email protected]>--- kernel/power/disk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)Index:
linux-2.6/kernel/power/disk.c
===================================================================kernel/power/disk.c +0
-2@@ -267,12 +267,12 @@ int hibernation_snapshot(int platform_mo {int error, ftrace_save; -/* Free memory before shutting down devices. */ - error =swsusp_shrink_memory ();
kernel/power/disk.c int hibernation_snapshot(int platform_mo · line 278
Quoted 10 lines
kernel/power/disk.c +3
-1+ error =platform_begin (platform_mode);if (error)return error; - error =platform_begin (platform_mode); +/* Free memory before shutting down devices. */ + error =swsusp_shrink_memory ();if (error) goto Close;
Re: [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory
In reply to Rafael J. WysockiQuoted 10 lines · Rafael J. Wysocki
From: Zhang Rui <[email protected]>
Hibernate: Call
platform_beginbeforeswsusp_shrink_memoryCall
platform_begin()beforeswsusp_shrink_memory()so that we can always allocate enough memory to save the ACPI NVS region fromplatform_begin().Signed-off-by Zhang Rui <[email protected]>Signed-off-by Rafael J. Wysocki <[email protected]>
ACK.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory
In reply to Rafael J. WysockiQuoted 10 lines · Rafael J. Wysocki
From: Zhang Rui <[email protected]>
Hibernate: Call
platform_beginbeforeswsusp_shrink_memoryCall
platform_begin()beforeswsusp_shrink_memory()so that we can always allocate enough memory to save the ACPI NVS region fromplatform_begin().Signed-off-by Zhang Rui <[email protected]>Signed-off-by Rafael J. Wysocki <[email protected]>
ACK.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH 2/4 ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the _PTS control method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the _WAK control method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.
Based on a patch by Zhang Rui.
--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)
drivers/acpi/sleep/main.c +43 -7
@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )
@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/*
@@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )
@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,
@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }
@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,
include/linux/suspend.h +13 -0
@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}
@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP
kernel/power/swsusp.c +121 -0
124 lines not on this page · raw message
--
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
Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
Hi.
Quoted 210 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +43
-7@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/* @@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,Index:
linux-2.6/include/linux/suspend.h
===================================================================include/linux/suspend.h +13
-0@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +50
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +}; + +static LIST_HEAD (nvs_list); + +/** +* hibernate_nvs_register - register platform NVS memory region to save +* @start - physical address of the region +* @size - size of the region +* +* The NVS region need not be page-aligned (both ends) and we arrange +* things so that the data from page-aligned addresses in this region will +* be copied into separate RAM pages. +*/ +int hibernate_nvs_register (unsigned long start,unsigned long size) +{ +struct nvs_page *entry, *next; + +while (size >0 ) { +unsigned int nr_bytes; + + entry =kzalloc (sizeof (struct nvs_page ),GFP_KERNEL ); +if (!entry) + goto Error; + +list_add_tail (&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes =PAGE_SIZE - (start & ~PAGE_MASK ); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } +return 0 ; + + Error: +list_for_each_entry_safe (entry, next, &nvs_list, node) { +list_del (&entry->node);
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 324
Quoted 10 lines
kernel/power/swsusp.c +10
-0+kfree (entry); + } +return -ENOMEM ; +} + +/** +* hibernate_nvs_free - free data pages allocated for saving NVS regions +* +* It is allowed to call this function many times in a row. +*/
If this one is safe for multiple calls, should nvs_alloc be safe for multiple calls too? Or, conversely, is something funny going on such that hibernate_nvs_free needs to be safe for multiple calls?
Quoted 35 lines
kernel/power/swsusp.c +35
-0+void hibernate_nvs_free (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { +free_page ((unsigned long )entry->data); + entry->data =NULL ; +if (entry->kaddr) { +iounmap (entry->kaddr); + entry->kaddr =NULL ; + } + } +} + +/** +* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions +*/ +int hibernate_nvs_alloc (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) { + entry->data = (void *)__get_free_page (GFP_KERNEL ); +if (!entry->data) { +hibernate_nvs_free (); +return -ENOMEM ; + } + } +return 0 ; +} + +/** +* hibernate_nvs_save - save NVS memory regions +*/
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 369
Quoted 10 lines
kernel/power/swsusp.c +10
-0+void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size);
Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Quoted 6 lines
kernel/power/swsusp.c +6
-0+ } +} + +/** +* hibernate_nvs_restore - restore NVS memory regions +*/
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 385
Quoted 10 lines
kernel/power/swsusp.c +10
-0+void hibernate_nvs_restore (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Restoring platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) +memcpy (entry->kaddr, entry->data, entry->size); +}
Regards,
Nigel
_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm
Re: [linux-pm] [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Rafael J. WysockiHi.
Quoted 210 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +43
-7@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/* @@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,Index:
linux-2.6/include/linux/suspend.h
===================================================================include/linux/suspend.h +13
-0@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +50
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +}; + +static LIST_HEAD (nvs_list); + +/** +* hibernate_nvs_register - register platform NVS memory region to save +* @start - physical address of the region +* @size - size of the region +* +* The NVS region need not be page-aligned (both ends) and we arrange +* things so that the data from page-aligned addresses in this region will +* be copied into separate RAM pages. +*/ +int hibernate_nvs_register (unsigned long start,unsigned long size) +{ +struct nvs_page *entry, *next; + +while (size >0 ) { +unsigned int nr_bytes; + + entry =kzalloc (sizeof (struct nvs_page ),GFP_KERNEL ); +if (!entry) + goto Error; + +list_add_tail (&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes =PAGE_SIZE - (start & ~PAGE_MASK ); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } +return 0 ; + + Error: +list_for_each_entry_safe (entry, next, &nvs_list, node) { +list_del (&entry->node);
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 324
Quoted 10 lines
kernel/power/swsusp.c +10
-0+kfree (entry); + } +return -ENOMEM ; +} + +/** +* hibernate_nvs_free - free data pages allocated for saving NVS regions +* +* It is allowed to call this function many times in a row. +*/
If this one is safe for multiple calls, should nvs_alloc be safe for multiple calls too? Or, conversely, is something funny going on such that hibernate_nvs_free needs to be safe for multiple calls?
Quoted 35 lines
kernel/power/swsusp.c +35
-0+void hibernate_nvs_free (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { +free_page ((unsigned long )entry->data); + entry->data =NULL ; +if (entry->kaddr) { +iounmap (entry->kaddr); + entry->kaddr =NULL ; + } + } +} + +/** +* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions +*/ +int hibernate_nvs_alloc (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) { + entry->data = (void *)__get_free_page (GFP_KERNEL ); +if (!entry->data) { +hibernate_nvs_free (); +return -ENOMEM ; + } + } +return 0 ; +} + +/** +* hibernate_nvs_save - save NVS memory regions +*/
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 369
Quoted 10 lines
kernel/power/swsusp.c +10
-0+void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size);
Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Quoted 6 lines
kernel/power/swsusp.c +6
-0+ } +} + +/** +* hibernate_nvs_restore - restore NVS memory regions +*/
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 385
Quoted 10 lines
kernel/power/swsusp.c +10
-0+void hibernate_nvs_restore (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Restoring platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) +memcpy (entry->kaddr, entry->data, entry->size); +}
Regards,
Nigel
--
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
Re: [linux-pm] [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
Quoted 1 line · Nigel Cunningham
Hi.
Hi,
Quoted 217 lines · Rafael J. Wysocki
Quoted 216 lines
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +43
-7@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/* @@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,Index:
linux-2.6/include/linux/suspend.h
===================================================================include/linux/suspend.h +13
-0@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +56
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +}; + +static LIST_HEAD (nvs_list); + +/** +* hibernate_nvs_register - register platform NVS memory region to save +* @start - physical address of the region +* @size - size of the region +* +* The NVS region need not be page-aligned (both ends) and we arrange +* things so that the data from page-aligned addresses in this region will +* be copied into separate RAM pages. +*/ +int hibernate_nvs_register (unsigned long start,unsigned long size) +{ +struct nvs_page *entry, *next; + +while (size >0 ) { +unsigned int nr_bytes; + + entry =kzalloc (sizeof (struct nvs_page ),GFP_KERNEL ); +if (!entry) + goto Error; + +list_add_tail (&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes =PAGE_SIZE - (start & ~PAGE_MASK ); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } +return 0 ; + + Error: +list_for_each_entry_safe (entry, next, &nvs_list, node) { +list_del (&entry->node); +kfree (entry); + } +return -ENOMEM ; +} + +/**
Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 324
Quoted 4 lines
kernel/power/swsusp.c +4
-0+* hibernate_nvs_free - free data pages allocated for saving NVS regions +* +* It is allowed to call this function many times in a row. +*/ If this one is safe for multiple calls, should
nvs_allocbe safe for multiple calls too? Or, conversely, is something funny going on such thathibernate_nvs_freeneeds to be safe for multiple calls?
I thought it would be necessary to call that additionally from platform_end() for the error path in which platform_pre_snapshot() fails, but that doesn't seem to be the case. It doesn't hurt to keep it in this form, though, IMO.
Quoted 41 lines
Quoted 41 lines
kernel/power/swsusp.c +41
-0+void hibernate_nvs_free (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { +free_page ((unsigned long )entry->data); + entry->data =NULL ; +if (entry->kaddr) { +iounmap (entry->kaddr); + entry->kaddr =NULL ; + } + } +} + +/** +* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions +*/ +int hibernate_nvs_alloc (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) { + entry->data = (void *)__get_free_page (GFP_KERNEL ); +if (!entry->data) { +hibernate_nvs_free (); +return -ENOMEM ; + } + } +return 0 ; +} + +/** +* hibernate_nvs_save - save NVS memory regions +*/ +void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); +
Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 369
Quoted 4 lines
kernel/power/swsusp.c +4
-0+list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size);Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Ah, this one is tricky. We cannot unmap from atomic context. :-)
Quoted 8 lines
Quoted 8 lines
kernel/power/swsusp.c +8
-0+ } +} + +/** +* hibernate_nvs_restore - restore NVS memory regions +*/ +void hibernate_nvs_restore (void ) +{
Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 385
Quoted 8 lines
kernel/power/swsusp.c +8
-0+struct nvs_page *entry; + +printk (KERN_INFO "PM: Restoring platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) +memcpy (entry->kaddr, entry->data, entry->size); +}
Thanks,
Rafael
--
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
Nigel Cunningham
Acked-byRe: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
Hi.
Quoted 231 lines · Rafael J. Wysocki
Quoted 1 line · Nigel Cunningham
Hi.
Hi,
Quoted 217 lines · Rafael J. Wysocki
Quoted 216 lines
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +43
-7@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/* @@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,Index:
linux-2.6/include/linux/suspend.h
===================================================================include/linux/suspend.h +13
-0@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +56
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +}; + +static LIST_HEAD (nvs_list); + +/** +* hibernate_nvs_register - register platform NVS memory region to save +* @start - physical address of the region +* @size - size of the region +* +* The NVS region need not be page-aligned (both ends) and we arrange +* things so that the data from page-aligned addresses in this region will +* be copied into separate RAM pages. +*/ +int hibernate_nvs_register (unsigned long start,unsigned long size) +{ +struct nvs_page *entry, *next; + +while (size >0 ) { +unsigned int nr_bytes; + + entry =kzalloc (sizeof (struct nvs_page ),GFP_KERNEL ); +if (!entry) + goto Error; + +list_add_tail (&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes =PAGE_SIZE - (start & ~PAGE_MASK ); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } +return 0 ; + + Error: +list_for_each_entry_safe (entry, next, &nvs_list, node) { +list_del (&entry->node); +kfree (entry); + } +return -ENOMEM ; +} + +/** Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 324
Quoted 4 lines
kernel/power/swsusp.c +4
-0+* hibernate_nvs_free - free data pages allocated for saving NVS regions +* +* It is allowed to call this function many times in a row. +*/ If this one is safe for multiple calls, should
nvs_allocbe safe for multiple calls too? Or, conversely, is something funny going on such thathibernate_nvs_freeneeds to be safe for multiple calls?
Quoted 3 lines
I thought it would be necessary to call that additionally from
platform_end()for the error path in whichplatform_pre_snapshot()fails, but that doesn't seem to be the case. It doesn't hurt to keep it in this form, though, IMO.
Okee doke.
Quoted 50 lines
Quoted 41 lines
Quoted 41 lines
kernel/power/swsusp.c +41
-0+void hibernate_nvs_free (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { +free_page ((unsigned long )entry->data); + entry->data =NULL ; +if (entry->kaddr) { +iounmap (entry->kaddr); + entry->kaddr =NULL ; + } + } +} + +/** +* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions +*/ +int hibernate_nvs_alloc (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) { + entry->data = (void *)__get_free_page (GFP_KERNEL ); +if (!entry->data) { +hibernate_nvs_free (); +return -ENOMEM ; + } + } +return 0 ; +} + +/** +* hibernate_nvs_save - save NVS memory regions +*/ +void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); +Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 369
Quoted 4 lines
kernel/power/swsusp.c +4
-0+list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size);Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Quoted 1 line
Ah, this one is tricky. We cannot unmap from atomic context. :-)
Maybe a comment then, lest someone get the same idea in future and be as ignorant as me? :)
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
kernel/power/swsusp.c +11
-0+ } +} + +/** +* hibernate_nvs_restore - restore NVS memory regions +*/ +void hibernate_nvs_restore (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Restoring platform NVS memory\n" );
Quoted 8 lines
Quoted 5 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 385
Quoted 5 lines
kernel/power/swsusp.c +5
-0+ +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) +memcpy (entry->kaddr, entry->data, entry->size); +}Thanks,
Rafael
Regards,
Nigel
_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm
Nigel Cunningham
Acked-byRe: [linux-pm] [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Rafael J. WysockiHi.
Quoted 231 lines · Rafael J. Wysocki
Quoted 1 line · Nigel Cunningham
Hi.
Hi,
Quoted 217 lines · Rafael J. Wysocki
Quoted 216 lines
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +43
-7@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/* @@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,Index:
linux-2.6/include/linux/suspend.h
===================================================================include/linux/suspend.h +13
-0@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +56
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +}; + +static LIST_HEAD (nvs_list); + +/** +* hibernate_nvs_register - register platform NVS memory region to save +* @start - physical address of the region +* @size - size of the region +* +* The NVS region need not be page-aligned (both ends) and we arrange +* things so that the data from page-aligned addresses in this region will +* be copied into separate RAM pages. +*/ +int hibernate_nvs_register (unsigned long start,unsigned long size) +{ +struct nvs_page *entry, *next; + +while (size >0 ) { +unsigned int nr_bytes; + + entry =kzalloc (sizeof (struct nvs_page ),GFP_KERNEL ); +if (!entry) + goto Error; + +list_add_tail (&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes =PAGE_SIZE - (start & ~PAGE_MASK ); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } +return 0 ; + + Error: +list_for_each_entry_safe (entry, next, &nvs_list, node) { +list_del (&entry->node); +kfree (entry); + } +return -ENOMEM ; +} + +/** Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 324
Quoted 4 lines
kernel/power/swsusp.c +4
-0+* hibernate_nvs_free - free data pages allocated for saving NVS regions +* +* It is allowed to call this function many times in a row. +*/ If this one is safe for multiple calls, should
nvs_allocbe safe for multiple calls too? Or, conversely, is something funny going on such thathibernate_nvs_freeneeds to be safe for multiple calls?
Quoted 3 lines
I thought it would be necessary to call that additionally from
platform_end()for the error path in whichplatform_pre_snapshot()fails, but that doesn't seem to be the case. It doesn't hurt to keep it in this form, though, IMO.
Okee doke.
Quoted 50 lines
Quoted 41 lines
Quoted 41 lines
kernel/power/swsusp.c +41
-0+void hibernate_nvs_free (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { +free_page ((unsigned long )entry->data); + entry->data =NULL ; +if (entry->kaddr) { +iounmap (entry->kaddr); + entry->kaddr =NULL ; + } + } +} + +/** +* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions +*/ +int hibernate_nvs_alloc (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) { + entry->data = (void *)__get_free_page (GFP_KERNEL ); +if (!entry->data) { +hibernate_nvs_free (); +return -ENOMEM ; + } + } +return 0 ; +} + +/** +* hibernate_nvs_save - save NVS memory regions +*/ +void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); +Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 369
Quoted 4 lines
kernel/power/swsusp.c +4
-0+list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size);Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Quoted 1 line
Ah, this one is tricky. We cannot unmap from atomic context. :-)
Maybe a comment then, lest someone get the same idea in future and be as ignorant as me? :)
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
kernel/power/swsusp.c +11
-0+ } +} + +/** +* hibernate_nvs_restore - restore NVS memory regions +*/ +void hibernate_nvs_restore (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Restoring platform NVS memory\n" );
Quoted 8 lines
Quoted 5 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 385
Quoted 5 lines
kernel/power/swsusp.c +5
-0+ +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) +memcpy (entry->kaddr, entry->data, entry->size); +}Thanks,
Rafael
Regards,
Nigel
--
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 2/4 ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2)
Quoted 1 line · Nigel Cunningham
Hi.
Hi,
Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · Nigel Cunningham
Quoted 2 lines · Rafael J. Wysocki
Quoted 1 line
From: Rafael J. Wysocki <[email protected]>
[--snip--]
Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
Review
Quoted 13 lines
(quoted diff) +13
-0+/** + * hibernate_nvs_save - save NVS memory regions + */ +void hibernate_nvs_save(void) +{ + struct nvs_page *entry; + + printk(KERN_INFO "PM: Saving platform NVS memory\n"); + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) { + entry->kaddr = ioremap(entry->phys_start, entry->size); + memcpy(entry->data, entry->kaddr, entry->size);Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Quoted 4 lines
Quoted 1 line
Ah, this one is tricky. We cannot unmap from atomic context. :-)
Maybe a comment then, lest someone get the same idea in future and be as ignorant as me? :)
Well, I was considering to add one, now changed the kerneldoc comment to mention that.
Please find updated patch below.
---
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2)
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the _PTS control method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the _WAK control method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.
Based on a patch by Zhang Rui.
--- drivers/acpi/sleep/main.c | 50 +++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 7 deletions(-)
drivers/acpi/sleep/main.c +43 -7
@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )
@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/*
@@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )
@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,
@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }
@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,
include/linux/suspend.h +13 -0
@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}
@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP
kernel/power/swsusp.c +124 -0
127 lines not on this page · raw message
--
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
Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2)
Hi.
Quoted 24 lines · Rafael J. Wysocki
Quoted 4 lines · Nigel Cunningham
Quoted 3 lines · Rafael J. Wysocki
Quoted 2 lines · Nigel Cunningham
Quoted 1 line · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
[--snip--]
Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 369
Quoted 13 lines
kernel/power/swsusp.c +13
-0+/** +* hibernate_nvs_save - save NVS memory regions +*/ +void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size);Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Ah, this one is tricky. We cannot unmap from atomic context. :-)
Maybe a comment then, lest someone get the same idea in future and be as ignorant as me? :)
Well, I was considering to add one, now changed the kerneldoc comment to mention that.
Terrific. Thanks.
Quoted 161 lines
Please find updated patch below.
---
From: Rafael J. Wysocki <[email protected]>ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2)
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Acked-by Nigel Cunningham <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 +++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 7 deletions(-)Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +43
-7@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/* @@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,Index:
linux-2.6/include/linux/suspend.h
===================================================================include/linux/suspend.h +13
-0@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP Index:
linux-2.6/kernel/power/swsusp.c
===================================================================
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 267
Quoted 6 lines
kernel/power/swsusp.c +3
-0@@ -262,3 +262,127 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during
Both commas should be removed from the line above.
Quoted 46 lines
kernel/power/swsusp.c +46
-0+* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +}; + +static LIST_HEAD (nvs_list); + +/** +* hibernate_nvs_register - register platform NVS memory region to save +* @start - physical address of the region +* @size - size of the region +* +* The NVS region need not be page-aligned (both ends) and we arrange +* things so that the data from page-aligned addresses in this region will +* be copied into separate RAM pages. +*/ +int hibernate_nvs_register (unsigned long start,unsigned long size) +{ +struct nvs_page *entry, *next; + +while (size >0 ) { +unsigned int nr_bytes; + + entry =kzalloc (sizeof (struct nvs_page ),GFP_KERNEL ); +if (!entry) + goto Error; + +list_add_tail (&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes =PAGE_SIZE - (start & ~PAGE_MASK ); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } +return 0 ; + + Error: +list_for_each_entry_safe (entry, next, &nvs_list, node) {
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 323
Quoted 10 lines
kernel/power/swsusp.c +10
-0+list_del (&entry->node); +kfree (entry); + } +return -ENOMEM ; +} + +/** +* hibernate_nvs_free - free data pages allocated for saving NVS regions +* +* It is allowed to call this function many times in a row.
"This function may safely be called multiple times." .... maybe just do without the comment?
Quoted 55 lines
kernel/power/swsusp.c +55
-0+*/ +void hibernate_nvs_free (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { +free_page ((unsigned long )entry->data); + entry->data =NULL ; +if (entry->kaddr) { +iounmap (entry->kaddr); + entry->kaddr =NULL ; + } + } +} + +/** +* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions +*/ +int hibernate_nvs_alloc (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) { + entry->data = (void *)__get_free_page (GFP_KERNEL ); +if (!entry->data) { +hibernate_nvs_free (); +return -ENOMEM ; + } + } +return 0 ; +} + +/** +* hibernate_nvs_save - save NVS memory regions +*/ +void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size); + } +} + +/** +* hibernate_nvs_restore - restore NVS memory regions +* +* This function is going to be called with interrupts disabled, so it +* cannot iounmap the virtual addresses used to access the NVS region. +*/
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 388
Quoted 10 lines
kernel/power/swsusp.c +10
-0+void hibernate_nvs_restore (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Restoring platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) +memcpy (entry->kaddr, entry->data, entry->size); +}
Regards,
Nigel
_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm
Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2)
In reply to Rafael J. WysockiHi.
Quoted 24 lines · Rafael J. Wysocki
Quoted 4 lines · Nigel Cunningham
Quoted 3 lines · Rafael J. Wysocki
Quoted 2 lines · Nigel Cunningham
Quoted 1 line · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
[--snip--]
Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 369
Quoted 13 lines
kernel/power/swsusp.c +13
-0+/** +* hibernate_nvs_save - save NVS memory regions +*/ +void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size);Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Ah, this one is tricky. We cannot unmap from atomic context. :-)
Maybe a comment then, lest someone get the same idea in future and be as ignorant as me? :)
Well, I was considering to add one, now changed the kerneldoc comment to mention that.
Terrific. Thanks.
Quoted 161 lines
Please find updated patch below.
---
From: Rafael J. Wysocki <[email protected]>ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2)
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Acked-by Nigel Cunningham <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 +++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 7 deletions(-)Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +43
-7@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/* @@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,Index:
linux-2.6/include/linux/suspend.h
===================================================================include/linux/suspend.h +13
-0@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP Index:
linux-2.6/kernel/power/swsusp.c
===================================================================
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 267
Quoted 6 lines
kernel/power/swsusp.c +3
-0@@ -262,3 +262,127 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during
Both commas should be removed from the line above.
Quoted 46 lines
kernel/power/swsusp.c +46
-0+* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +}; + +static LIST_HEAD (nvs_list); + +/** +* hibernate_nvs_register - register platform NVS memory region to save +* @start - physical address of the region +* @size - size of the region +* +* The NVS region need not be page-aligned (both ends) and we arrange +* things so that the data from page-aligned addresses in this region will +* be copied into separate RAM pages. +*/ +int hibernate_nvs_register (unsigned long start,unsigned long size) +{ +struct nvs_page *entry, *next; + +while (size >0 ) { +unsigned int nr_bytes; + + entry =kzalloc (sizeof (struct nvs_page ),GFP_KERNEL ); +if (!entry) + goto Error; + +list_add_tail (&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes =PAGE_SIZE - (start & ~PAGE_MASK ); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } +return 0 ; + + Error: +list_for_each_entry_safe (entry, next, &nvs_list, node) {
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 323
Quoted 10 lines
kernel/power/swsusp.c +10
-0+list_del (&entry->node); +kfree (entry); + } +return -ENOMEM ; +} + +/** +* hibernate_nvs_free - free data pages allocated for saving NVS regions +* +* It is allowed to call this function many times in a row.
"This function may safely be called multiple times." .... maybe just do without the comment?
Quoted 55 lines
kernel/power/swsusp.c +55
-0+*/ +void hibernate_nvs_free (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { +free_page ((unsigned long )entry->data); + entry->data =NULL ; +if (entry->kaddr) { +iounmap (entry->kaddr); + entry->kaddr =NULL ; + } + } +} + +/** +* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions +*/ +int hibernate_nvs_alloc (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) { + entry->data = (void *)__get_free_page (GFP_KERNEL ); +if (!entry->data) { +hibernate_nvs_free (); +return -ENOMEM ; + } + } +return 0 ; +} + +/** +* hibernate_nvs_save - save NVS memory regions +*/ +void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size); + } +} + +/** +* hibernate_nvs_restore - restore NVS memory regions +* +* This function is going to be called with interrupts disabled, so it +* cannot iounmap the virtual addresses used to access the NVS region. +*/
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 388
Quoted 10 lines
kernel/power/swsusp.c +10
-0+void hibernate_nvs_restore (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Restoring platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) +memcpy (entry->kaddr, entry->data, entry->size); +}
Regards,
Nigel
--
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 2/4 ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2)
In reply to Nigel CunninghamQuoted 1 line · Nigel Cunningham
Hi.
Hi,
Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · Nigel Cunningham
Quoted 2 lines · Rafael J. Wysocki
Quoted 1 line
From: Rafael J. Wysocki <[email protected]>
[--snip--]
Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
Review
Quoted 13 lines
(quoted diff) +13
-0+/** + * hibernate_nvs_save - save NVS memory regions + */ +void hibernate_nvs_save(void) +{ + struct nvs_page *entry; + + printk(KERN_INFO "PM: Saving platform NVS memory\n"); + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) { + entry->kaddr = ioremap(entry->phys_start, entry->size); + memcpy(entry->data, entry->kaddr, entry->size);Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Quoted 4 lines
Quoted 1 line
Ah, this one is tricky. We cannot unmap from atomic context. :-)
Maybe a comment then, lest someone get the same idea in future and be as ignorant as me? :)
Well, I was considering to add one, now changed the kerneldoc comment to mention that.
Please find updated patch below.
---
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2)
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the _PTS control method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the _WAK control method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.
Based on a patch by Zhang Rui.
--- drivers/acpi/sleep/main.c | 50 +++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 7 deletions(-)
drivers/acpi/sleep/main.c +43 -7
@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )
@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/*
@@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )
@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,
@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }
@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,
include/linux/suspend.h +13 -0
@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}
@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP
kernel/power/swsusp.c +124 -0
127 lines not on this page · raw message
_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm
Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Nigel CunninghamQuoted 1 line · Nigel Cunningham
Hi.
Hi,
Quoted 217 lines · Rafael J. Wysocki
Quoted 216 lines
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +43
-7@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/* @@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,Index:
linux-2.6/include/linux/suspend.h
===================================================================include/linux/suspend.h +13
-0@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +56
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +}; + +static LIST_HEAD (nvs_list); + +/** +* hibernate_nvs_register - register platform NVS memory region to save +* @start - physical address of the region +* @size - size of the region +* +* The NVS region need not be page-aligned (both ends) and we arrange +* things so that the data from page-aligned addresses in this region will +* be copied into separate RAM pages. +*/ +int hibernate_nvs_register (unsigned long start,unsigned long size) +{ +struct nvs_page *entry, *next; + +while (size >0 ) { +unsigned int nr_bytes; + + entry =kzalloc (sizeof (struct nvs_page ),GFP_KERNEL ); +if (!entry) + goto Error; + +list_add_tail (&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes =PAGE_SIZE - (start & ~PAGE_MASK ); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } +return 0 ; + + Error: +list_for_each_entry_safe (entry, next, &nvs_list, node) { +list_del (&entry->node); +kfree (entry); + } +return -ENOMEM ; +} + +/**
Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 324
Quoted 4 lines
kernel/power/swsusp.c +4
-0+* hibernate_nvs_free - free data pages allocated for saving NVS regions +* +* It is allowed to call this function many times in a row. +*/ If this one is safe for multiple calls, should
nvs_allocbe safe for multiple calls too? Or, conversely, is something funny going on such thathibernate_nvs_freeneeds to be safe for multiple calls?
I thought it would be necessary to call that additionally from platform_end() for the error path in which platform_pre_snapshot() fails, but that doesn't seem to be the case. It doesn't hurt to keep it in this form, though, IMO.
Quoted 41 lines
Quoted 41 lines
kernel/power/swsusp.c +41
-0+void hibernate_nvs_free (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { +free_page ((unsigned long )entry->data); + entry->data =NULL ; +if (entry->kaddr) { +iounmap (entry->kaddr); + entry->kaddr =NULL ; + } + } +} + +/** +* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions +*/ +int hibernate_nvs_alloc (void ) +{ +struct nvs_page *entry; + +list_for_each_entry (entry, &nvs_list, node) { + entry->data = (void *)__get_free_page (GFP_KERNEL ); +if (!entry->data) { +hibernate_nvs_free (); +return -ENOMEM ; + } + } +return 0 ; +} + +/** +* hibernate_nvs_save - save NVS memory regions +*/ +void hibernate_nvs_save (void ) +{ +struct nvs_page *entry; + +printk (KERN_INFO "PM: Saving platform NVS memory\n" ); +
Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 369
Quoted 4 lines
kernel/power/swsusp.c +4
-0+list_for_each_entry (entry, &nvs_list, node) +if (entry->data) { + entry->kaddr =ioremap (entry->phys_start, entry->size); +memcpy (entry->data, entry->kaddr, entry->size);Why not unmap here? (I know you're delaying the unmap until the free, but it's probably clearer to map and unmap each time the memory is accessed (ie in restore too).
Ah, this one is tricky. We cannot unmap from atomic context. :-)
Quoted 8 lines
Quoted 8 lines
kernel/power/swsusp.c +8
-0+ } +} + +/** +* hibernate_nvs_restore - restore NVS memory regions +*/ +void hibernate_nvs_restore (void ) +{
Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 385
Quoted 8 lines
kernel/power/swsusp.c +8
-0+struct nvs_page *entry; + +printk (KERN_INFO "PM: Restoring platform NVS memory\n" ); + +list_for_each_entry (entry, &nvs_list, node) +if (entry->data) +memcpy (entry->kaddr, entry->data, entry->size); +}
Thanks,
Rafael
_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm
Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Rafael J. WysockiHi!
Quoted 27 lines
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform???s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)
drivers/acpi/sleep/main.c static int acpi_hibernation_begin_old(vo · line 419
Quoted 10 lines
drivers/acpi/sleep/main.c +7
-0@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +}
You can chain this without nesting...
If sleep_prepare() succeeds but nvs_alloc() fails, you should undo sleep_prepare here, right?
Quoted 6 lines
include/linux/suspend.h +0
-0#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }
include/linux/suspend.h static inline void swsusp_unset_page_fre · line 257
Quoted 10 lines
include/linux/suspend.h +8
-0static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */
Can someone call these for !hibernation case? Should they fake success if they do call them?
Quoted 12 lines
Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +4
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 278
Quoted 10 lines
kernel/power/swsusp.c +10
-0+* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +};
Maybe separate nvs.c file would be good? I believe this _is_ acpi specific, altrough in theory it may not be.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Rafael J. WysockiHi!
Quoted 27 lines
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform???s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)
drivers/acpi/sleep/main.c static int acpi_hibernation_begin_old(vo · line 419
Quoted 10 lines
drivers/acpi/sleep/main.c +7
-0@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +}
You can chain this without nesting...
If sleep_prepare() succeeds but nvs_alloc() fails, you should undo sleep_prepare here, right?
Quoted 6 lines
include/linux/suspend.h +0
-0#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }
include/linux/suspend.h static inline void swsusp_unset_page_fre · line 257
Quoted 10 lines
include/linux/suspend.h +8
-0static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */
Can someone call these for !hibernation case? Should they fake success if they do call them?
Quoted 12 lines
Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +4
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 278
Quoted 10 lines
kernel/power/swsusp.c +10
-0+* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start; +unsigned int size; +void *kaddr; +void *data; +struct list_head node; +};
Maybe separate nvs.c file would be good? I believe this _is_ acpi specific, altrough in theory it may not be.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
Quoted 42 lines · Pavel Machek
Hi!
Quoted 27 lines
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform???s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)drivers/acpi/sleep/main.c static int acpi_hibernation_begin_old(vo · line 419
Quoted 10 lines
drivers/acpi/sleep/main.c +7
-0@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +}You can chain this without nesting...
Quoted 2 lines
If
sleep_prepare()succeeds butnvs_alloc()fails, you should undosleep_preparehere, right?
No. acpi_hibernation_finish() will undo it anyway.
Quoted 10 lines
Quoted 10 lines
include/linux/suspend.h +3
-0#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ;
Quoted 8 lines
include/linux/suspend.h static inline void swsusp_unset_page_fre · line 257
Quoted 6 lines
include/linux/suspend.h +5
-0+} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ Can someone call these for !hibernation case?
Not at the moment, but why not to add them?
Quoted 20 lines
Should they fake success if they do call them?
Quoted 17 lines
Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +9
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start;
Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 278
Quoted 5 lines
kernel/power/swsusp.c +5
-0+unsigned int size; +void *kaddr; +void *data; +struct list_head node; +};Maybe separate
nvs.cfile would be good? I believe this _is_ acpi specific, altrough in theory it may not be.
No, I don't think so. The patch is correct IMO.
Thanks,
Rafael
Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
Hi!
Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
#else /*
CONFIG_HIBERNATION*/
static inline intswsusp_page_is_forbidden(struct page *p){ return 0; } static inline voidswsusp_set_page_free(struct page *p){}include/linux/suspend.h +3
-0@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ;Quoted 8 lines
include/linux/suspend.h static inline void swsusp_unset_page_fre · line 257
Quoted 6 lines
include/linux/suspend.h +5
-0+} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ Can someone call these for !hibernation case?
Quoted 1 line
Not at the moment, but why not to add them?
Well, someone may call them, expecting them to save / restore nvs, except that they will not be there. I'd prefer inlines not to exist (so mistake is caught at compile time) or them to contain BUG(), so that mistake is obvious.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Rafael J. WysockiHi!
Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
#else /*
CONFIG_HIBERNATION*/
static inline intswsusp_page_is_forbidden(struct page *p){ return 0; } static inline voidswsusp_set_page_free(struct page *p){}include/linux/suspend.h +3
-0@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ;Quoted 8 lines
include/linux/suspend.h static inline void swsusp_unset_page_fre · line 257
Quoted 6 lines
include/linux/suspend.h +5
-0+} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ Can someone call these for !hibernation case?
Quoted 1 line
Not at the moment, but why not to add them?
Well, someone may call them, expecting them to save / restore nvs, except that they will not be there. I'd prefer inlines not to exist (so mistake is caught at compile time) or them to contain BUG(), so that mistake is obvious.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Pavel MachekQuoted 42 lines · Pavel Machek
Hi!
Quoted 27 lines
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the
_PTScontrol method some time before entering a sleeping state, to allow the platform???s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the_WAKcontrol method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)drivers/acpi/sleep/main.c static int acpi_hibernation_begin_old(vo · line 419
Quoted 10 lines
drivers/acpi/sleep/main.c +7
-0@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +}You can chain this without nesting...
Quoted 2 lines
If
sleep_prepare()succeeds butnvs_alloc()fails, you should undosleep_preparehere, right?
No. acpi_hibernation_finish() will undo it anyway.
Quoted 10 lines
Quoted 10 lines
include/linux/suspend.h +3
-0#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ;
Quoted 8 lines
include/linux/suspend.h static inline void swsusp_unset_page_fre · line 257
Quoted 6 lines
include/linux/suspend.h +5
-0+} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ Can someone call these for !hibernation case?
Not at the moment, but why not to add them?
Quoted 20 lines
Should they fake success if they do call them?
Quoted 17 lines
Index:
linux-2.6/kernel/power/swsusp.c
===================================================================kernel/power/swsusp.c +9
-0@@ -262,3 +262,124 @@ int swsusp_shrink_memory(void)return 0 ; } + +/* +* Platforms, like ACPI, may want us to save some memory used by them during +* hibernation and to restore the contents of this memory during the subsequent +* resume. The code below implements a mechanism allowing us to do that. +*/ + +struct nvs_page { +unsigned long phys_start;
Quoted 8 lines
kernel/power/swsusp.c int swsusp_shrink_memory(void) · line 278
Quoted 5 lines
kernel/power/swsusp.c +5
-0+unsigned int size; +void *kaddr; +void *data; +struct list_head node; +};Maybe separate
nvs.cfile would be good? I believe this _is_ acpi specific, altrough in theory it may not be.
No, I don't think so. The patch is correct IMO.
Thanks,
Rafael
PATCH 2/4 ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory
According to the ACPI Specification 3.0b, Section 15.3.2, "OSPM will call the _PTS control method some time before entering a sleeping state, to allow the platform’s AML code to update this memory image before entering the sleeping state. After the system awakes from an S4 state, OSPM will restore this memory area and call the _WAK control method to enable the BIOS to reclaim its memory image." For this reason, implement a mechanism allowing us to save the NVS memory during hibernation and to restore it during the subsequent resume.
Based on a patch by Zhang Rui.
--- drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- include/linux/suspend.h | 13 ++++ kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 7 deletions(-)
drivers/acpi/sleep/main.c +43 -7
@@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(voidstatic int acpi_hibernation_begin (void ) { - acpi_target_sleep_state =ACPI_STATE_S4 ; -return 0 ; +int error; + + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + +return error; +} + +static int acpi_hibernation_pre_snapshot (void ) +{ +int error =acpi_pm_prepare (); + +if (!error) +hibernate_nvs_save (); + +return error; }static int acpi_hibernation_enter (void )
@@ -343,6 +358,12 @@ static int acpi_hibernation_enter(void)return ACPI_SUCCESS (status) ?0 : -EFAULT ; } +static void acpi_hibernation_finish (void ) +{ +hibernate_nvs_free (); +acpi_pm_finish (); +} +static void acpi_hibernation_leave (void ) {/*
@@ -358,6 +379,8 @@ static void acpi_hibernation_leave(void) "cannot resume!\n");panic ("ACPI S4 hardware signature mismatch" ); } +/* Restore the NVS memory area */ +hibernate_nvs_restore (); }static void acpi_pm_enable_gpes (void )
@@ -368,8 +391,8 @@ static void acpi_pm_enable_gpes(void)static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,
@@ -387,8 +410,21 @@ static int acpi_hibernation_begin_old(vo {int error =acpi_sleep_prepare (ACPI_STATE_S4 ); +if (!error) { + error =hibernate_nvs_alloc (); +if (!error) + acpi_target_sleep_state =ACPI_STATE_S4 ; + } +return error; +} + +static int acpi_hibernation_pre_snapshot_old (void ) +{ +int error =acpi_pm_disable_gpes (); +if (!error) - acpi_target_sleep_state =ACPI_STATE_S4 ; +hibernate_nvs_save (); +return error; }
@@ -399,8 +435,8 @@ static int acpi_hibernation_begin_old(vostatic struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave,
include/linux/suspend.h +13 -0
@@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_textern void hibernation_set_ops (struct platform_hibernation_ops *ops);extern int hibernate (void );extern bool system_entering_hibernation (void ); +extern int hibernate_nvs_register (unsigned long start,unsigned long size); +extern int hibernate_nvs_alloc (void ); +extern void hibernate_nvs_free (void ); +extern void hibernate_nvs_save (void ); +extern void hibernate_nvs_restore (void );#else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}
@@ -241,6 +246,14 @@ static inline void swsusp_unset_page_frestatic inline void hibernation_set_ops (struct platform_hibernation_ops *ops) {}static inline int hibernate (void ) {return -ENOSYS ; }static inline bool system_entering_hibernation (void ) {return false; } +static inline int hibernate_nvs_register (unsigned long a,unsigned long b) +{ +return 0 ; +} +static inline int hibernate_nvs_alloc (void ) {return 0 ; } +static inline void hibernate_nvs_free (void ) {} +static inline void hibernate_nvs_save (void ) {} +static inline void hibernate_nvs_restore (void ) {}#endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP
kernel/power/swsusp.c +121 -0
124 lines not on this page · raw message
_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm
PATCH 3/4 x86 hibernate: Mark ACPI NVS memory region at startup
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
x86 hibernate: Mark ACPI NVS memory region at startup
Introduce new initcall for marking the ACPI NVS memory at startup, so that it can be saved/restore during hibernation/resume.
Based on a patch by Zhang Rui.
--- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
arch/x86/kernel/e820.c +25 -0
@@ -20,6 +20,7 @@#include <linux/pfn.h> #include <linux/suspend.h> #include <linux/firmware-map.h> +#include <linux/efi.h> #include <asm/pgtable.h> #include <asm/page.h>
@@ -665,6 +666,30 @@ void __init e820_mark_nosave_regions(uns }#endif +#ifdef CONFIG_HIBERNATION +/** +* Mark ACPI NVS memory region, so that we can save/restore it during +* hibernation and the subsequent resume. +*/ +static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ; + +for (i =0 ; i < e820.nr_map; i++) { +struct e820entry *ei = &e820.map[i]; + +if (ei->type ==E820_NVS ) +hibernate_nvs_register (ei->addr, ei->size); + } + +return 0 ; +} +core_initcall (e820_mark_nvs_memory); +#endif +/* * Early reserved memory areas. */
Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
Quoted 20 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
x86 hibernate: Mark ACPI NVS memory region at startup
Introduce new initcall for marking the ACPI NVS memory at startup, so that it can be saved/restore during hibernation/resume.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)Index:
linux-2.6/arch/x86/kernel/e820.c
===================================================================
arch/x86/kernel/e820.c line 26
Quoted 7 lines
arch/x86/kernel/e820.c +1
-0@@ -20,6 +20,7 @@#include <linux/pfn.h> #include <linux/suspend.h> #include <linux/firmware-map.h> +#include <linux/efi.h> #include <asm/pgtable.h> #include <asm/page.h>
Unrelated chunk?
Quoted 5 lines
arch/x86/kernel/e820.c +1
-0@@ -665,6 +666,30 @@ void __init e820_mark_nosave_regions(uns }#endif +#ifdef CONFIG_HIBERNATION
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 10 lines
arch/x86/kernel/e820.c +10
-0+/** +* Mark ACPI NVS memory region, so that we can save/restore it during +* hibernation and the subsequent resume. +*/ +static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;
Aha, not unrelated... why is that? EFI does not use acpi?
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 685
Quoted 5 lines
arch/x86/kernel/e820.c +5
-0+for (i =0 ; i < e820.nr_map; i++) { +struct e820entry *ei = &e820.map[i]; + +if (ei->type ==E820_NVS ) +hibernate_nvs_register (ei->addr, ei->size);
can nvs_register fail? (OOM?)
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
In reply to Rafael J. WysockiQuoted 20 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
x86 hibernate: Mark ACPI NVS memory region at startup
Introduce new initcall for marking the ACPI NVS memory at startup, so that it can be saved/restore during hibernation/resume.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)Index:
linux-2.6/arch/x86/kernel/e820.c
===================================================================
arch/x86/kernel/e820.c line 26
Quoted 7 lines
arch/x86/kernel/e820.c +1
-0@@ -20,6 +20,7 @@#include <linux/pfn.h> #include <linux/suspend.h> #include <linux/firmware-map.h> +#include <linux/efi.h> #include <asm/pgtable.h> #include <asm/page.h>
Unrelated chunk?
Quoted 5 lines
arch/x86/kernel/e820.c +1
-0@@ -665,6 +666,30 @@ void __init e820_mark_nosave_regions(uns }#endif +#ifdef CONFIG_HIBERNATION
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 10 lines
arch/x86/kernel/e820.c +10
-0+/** +* Mark ACPI NVS memory region, so that we can save/restore it during +* hibernation and the subsequent resume. +*/ +static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;
Aha, not unrelated... why is that? EFI does not use acpi?
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 685
Quoted 5 lines
arch/x86/kernel/e820.c +5
-0+for (i =0 ; i < e820.nr_map; i++) { +struct e820entry *ei = &e820.map[i]; + +if (ei->type ==E820_NVS ) +hibernate_nvs_register (ei->addr, ei->size);
can nvs_register fail? (OOM?)
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
Quoted 35 lines · Pavel Machek
Quoted 20 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
x86 hibernate: Mark ACPI NVS memory region at startup
Introduce new initcall for marking the ACPI NVS memory at startup, so that it can be saved/restore during hibernation/resume.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)Index:
linux-2.6/arch/x86/kernel/e820.c
===================================================================arch/x86/kernel/e820.c line 26
Quoted 7 lines
arch/x86/kernel/e820.c +1
-0@@ -20,6 +20,7 @@#include <linux/pfn.h> #include <linux/suspend.h> #include <linux/firmware-map.h> +#include <linux/efi.h> #include <asm/pgtable.h> #include <asm/page.h> Unrelated chunk?
Quoted 4 lines
arch/x86/kernel/e820.c +0
-0@@ -665,6 +666,30 @@ void __init e820_mark_nosave_regions(uns }#endif
Quoted 13 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 11 lines
arch/x86/kernel/e820.c +11
-0+#ifdef CONFIG_HIBERNATION +/** +* Mark ACPI NVS memory region, so that we can save/restore it during +* hibernation and the subsequent resume. +*/ +static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;Aha, not unrelated... why is that? EFI does not use acpi?
With EFI we are not supposed to do that. Rui knows the details. Rui?
Quoted 7 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 685
Quoted 5 lines
arch/x86/kernel/e820.c +5
-0+for (i =0 ; i < e820.nr_map; i++) { +struct e820entry *ei = &e820.map[i]; + +if (ei->type ==E820_NVS ) +hibernate_nvs_register (ei->addr, ei->size);can
nvs_registerfail? (OOM?)
It can, in which case it will do the cleanup.
Thanks,
Rafael
Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
Hi, sorry for the delay,
Quoted 50 lines · Rafael J. Wysocki
Quoted 35 lines · Pavel Machek
Quoted 20 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
x86 hibernate: Mark ACPI NVS memory region at startup
Introduce new initcall for marking the ACPI NVS memory at startup, so that it can be saved/restore during hibernation/resume.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)Index:
linux-2.6/arch/x86/kernel/e820.c
===================================================================arch/x86/kernel/e820.c line 26
Quoted 7 lines
arch/x86/kernel/e820.c +1
-0@@ -20,6 +20,7 @@#include <linux/pfn.h> #include <linux/suspend.h> #include <linux/firmware-map.h> +#include <linux/efi.h> #include <asm/pgtable.h> #include <asm/page.h> Unrelated chunk?
Quoted 4 lines
arch/x86/kernel/e820.c +0
-0@@ -665,6 +666,30 @@ void __init e820_mark_nosave_regions(uns }#endif Quoted 13 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 11 lines
arch/x86/kernel/e820.c +11
-0+#ifdef CONFIG_HIBERNATION +/** +* Mark ACPI NVS memory region, so that we can save/restore it during +* hibernation and the subsequent resume. +*/ +static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;Aha, not unrelated... why is that? EFI does not use acpi?
Quoted 2 lines
With EFI we are not supposed to do that. Rui knows the details. Rui?
well,
about EFI nvs memory, I only get
"EfiACPIMemoryNVS: The OS and loader must preserve this memory range in the working and ACPI S1–S3 states." in the ACPI spec 3.0b. whether we should save/restore this piece of memory is not clear. I'd prefer not to touch it currently.
thanks,
rui
Quoted 8 lines
Quoted 7 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 685
Quoted 5 lines
arch/x86/kernel/e820.c +5
-0+for (i =0 ; i < e820.nr_map; i++) { +struct e820entry *ei = &e820.map[i]; + +if (ei->type ==E820_NVS ) +hibernate_nvs_register (ei->addr, ei->size);can
nvs_registerfail? (OOM?)
Quoted 4 lines
It can, in which case it will do the cleanup.
Thanks,
Rafael
_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm
Re: [linux-pm] [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
In reply to Rafael J. WysockiHi, sorry for the delay,
Quoted 50 lines · Rafael J. Wysocki
Quoted 35 lines · Pavel Machek
Quoted 20 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
x86 hibernate: Mark ACPI NVS memory region at startup
Introduce new initcall for marking the ACPI NVS memory at startup, so that it can be saved/restore during hibernation/resume.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)Index:
linux-2.6/arch/x86/kernel/e820.c
===================================================================arch/x86/kernel/e820.c line 26
Quoted 7 lines
arch/x86/kernel/e820.c +1
-0@@ -20,6 +20,7 @@#include <linux/pfn.h> #include <linux/suspend.h> #include <linux/firmware-map.h> +#include <linux/efi.h> #include <asm/pgtable.h> #include <asm/page.h> Unrelated chunk?
Quoted 4 lines
arch/x86/kernel/e820.c +0
-0@@ -665,6 +666,30 @@ void __init e820_mark_nosave_regions(uns }#endif Quoted 13 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 11 lines
arch/x86/kernel/e820.c +11
-0+#ifdef CONFIG_HIBERNATION +/** +* Mark ACPI NVS memory region, so that we can save/restore it during +* hibernation and the subsequent resume. +*/ +static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;Aha, not unrelated... why is that? EFI does not use acpi?
Quoted 2 lines
With EFI we are not supposed to do that. Rui knows the details. Rui?
well,
about EFI nvs memory, I only get
"EfiACPIMemoryNVS: The OS and loader must preserve this memory range in the working and ACPI S1–S3 states." in the ACPI spec 3.0b. whether we should save/restore this piece of memory is not clear. I'd prefer not to touch it currently.
thanks,
rui
Quoted 8 lines
Quoted 7 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 685
Quoted 5 lines
arch/x86/kernel/e820.c +5
-0+for (i =0 ; i < e820.nr_map; i++) { +struct e820entry *ei = &e820.map[i]; + +if (ei->type ==E820_NVS ) +hibernate_nvs_register (ei->addr, ei->size);can
nvs_registerfail? (OOM?)
Quoted 4 lines
It can, in which case it will do the cleanup.
Thanks,
Rafael
--
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
Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
Hi!
Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 6 lines
arch/x86/kernel/e820.c +6
-0+static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;Aha, not unrelated... why is that? EFI does not use acpi?
Quoted 8 lines
Quoted 2 lines
With EFI we are not supposed to do that. Rui knows the details. Rui?
well,
about EFI nvs memory, I only get
"EfiACPIMemoryNVS: The OS and loader must preserve this memory range in the working and ACPI S1???S3 states." in the ACPI spec 3.0b. whether we should save/restore this piece of memory is not clear. I'd prefer not to touch it currently.
EFI is a bootloader. Why should we change our runtime behaviour depending on bootloader?
EFI should be still compatible with normal ACPI, right? ...like you should be able to boot the same kernel with the same ACPI BIOS using EFI or EFI w/ legacy emulation.
So special-casing it here does not seem right.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
In reply to Zhang RuiHi!
Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 6 lines
arch/x86/kernel/e820.c +6
-0+static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;Aha, not unrelated... why is that? EFI does not use acpi?
Quoted 8 lines
Quoted 2 lines
With EFI we are not supposed to do that. Rui knows the details. Rui?
well,
about EFI nvs memory, I only get
"EfiACPIMemoryNVS: The OS and loader must preserve this memory range in the working and ACPI S1???S3 states." in the ACPI spec 3.0b. whether we should save/restore this piece of memory is not clear. I'd prefer not to touch it currently.
EFI is a bootloader. Why should we change our runtime behaviour depending on bootloader?
EFI should be still compatible with normal ACPI, right? ...like you should be able to boot the same kernel with the same ACPI BIOS using EFI or EFI w/ legacy emulation.
So special-casing it here does not seem right.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
Quoted 18 lines · Pavel Machek
Hi!
Quoted 16 lines
Quoted 11 lines
Quoted 8 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 6 lines
arch/x86/kernel/e820.c +6
-0+static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;Aha, not unrelated... why is that? EFI does not use acpi?
With EFI we are not supposed to do that. Rui knows the details. Rui?
well,
about EFI nvs memory, I only get
"EfiACPIMemoryNVS: The OS and loader must preserve this memory range in the working and ACPI S1???S3 states." in the ACPI spec 3.0b. whether we should save/restore this piece of memory is not clear.
Well. it's clear enough. Section 15.3.2 evidently refers to E820 and the EFI's GetMemoryMap() on equal footing.
Quoted 10 lines
Quoted 1 line
I'd prefer not to touch it currently.
EFI is a bootloader. Why should we change our runtime behaviour depending on bootloader?
EFI should be still compatible with normal ACPI, right? ...like you should be able to boot the same kernel with the same ACPI BIOS using EFI or EFI w/ legacy emulation.
So special-casing it here does not seem right.
I agree.
I'm going to send an updated patch to Len.
Thanks,
Rafael
Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
In reply to Pavel MachekQuoted 18 lines · Pavel Machek
Hi!
Quoted 16 lines
Quoted 11 lines
Quoted 8 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 6 lines
arch/x86/kernel/e820.c +6
-0+static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;Aha, not unrelated... why is that? EFI does not use acpi?
With EFI we are not supposed to do that. Rui knows the details. Rui?
well,
about EFI nvs memory, I only get
"EfiACPIMemoryNVS: The OS and loader must preserve this memory range in the working and ACPI S1???S3 states." in the ACPI spec 3.0b. whether we should save/restore this piece of memory is not clear.
Well. it's clear enough. Section 15.3.2 evidently refers to E820 and the EFI's GetMemoryMap() on equal footing.
Quoted 10 lines
Quoted 1 line
I'd prefer not to touch it currently.
EFI is a bootloader. Why should we change our runtime behaviour depending on bootloader?
EFI should be still compatible with normal ACPI, right? ...like you should be able to boot the same kernel with the same ACPI BIOS using EFI or EFI w/ legacy emulation.
So special-casing it here does not seem right.
I agree.
I'm going to send an updated patch to Len.
Thanks,
Rafael
Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup
In reply to Pavel MachekQuoted 35 lines · Pavel Machek
Quoted 20 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
x86 hibernate: Mark ACPI NVS memory region at startup
Introduce new initcall for marking the ACPI NVS memory at startup, so that it can be saved/restore during hibernation/resume.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)Index:
linux-2.6/arch/x86/kernel/e820.c
===================================================================arch/x86/kernel/e820.c line 26
Quoted 7 lines
arch/x86/kernel/e820.c +1
-0@@ -20,6 +20,7 @@#include <linux/pfn.h> #include <linux/suspend.h> #include <linux/firmware-map.h> +#include <linux/efi.h> #include <asm/pgtable.h> #include <asm/page.h> Unrelated chunk?
Quoted 4 lines
arch/x86/kernel/e820.c +0
-0@@ -665,6 +666,30 @@ void __init e820_mark_nosave_regions(uns }#endif
Quoted 13 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 679
Quoted 11 lines
arch/x86/kernel/e820.c +11
-0+#ifdef CONFIG_HIBERNATION +/** +* Mark ACPI NVS memory region, so that we can save/restore it during +* hibernation and the subsequent resume. +*/ +static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ;Aha, not unrelated... why is that? EFI does not use acpi?
With EFI we are not supposed to do that. Rui knows the details. Rui?
Quoted 7 lines
arch/x86/kernel/e820.c void __init e820_mark_nosave_regions(uns · line 685
Quoted 5 lines
arch/x86/kernel/e820.c +5
-0+for (i =0 ; i < e820.nr_map; i++) { +struct e820entry *ei = &e820.map[i]; + +if (ei->type ==E820_NVS ) +hibernate_nvs_register (ei->addr, ei->size);can
nvs_registerfail? (OOM?)
It can, in which case it will do the cleanup.
Thanks,
Rafael
PATCH 3/4 x86 hibernate: Mark ACPI NVS memory region at startup
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
x86 hibernate: Mark ACPI NVS memory region at startup
Introduce new initcall for marking the ACPI NVS memory at startup, so that it can be saved/restore during hibernation/resume.
Based on a patch by Zhang Rui.
--- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
arch/x86/kernel/e820.c +25 -0
@@ -20,6 +20,7 @@#include <linux/pfn.h> #include <linux/suspend.h> #include <linux/firmware-map.h> +#include <linux/efi.h> #include <asm/pgtable.h> #include <asm/page.h>
@@ -665,6 +666,30 @@ void __init e820_mark_nosave_regions(uns }#endif +#ifdef CONFIG_HIBERNATION +/** +* Mark ACPI NVS memory region, so that we can save/restore it during +* hibernation and the subsequent resume. +*/ +static int __init e820_mark_nvs_memory (void ) +{ +int i; + +if (efi_enabled) +return 0 ; + +for (i =0 ; i < e820.nr_map; i++) { +struct e820entry *ei = &e820.map[i]; + +if (ei->type ==E820_NVS ) +hibernate_nvs_register (ei->addr, ei->size); + } + +return 0 ; +} +core_initcall (e820_mark_nvs_memory); +#endif +/* * Early reserved memory areas. */
PATCH 4/4 ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)
Documentation/kernel-parameters.txt +4 -1
@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.
@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation. acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }
arch/x86/kernel/acpi/sleep.c +2 -0
@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 ) +acpi_s4_no_nvs (); str =strchr (str,',' );if (str !=NULL ) str +=strspn (str,", \t" );
drivers/acpi/sleep/main.c +17 -2
@@ -59,6 +59,20 @@ void __init acpi_old_suspend_ordering(vo old_suspend_ordering = true; } +/* +* The ACPI specification wants us to save NVS memory regions during hibernation +* and to restore them during the subsequent resume. However, it is not certain +* if this mechanism is going to work on all machines, so we allow the user to +* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line +* option. +*/ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs (void ) +{ + s4_no_nvs = true; +} +/** * acpi_pm_disable_gpes - Disable the GPEs. */
@@ -323,7 +337,7 @@ static int acpi_hibernation_begin(void) {int error; - error =hibernate_nvs_alloc (); + error = s4_no_nvs ?0 :hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ;
@@ -411,7 +425,8 @@ static int acpi_hibernation_begin_old(voint error =acpi_sleep_prepare (ACPI_STATE_S4 );if (!error) { - error =hibernate_nvs_alloc (); +if (!s4_no_nvs) + error =hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ; }
include/linux/acpi.h +1 -0
@@ -238,6 +238,7 @@ int acpi_check_mem_region(resource_size_#ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature (void );void __init acpi_old_suspend_ordering (void ); +void __init acpi_s4_no_nvs (void );#endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */
Re: [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
Hi.
Quoted 48 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt +4
-1@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation. acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }Index:
linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================
arch/x86/kernel/acpi/sleep.c static int __init acpi_sleep_setup(char · line 164
Quoted 4 lines
arch/x86/kernel/acpi/sleep.c +1
-0@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 )
s/13/8/
Quoted 53 lines
arch/x86/kernel/acpi/sleep.c +1
-0+acpi_s4_no_nvs (); str =strchr (str,',' );if (str !=NULL ) str +=strspn (str,", \t" );Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +17
-2@@ -59,6 +59,20 @@ void __init acpi_old_suspend_ordering(vo old_suspend_ordering = true; } +/* +* The ACPI specification wants us to save NVS memory regions during hibernation +* and to restore them during the subsequent resume. However, it is not certain +* if this mechanism is going to work on all machines, so we allow the user to +* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line +* option. +*/ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs (void ) +{ + s4_no_nvs = true; +} +/** * acpi_pm_disable_gpes - Disable the GPEs. */ @@ -323,7 +337,7 @@ static int acpi_hibernation_begin(void) {int error; - error =hibernate_nvs_alloc (); + error = s4_no_nvs ?0 :hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ;@@ -411,7 +425,8 @@ static int acpi_hibernation_begin_old(voint error =acpi_sleep_prepare (ACPI_STATE_S4 );if (!error) { - error =hibernate_nvs_alloc (); +if (!s4_no_nvs) + error =hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ; }Index:
linux-2.6/include/linux/acpi.h
===================================================================
include/linux/acpi.h int acpi_check_mem_region(resource_size_ · line 243
Quoted 6 lines
include/linux/acpi.h +1
-0@@ -238,6 +238,7 @@ int acpi_check_mem_region(resource_size_#ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature (void );void __init acpi_old_suspend_ordering (void ); +void __init acpi_s4_no_nvs (void );#endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */
Apart from the above,
Re: [linux-pm] [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
In reply to Rafael J. WysockiHi.
Quoted 48 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt +4
-1@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation. acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }Index:
linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================
arch/x86/kernel/acpi/sleep.c static int __init acpi_sleep_setup(char · line 164
Quoted 4 lines
arch/x86/kernel/acpi/sleep.c +1
-0@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 )
s/13/8/
Quoted 53 lines
arch/x86/kernel/acpi/sleep.c +1
-0+acpi_s4_no_nvs (); str =strchr (str,',' );if (str !=NULL ) str +=strspn (str,", \t" );Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +17
-2@@ -59,6 +59,20 @@ void __init acpi_old_suspend_ordering(vo old_suspend_ordering = true; } +/* +* The ACPI specification wants us to save NVS memory regions during hibernation +* and to restore them during the subsequent resume. However, it is not certain +* if this mechanism is going to work on all machines, so we allow the user to +* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line +* option. +*/ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs (void ) +{ + s4_no_nvs = true; +} +/** * acpi_pm_disable_gpes - Disable the GPEs. */ @@ -323,7 +337,7 @@ static int acpi_hibernation_begin(void) {int error; - error =hibernate_nvs_alloc (); + error = s4_no_nvs ?0 :hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ;@@ -411,7 +425,8 @@ static int acpi_hibernation_begin_old(voint error =acpi_sleep_prepare (ACPI_STATE_S4 );if (!error) { - error =hibernate_nvs_alloc (); +if (!s4_no_nvs) + error =hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ; }Index:
linux-2.6/include/linux/acpi.h
===================================================================
include/linux/acpi.h int acpi_check_mem_region(resource_size_ · line 243
Quoted 6 lines
include/linux/acpi.h +1
-0@@ -238,6 +238,7 @@ int acpi_check_mem_region(resource_size_#ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature (void );void __init acpi_old_suspend_ordering (void ); +void __init acpi_s4_no_nvs (void );#endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */
Apart from the above,
Re: [linux-pm] [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
Quoted 44 lines · Nigel Cunningham
Hi.
Quoted 41 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt +4
-1@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation.
Quoted 13 lines
arch/x86/kernel/acpi/sleep.c static int __init acpi_sleep_setup(char · line 164
Quoted 11 lines
Documentation/kernel-parameters.txt +0
-0acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }Index:
linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================arch/x86/kernel/acpi/sleep.c +1
-0@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 )s/13/8/
Sure, thanks for catching that (it was a different string in the original patch).
Quoted 62 lines
Quoted 53 lines
arch/x86/kernel/acpi/sleep.c +1
-0+acpi_s4_no_nvs (); str =strchr (str,',' );if (str !=NULL ) str +=strspn (str,", \t" );Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +17
-2@@ -59,6 +59,20 @@ void __init acpi_old_suspend_ordering(vo old_suspend_ordering = true; } +/* +* The ACPI specification wants us to save NVS memory regions during hibernation +* and to restore them during the subsequent resume. However, it is not certain +* if this mechanism is going to work on all machines, so we allow the user to +* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line +* option. +*/ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs (void ) +{ + s4_no_nvs = true; +} +/** * acpi_pm_disable_gpes - Disable the GPEs. */ @@ -323,7 +337,7 @@ static int acpi_hibernation_begin(void) {int error; - error =hibernate_nvs_alloc (); + error = s4_no_nvs ?0 :hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ;@@ -411,7 +425,8 @@ static int acpi_hibernation_begin_old(voint error =acpi_sleep_prepare (ACPI_STATE_S4 );if (!error) { - error =hibernate_nvs_alloc (); +if (!s4_no_nvs) + error =hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ; }Index:
linux-2.6/include/linux/acpi.h
===================================================================include/linux/acpi.h int acpi_check_mem_region(resource_size_ · line 243
Quoted 6 lines
include/linux/acpi.h +1
-0@@ -238,6 +238,7 @@ int acpi_check_mem_region(resource_size_#ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature (void );void __init acpi_old_suspend_ordering (void ); +void __init acpi_s4_no_nvs (void );#endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */ Apart from the above,
Quoted 1 line
Acked-by Nigel Cunningham <[email protected]>
Thanks,
Rafael
PATCH 4/4 ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2)
Quoted 59 lines · Rafael J. Wysocki
Quoted 44 lines · Nigel Cunningham
Hi.
Quoted 41 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt +4
-1@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation.Quoted 13 lines
arch/x86/kernel/acpi/sleep.c static int __init acpi_sleep_setup(char · line 164
Quoted 11 lines
Documentation/kernel-parameters.txt +0
-0acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }Index:
linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================arch/x86/kernel/acpi/sleep.c +1
-0@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 )s/13/8/
Quoted 2 lines
Sure, thanks for catching that (it was a different string in the original patch).
Fixed version below, already with your ACK. ;-)
---
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2)
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)
Documentation/kernel-parameters.txt +4 -1
@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.
@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation. acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }
arch/x86/kernel/acpi/sleep.c +2 -0
@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,8 ) ==0 ) +acpi_s4_no_nvs (); str =strchr (str,',' );if (str !=NULL ) str +=strspn (str,", \t" );
drivers/acpi/sleep/main.c +17 -2
@@ -59,6 +59,20 @@ void __init acpi_old_suspend_ordering(vo old_suspend_ordering = true; } +/* +* The ACPI specification wants us to save NVS memory regions during hibernation +* and to restore them during the subsequent resume. However, it is not certain +* if this mechanism is going to work on all machines, so we allow the user to +* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line +* option. +*/ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs (void ) +{ + s4_no_nvs = true; +} +/** * acpi_pm_disable_gpes - Disable the GPEs. */
@@ -323,7 +337,7 @@ static int acpi_hibernation_begin(void) {int error; - error =hibernate_nvs_alloc (); + error = s4_no_nvs ?0 :hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ;
@@ -411,7 +425,8 @@ static int acpi_hibernation_begin_old(voint error =acpi_sleep_prepare (ACPI_STATE_S4 );if (!error) { - error =hibernate_nvs_alloc (); +if (!s4_no_nvs) + error =hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ; }
include/linux/acpi.h +1 -0
@@ -238,6 +238,7 @@ int acpi_check_mem_region(resource_size_#ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature (void );void __init acpi_old_suspend_ordering (void ); +void __init acpi_s4_no_nvs (void );#endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */
Re: [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2)
Quoted 75 lines · Rafael J. Wysocki
Quoted 59 lines · Rafael J. Wysocki
Quoted 44 lines · Nigel Cunningham
Hi.
Quoted 41 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt +4
-1@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation.Quoted 13 lines
arch/x86/kernel/acpi/sleep.c static int __init acpi_sleep_setup(char · line 164
Quoted 11 lines
Documentation/kernel-parameters.txt +0
-0acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }Index:
linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================arch/x86/kernel/acpi/sleep.c +1
-0@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 )s/13/8/
Quoted 2 lines
Sure, thanks for catching that (it was a different string in the original patch).
Fixed version below, already with your ACK. ;-)
---
From: Rafael J. Wysocki <[email protected]>ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2)
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Quoted 5 lines
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Acked-by Nigel Cunningham <[email protected]>Cc Zhang Rui <[email protected]>
ACK.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [linux-pm] [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2)
In reply to Rafael J. WysockiQuoted 75 lines · Rafael J. Wysocki
Quoted 59 lines · Rafael J. Wysocki
Quoted 44 lines · Nigel Cunningham
Hi.
Quoted 41 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt +4
-1@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation.Quoted 13 lines
arch/x86/kernel/acpi/sleep.c static int __init acpi_sleep_setup(char · line 164
Quoted 11 lines
Documentation/kernel-parameters.txt +0
-0acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }Index:
linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================arch/x86/kernel/acpi/sleep.c +1
-0@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 )s/13/8/
Quoted 2 lines
Sure, thanks for catching that (it was a different string in the original patch).
Fixed version below, already with your ACK. ;-)
---
From: Rafael J. Wysocki <[email protected]>ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2)
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Quoted 5 lines
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Acked-by Nigel Cunningham <[email protected]>Cc Zhang Rui <[email protected]>
ACK.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH 4/4 ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2)
In reply to Rafael J. WysockiQuoted 59 lines · Rafael J. Wysocki
Quoted 44 lines · Nigel Cunningham
Hi.
Quoted 41 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt +4
-1@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation.Quoted 13 lines
arch/x86/kernel/acpi/sleep.c static int __init acpi_sleep_setup(char · line 164
Quoted 11 lines
Documentation/kernel-parameters.txt +0
-0acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }Index:
linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================arch/x86/kernel/acpi/sleep.c +1
-0@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 )s/13/8/
Quoted 2 lines
Sure, thanks for catching that (it was a different string in the original patch).
Fixed version below, already with your ACK. ;-)
---
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2)
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)
Documentation/kernel-parameters.txt +4 -1
@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.
@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation. acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }
arch/x86/kernel/acpi/sleep.c +2 -0
@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,8 ) ==0 ) +acpi_s4_no_nvs (); str =strchr (str,',' );if (str !=NULL ) str +=strspn (str,", \t" );
drivers/acpi/sleep/main.c +17 -2
@@ -59,6 +59,20 @@ void __init acpi_old_suspend_ordering(vo old_suspend_ordering = true; } +/* +* The ACPI specification wants us to save NVS memory regions during hibernation +* and to restore them during the subsequent resume. However, it is not certain +* if this mechanism is going to work on all machines, so we allow the user to +* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line +* option. +*/ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs (void ) +{ + s4_no_nvs = true; +} +/** * acpi_pm_disable_gpes - Disable the GPEs. */
@@ -323,7 +337,7 @@ static int acpi_hibernation_begin(void) {int error; - error =hibernate_nvs_alloc (); + error = s4_no_nvs ?0 :hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ;
@@ -411,7 +425,8 @@ static int acpi_hibernation_begin_old(voint error =acpi_sleep_prepare (ACPI_STATE_S4 );if (!error) { - error =hibernate_nvs_alloc (); +if (!s4_no_nvs) + error =hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ; }
include/linux/acpi.h +1 -0
@@ -238,6 +238,7 @@ int acpi_check_mem_region(resource_size_#ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature (void );void __init acpi_old_suspend_ordering (void ); +void __init acpi_s4_no_nvs (void );#endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */
Re: [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
In reply to Nigel CunninghamQuoted 44 lines · Nigel Cunningham
Hi.
Quoted 41 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
Signed-off-by Rafael J. Wysocki <[email protected]>Cc Zhang Rui <[email protected]>--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt +4
-1@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation.
Quoted 13 lines
arch/x86/kernel/acpi/sleep.c static int __init acpi_sleep_setup(char · line 164
Quoted 11 lines
Documentation/kernel-parameters.txt +0
-0acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }Index:
linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================arch/x86/kernel/acpi/sleep.c +1
-0@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 )s/13/8/
Sure, thanks for catching that (it was a different string in the original patch).
Quoted 62 lines
Quoted 53 lines
arch/x86/kernel/acpi/sleep.c +1
-0+acpi_s4_no_nvs (); str =strchr (str,',' );if (str !=NULL ) str +=strspn (str,", \t" );Index:
linux-2.6/drivers/acpi/sleep/main.c
===================================================================drivers/acpi/sleep/main.c +17
-2@@ -59,6 +59,20 @@ void __init acpi_old_suspend_ordering(vo old_suspend_ordering = true; } +/* +* The ACPI specification wants us to save NVS memory regions during hibernation +* and to restore them during the subsequent resume. However, it is not certain +* if this mechanism is going to work on all machines, so we allow the user to +* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line +* option. +*/ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs (void ) +{ + s4_no_nvs = true; +} +/** * acpi_pm_disable_gpes - Disable the GPEs. */ @@ -323,7 +337,7 @@ static int acpi_hibernation_begin(void) {int error; - error =hibernate_nvs_alloc (); + error = s4_no_nvs ?0 :hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ;@@ -411,7 +425,8 @@ static int acpi_hibernation_begin_old(voint error =acpi_sleep_prepare (ACPI_STATE_S4 );if (!error) { - error =hibernate_nvs_alloc (); +if (!s4_no_nvs) + error =hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ; }Index:
linux-2.6/include/linux/acpi.h
===================================================================include/linux/acpi.h int acpi_check_mem_region(resource_size_ · line 243
Quoted 6 lines
include/linux/acpi.h +1
-0@@ -238,6 +238,7 @@ int acpi_check_mem_region(resource_size_#ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature (void );void __init acpi_old_suspend_ordering (void ); +void __init acpi_s4_no_nvs (void );#endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */ Apart from the above,
Quoted 1 line
Acked-by Nigel Cunningham <[email protected]>
Thanks,
Rafael
PATCH 4/4 ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs
On some machines it may be necessary to disable the saving/restoring of the ACPI NVS memory region during hibernation/resume. For this purpose, introduce new ACPI kernel command line option acpi_sleep=s4_nonvs.
Based on a patch by Zhang Rui.
--- Documentation/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep/main.c | 19 +++++++++++++++++-- include/linux/acpi.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-)
Documentation/kernel-parameters.txt +4 -1
@@ -149,7 +149,8 @@ and is between 256 and 4096 characters. default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } See Documentation/power/video.txt for s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called.
@@ -159,6 +160,8 @@ and is between 256 and 4096 characters. control method, wrt putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation. acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low }
arch/x86/kernel/acpi/sleep.c +2 -0
@@ -161,6 +161,8 @@ static int __init acpi_sleep_setup(char#endif if (strncmp (str,"old_ordering" ,12 ) ==0 )acpi_old_suspend_ordering (); +if (strncmp (str,"s4_nonvs" ,13 ) ==0 ) +acpi_s4_no_nvs (); str =strchr (str,',' );if (str !=NULL ) str +=strspn (str,", \t" );
drivers/acpi/sleep/main.c +17 -2
@@ -59,6 +59,20 @@ void __init acpi_old_suspend_ordering(vo old_suspend_ordering = true; } +/* +* The ACPI specification wants us to save NVS memory regions during hibernation +* and to restore them during the subsequent resume. However, it is not certain +* if this mechanism is going to work on all machines, so we allow the user to +* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line +* option. +*/ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs (void ) +{ + s4_no_nvs = true; +} +/** * acpi_pm_disable_gpes - Disable the GPEs. */
@@ -323,7 +337,7 @@ static int acpi_hibernation_begin(void) {int error; - error =hibernate_nvs_alloc (); + error = s4_no_nvs ?0 :hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ;
@@ -411,7 +425,8 @@ static int acpi_hibernation_begin_old(voint error =acpi_sleep_prepare (ACPI_STATE_S4 );if (!error) { - error =hibernate_nvs_alloc (); +if (!s4_no_nvs) + error =hibernate_nvs_alloc ();if (!error) acpi_target_sleep_state =ACPI_STATE_S4 ; }
include/linux/acpi.h +1 -0
@@ -238,6 +238,7 @@ int acpi_check_mem_region(resource_size_#ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature (void );void __init acpi_old_suspend_ordering (void ); +void __init acpi_s4_no_nvs (void );#endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */