mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
PM/Hibernate: Move NVS routines into a seperate file (v2).
The *_nvs_* routines in swsusp.c make use of the io*map() functions, which are only provided for HAS_IOMEM, thus breaking compilation if HAS_IOMEM is not set. Fix this by moving the *_nvs_* routines into hibernate_nvs.c, which is only compiled if HAS_IOMEM is set. [rjw: Change the name of the new file to hibernate_nvs.c, add the license line to the header comment.] Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
This commit is contained in:
parent
8b759b84c8
commit
fce2b111fa
5 changed files with 151 additions and 129 deletions
|
@ -245,11 +245,6 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
|
||||||
|
|
||||||
extern void hibernation_set_ops(struct platform_hibernation_ops *ops);
|
extern void hibernation_set_ops(struct platform_hibernation_ops *ops);
|
||||||
extern int hibernate(void);
|
extern int hibernate(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);
|
|
||||||
extern bool system_entering_hibernation(void);
|
extern bool system_entering_hibernation(void);
|
||||||
#else /* CONFIG_HIBERNATION */
|
#else /* CONFIG_HIBERNATION */
|
||||||
static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
|
static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
|
||||||
|
@ -258,6 +253,16 @@ static inline void swsusp_unset_page_free(struct page *p) {}
|
||||||
|
|
||||||
static inline void hibernation_set_ops(struct platform_hibernation_ops *ops) {}
|
static inline void hibernation_set_ops(struct platform_hibernation_ops *ops) {}
|
||||||
static inline int hibernate(void) { return -ENOSYS; }
|
static inline int hibernate(void) { return -ENOSYS; }
|
||||||
|
static inline bool system_entering_hibernation(void) { return false; }
|
||||||
|
#endif /* CONFIG_HIBERNATION */
|
||||||
|
|
||||||
|
#ifdef CONFIG_HIBERNATION_NVS
|
||||||
|
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_NVS */
|
||||||
static inline int hibernate_nvs_register(unsigned long a, unsigned long b)
|
static inline int hibernate_nvs_register(unsigned long a, unsigned long b)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -266,8 +271,7 @@ static inline int hibernate_nvs_alloc(void) { return 0; }
|
||||||
static inline void hibernate_nvs_free(void) {}
|
static inline void hibernate_nvs_free(void) {}
|
||||||
static inline void hibernate_nvs_save(void) {}
|
static inline void hibernate_nvs_save(void) {}
|
||||||
static inline void hibernate_nvs_restore(void) {}
|
static inline void hibernate_nvs_restore(void) {}
|
||||||
static inline bool system_entering_hibernation(void) { return false; }
|
#endif /* CONFIG_HIBERNATION_NVS */
|
||||||
#endif /* CONFIG_HIBERNATION */
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
void save_processor_state(void);
|
void save_processor_state(void);
|
||||||
|
|
|
@ -116,9 +116,13 @@ config SUSPEND_FREEZER
|
||||||
|
|
||||||
Turning OFF this setting is NOT recommended! If in doubt, say Y.
|
Turning OFF this setting is NOT recommended! If in doubt, say Y.
|
||||||
|
|
||||||
|
config HIBERNATION_NVS
|
||||||
|
bool
|
||||||
|
|
||||||
config HIBERNATION
|
config HIBERNATION
|
||||||
bool "Hibernation (aka 'suspend to disk')"
|
bool "Hibernation (aka 'suspend to disk')"
|
||||||
depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
|
depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
|
||||||
|
select HIBERNATION_NVS if HAS_IOMEM
|
||||||
---help---
|
---help---
|
||||||
Enable the suspend to disk (STD) functionality, which is usually
|
Enable the suspend to disk (STD) functionality, which is usually
|
||||||
called "hibernation" in user interfaces. STD checkpoints the
|
called "hibernation" in user interfaces. STD checkpoints the
|
||||||
|
|
|
@ -9,5 +9,6 @@ obj-$(CONFIG_FREEZER) += process.o
|
||||||
obj-$(CONFIG_SUSPEND) += suspend.o
|
obj-$(CONFIG_SUSPEND) += suspend.o
|
||||||
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
|
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
|
||||||
obj-$(CONFIG_HIBERNATION) += swsusp.o hibernate.o snapshot.o swap.o user.o
|
obj-$(CONFIG_HIBERNATION) += swsusp.o hibernate.o snapshot.o swap.o user.o
|
||||||
|
obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o
|
||||||
|
|
||||||
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
|
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
|
||||||
|
|
135
kernel/power/hibernate_nvs.c
Normal file
135
kernel/power/hibernate_nvs.c
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008,2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
||||||
|
*
|
||||||
|
* This file is released under the GPLv2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
|
@ -186,125 +186,3 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
|
||||||
centisecs / 100, centisecs % 100,
|
centisecs / 100, centisecs % 100,
|
||||||
kps / 1000, (kps % 1000) / 10);
|
kps / 1000, (kps % 1000) / 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue