mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
Merge branch 'suspend-ioremap-cache' into release
This commit is contained in:
commit
d16675e1f1
11 changed files with 43 additions and 36 deletions
|
|
@ -24,7 +24,7 @@ acpi-y += atomicio.o
|
|||
# sleep related files
|
||||
acpi-y += wakeup.o
|
||||
acpi-y += sleep.o
|
||||
acpi-$(CONFIG_ACPI_SLEEP) += proc.o
|
||||
acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o
|
||||
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -83,8 +83,16 @@ extern int acpi_sleep_init(void);
|
|||
|
||||
#ifdef CONFIG_ACPI_SLEEP
|
||||
int acpi_sleep_proc_init(void);
|
||||
int suspend_nvs_alloc(void);
|
||||
void suspend_nvs_free(void);
|
||||
int suspend_nvs_save(void);
|
||||
void suspend_nvs_restore(void);
|
||||
#else
|
||||
static inline int acpi_sleep_proc_init(void) { return 0; }
|
||||
static inline int suspend_nvs_alloc(void) { return 0; }
|
||||
static inline void suspend_nvs_free(void) {}
|
||||
static inline int suspend_nvs_save(void) {}
|
||||
static inline void suspend_nvs_restore(void) {}
|
||||
#endif
|
||||
|
||||
#endif /* _ACPI_INTERNAL_H_ */
|
||||
|
|
|
|||
144
drivers/acpi/nvs.c
Normal file
144
drivers/acpi/nvs.c
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* nvs.c - Routines for saving and restoring ACPI NVS memory region
|
||||
*
|
||||
* Copyright (C) 2008-2011 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/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/acpiosxf.h>
|
||||
|
||||
/*
|
||||
* Platforms, like ACPI, may want us to save some memory used by them during
|
||||
* suspend 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);
|
||||
|
||||
/**
|
||||
* suspend_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 suspend_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* suspend_nvs_free - free data pages allocated for saving NVS regions
|
||||
*/
|
||||
void suspend_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) {
|
||||
acpi_os_unmap_memory(entry->kaddr, entry->size);
|
||||
entry->kaddr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* suspend_nvs_alloc - allocate memory necessary for saving NVS regions
|
||||
*/
|
||||
int suspend_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) {
|
||||
suspend_nvs_free();
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* suspend_nvs_save - save NVS memory regions
|
||||
*/
|
||||
int suspend_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 = acpi_os_map_memory(entry->phys_start,
|
||||
entry->size);
|
||||
if (!entry->kaddr) {
|
||||
suspend_nvs_free();
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(entry->data, entry->kaddr, entry->size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* suspend_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 suspend_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);
|
||||
}
|
||||
|
|
@ -320,7 +320,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
|
|||
|
||||
pg_off = round_down(phys, PAGE_SIZE);
|
||||
pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
|
||||
virt = ioremap(pg_off, pg_sz);
|
||||
virt = ioremap_cache(pg_off, pg_sz);
|
||||
if (!virt) {
|
||||
kfree(map);
|
||||
return NULL;
|
||||
|
|
@ -642,7 +642,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
|
|||
virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
|
||||
rcu_read_unlock();
|
||||
if (!virt_addr) {
|
||||
virt_addr = ioremap(phys_addr, size);
|
||||
virt_addr = ioremap_cache(phys_addr, size);
|
||||
unmap = 1;
|
||||
}
|
||||
if (!value)
|
||||
|
|
@ -678,7 +678,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
|
|||
virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
|
||||
rcu_read_unlock();
|
||||
if (!virt_addr) {
|
||||
virt_addr = ioremap(phys_addr, size);
|
||||
virt_addr = ioremap_cache(phys_addr, size);
|
||||
unmap = 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,8 +124,7 @@ static int acpi_pm_freeze(void)
|
|||
static int acpi_pm_pre_suspend(void)
|
||||
{
|
||||
acpi_pm_freeze();
|
||||
suspend_nvs_save();
|
||||
return 0;
|
||||
return suspend_nvs_save();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,7 +150,7 @@ static int acpi_pm_prepare(void)
|
|||
{
|
||||
int error = __acpi_pm_prepare();
|
||||
if (!error)
|
||||
acpi_pm_pre_suspend();
|
||||
error = acpi_pm_pre_suspend();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue