2 * nvs.c - Routines for saving and restoring ACPI NVS memory region
6 * This file is released under the GPLv2.
10 #include <linux/kernel.h>
11 #include <linux/list.h>
13 #include <linux/slab.h>
14 #include <linux/acpi.h>
15 #include <acpi/acpiosxf.h>
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.
24 unsigned long phys_start;
28 struct list_head node;
31 static LIST_HEAD(nvs_list);
34 * suspend_nvs_register - register platform NVS memory region to save
35 * @start - physical address of the region
36 * @size - size of the region
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.
42 int suspend_nvs_register(unsigned long start, unsigned long size)
44 struct nvs_page *entry, *next;
47 unsigned int nr_bytes;
49 entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
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;
64 list_for_each_entry_safe(entry, next, &nvs_list, node) {
65 list_del(&entry->node);
72 * suspend_nvs_free - free data pages allocated for saving NVS regions
74 void suspend_nvs_free(void)
76 struct nvs_page *entry;
78 list_for_each_entry(entry, &nvs_list, node)
80 free_page((unsigned long)entry->data);
83 acpi_os_unmap_memory(entry->kaddr, entry->size);
90 * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
92 int suspend_nvs_alloc(void)
94 struct nvs_page *entry;
96 list_for_each_entry(entry, &nvs_list, node) {
97 entry->data = (void *)__get_free_page(GFP_KERNEL);
107 * suspend_nvs_save - save NVS memory regions
109 int suspend_nvs_save(void)
111 struct nvs_page *entry;
113 printk(KERN_INFO "PM: Saving platform NVS memory\n");
115 list_for_each_entry(entry, &nvs_list, node)
117 entry->kaddr = acpi_os_map_memory(entry->phys_start,
123 memcpy(entry->data, entry->kaddr, entry->size);
130 * suspend_nvs_restore - restore NVS memory regions
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.
135 void suspend_nvs_restore(void)
137 struct nvs_page *entry;
139 printk(KERN_INFO "PM: Restoring platform NVS memory\n");
141 list_for_each_entry(entry, &nvs_list, node)
143 memcpy(entry->kaddr, entry->data, entry->size);