Commit 976513dbfc1547c7b1822566923058655f0c32fd

Authored by Rafael J. Wysocki
Committed by Len Brown
1 parent 26fcaf60fe

PM / ACPI: Move NVS saving and restoring code to drivers/acpi

The saving of the ACPI NVS area during hibernation and suspend and
restoring it during the subsequent resume is entirely specific to
ACPI, so move it to drivers/acpi and drop the CONFIG_SUSPEND_NVS
configuration option which is redundant.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>

Showing 9 changed files with 161 additions and 166 deletions Side-by-side Diff

arch/x86/kernel/e820.c
... ... @@ -14,6 +14,7 @@
14 14 #include <linux/bootmem.h>
15 15 #include <linux/pfn.h>
16 16 #include <linux/suspend.h>
  17 +#include <linux/acpi.h>
17 18 #include <linux/firmware-map.h>
18 19 #include <linux/memblock.h>
19 20  
drivers/acpi/Makefile
... ... @@ -24,7 +24,7 @@
24 24 # sleep related files
25 25 acpi-y += wakeup.o
26 26 acpi-y += sleep.o
27   -acpi-$(CONFIG_ACPI_SLEEP) += proc.o
  27 +acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o
28 28  
29 29  
30 30 #
drivers/acpi/internal.h
... ... @@ -82,8 +82,16 @@
82 82  
83 83 #ifdef CONFIG_ACPI_SLEEP
84 84 int acpi_sleep_proc_init(void);
  85 +int suspend_nvs_alloc(void);
  86 +void suspend_nvs_free(void);
  87 +int suspend_nvs_save(void);
  88 +void suspend_nvs_restore(void);
85 89 #else
86 90 static inline int acpi_sleep_proc_init(void) { return 0; }
  91 +static inline int suspend_nvs_alloc(void) { return 0; }
  92 +static inline void suspend_nvs_free(void) {}
  93 +static inline int suspend_nvs_save(void) {}
  94 +static inline void suspend_nvs_restore(void) {}
87 95 #endif
88 96  
89 97 #endif /* _ACPI_INTERNAL_H_ */
  1 +/*
  2 + * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory
  3 + *
  4 + * Copyright (C) 2008,2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
  5 + *
  6 + * This file is released under the GPLv2.
  7 + */
  8 +
  9 +#include <linux/io.h>
  10 +#include <linux/kernel.h>
  11 +#include <linux/list.h>
  12 +#include <linux/mm.h>
  13 +#include <linux/slab.h>
  14 +#include <linux/suspend.h>
  15 +
  16 +/*
  17 + * Platforms, like ACPI, may want us to save some memory used by them during
  18 + * suspend and to restore the contents of this memory during the subsequent
  19 + * resume. The code below implements a mechanism allowing us to do that.
  20 + */
  21 +
  22 +struct nvs_page {
  23 + unsigned long phys_start;
  24 + unsigned int size;
  25 + void *kaddr;
  26 + void *data;
  27 + struct list_head node;
  28 +};
  29 +
  30 +static LIST_HEAD(nvs_list);
  31 +
  32 +/**
  33 + * suspend_nvs_register - register platform NVS memory region to save
  34 + * @start - physical address of the region
  35 + * @size - size of the region
  36 + *
  37 + * The NVS region need not be page-aligned (both ends) and we arrange
  38 + * things so that the data from page-aligned addresses in this region will
  39 + * be copied into separate RAM pages.
  40 + */
  41 +int suspend_nvs_register(unsigned long start, unsigned long size)
  42 +{
  43 + struct nvs_page *entry, *next;
  44 +
  45 + while (size > 0) {
  46 + unsigned int nr_bytes;
  47 +
  48 + entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
  49 + if (!entry)
  50 + goto Error;
  51 +
  52 + list_add_tail(&entry->node, &nvs_list);
  53 + entry->phys_start = start;
  54 + nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
  55 + entry->size = (size < nr_bytes) ? size : nr_bytes;
  56 +
  57 + start += entry->size;
  58 + size -= entry->size;
  59 + }
  60 + return 0;
  61 +
  62 + Error:
  63 + list_for_each_entry_safe(entry, next, &nvs_list, node) {
  64 + list_del(&entry->node);
  65 + kfree(entry);
  66 + }
  67 + return -ENOMEM;
  68 +}
  69 +
  70 +/**
  71 + * suspend_nvs_free - free data pages allocated for saving NVS regions
  72 + */
  73 +void suspend_nvs_free(void)
  74 +{
  75 + struct nvs_page *entry;
  76 +
  77 + list_for_each_entry(entry, &nvs_list, node)
  78 + if (entry->data) {
  79 + free_page((unsigned long)entry->data);
  80 + entry->data = NULL;
  81 + if (entry->kaddr) {
  82 + iounmap(entry->kaddr);
  83 + entry->kaddr = NULL;
  84 + }
  85 + }
  86 +}
  87 +
  88 +/**
  89 + * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
  90 + */
  91 +int suspend_nvs_alloc(void)
  92 +{
  93 + struct nvs_page *entry;
  94 +
  95 + list_for_each_entry(entry, &nvs_list, node) {
  96 + entry->data = (void *)__get_free_page(GFP_KERNEL);
  97 + if (!entry->data) {
  98 + suspend_nvs_free();
  99 + return -ENOMEM;
  100 + }
  101 + }
  102 + return 0;
  103 +}
  104 +
  105 +/**
  106 + * suspend_nvs_save - save NVS memory regions
  107 + */
  108 +int suspend_nvs_save(void)
  109 +{
  110 + struct nvs_page *entry;
  111 +
  112 + printk(KERN_INFO "PM: Saving platform NVS memory\n");
  113 +
  114 + list_for_each_entry(entry, &nvs_list, node)
  115 + if (entry->data) {
  116 + entry->kaddr = ioremap(entry->phys_start, entry->size);
  117 + if (!entry->kaddr) {
  118 + suspend_nvs_free();
  119 + return -ENOMEM;
  120 + }
  121 + memcpy(entry->data, entry->kaddr, entry->size);
  122 + }
  123 +
  124 + return 0;
  125 +}
  126 +
  127 +/**
  128 + * suspend_nvs_restore - restore NVS memory regions
  129 + *
  130 + * This function is going to be called with interrupts disabled, so it
  131 + * cannot iounmap the virtual addresses used to access the NVS region.
  132 + */
  133 +void suspend_nvs_restore(void)
  134 +{
  135 + struct nvs_page *entry;
  136 +
  137 + printk(KERN_INFO "PM: Restoring platform NVS memory\n");
  138 +
  139 + list_for_each_entry(entry, &nvs_list, node)
  140 + if (entry->data)
  141 + memcpy(entry->kaddr, entry->data, entry->size);
  142 +}
