* [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory [not found] <200810222249.20629.rjw@sisk.pl> @ 2008-10-22 20:50 ` Rafael J. Wysocki 2008-10-22 20:52 ` [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory Rafael J. Wysocki ` (6 subsequent siblings) 7 siblings, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-22 20:50 UTC (permalink / raw) To: Len Brown; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar From: Zhang Rui <rui.zhang@intel.com> 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(). Signed-off-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> --- kernel/power/disk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) Index: linux-2.6/kernel/power/disk.c =================================================================== --- linux-2.6.orig/kernel/power/disk.c +++ linux-2.6/kernel/power/disk.c @@ -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; ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory [not found] <200810222249.20629.rjw@sisk.pl> 2008-10-22 20:50 ` [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory Rafael J. Wysocki @ 2008-10-22 20:52 ` Rafael J. Wysocki 2008-10-22 20:53 ` [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup Rafael J. Wysocki ` (5 subsequent siblings) 7 siblings, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-22 20:52 UTC (permalink / raw) To: Len Brown; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar From: Rafael J. Wysocki <rjw@sisk.pl> 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. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Zhang Rui <rui.zhang@intel.com> --- 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 =================================================================== --- linux-2.6.orig/drivers/acpi/sleep/main.c +++ linux-2.6/drivers/acpi/sleep/main.c @@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(void static 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(vo static 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 =================================================================== --- linux-2.6.orig/include/linux/suspend.h +++ linux-2.6/include/linux/suspend.h @@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_t extern 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_fre static 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 =================================================================== --- linux-2.6.orig/kernel/power/swsusp.c +++ linux-2.6/kernel/power/swsusp.c @@ -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; +} + +/** + * hibernate_nvs_free - free data pages allocated for saving NVS regions + * + * It is allowed to call this function many times in a row. + */ +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 + */ +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); +} _______________________________________________ linux-pm mailing list linux-pm@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/linux-pm ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup [not found] <200810222249.20629.rjw@sisk.pl> 2008-10-22 20:50 ` [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory Rafael J. Wysocki 2008-10-22 20:52 ` [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory Rafael J. Wysocki @ 2008-10-22 20:53 ` Rafael J. Wysocki 2008-10-22 20:54 ` [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs Rafael J. Wysocki ` (4 subsequent siblings) 7 siblings, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-22 20:53 UTC (permalink / raw) To: Len Brown; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar From: Rafael J. Wysocki <rjw@sisk.pl> 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 <rjw@sisk.pl> Cc: Zhang Rui <rui.zhang@intel.com> --- arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) Index: linux-2.6/arch/x86/kernel/e820.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/e820.c +++ linux-2.6/arch/x86/kernel/e820.c @@ -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. */ ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs [not found] <200810222249.20629.rjw@sisk.pl> ` (2 preceding siblings ...) 2008-10-22 20:53 ` [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup Rafael J. Wysocki @ 2008-10-22 20:54 ` Rafael J. Wysocki [not found] ` <200810222252.11625.rjw@sisk.pl> ` (3 subsequent siblings) 7 siblings, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-22 20:54 UTC (permalink / raw) To: Len Brown; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar From: Rafael J. Wysocki <rjw@sisk.pl> 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 <rjw@sisk.pl> Cc: Zhang Rui <rui.zhang@intel.com> --- 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 =================================================================== --- linux-2.6.orig/Documentation/kernel-parameters.txt +++ linux-2.6/Documentation/kernel-parameters.txt @@ -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 =================================================================== --- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c +++ linux-2.6/arch/x86/kernel/acpi/sleep.c @@ -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"); Index: linux-2.6/drivers/acpi/sleep/main.c =================================================================== --- linux-2.6.orig/drivers/acpi/sleep/main.c +++ linux-2.6/drivers/acpi/sleep/main.c @@ -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(vo int 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 =================================================================== --- linux-2.6.orig/include/linux/acpi.h +++ linux-2.6/include/linux/acpi.h @@ -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 */ ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810222252.11625.rjw@sisk.pl>]
* Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory [not found] ` <200810222252.11625.rjw@sisk.pl> @ 2008-10-22 22:48 ` Nigel Cunningham [not found] ` <1224715703.8156.11.camel@nigel-laptop> ` (2 subsequent siblings) 3 siblings, 0 replies; 24+ messages in thread From: Nigel Cunningham @ 2008-10-22 22:48 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar Hi. On Wed, 2008-10-22 at 22:52 +0200, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rjw@sisk.pl> > > 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. > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> > Cc: Zhang Rui <rui.zhang@intel.com> > --- > 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 > =================================================================== > --- linux-2.6.orig/drivers/acpi/sleep/main.c > +++ linux-2.6/drivers/acpi/sleep/main.c > @@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(void > > static 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(vo > static 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 > =================================================================== > --- linux-2.6.orig/include/linux/suspend.h > +++ linux-2.6/include/linux/suspend.h > @@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_t > extern 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_fre > static 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 > =================================================================== > --- linux-2.6.orig/kernel/power/swsusp.c > +++ linux-2.6/kernel/power/swsusp.c > @@ -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; > +} > + > +/** > + * 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? > +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); 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). > + } > +} > + > +/** > + * 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"); > + > + list_for_each_entry(entry, &nvs_list, node) > + if (entry->data) > + memcpy(entry->kaddr, entry->data, entry->size); > +} Regards, Nigel _______________________________________________ linux-pm mailing list linux-pm@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/linux-pm ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <1224715703.8156.11.camel@nigel-laptop>]
* Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory [not found] ` <1224715703.8156.11.camel@nigel-laptop> @ 2008-10-22 23:08 ` Rafael J. Wysocki [not found] ` <200810230108.45101.rjw@sisk.pl> 1 sibling, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-22 23:08 UTC (permalink / raw) To: Nigel Cunningham; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar On Thursday, 23 of October 2008, Nigel Cunningham wrote: > Hi. Hi, > On Wed, 2008-10-22 at 22:52 +0200, Rafael J. Wysocki wrote: > > From: Rafael J. Wysocki <rjw@sisk.pl> > > > > 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. > > > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> > > Cc: Zhang Rui <rui.zhang@intel.com> > > --- > > 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 > > =================================================================== > > --- linux-2.6.orig/drivers/acpi/sleep/main.c > > +++ linux-2.6/drivers/acpi/sleep/main.c > > @@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(void > > > > static 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(vo > > static 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 > > =================================================================== > > --- linux-2.6.orig/include/linux/suspend.h > > +++ linux-2.6/include/linux/suspend.h > > @@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_t > > extern 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_fre > > static 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 > > =================================================================== > > --- linux-2.6.orig/kernel/power/swsusp.c > > +++ linux-2.6/kernel/power/swsusp.c > > @@ -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; > > +} > > + > > +/** > > + * 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? 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. > > +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); > > 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. :-) > > + } > > +} > > + > > +/** > > + * 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"); > > + > > + list_for_each_entry(entry, &nvs_list, node) > > + if (entry->data) > > + memcpy(entry->kaddr, entry->data, entry->size); > > +} Thanks, Rafael _______________________________________________ linux-pm mailing list linux-pm@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/linux-pm ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810230108.45101.rjw@sisk.pl>]
* Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory [not found] ` <200810230108.45101.rjw@sisk.pl> @ 2008-10-23 1:37 ` Nigel Cunningham [not found] ` <1224725825.15620.1.camel@nigel-laptop> 1 sibling, 0 replies; 24+ messages in thread From: Nigel Cunningham @ 2008-10-23 1:37 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar Hi. On Thu, 2008-10-23 at 01:08 +0200, Rafael J. Wysocki wrote: > On Thursday, 23 of October 2008, Nigel Cunningham wrote: > > Hi. > > Hi, > > > On Wed, 2008-10-22 at 22:52 +0200, Rafael J. Wysocki wrote: > > > From: Rafael J. Wysocki <rjw@sisk.pl> > > > > > > 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. > > > > > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> > > > Cc: Zhang Rui <rui.zhang@intel.com> > > > --- > > > 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 > > > =================================================================== > > > --- linux-2.6.orig/drivers/acpi/sleep/main.c > > > +++ linux-2.6/drivers/acpi/sleep/main.c > > > @@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(void > > > > > > static 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(vo > > > static 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 > > > =================================================================== > > > --- linux-2.6.orig/include/linux/suspend.h > > > +++ linux-2.6/include/linux/suspend.h > > > @@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_t > > > extern 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_fre > > > static 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 > > > =================================================================== > > > --- linux-2.6.orig/kernel/power/swsusp.c > > > +++ linux-2.6/kernel/power/swsusp.c > > > @@ -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; > > > +} > > > + > > > +/** > > > + * 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? > > 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. Okee doke. > > > +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); > > > > 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. :-) Maybe a comment then, lest someone get the same idea in future and be as ignorant as me? :) > > > + } > > > +} > > > + > > > +/** > > > + * 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"); > > > + > > > + list_for_each_entry(entry, &nvs_list, node) > > > + if (entry->data) > > > + memcpy(entry->kaddr, entry->data, entry->size); > > > +} > > Thanks, > Rafael Acked-by: Nigel Cunningham <nigel@tuxonice.net> Regards, Nigel _______________________________________________ linux-pm mailing list linux-pm@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/linux-pm ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <1224725825.15620.1.camel@nigel-laptop>]
* [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2) [not found] ` <1224725825.15620.1.camel@nigel-laptop> @ 2008-10-23 5:47 ` Rafael J. Wysocki [not found] ` <200810230747.36119.rjw@sisk.pl> 1 sibling, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-23 5:47 UTC (permalink / raw) To: Nigel Cunningham; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar On Thursday, 23 of October 2008, Nigel Cunningham wrote: > Hi. Hi, > On Thu, 2008-10-23 at 01:08 +0200, Rafael J. Wysocki wrote: > > On Thursday, 23 of October 2008, Nigel Cunningham wrote: > > > On Wed, 2008-10-22 at 22:52 +0200, Rafael J. Wysocki wrote: > > > > From: Rafael J. Wysocki <rjw@sisk.pl> [--snip--] > > > > +/** > > > > + * 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). > > > > 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 <rjw@sisk.pl> 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. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Nigel Cunningham <nigel@tuxonice.net> Cc: Zhang Rui <rui.zhang@intel.com> --- 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 =================================================================== --- linux-2.6.orig/drivers/acpi/sleep/main.c +++ linux-2.6/drivers/acpi/sleep/main.c @@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(void static 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(vo static 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 =================================================================== --- linux-2.6.orig/include/linux/suspend.h +++ linux-2.6/include/linux/suspend.h @@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_t extern 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_fre static 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 =================================================================== --- linux-2.6.orig/kernel/power/swsusp.c +++ linux-2.6/kernel/power/swsusp.c @@ -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 + * 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; +} + +/** + * hibernate_nvs_free - free data pages allocated for saving NVS regions + * + * It is allowed to call this function many times in a row. + */ +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. + */ +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); +} _______________________________________________ linux-pm mailing list linux-pm@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/linux-pm ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810230747.36119.rjw@sisk.pl>]
* Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2) [not found] ` <200810230747.36119.rjw@sisk.pl> @ 2008-10-23 8:03 ` Nigel Cunningham 0 siblings, 0 replies; 24+ messages in thread From: Nigel Cunningham @ 2008-10-23 8:03 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar Hi. On Thu, 2008-10-23 at 07:47 +0200, Rafael J. Wysocki wrote: > On Thursday, 23 of October 2008, Nigel Cunningham wrote: > > On Thu, 2008-10-23 at 01:08 +0200, Rafael J. Wysocki wrote: > > > On Thursday, 23 of October 2008, Nigel Cunningham wrote: > > > > On Wed, 2008-10-22 at 22:52 +0200, Rafael J. Wysocki wrote: > > > > > From: Rafael J. Wysocki <rjw@sisk.pl> > [--snip--] > > > > > +/** > > > > > + * 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). > > > > > > 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. > Please find updated patch below. > > --- > From: Rafael J. Wysocki <rjw@sisk.pl> > > 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. > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> > Acked-by: Nigel Cunningham <nigel@tuxonice.net> > Cc: Zhang Rui <rui.zhang@intel.com> > --- > 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 > =================================================================== > --- linux-2.6.orig/drivers/acpi/sleep/main.c > +++ linux-2.6/drivers/acpi/sleep/main.c > @@ -321,8 +321,23 @@ void __init acpi_no_s4_hw_signature(void > > static 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(vo > static 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 > =================================================================== > --- linux-2.6.orig/include/linux/suspend.h > +++ linux-2.6/include/linux/suspend.h > @@ -233,6 +233,11 @@ extern unsigned long get_safe_page(gfp_t > extern 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_fre > static 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 > =================================================================== > --- linux-2.6.orig/kernel/power/swsusp.c > +++ linux-2.6/kernel/power/swsusp.c > @@ -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. > + * 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; > +} > + > +/** > + * 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? > + */ > +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. > + */ > +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 linux-pm@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/linux-pm ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory [not found] ` <200810222252.11625.rjw@sisk.pl> 2008-10-22 22:48 ` [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory Nigel Cunningham [not found] ` <1224715703.8156.11.camel@nigel-laptop> @ 2008-10-26 12:08 ` Pavel Machek [not found] ` <20081026120838.GB1607@ucw.cz> 3 siblings, 0 replies; 24+ messages in thread From: Pavel Machek @ 2008-10-26 12:08 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar Hi! > From: Rafael J. Wysocki <rjw@sisk.pl> > > 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. > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> > Cc: Zhang Rui <rui.zhang@intel.com> > --- > drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- > include/linux/suspend.h | 13 ++++ > kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 177 insertions(+), 7 deletions(-) > > @@ -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? > #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_fre > static 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 */ Can someone call these for !hibernation case? Should they fake success if they do call them? > Index: linux-2.6/kernel/power/swsusp.c > =================================================================== > --- linux-2.6.orig/kernel/power/swsusp.c > +++ linux-2.6/kernel/power/swsusp.c > @@ -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; > +}; Maybe separate nvs.c file would be good? I believe this _is_ acpi specific, altrough in theory it may not be. -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <20081026120838.GB1607@ucw.cz>]
* Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory [not found] ` <20081026120838.GB1607@ucw.cz> @ 2008-10-26 12:23 ` Rafael J. Wysocki [not found] ` <200810261323.21293.rjw@sisk.pl> 1 sibling, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-26 12:23 UTC (permalink / raw) To: Pavel Machek; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar On Sunday, 26 of October 2008, Pavel Machek wrote: > Hi! > > > From: Rafael J. Wysocki <rjw@sisk.pl> > > > > 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. > > > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> > > Cc: Zhang Rui <rui.zhang@intel.com> > > --- > > drivers/acpi/sleep/main.c | 50 ++++++++++++++++--- > > include/linux/suspend.h | 13 ++++ > > kernel/power/swsusp.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 177 insertions(+), 7 deletions(-) > > > > > > @@ -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? No. acpi_hibernation_finish() will undo it anyway. > > #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_fre > > static 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 */ > > Can someone call these for !hibernation case? Not at the moment, but why not to add them? > Should they fake success if they do call them? > > > > Index: linux-2.6/kernel/power/swsusp.c > > =================================================================== > > --- linux-2.6.orig/kernel/power/swsusp.c > > +++ linux-2.6/kernel/power/swsusp.c > > @@ -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; > > +}; > > Maybe separate nvs.c file 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 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810261323.21293.rjw@sisk.pl>]
* Re: [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory [not found] ` <200810261323.21293.rjw@sisk.pl> @ 2008-11-18 16:14 ` Pavel Machek 0 siblings, 0 replies; 24+ messages in thread From: Pavel Machek @ 2008-11-18 16:14 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar Hi! > > > #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_fre > > > static 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 */ > > > > Can someone call these for !hibernation case? > > 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 -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810222254.48666.rjw@sisk.pl>]
* Re: [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs [not found] ` <200810222254.48666.rjw@sisk.pl> @ 2008-10-22 22:51 ` Nigel Cunningham [not found] ` <1224715892.8156.16.camel@nigel-laptop> 1 sibling, 0 replies; 24+ messages in thread From: Nigel Cunningham @ 2008-10-22 22:51 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar Hi. On Wed, 2008-10-22 at 22:54 +0200, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rjw@sisk.pl> > > 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 <rjw@sisk.pl> > Cc: Zhang Rui <rui.zhang@intel.com> > --- > 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 > =================================================================== > --- linux-2.6.orig/Documentation/kernel-parameters.txt > +++ linux-2.6/Documentation/kernel-parameters.txt > @@ -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 > =================================================================== > --- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c > +++ linux-2.6/arch/x86/kernel/acpi/sleep.c > @@ -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/ > + acpi_s4_no_nvs(); > str = strchr(str, ','); > if (str != NULL) > str += strspn(str, ", \t"); > Index: linux-2.6/drivers/acpi/sleep/main.c > =================================================================== > --- linux-2.6.orig/drivers/acpi/sleep/main.c > +++ linux-2.6/drivers/acpi/sleep/main.c > @@ -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(vo > int 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 > =================================================================== > --- linux-2.6.orig/include/linux/acpi.h > +++ linux-2.6/include/linux/acpi.h > @@ -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, Acked-by: Nigel Cunningham <nigel@tuxonice.net> ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <1224715892.8156.16.camel@nigel-laptop>]
* Re: [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs [not found] ` <1224715892.8156.16.camel@nigel-laptop> @ 2008-10-22 23:10 ` Rafael J. Wysocki [not found] ` <200810230110.04039.rjw@sisk.pl> 1 sibling, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-22 23:10 UTC (permalink / raw) To: Nigel Cunningham; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar On Thursday, 23 of October 2008, Nigel Cunningham wrote: > Hi. > > On Wed, 2008-10-22 at 22:54 +0200, Rafael J. Wysocki wrote: > > From: Rafael J. Wysocki <rjw@sisk.pl> > > > > 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 <rjw@sisk.pl> > > Cc: Zhang Rui <rui.zhang@intel.com> > > --- > > 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 > > =================================================================== > > --- linux-2.6.orig/Documentation/kernel-parameters.txt > > +++ linux-2.6/Documentation/kernel-parameters.txt > > @@ -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 > > =================================================================== > > --- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c > > +++ linux-2.6/arch/x86/kernel/acpi/sleep.c > > @@ -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). > > + acpi_s4_no_nvs(); > > str = strchr(str, ','); > > if (str != NULL) > > str += strspn(str, ", \t"); > > Index: linux-2.6/drivers/acpi/sleep/main.c > > =================================================================== > > --- linux-2.6.orig/drivers/acpi/sleep/main.c > > +++ linux-2.6/drivers/acpi/sleep/main.c > > @@ -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(vo > > int 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 > > =================================================================== > > --- linux-2.6.orig/include/linux/acpi.h > > +++ linux-2.6/include/linux/acpi.h > > @@ -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, > > Acked-by: Nigel Cunningham <nigel@tuxonice.net> Thanks, Rafael ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810230110.04039.rjw@sisk.pl>]
* [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2) [not found] ` <200810230110.04039.rjw@sisk.pl> @ 2008-10-22 23:19 ` Rafael J. Wysocki [not found] ` <200810230119.55519.rjw@sisk.pl> 1 sibling, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-22 23:19 UTC (permalink / raw) To: Nigel Cunningham; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar On Thursday, 23 of October 2008, Rafael J. Wysocki wrote: > On Thursday, 23 of October 2008, Nigel Cunningham wrote: > > Hi. > > > > On Wed, 2008-10-22 at 22:54 +0200, Rafael J. Wysocki wrote: > > > From: Rafael J. Wysocki <rjw@sisk.pl> > > > > > > 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 <rjw@sisk.pl> > > > Cc: Zhang Rui <rui.zhang@intel.com> > > > --- > > > 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 > > > =================================================================== > > > --- linux-2.6.orig/Documentation/kernel-parameters.txt > > > +++ linux-2.6/Documentation/kernel-parameters.txt > > > @@ -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 > > > =================================================================== > > > --- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c > > > +++ linux-2.6/arch/x86/kernel/acpi/sleep.c > > > @@ -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). Fixed version below, already with your ACK. ;-) --- From: Rafael J. Wysocki <rjw@sisk.pl> 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. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Nigel Cunningham <nigel@tuxonice.net> Cc: Zhang Rui <rui.zhang@intel.com> --- 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 =================================================================== --- linux-2.6.orig/Documentation/kernel-parameters.txt +++ linux-2.6/Documentation/kernel-parameters.txt @@ -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 =================================================================== --- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c +++ linux-2.6/arch/x86/kernel/acpi/sleep.c @@ -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"); Index: linux-2.6/drivers/acpi/sleep/main.c =================================================================== --- linux-2.6.orig/drivers/acpi/sleep/main.c +++ linux-2.6/drivers/acpi/sleep/main.c @@ -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(vo int 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 =================================================================== --- linux-2.6.orig/include/linux/acpi.h +++ linux-2.6/include/linux/acpi.h @@ -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 */ ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810230119.55519.rjw@sisk.pl>]
* Re: [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2) [not found] ` <200810230119.55519.rjw@sisk.pl> @ 2008-10-26 12:18 ` Pavel Machek 0 siblings, 0 replies; 24+ messages in thread From: Pavel Machek @ 2008-10-26 12:18 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Nigel Cunningham, Ingo Molnar, pm list On Thu 2008-10-23 01:19:54, Rafael J. Wysocki wrote: > On Thursday, 23 of October 2008, Rafael J. Wysocki wrote: > > On Thursday, 23 of October 2008, Nigel Cunningham wrote: > > > Hi. > > > > > > On Wed, 2008-10-22 at 22:54 +0200, Rafael J. Wysocki wrote: > > > > From: Rafael J. Wysocki <rjw@sisk.pl> > > > > > > > > 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 <rjw@sisk.pl> > > > > Cc: Zhang Rui <rui.zhang@intel.com> > > > > --- > > > > 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 > > > > =================================================================== > > > > --- linux-2.6.orig/Documentation/kernel-parameters.txt > > > > +++ linux-2.6/Documentation/kernel-parameters.txt > > > > @@ -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 > > > > =================================================================== > > > > --- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c > > > > +++ linux-2.6/arch/x86/kernel/acpi/sleep.c > > > > @@ -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). > > Fixed version below, already with your ACK. ;-) > > --- > From: Rafael J. Wysocki <rjw@sisk.pl> > > 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. > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> > Acked-by: Nigel Cunningham <nigel@tuxonice.net> > Cc: Zhang Rui <rui.zhang@intel.com> ACK. Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810222250.36537.rjw@sisk.pl>]
* Re: [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory [not found] ` <200810222250.36537.rjw@sisk.pl> @ 2008-10-22 22:37 ` Nigel Cunningham 2008-10-26 12:00 ` Pavel Machek 1 sibling, 0 replies; 24+ messages in thread From: Nigel Cunningham @ 2008-10-22 22:37 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar Hi. On Wed, 2008-10-22 at 22:50 +0200, Rafael J. Wysocki wrote: > From: Zhang Rui <rui.zhang@intel.com> > > 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(). > > Signed-off-by: Zhang Rui <rui.zhang@intel.com> > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> > --- > kernel/power/disk.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > Index: linux-2.6/kernel/power/disk.c > =================================================================== > --- linux-2.6.orig/kernel/power/disk.c > +++ linux-2.6/kernel/power/disk.c > @@ -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; > Acked-by: Nigel Cunningham <nigel@tuxonice.net> ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory [not found] ` <200810222250.36537.rjw@sisk.pl> 2008-10-22 22:37 ` [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory Nigel Cunningham @ 2008-10-26 12:00 ` Pavel Machek 1 sibling, 0 replies; 24+ messages in thread From: Pavel Machek @ 2008-10-26 12:00 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar On Wed 2008-10-22 22:50:35, Rafael J. Wysocki wrote: > From: Zhang Rui <rui.zhang@intel.com> > > 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(). > > Signed-off-by: Zhang Rui <rui.zhang@intel.com> > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> ACK. -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810222253.16264.rjw@sisk.pl>]
* Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup [not found] ` <200810222253.16264.rjw@sisk.pl> @ 2008-10-26 12:14 ` Pavel Machek [not found] ` <20081026121404.GC1607@ucw.cz> 1 sibling, 0 replies; 24+ messages in thread From: Pavel Machek @ 2008-10-26 12:14 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar On Wed 2008-10-22 22:53:15, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rjw@sisk.pl> > > 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 <rjw@sisk.pl> > Cc: Zhang Rui <rui.zhang@intel.com> > --- > arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ > 1 file changed, 25 insertions(+) > > Index: linux-2.6/arch/x86/kernel/e820.c > =================================================================== > --- linux-2.6.orig/arch/x86/kernel/e820.c > +++ linux-2.6/arch/x86/kernel/e820.c > @@ -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? > @@ -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; Aha, not unrelated... why is that? EFI does not use acpi? > + 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?) -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <20081026121404.GC1607@ucw.cz>]
* Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup [not found] ` <20081026121404.GC1607@ucw.cz> @ 2008-10-26 12:29 ` Rafael J. Wysocki [not found] ` <200810261329.16260.rjw@sisk.pl> 1 sibling, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-26 12:29 UTC (permalink / raw) To: Pavel Machek; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar On Sunday, 26 of October 2008, Pavel Machek wrote: > On Wed 2008-10-22 22:53:15, Rafael J. Wysocki wrote: > > From: Rafael J. Wysocki <rjw@sisk.pl> > > > > 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 <rjw@sisk.pl> > > Cc: Zhang Rui <rui.zhang@intel.com> > > --- > > arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ > > 1 file changed, 25 insertions(+) > > > > Index: linux-2.6/arch/x86/kernel/e820.c > > =================================================================== > > --- linux-2.6.orig/arch/x86/kernel/e820.c > > +++ linux-2.6/arch/x86/kernel/e820.c > > @@ -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? > > > @@ -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; > > 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? > > + 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?) It can, in which case it will do the cleanup. Thanks, Rafael ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810261329.16260.rjw@sisk.pl>]
* Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup [not found] ` <200810261329.16260.rjw@sisk.pl> @ 2008-10-29 9:21 ` Zhang Rui [not found] ` <1225272091.2665.4.camel@rzhang-dt> 1 sibling, 0 replies; 24+ messages in thread From: Zhang Rui @ 2008-10-29 9:21 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Pavel Machek, Ingo Molnar, pm list Hi, sorry for the delay, On Sun, 2008-10-26 at 20:29 +0800, Rafael J. Wysocki wrote: > On Sunday, 26 of October 2008, Pavel Machek wrote: > > On Wed 2008-10-22 22:53:15, Rafael J. Wysocki wrote: > > > From: Rafael J. Wysocki <rjw@sisk.pl> > > > > > > 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 <rjw@sisk.pl> > > > Cc: Zhang Rui <rui.zhang@intel.com> > > > --- > > > arch/x86/kernel/e820.c | 25 +++++++++++++++++++++++++ > > > 1 file changed, 25 insertions(+) > > > > > > Index: linux-2.6/arch/x86/kernel/e820.c > > > =================================================================== > > > --- linux-2.6.orig/arch/x86/kernel/e820.c > > > +++ linux-2.6/arch/x86/kernel/e820.c > > > @@ -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? > > > > > @@ -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; > > > > 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. I'd prefer not to touch it currently. thanks, rui > > > + 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?) > > It can, in which case it will do the cleanup. > > Thanks, > Rafael _______________________________________________ linux-pm mailing list linux-pm@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/linux-pm ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <1225272091.2665.4.camel@rzhang-dt>]
* Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup [not found] ` <1225272091.2665.4.camel@rzhang-dt> @ 2008-10-29 11:18 ` Pavel Machek [not found] ` <20081029111837.GA20466@atrey.karlin.mff.cuni.cz> 1 sibling, 0 replies; 24+ messages in thread From: Pavel Machek @ 2008-10-29 11:18 UTC (permalink / raw) To: Zhang Rui; +Cc: ACPI Devel Maling List, pm list, Ingo Molnar Hi! > > > > +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. > 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. -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <20081029111837.GA20466@atrey.karlin.mff.cuni.cz>]
* Re: [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup [not found] ` <20081029111837.GA20466@atrey.karlin.mff.cuni.cz> @ 2008-10-30 23:59 ` Rafael J. Wysocki 0 siblings, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-30 23:59 UTC (permalink / raw) To: Pavel Machek; +Cc: ACPI Devel Maling List, Ingo Molnar, pm list On Wednesday, 29 of October 2008, Pavel Machek wrote: > Hi! > > > > > > +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. > > 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 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <200810262048.23468.rjw@sisk.pl>]
* [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory [not found] <200810262048.23468.rjw@sisk.pl> @ 2008-10-26 19:50 ` Rafael J. Wysocki 0 siblings, 0 replies; 24+ messages in thread From: Rafael J. Wysocki @ 2008-10-26 19:50 UTC (permalink / raw) To: Len Brown Cc: Nigel Cunningham, Ingo Molnar, ACPI Devel Maling List, Pavel Machek, pm list From: Zhang Rui <rui.zhang@intel.com> Subject: 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(). Signed-off-by: Zhang Rui <rui.zhang@intel.com> Acked-by: Nigel Cunningham <nigel@tuxonice.net> Acked-by: Pavel Machek <pavel@suse.cz> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> --- kernel/power/disk.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/power/disk.c b/kernel/power/disk.c index c9d7408..096fe48 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -259,12 +259,12 @@ int hibernation_snapshot(int platform_mode) { 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; -- 1.5.6 ^ permalink raw reply related [flat|nested] 24+ messages in thread
end of thread, other threads:[~2008-11-18 16:14 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <200810222249.20629.rjw@sisk.pl>
2008-10-22 20:50 ` [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory Rafael J. Wysocki
2008-10-22 20:52 ` [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory Rafael J. Wysocki
2008-10-22 20:53 ` [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup Rafael J. Wysocki
2008-10-22 20:54 ` [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs Rafael J. Wysocki
[not found] ` <200810222252.11625.rjw@sisk.pl>
2008-10-22 22:48 ` [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory Nigel Cunningham
[not found] ` <1224715703.8156.11.camel@nigel-laptop>
2008-10-22 23:08 ` Rafael J. Wysocki
[not found] ` <200810230108.45101.rjw@sisk.pl>
2008-10-23 1:37 ` Nigel Cunningham
[not found] ` <1224725825.15620.1.camel@nigel-laptop>
2008-10-23 5:47 ` [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory (rev. 2) Rafael J. Wysocki
[not found] ` <200810230747.36119.rjw@sisk.pl>
2008-10-23 8:03 ` Nigel Cunningham
2008-10-26 12:08 ` [PATCH 2/4] ACPI hibernate: Add a mechanism to save/restore ACPI NVS memory Pavel Machek
[not found] ` <20081026120838.GB1607@ucw.cz>
2008-10-26 12:23 ` Rafael J. Wysocki
[not found] ` <200810261323.21293.rjw@sisk.pl>
2008-11-18 16:14 ` Pavel Machek
[not found] ` <200810222254.48666.rjw@sisk.pl>
2008-10-22 22:51 ` [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs Nigel Cunningham
[not found] ` <1224715892.8156.16.camel@nigel-laptop>
2008-10-22 23:10 ` Rafael J. Wysocki
[not found] ` <200810230110.04039.rjw@sisk.pl>
2008-10-22 23:19 ` [PATCH 4/4] ACPI hibernate: Introduce new kernel parameter acpi_sleep=s4_nonvs (rev. 2) Rafael J. Wysocki
[not found] ` <200810230119.55519.rjw@sisk.pl>
2008-10-26 12:18 ` Pavel Machek
[not found] ` <200810222250.36537.rjw@sisk.pl>
2008-10-22 22:37 ` [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory Nigel Cunningham
2008-10-26 12:00 ` Pavel Machek
[not found] ` <200810222253.16264.rjw@sisk.pl>
2008-10-26 12:14 ` [PATCH 3/4] x86 hibernate: Mark ACPI NVS memory region at startup Pavel Machek
[not found] ` <20081026121404.GC1607@ucw.cz>
2008-10-26 12:29 ` Rafael J. Wysocki
[not found] ` <200810261329.16260.rjw@sisk.pl>
2008-10-29 9:21 ` Zhang Rui
[not found] ` <1225272091.2665.4.camel@rzhang-dt>
2008-10-29 11:18 ` Pavel Machek
[not found] ` <20081029111837.GA20466@atrey.karlin.mff.cuni.cz>
2008-10-30 23:59 ` Rafael J. Wysocki
[not found] <200810262048.23468.rjw@sisk.pl>
2008-10-26 19:50 ` [PATCH 1/4] Hibernate: Call platform_begin before swsusp_shrink_memory Rafael J. Wysocki
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox