lkml.org 
[lkml]   [2009]   [Jun]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH v2] pm: Move nvs routines into a seperate file.
    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 hibernation_nvs.c, which
    is only compiled if HAS_IOMEM is set.

    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>

    ---
    include/linux/suspend.h | 18 +++--
    kernel/power/Kconfig | 4 +
    kernel/power/Makefile | 1
    kernel/power/hibernation_nvs.c | 135 +++++++++++++++++++++++++++++++++++++++++
    kernel/power/swsusp.c | 122 -------------------------------------
    5 files changed, 151 insertions(+), 129 deletions(-)

    --- /dev/null
    +++ linux-suspend/kernel/power/hibernation_nvs.c
    @@ -0,0 +1,135 @@
    +/*
    + * linux/kernel/power/hibernation_nvs.c
    + *
    + * Copyright (C) 2008,2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
    + *
    + * Routines for NVS memory handling
    + */
    +
    +#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);
    +}
    --- linux-suspend.orig/kernel/power/swsusp.c
    +++ linux-suspend/kernel/power/swsusp.c
    @@ -186,125 +186,3 @@ void swsusp_show_speed(struct timeval *s
    centisecs / 100, centisecs % 100,
    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);
    -}
    --- linux-suspend.orig/kernel/power/Kconfig
    +++ linux-suspend/kernel/power/Kconfig
    @@ -116,9 +116,13 @@ config SUSPEND_FREEZER

    Turning OFF this setting is NOT recommended! If in doubt, say Y.

    +config HIBERNATION_NVS
    + bool
    +
    config HIBERNATION
    bool "Hibernation (aka 'suspend to disk')"
    depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
    + select HIBERNATION_NVS if HAS_IOMEM
    ---help---
    Enable the suspend to disk (STD) functionality, which is usually
    called "hibernation" in user interfaces. STD checkpoints the
    --- linux-suspend.orig/kernel/power/Makefile
    +++ linux-suspend/kernel/power/Makefile
    @@ -7,5 +7,6 @@ obj-$(CONFIG_PM) += main.o
    obj-$(CONFIG_PM_SLEEP) += console.o
    obj-$(CONFIG_FREEZER) += process.o
    obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o
    +obj-$(CONFIG_HIBERNATION_NVS) += hibernation_nvs.o

    obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
    --- linux-suspend.orig/include/linux/suspend.h
    +++ linux-suspend/include/linux/suspend.h
    @@ -245,11 +245,6 @@ extern unsigned long get_safe_page(gfp_t

    extern void hibernation_set_ops(struct platform_hibernation_ops *ops);
    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);
    #else /* CONFIG_HIBERNATION */
    static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
    @@ -258,6 +253,16 @@ 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; }
    +#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)
    {
    return 0;
    @@ -266,8 +271,7 @@ static inline int hibernate_nvs_alloc(vo
    static inline void hibernate_nvs_free(void) {}
    static inline void hibernate_nvs_save(void) {}
    static inline void hibernate_nvs_restore(void) {}
    -static inline bool system_entering_hibernation(void) { return false; }
    -#endif /* CONFIG_HIBERNATION */
    +#endif /* CONFIG_HIBERNATION_NVS */

    #ifdef CONFIG_PM_SLEEP
    void save_processor_state(void);

    \
     
     \ /
      Last update: 2009-06-09 10:43    [W:2.641 / U:0.180 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site