include/linux/acpi.h
... ... @@ -254,6 +254,15 @@
254 254 void __init acpi_nvs_nosave(void);
255 255 #endif /* CONFIG_PM_SLEEP */
256 256  
  257 +#ifdef CONFIG_ACPI_SLEEP
  258 +int suspend_nvs_register(unsigned long start, unsigned long size);
  259 +#else
  260 +static inline int suspend_nvs_register(unsigned long a, unsigned long b)
  261 +{
  262 + return 0;
  263 +}
  264 +#endif
  265 +
257 266 struct acpi_osc_context {
258 267 char *uuid_str; /* uuid string */
259 268 int rev;
include/linux/suspend.h
... ... @@ -258,23 +258,6 @@
258 258 static inline bool system_entering_hibernation(void) { return false; }
259 259 #endif /* CONFIG_HIBERNATION */
260 260  
261   -#ifdef CONFIG_SUSPEND_NVS
262   -extern int suspend_nvs_register(unsigned long start, unsigned long size);
263   -extern int suspend_nvs_alloc(void);
264   -extern void suspend_nvs_free(void);
265   -extern int suspend_nvs_save(void);
266   -extern void suspend_nvs_restore(void);
267   -#else /* CONFIG_SUSPEND_NVS */
268   -static inline int suspend_nvs_register(unsigned long a, unsigned long b)
269   -{
270   - return 0;
271   -}
272   -static inline int suspend_nvs_alloc(void) { return 0; }
273   -static inline void suspend_nvs_free(void) {}
274   -static inline int suspend_nvs_save(void) {}
275   -static inline void suspend_nvs_restore(void) {}
276   -#endif /* CONFIG_SUSPEND_NVS */
277   -
278 261 #ifdef CONFIG_PM_SLEEP
279 262 void save_processor_state(void);
280 263 void restore_processor_state(void);
kernel/power/Kconfig
... ... @@ -100,13 +100,9 @@
100 100 depends on PM_ADVANCED_DEBUG
101 101 default n
102 102  
103   -config SUSPEND_NVS
104   - bool
105   -
106 103 config SUSPEND
107 104 bool "Suspend to RAM and standby"
108 105 depends on PM && ARCH_SUSPEND_POSSIBLE
109   - select SUSPEND_NVS if HAS_IOMEM
110 106 default y
111 107 ---help---
112 108 Allow the system to enter sleep states in which main memory is
... ... @@ -140,7 +136,6 @@
140 136 depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
141 137 select LZO_COMPRESS
142 138 select LZO_DECOMPRESS
143   - select SUSPEND_NVS if HAS_IOMEM
144 139 ---help---
145 140 Enable the suspend to disk (STD) functionality, which is usually
146 141 called "hibernation" in user interfaces. STD checkpoints the
kernel/power/Makefile
... ... @@ -10,7 +10,6 @@
10 10 obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
11 11 obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \
12 12 block_io.o
13   -obj-$(CONFIG_SUSPEND_NVS) += nvs.o
14 13  
15 14 obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
kernel/power/nvs.c
1   -/*
2   - * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory
3   - *
4   - * Copyright (C) 2008,2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
5   - *
6   - * This file is released under the GPLv2.
7   - */
8   -
9   -#include <linux/io.h>
10   -#include <linux/kernel.h>
11   -#include <linux/list.h>
12   -#include <linux/mm.h>
13   -#include <linux/slab.h>
14   -#include <linux/suspend.h>
15   -
16   -/*
17   - * Platforms, like ACPI, may want us to save some memory used by them during
18   - * suspend and to restore the contents of this memory during the subsequent
19   - * resume. The code below implements a mechanism allowing us to do that.
20   - */
21   -
22   -struct nvs_page {
23   - unsigned long phys_start;
24   - unsigned int size;
25   - void *kaddr;
26   - void *data;
27   - struct list_head node;
28   -};
29   -
30   -static LIST_HEAD(nvs_list);
31   -
32   -/**
33   - * suspend_nvs_register - register platform NVS memory region to save
34   - * @start - physical address of the region
35   - * @size - size of the region
36   - *
37   - * The NVS region need not be page-aligned (both ends) and we arrange
38   - * things so that the data from page-aligned addresses in this region will
39   - * be copied into separate RAM pages.
40   - */
41   -int suspend_nvs_register(unsigned long start, unsigned long size)
42   -{
43   - struct nvs_page *entry, *next;
44   -
45   - while (size > 0) {
46   - unsigned int nr_bytes;
47   -
48   - entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
49   - if (!entry)
50   - goto Error;
51   -
52   - list_add_tail(&entry->node, &nvs_list);
53   - entry->phys_start = start;
54   - nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
55   - entry->size = (size < nr_bytes) ? size : nr_bytes;
56   -
57   - start += entry->size;
58   - size -= entry->size;
59   - }
60   - return 0;
61   -
62   - Error:
63   - list_for_each_entry_safe(entry, next, &nvs_list, node) {
64   - list_del(&entry->node);
65   - kfree(entry);
66   - }
67   - return -ENOMEM;
68   -}
69   -
70   -/**
71   - * suspend_nvs_free - free data pages allocated for saving NVS regions
72   - */
73   -void suspend_nvs_free(void)
74   -{
75   - struct nvs_page *entry;
76   -
77   - list_for_each_entry(entry, &nvs_list, node)
78   - if (entry->data) {
79   - free_page((unsigned long)entry->data);
80   - entry->data = NULL;
81   - if (entry->kaddr) {
82   - iounmap(entry->kaddr);
83   - entry->kaddr = NULL;
84   - }
85   - }
86   -}
87   -
88   -/**
89   - * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
90   - */
91   -int suspend_nvs_alloc(void)
92   -{
93   - struct nvs_page *entry;
94   -
95   - list_for_each_entry(entry, &nvs_list, node) {
96   - entry->data = (void *)__get_free_page(GFP_KERNEL);
97   - if (!entry->data) {
98   - suspend_nvs_free();
99   - return -ENOMEM;
100   - }
101   - }
102   - return 0;
103   -}
104   -
105   -/**
106   - * suspend_nvs_save - save NVS memory regions
107   - */
108   -int suspend_nvs_save(void)
109   -{
110   - struct nvs_page *entry;
111   -
112   - printk(KERN_INFO "PM: Saving platform NVS memory\n");
113   -
114   - list_for_each_entry(entry, &nvs_list, node)
115   - if (entry->data) {
116   - entry->kaddr = ioremap(entry->phys_start, entry->size);
117   - if (!entry->kaddr) {
118   - suspend_nvs_free();
119   - return -ENOMEM;
120   - }
121   - memcpy(entry->data, entry->kaddr, entry->size);
122   - }
123   -
124   - return 0;
125   -}
126   -
127   -/**
128   - * suspend_nvs_restore - restore NVS memory regions
129   - *
130   - * This function is going to be called with interrupts disabled, so it
131   - * cannot iounmap the virtual addresses used to access the NVS region.
132   - */
133   -void suspend_nvs_restore(void)
134   -{
135   - struct nvs_page *entry;
136   -
137   - printk(KERN_INFO "PM: Restoring platform NVS memory\n");
138   -
139   - list_for_each_entry(entry, &nvs_list, node)
140   - if (entry->data)
141   - memcpy(entry->kaddr, entry->data, entry->size);
142   -}