From 404a6043385de17273624b076599669db5ad891f Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 7 Mar 2012 17:34:34 -0800 Subject: staging: android: persistent_ram: handle reserving and mapping memory Replace the ioremapped memory passed in from the drivers with a memblock_reserve and vmap. Adds a new function, persistent_ram_early_init, designed to be called from the machine init_early callback, that calls memblock_remove and saves the provided persistent ram area layout. Drivers only pass in their struct device * and ecc settings. Locating and mapping the memory is now handled entirely within persistent_ram. Also, convert ram_console to the new persistent_ram_init parameters that only take a struct device * and ecc settings. [jstultz: Fix pr_info casting issues on 64bit, folded two patches as the build breaks if they are apart. Also replaced phys_to_page() w/ pfn_to_page(addr>>PAGE_SHIFT), as phys_to_page is only on a few arches.] CC: Greg KH CC: Android Kernel Team Signed-off-by: Colin Cross Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/persistent_ram.c | 139 +++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 27 deletions(-) (limited to 'drivers/staging/android/persistent_ram.c') diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c index 35c57a05f16d..81950e61db9b 100644 --- a/drivers/staging/android/persistent_ram.c +++ b/drivers/staging/android/persistent_ram.c @@ -12,12 +12,17 @@ * */ +#include +#include #include #include #include #include +#include +#include #include #include +#include #include "persistent_ram.h" struct persistent_ram_buffer { @@ -29,7 +34,7 @@ struct persistent_ram_buffer { #define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ -static LIST_HEAD(zone_list); +static __initdata LIST_HEAD(persistent_ram_list); static void persistent_ram_encode_rs8(struct persistent_ram_zone *prz, uint8_t *data, size_t len, uint8_t *ecc) @@ -270,54 +275,134 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz) prz->old_log_size = 0; } -static int __init __persistent_ram_init(struct persistent_ram_zone *prz, - void __iomem *mem, size_t buffer_size, bool ecc) +static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, + struct persistent_ram_zone *prz) { - struct persistent_ram_buffer *buffer = mem; + struct page **pages; + phys_addr_t page_start; + unsigned int page_count; + pgprot_t prot; + unsigned int i; + + page_start = start - offset_in_page(start); + page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); + + prot = pgprot_noncached(PAGE_KERNEL); + + pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL); + if (!pages) { + pr_err("%s: Failed to allocate array for %u pages\n", __func__, + page_count); + return -ENOMEM; + } + + for (i = 0; i < page_count; i++) { + phys_addr_t addr = page_start + i * PAGE_SIZE; + pages[i] = pfn_to_page(addr >> PAGE_SHIFT); + } + prz->vaddr = vmap(pages, page_count, VM_MAP, prot); + kfree(pages); + if (!prz->vaddr) { + pr_err("%s: Failed to map %u pages\n", __func__, page_count); + return -ENOMEM; + } + + prz->buffer = prz->vaddr + offset_in_page(start); + prz->buffer_size = size - sizeof(struct persistent_ram_buffer); + + return 0; +} + +static int __init persistent_ram_buffer_init(const char *name, + struct persistent_ram_zone *prz) +{ + int i; + struct persistent_ram *ram; + struct persistent_ram_descriptor *desc; + phys_addr_t start; + + list_for_each_entry(ram, &persistent_ram_list, node) { + start = ram->start; + for (i = 0; i < ram->num_descs; i++) { + desc = &ram->descs[i]; + if (!strcmp(desc->name, name)) + return persistent_ram_buffer_map(start, + desc->size, prz); + start += desc->size; + } + } + + return -EINVAL; +} + +static __init +struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) +{ + struct persistent_ram_zone *prz; int ret; - INIT_LIST_HEAD(&prz->node); + prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL); + if (!prz) { + pr_err("persistent_ram: failed to allocate persistent ram zone\n"); + return ERR_PTR(-ENOMEM); + } - prz->buffer = buffer; - prz->buffer_size = buffer_size - sizeof(struct persistent_ram_buffer); + INIT_LIST_HEAD(&prz->node); - if (prz->buffer_size > buffer_size) { - pr_err("persistent_ram: buffer %p, invalid size %zu, datasize %zu\n", - buffer, buffer_size, prz->buffer_size); - return -EINVAL; + ret = persistent_ram_buffer_init(dev_name(dev), prz); + if (ret) { + pr_err("persistent_ram: failed to initialize buffer\n"); + return ERR_PTR(ret); } prz->ecc = ecc; - ret = persistent_ram_init_ecc(prz, buffer_size); + ret = persistent_ram_init_ecc(prz, prz->buffer_size); if (ret) - return ret; + return ERR_PTR(ret); - if (buffer->sig == PERSISTENT_RAM_SIG) { - if (buffer->size > prz->buffer_size - || buffer->start > buffer->size) + if (prz->buffer->sig == PERSISTENT_RAM_SIG) { + if (prz->buffer->size > prz->buffer_size + || prz->buffer->start > prz->buffer->size) pr_info("persistent_ram: found existing invalid buffer, size %d, start %d\n", - buffer->size, buffer->start); + prz->buffer->size, prz->buffer->start); else { pr_info("persistent_ram: found existing buffer, size %d, start %d\n", - buffer->size, buffer->start); + prz->buffer->size, prz->buffer->start); persistent_ram_save_old(prz); } } else { pr_info("persistent_ram: no valid data in buffer (sig = 0x%08x)\n", - buffer->sig); + prz->buffer->sig); } - buffer->sig = PERSISTENT_RAM_SIG; - buffer->start = 0; - buffer->size = 0; + prz->buffer->sig = PERSISTENT_RAM_SIG; + prz->buffer->start = 0; + prz->buffer->size = 0; - list_add_tail(&prz->node, &zone_list); + return prz; +} - return 0; +struct persistent_ram_zone * __init +persistent_ram_init_ringbuffer(struct device *dev, bool ecc) +{ + return __persistent_ram_init(dev, ecc); } -int __init persistent_ram_init_ringbuffer(struct persistent_ram_zone *prz, - void __iomem *mem, size_t buffer_size, bool ecc) +int __init persistent_ram_early_init(struct persistent_ram *ram) { - return __persistent_ram_init(prz, mem, buffer_size, true); + int ret; + + ret = memblock_reserve(ram->start, ram->size); + if (ret) { + pr_err("Failed to reserve persistent memory from %08lx-%08lx\n", + (long)ram->start, (long)(ram->start + ram->size - 1)); + return ret; + } + + list_add_tail(&ram->node, &persistent_ram_list); + + pr_info("Initialized persistent memory from %08lx-%08lx\n", + (long)ram->start, (long)(ram->start + ram->size - 1)); + + return 0; } -- cgit v1.2.3