aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2011-01-12 04:56:08 -0500
committerLen Brown <len.brown@intel.com>2011-01-12 04:56:08 -0500
commitd16675e1f1de98cc73ae77c6df26154ffae6230a (patch)
treebe7ffdaabdaa06f8c917c7a6c9919d4b5fd13a52 /drivers/acpi
parentfb4af417cce9ff87abf33a6bb9a0cf613e285364 (diff)
parent6d5bbf00d251cc73223a71422d69e069dc2e0b8d (diff)
Merge branch 'suspend-ioremap-cache' into release
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/internal.h8
-rw-r--r--drivers/acpi/nvs.c144
-rw-r--r--drivers/acpi/osl.c6
-rw-r--r--drivers/acpi/sleep.c5
5 files changed, 158 insertions, 7 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 3d031d02e54b..9cc9f2c4da79 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -24,7 +24,7 @@ acpi-y += atomicio.o
24# sleep related files 24# sleep related files
25acpi-y += wakeup.o 25acpi-y += wakeup.o
26acpi-y += sleep.o 26acpi-y += sleep.o
27acpi-$(CONFIG_ACPI_SLEEP) += proc.o 27acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o
28 28
29 29
30# 30#
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 8df5d7061a45..bc428a9607df 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -83,8 +83,16 @@ extern int acpi_sleep_init(void);
83 83
84#ifdef CONFIG_ACPI_SLEEP 84#ifdef CONFIG_ACPI_SLEEP
85int acpi_sleep_proc_init(void); 85int acpi_sleep_proc_init(void);
86int suspend_nvs_alloc(void);
87void suspend_nvs_free(void);
88int suspend_nvs_save(void);
89void suspend_nvs_restore(void);
86#else 90#else
87static inline int acpi_sleep_proc_init(void) { return 0; } 91static inline int acpi_sleep_proc_init(void) { return 0; }
92static inline int suspend_nvs_alloc(void) { return 0; }
93static inline void suspend_nvs_free(void) {}
94static inline int suspend_nvs_save(void) {}
95static inline void suspend_nvs_restore(void) {}
88#endif 96#endif
89 97
90#endif /* _ACPI_INTERNAL_H_ */ 98#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c
new file mode 100644
index 000000000000..54b6ab8040a6
--- /dev/null
+++ b/drivers/acpi/nvs.c
@@ -0,0 +1,144 @@
1/*
2 * nvs.c - Routines for saving and restoring ACPI NVS memory region
3 *
4 * Copyright (C) 2008-2011 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/acpi.h>
15#include <acpi/acpiosxf.h>
16
17/*
18 * Platforms, like ACPI, may want us to save some memory used by them during
19 * suspend and to restore the contents of this memory during the subsequent
20 * resume. The code below implements a mechanism allowing us to do that.
21 */
22
23struct nvs_page {
24 unsigned long phys_start;
25 unsigned int size;
26 void *kaddr;
27 void *data;
28 struct list_head node;
29};
30
31static LIST_HEAD(nvs_list);
32
33/**
34 * suspend_nvs_register - register platform NVS memory region to save
35 * @start - physical address of the region
36 * @size - size of the region
37 *
38 * The NVS region need not be page-aligned (both ends) and we arrange
39 * things so that the data from page-aligned addresses in this region will
40 * be copied into separate RAM pages.
41 */
42int suspend_nvs_register(unsigned long start, unsigned long size)
43{
44 struct nvs_page *entry, *next;
45
46 while (size > 0) {
47 unsigned int nr_bytes;
48
49 entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
50 if (!entry)
51 goto Error;
52
53 list_add_tail(&entry->node, &nvs_list);
54 entry->phys_start = start;
55 nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
56 entry->size = (size < nr_bytes) ? size : nr_bytes;
57
58 start += entry->size;
59 size -= entry->size;
60 }
61 return 0;
62
63 Error:
64 list_for_each_entry_safe(entry, next, &nvs_list, node) {
65 list_del(&entry->node);
66 kfree(entry);
67 }
68 return -ENOMEM;
69}
70
71/**
72 * suspend_nvs_free - free data pages allocated for saving NVS regions
73 */
74void suspend_nvs_free(void)
75{
76 struct nvs_page *entry;
77
78 list_for_each_entry(entry, &nvs_list, node)
79 if (entry->data) {
80 free_page((unsigned long)entry->data);
81 entry->data = NULL;
82 if (entry->kaddr) {
83 acpi_os_unmap_memory(entry->kaddr, entry->size);
84 entry->kaddr = NULL;
85 }
86 }
87}
88
89/**
90 * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
91 */
92int suspend_nvs_alloc(void)
93{
94 struct nvs_page *entry;
95
96 list_for_each_entry(entry, &nvs_list, node) {
97 entry->data = (void *)__get_free_page(GFP_KERNEL);
98 if (!entry->data) {
99 suspend_nvs_free();
100 return -ENOMEM;
101 }
102 }
103 return 0;
104}
105
106/**
107 * suspend_nvs_save - save NVS memory regions
108 */
109int suspend_nvs_save(void)
110{
111 struct nvs_page *entry;
112
113 printk(KERN_INFO "PM: Saving platform NVS memory\n");
114
115 list_for_each_entry(entry, &nvs_list, node)
116 if (entry->data) {
117 entry->kaddr = acpi_os_map_memory(entry->phys_start,
118 entry->size);
119 if (!entry->kaddr) {
120 suspend_nvs_free();
121 return -ENOMEM;
122 }
123 memcpy(entry->data, entry->kaddr, entry->size);
124 }
125
126 return 0;
127}
128
129/**
130 * suspend_nvs_restore - restore NVS memory regions
131 *
132 * This function is going to be called with interrupts disabled, so it
133 * cannot iounmap the virtual addresses used to access the NVS region.
134 */
135void suspend_nvs_restore(void)
136{
137 struct nvs_page *entry;
138
139 printk(KERN_INFO "PM: Restoring platform NVS memory\n");
140
141 list_for_each_entry(entry, &nvs_list, node)
142 if (entry->data)
143 memcpy(entry->kaddr, entry->data, entry->size);
144}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 055d7b701fff..3a7b4879fd99 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -320,7 +320,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
320 320
321 pg_off = round_down(phys, PAGE_SIZE); 321 pg_off = round_down(phys, PAGE_SIZE);
322 pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; 322 pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
323 virt = ioremap(pg_off, pg_sz); 323 virt = ioremap_cache(pg_off, pg_sz);
324 if (!virt) { 324 if (!virt) {
325 kfree(map); 325 kfree(map);
326 return NULL; 326 return NULL;
@@ -642,7 +642,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
642 virt_addr = acpi_map_vaddr_lookup(phys_addr, size); 642 virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
643 rcu_read_unlock(); 643 rcu_read_unlock();
644 if (!virt_addr) { 644 if (!virt_addr) {
645 virt_addr = ioremap(phys_addr, size); 645 virt_addr = ioremap_cache(phys_addr, size);
646 unmap = 1; 646 unmap = 1;
647 } 647 }
648 if (!value) 648 if (!value)
@@ -678,7 +678,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
678 virt_addr = acpi_map_vaddr_lookup(phys_addr, size); 678 virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
679 rcu_read_unlock(); 679 rcu_read_unlock();
680 if (!virt_addr) { 680 if (!virt_addr) {
681 virt_addr = ioremap(phys_addr, size); 681 virt_addr = ioremap_cache(phys_addr, size);
682 unmap = 1; 682 unmap = 1;
683 } 683 }
684 684
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index ddc5cce508a1..75c232084740 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -124,8 +124,7 @@ static int acpi_pm_freeze(void)
124static int acpi_pm_pre_suspend(void) 124static int acpi_pm_pre_suspend(void)
125{ 125{
126 acpi_pm_freeze(); 126 acpi_pm_freeze();
127 suspend_nvs_save(); 127 return suspend_nvs_save();
128 return 0;
129} 128}
130 129
131/** 130/**
@@ -151,7 +150,7 @@ static int acpi_pm_prepare(void)
151{ 150{
152 int error = __acpi_pm_prepare(); 151 int error = __acpi_pm_prepare();
153 if (!error) 152 if (!error)
154 acpi_pm_pre_suspend(); 153 error = acpi_pm_pre_suspend();
155 154
156 return error; 155 return error;
157} 156}