summaryrefslogtreecommitdiffstats
path: root/fs/pstore
diff options
context:
space:
mode:
Diffstat (limited to 'fs/pstore')
-rw-r--r--fs/pstore/Kconfig7
-rw-r--r--fs/pstore/inode.c3
-rw-r--r--fs/pstore/platform.c54
-rw-r--r--fs/pstore/ram.c307
-rw-r--r--fs/pstore/ram_core.c126
5 files changed, 303 insertions, 194 deletions
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 23ade2680a4a..d044de6ee308 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -12,6 +12,13 @@ config PSTORE
If you don't have a platform persistent store driver,
say N.
+config PSTORE_CONSOLE
+ bool "Log kernel console messages"
+ depends on PSTORE
+ help
+ When the option is enabled, pstore will log all kernel
+ messages, even if no oops or panic happened.
+
config PSTORE_RAM
tristate "Log panic/oops to a RAM buffer"
depends on PSTORE
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 11a2aa2a56c4..45bff5441b04 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -212,6 +212,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
case PSTORE_TYPE_DMESG:
sprintf(name, "dmesg-%s-%lld", psname, id);
break;
+ case PSTORE_TYPE_CONSOLE:
+ sprintf(name, "console-%s", psname);
+ break;
case PSTORE_TYPE_MCE:
sprintf(name, "mce-%s-%lld", psname, id);
break;
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 03ce7a9b81cc..6b3ff045fe6e 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -1,6 +1,7 @@
/*
* Persistent Storage - platform driver interface parts.
*
+ * Copyright (C) 2007-2008 Google, Inc.
* Copyright (C) 2010 Intel Corporation <tony.luck@intel.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kmsg_dump.h>
+#include <linux/console.h>
#include <linux/module.h>
#include <linux/pstore.h>
#include <linux/string.h>
@@ -29,6 +31,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/hardirq.h>
+#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include "internal.h"
@@ -38,7 +41,12 @@
* whether the system is actually still running well enough
* to let someone see the entry
*/
-#define PSTORE_INTERVAL (60 * HZ)
+static int pstore_update_ms = -1;
+module_param_named(update_ms, pstore_update_ms, int, 0600);
+MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
+ "(default is -1, which means runtime updates are disabled; "
+ "enabling this option is not safe, it may lead to further "
+ "corruption on Oopses)");
static int pstore_new_entry;
@@ -146,6 +154,40 @@ static struct kmsg_dumper pstore_dumper = {
.dump = pstore_dump,
};
+#ifdef CONFIG_PSTORE_CONSOLE
+static void pstore_console_write(struct console *con, const char *s, unsigned c)
+{
+ const char *e = s + c;
+
+ while (s < e) {
+ unsigned long flags;
+
+ if (c > psinfo->bufsize)
+ c = psinfo->bufsize;
+ spin_lock_irqsave(&psinfo->buf_lock, flags);
+ memcpy(psinfo->buf, s, c);
+ psinfo->write(PSTORE_TYPE_CONSOLE, 0, NULL, 0, c, psinfo);
+ spin_unlock_irqrestore(&psinfo->buf_lock, flags);
+ s += c;
+ c = e - s;
+ }
+}
+
+static struct console pstore_console = {
+ .name = "pstore",
+ .write = pstore_console_write,
+ .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
+ .index = -1,
+};
+
+static void pstore_register_console(void)
+{
+ register_console(&pstore_console);
+}
+#else
+static void pstore_register_console(void) {}
+#endif
+
/*
* platform specific persistent storage driver registers with
* us here. If pstore is already mounted, call the platform
@@ -183,9 +225,13 @@ int pstore_register(struct pstore_info *psi)
pstore_get_records(0);
kmsg_dump_register(&pstore_dumper);
+ pstore_register_console();
- pstore_timer.expires = jiffies + PSTORE_INTERVAL;
- add_timer(&pstore_timer);
+ if (pstore_update_ms >= 0) {
+ pstore_timer.expires = jiffies +
+ msecs_to_jiffies(pstore_update_ms);
+ add_timer(&pstore_timer);
+ }
return 0;
}
@@ -244,7 +290,7 @@ static void pstore_timefunc(unsigned long dummy)
schedule_work(&pstore_work);
}
- mod_timer(&pstore_timer, jiffies + PSTORE_INTERVAL);
+ mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
}
module_param(backend, charp, 0444);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 453030f9c5bc..58b93fbd117e 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -41,6 +41,10 @@ module_param(record_size, ulong, 0400);
MODULE_PARM_DESC(record_size,
"size of each dump done on oops/panic");
+static ulong ramoops_console_size = MIN_MEM_SIZE;
+module_param_named(console_size, ramoops_console_size, ulong, 0400);
+MODULE_PARM_DESC(console_size, "size of kernel console log");
+
static ulong mem_address;
module_param(mem_address, ulong, 0400);
MODULE_PARM_DESC(mem_address,
@@ -63,14 +67,17 @@ MODULE_PARM_DESC(ramoops_ecc,
struct ramoops_context {
struct persistent_ram_zone **przs;
+ struct persistent_ram_zone *cprz;
phys_addr_t phys_addr;
unsigned long size;
size_t record_size;
+ size_t console_size;
int dump_oops;
bool ecc;
- unsigned int count;
- unsigned int max_count;
- unsigned int read_count;
+ unsigned int max_dump_cnt;
+ unsigned int dump_write_cnt;
+ unsigned int dump_read_cnt;
+ unsigned int console_read_cnt;
struct pstore_info pstore;
};
@@ -81,10 +88,38 @@ static int ramoops_pstore_open(struct pstore_info *psi)
{
struct ramoops_context *cxt = psi->data;
- cxt->read_count = 0;
+ cxt->dump_read_cnt = 0;
+ cxt->console_read_cnt = 0;
return 0;
}
+static struct persistent_ram_zone *
+ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
+ u64 *id,
+ enum pstore_type_id *typep, enum pstore_type_id type,
+ bool update)
+{
+ struct persistent_ram_zone *prz;
+ int i = (*c)++;
+
+ if (i >= max)
+ return NULL;
+
+ prz = przs[i];
+
+ if (update) {
+ /* Update old/shadowed buffer. */
+ persistent_ram_save_old(prz);
+ if (!persistent_ram_old_size(prz))
+ return NULL;
+ }
+
+ *typep = type;
+ *id = i;
+
+ return prz;
+}
+
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
struct timespec *time,
char **buf,
@@ -94,20 +129,19 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
struct ramoops_context *cxt = psi->data;
struct persistent_ram_zone *prz;
- if (cxt->read_count >= cxt->max_count)
- return -EINVAL;
+ prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
+ cxt->max_dump_cnt, id, type,
+ PSTORE_TYPE_DMESG, 1);
+ if (!prz)
+ prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
+ 1, id, type, PSTORE_TYPE_CONSOLE, 0);
+ if (!prz)
+ return 0;
- *id = cxt->read_count++;
- prz = cxt->przs[*id];
-
- /* Only supports dmesg output so far. */
- *type = PSTORE_TYPE_DMESG;
/* TODO(kees): Bogus time for the moment. */
time->tv_sec = 0;
time->tv_nsec = 0;
- /* Update old/shadowed buffer. */
- persistent_ram_save_old(prz);
size = persistent_ram_old_size(prz);
*buf = kmalloc(size, GFP_KERNEL);
if (*buf == NULL)
@@ -141,10 +175,16 @@ static int ramoops_pstore_write(enum pstore_type_id type,
size_t size, struct pstore_info *psi)
{
struct ramoops_context *cxt = psi->data;
- struct persistent_ram_zone *prz = cxt->przs[cxt->count];
+ struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt];
size_t hlen;
- /* Currently ramoops is designed to only store dmesg dumps. */
+ if (type == PSTORE_TYPE_CONSOLE) {
+ if (!cxt->cprz)
+ return -ENOMEM;
+ persistent_ram_write(cxt->cprz, cxt->pstore.buf, size);
+ return 0;
+ }
+
if (type != PSTORE_TYPE_DMESG)
return -EINVAL;
@@ -172,7 +212,7 @@ static int ramoops_pstore_write(enum pstore_type_id type,
size = prz->buffer_size - hlen;
persistent_ram_write(prz, cxt->pstore.buf, size);
- cxt->count = (cxt->count + 1) % cxt->max_count;
+ cxt->dump_write_cnt = (cxt->dump_write_cnt + 1) % cxt->max_dump_cnt;
return 0;
}
@@ -181,12 +221,23 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
struct pstore_info *psi)
{
struct ramoops_context *cxt = psi->data;
+ struct persistent_ram_zone *prz;
- if (id >= cxt->max_count)
+ switch (type) {
+ case PSTORE_TYPE_DMESG:
+ if (id >= cxt->max_dump_cnt)
+ return -EINVAL;
+ prz = cxt->przs[id];
+ break;
+ case PSTORE_TYPE_CONSOLE:
+ prz = cxt->cprz;
+ break;
+ default:
return -EINVAL;
+ }
- persistent_ram_free_old(cxt->przs[id]);
- persistent_ram_zap(cxt->przs[id]);
+ persistent_ram_free_old(prz);
+ persistent_ram_zap(prz);
return 0;
}
@@ -202,73 +253,142 @@ static struct ramoops_context oops_cxt = {
},
};
-static int __init ramoops_probe(struct platform_device *pdev)
+static void ramoops_free_przs(struct ramoops_context *cxt)
+{
+ int i;
+
+ if (!cxt->przs)
+ return;
+
+ for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
+ persistent_ram_free(cxt->przs[i]);
+ kfree(cxt->przs);
+}
+
+static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
+ phys_addr_t *paddr, size_t dump_mem_sz)
+{
+ int err = -ENOMEM;
+ int i;
+
+ if (!cxt->record_size)
+ return 0;
+
+ cxt->max_dump_cnt = dump_mem_sz / cxt->record_size;
+ if (!cxt->max_dump_cnt)
+ return -ENOMEM;
+
+ cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt,
+ GFP_KERNEL);
+ if (!cxt->przs) {
+ dev_err(dev, "failed to initialize a prz array for dumps\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < cxt->max_dump_cnt; i++) {
+ size_t sz = cxt->record_size;
+
+ cxt->przs[i] = persistent_ram_new(*paddr, sz, cxt->ecc);
+ if (IS_ERR(cxt->przs[i])) {
+ err = PTR_ERR(cxt->przs[i]);
+ dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
+ sz, (unsigned long long)*paddr, err);
+ goto fail_prz;
+ }
+ *paddr += sz;
+ }
+
+ return 0;
+fail_prz:
+ ramoops_free_przs(cxt);
+ return err;
+}
+
+static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
+ struct persistent_ram_zone **prz,
+ phys_addr_t *paddr, size_t sz)
+{
+ if (!sz)
+ return 0;
+
+ if (*paddr + sz > *paddr + cxt->size)
+ return -ENOMEM;
+
+ *prz = persistent_ram_new(*paddr, sz, cxt->ecc);
+ if (IS_ERR(*prz)) {
+ int err = PTR_ERR(*prz);
+
+ dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
+ sz, (unsigned long long)*paddr, err);
+ return err;
+ }
+
+ persistent_ram_zap(*prz);
+
+ *paddr += sz;
+
+ return 0;
+}
+
+static int __devinit ramoops_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ramoops_platform_data *pdata = pdev->dev.platform_data;
struct ramoops_context *cxt = &oops_cxt;
+ size_t dump_mem_sz;
+ phys_addr_t paddr;
int err = -EINVAL;
- int i;
/* Only a single ramoops area allowed at a time, so fail extra
* probes.
*/
- if (cxt->max_count)
+ if (cxt->max_dump_cnt)
goto fail_out;
- if (!pdata->mem_size || !pdata->record_size) {
- pr_err("The memory size and the record size must be "
+ if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size)) {
+ pr_err("The memory size and the record/console size must be "
"non-zero\n");
goto fail_out;
}
pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
pdata->record_size = rounddown_pow_of_two(pdata->record_size);
+ pdata->console_size = rounddown_pow_of_two(pdata->console_size);
- /* Check for the minimum memory size */
- if (pdata->mem_size < MIN_MEM_SIZE &&
- pdata->record_size < MIN_MEM_SIZE) {
- pr_err("memory size too small, minimum is %lu\n",
- MIN_MEM_SIZE);
- goto fail_out;
- }
-
- if (pdata->mem_size < pdata->record_size) {
- pr_err("The memory size must be larger than the "
- "records size\n");
- goto fail_out;
- }
-
- cxt->max_count = pdata->mem_size / pdata->record_size;
- cxt->count = 0;
+ cxt->dump_read_cnt = 0;
cxt->size = pdata->mem_size;
cxt->phys_addr = pdata->mem_address;
cxt->record_size = pdata->record_size;
+ cxt->console_size = pdata->console_size;
cxt->dump_oops = pdata->dump_oops;
cxt->ecc = pdata->ecc;
- cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL);
- if (!cxt->przs) {
- err = -ENOMEM;
- dev_err(dev, "failed to initialize a prz array\n");
+ paddr = cxt->phys_addr;
+
+ dump_mem_sz = cxt->size - cxt->console_size;
+ err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz);
+ if (err)
goto fail_out;
- }
- for (i = 0; i < cxt->max_count; i++) {
- size_t sz = cxt->record_size;
- phys_addr_t start = cxt->phys_addr + sz * i;
+ err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr, cxt->console_size);
+ if (err)
+ goto fail_init_cprz;
- cxt->przs[i] = persistent_ram_new(start, sz, cxt->ecc);
- if (IS_ERR(cxt->przs[i])) {
- err = PTR_ERR(cxt->przs[i]);
- dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
- sz, (unsigned long long)start, err);
- goto fail_przs;
- }
+ if (!cxt->przs && !cxt->cprz) {
+ pr_err("memory size too small, minimum is %lu\n",
+ cxt->console_size + cxt->record_size);
+ goto fail_cnt;
}
cxt->pstore.data = cxt;
- cxt->pstore.bufsize = cxt->przs[0]->buffer_size;
+ /*
+ * Console can handle any buffer size, so prefer dumps buffer
+ * size since usually it is smaller.
+ */
+ if (cxt->przs)
+ cxt->pstore.bufsize = cxt->przs[0]->buffer_size;
+ else
+ cxt->pstore.bufsize = cxt->cprz->buffer_size;
cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
spin_lock_init(&cxt->pstore.buf_lock);
if (!cxt->pstore.buf) {
@@ -291,9 +411,8 @@ static int __init ramoops_probe(struct platform_device *pdev)
record_size = pdata->record_size;
dump_oops = pdata->dump_oops;
- pr_info("attached 0x%lx@0x%llx (%ux0x%zx), ecc: %s\n",
+ pr_info("attached 0x%lx@0x%llx, ecc: %s\n",
cxt->size, (unsigned long long)cxt->phys_addr,
- cxt->max_count, cxt->record_size,
ramoops_ecc ? "on" : "off");
return 0;
@@ -302,11 +421,11 @@ fail_buf:
kfree(cxt->pstore.buf);
fail_clear:
cxt->pstore.bufsize = 0;
- cxt->max_count = 0;
-fail_przs:
- for (i = 0; cxt->przs[i]; i++)
- persistent_ram_free(cxt->przs[i]);
- kfree(cxt->przs);
+ cxt->max_dump_cnt = 0;
+fail_cnt:
+ kfree(cxt->cprz);
+fail_init_cprz:
+ ramoops_free_przs(cxt);
fail_out:
return err;
}
@@ -321,7 +440,7 @@ static int __exit ramoops_remove(struct platform_device *pdev)
iounmap(cxt->virt_addr);
release_mem_region(cxt->phys_addr, cxt->size);
- cxt->max_count = 0;
+ cxt->max_dump_cnt = 0;
/* TODO(kees): When pstore supports unregistering, call it here. */
kfree(cxt->pstore.buf);
@@ -333,6 +452,7 @@ static int __exit ramoops_remove(struct platform_device *pdev)
}
static struct platform_driver ramoops_driver = {
+ .probe = ramoops_probe,
.remove = __exit_p(ramoops_remove),
.driver = {
.name = "ramoops",
@@ -340,45 +460,46 @@ static struct platform_driver ramoops_driver = {
},
};
-static int __init ramoops_init(void)
+static void ramoops_register_dummy(void)
{
- int ret;
- ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
- if (ret == -ENODEV) {
- /*
- * If we didn't find a platform device, we use module parameters
- * building platform data on the fly.
- */
- pr_info("platform device not found, using module parameters\n");
- dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
- GFP_KERNEL);
- if (!dummy_data)
- return -ENOMEM;
- dummy_data->mem_size = mem_size;
- dummy_data->mem_address = mem_address;
- dummy_data->record_size = record_size;
- dummy_data->dump_oops = dump_oops;
- dummy_data->ecc = ramoops_ecc;
- dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
- NULL, 0, dummy_data,
- sizeof(struct ramoops_platform_data));
-
- if (IS_ERR(dummy))
- ret = PTR_ERR(dummy);
- else
- ret = 0;
+ if (!mem_size)
+ return;
+
+ pr_info("using module parameters\n");
+
+ dummy_data = kzalloc(sizeof(*dummy_data), GFP_KERNEL);
+ if (!dummy_data) {
+ pr_info("could not allocate pdata\n");
+ return;
}
- return ret;
+ dummy_data->mem_size = mem_size;
+ dummy_data->mem_address = mem_address;
+ dummy_data->record_size = record_size;
+ dummy_data->console_size = ramoops_console_size;
+ dummy_data->dump_oops = dump_oops;
+ dummy_data->ecc = ramoops_ecc;
+
+ dummy = platform_device_register_data(NULL, "ramoops", -1,
+ dummy_data, sizeof(struct ramoops_platform_data));
+ if (IS_ERR(dummy)) {
+ pr_info("could not create platform device: %ld\n",
+ PTR_ERR(dummy));
+ }
}
+static int __init ramoops_init(void)
+{
+ ramoops_register_dummy();
+ return platform_driver_register(&ramoops_driver);
+}
+postcore_initcall(ramoops_init);
+
static void __exit ramoops_exit(void)
{
platform_driver_unregister(&ramoops_driver);
kfree(dummy_data);
}
-
-module_init(ramoops_init);
module_exit(ramoops_exit);
MODULE_LICENSE("GPL");
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
index c5fbdbbf81ac..a5a7b13d358c 100644
--- a/fs/pstore/ram_core.c
+++ b/fs/pstore/ram_core.c
@@ -35,8 +35,6 @@ struct persistent_ram_buffer {
#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
-static __initdata LIST_HEAD(persistent_ram_list);
-
static inline size_t buffer_size(struct persistent_ram_zone *prz)
{
return atomic_read(&prz->buffer->size);
@@ -173,12 +171,12 @@ static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
}
}
-static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
- size_t buffer_size)
+static int persistent_ram_init_ecc(struct persistent_ram_zone *prz)
{
int numerr;
struct persistent_ram_buffer *buffer = prz->buffer;
int ecc_blocks;
+ size_t ecc_total;
if (!prz->ecc)
return 0;
@@ -189,14 +187,14 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
prz->ecc_poly = 0x11d;
ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
- prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
-
- if (prz->buffer_size > buffer_size) {
- pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
- buffer_size, prz->buffer_size);
+ ecc_total = (ecc_blocks + 1) * prz->ecc_size;
+ if (ecc_total >= prz->buffer_size) {
+ pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n",
+ __func__, prz->ecc_size, ecc_total, prz->buffer_size);
return -EINVAL;
}
+ prz->buffer_size -= ecc_total;
prz->par_buffer = buffer->data + prz->buffer_size;
prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
@@ -392,13 +390,14 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
return 0;
}
-static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc)
+static int __devinit persistent_ram_post_init(struct persistent_ram_zone *prz,
+ bool ecc)
{
int ret;
prz->ecc = ecc;
- ret = persistent_ram_init_ecc(prz, prz->buffer_size);
+ ret = persistent_ram_init_ecc(prz);
if (ret)
return ret;
@@ -409,14 +408,14 @@ static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool
" size %zu, start %zu\n",
buffer_size(prz), buffer_start(prz));
else {
- pr_info("persistent_ram: found existing buffer,"
+ pr_debug("persistent_ram: found existing buffer,"
" size %zu, start %zu\n",
buffer_size(prz), buffer_start(prz));
persistent_ram_save_old(prz);
return 0;
}
} else {
- pr_info("persistent_ram: no valid data in buffer"
+ pr_debug("persistent_ram: no valid data in buffer"
" (sig = 0x%08x)\n", prz->buffer->sig);
}
@@ -428,19 +427,25 @@ static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool
void persistent_ram_free(struct persistent_ram_zone *prz)
{
- if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
- vunmap(prz->vaddr);
- } else {
- iounmap(prz->vaddr);
- release_mem_region(prz->paddr, prz->size);
+ if (!prz)
+ return;
+
+ if (prz->vaddr) {
+ if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
+ vunmap(prz->vaddr);
+ } else {
+ iounmap(prz->vaddr);
+ release_mem_region(prz->paddr, prz->size);
+ }
+ prz->vaddr = NULL;
}
persistent_ram_free_old(prz);
kfree(prz);
}
-struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
- size_t size,
- bool ecc)
+struct persistent_ram_zone * __devinit persistent_ram_new(phys_addr_t start,
+ size_t size,
+ bool ecc)
{
struct persistent_ram_zone *prz;
int ret = -ENOMEM;
@@ -455,85 +460,12 @@ struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
if (ret)
goto err;
- persistent_ram_post_init(prz, ecc);
-
- return prz;
-err:
- kfree(prz);
- return ERR_PTR(ret);
-}
-
-#ifndef MODULE
-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 = -ENOMEM;
-
- prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
- if (!prz) {
- pr_err("persistent_ram: failed to allocate persistent ram zone\n");
- goto err;
- }
-
- ret = persistent_ram_buffer_init(dev_name(dev), prz);
- if (ret) {
- pr_err("persistent_ram: failed to initialize buffer\n");
+ ret = persistent_ram_post_init(prz, ecc);
+ if (ret)
goto err;
- }
-
- persistent_ram_post_init(prz, ecc);
return prz;
err:
- kfree(prz);
+ persistent_ram_free(prz);
return ERR_PTR(ret);
}
-
-struct persistent_ram_zone * __init
-persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
-{
- return __persistent_ram_init(dev, ecc);
-}
-
-int __init persistent_ram_early_init(struct persistent_ram *ram)
-{
- 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;
-}
-#endif