summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/pstore/Kconfig6
-rw-r--r--fs/pstore/fs.c45
-rw-r--r--fs/pstore/internal.h4
-rw-r--r--fs/pstore/platform.c109
-rw-r--r--fs/pstore/ram.c372
-rw-r--r--fs/pstore/ram_core.c42
6 files changed, 447 insertions, 131 deletions
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 0e042cb162..30c2de19c8 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -8,6 +8,12 @@ menuconfig FS_PSTORE
if FS_PSTORE
+config FS_PSTORE_CONSOLE
+ bool
+ prompt "Log console messages"
+ help
+ When the option is enabled, pstore will log console messages.
+
config FS_PSTORE_RAMOOPS
bool
depends on RELOCATABLE
diff --git a/fs/pstore/fs.c b/fs/pstore/fs.c
index 9a7e0b5526..e9c7ae7adb 100644
--- a/fs/pstore/fs.c
+++ b/fs/pstore/fs.c
@@ -52,68 +52,71 @@ struct pstore_private {
* Load it up with "size" bytes of data from "buf".
* Set the mtime & ctime to the date that this record was originally stored.
*/
-int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
- char *data, bool compressed, size_t size,
- struct pstore_info *psi)
+int pstore_mkfile(struct pstore_record *record)
{
struct pstore_private *private, *pos;
+ size_t size = record->size;
list_for_each_entry(pos, &allpstore, list) {
- if (pos->type == type && pos->id == id && pos->psi == psi)
+ if (pos->type == record->type &&
+ pos->id == record->id &&
+ pos->psi == record->psi)
return -EEXIST;
}
private = xzalloc(sizeof(*private) + size);
- private->type = type;
- private->id = id;
- private->count = count;
- private->psi = psi;
+ private->type = record->type;
+ private->id = record->id;
+ private->count = record->count;
+ private->psi = record->psi;
- switch (type) {
+ switch (record->type) {
case PSTORE_TYPE_DMESG:
scnprintf(private->name, sizeof(private->name),
- "dmesg-%s-%lld%s", psname, id,
- compressed ? ".enc.z" : "");
+ "dmesg-%s-%lld%s", record->psi->name, record->id,
+ record->compressed ? ".enc.z" : "");
break;
case PSTORE_TYPE_CONSOLE:
scnprintf(private->name, sizeof(private->name),
- "console-%s-%lld", psname, id);
+ "console-%s-%lld", record->psi->name, record->id);
break;
case PSTORE_TYPE_FTRACE:
scnprintf(private->name, sizeof(private->name),
- "ftrace-%s-%lld", psname, id);
+ "ftrace-%s-%lld", record->psi->name, record->id);
break;
case PSTORE_TYPE_MCE:
scnprintf(private->name, sizeof(private->name),
- "mce-%s-%lld", psname, id);
+ "mce-%s-%lld", record->psi->name, record->id);
break;
case PSTORE_TYPE_PPC_RTAS:
scnprintf(private->name, sizeof(private->name),
- "rtas-%s-%lld", psname, id);
+ "rtas-%s-%lld", record->psi->name, record->id);
break;
case PSTORE_TYPE_PPC_OF:
scnprintf(private->name, sizeof(private->name),
- "powerpc-ofw-%s-%lld", psname, id);
+ "powerpc-ofw-%s-%lld", record->psi->name, record->id);
break;
case PSTORE_TYPE_PPC_COMMON:
scnprintf(private->name, sizeof(private->name),
- "powerpc-common-%s-%lld", psname, id);
+ "powerpc-common-%s-%lld", record->psi->name,
+ record->id);
break;
case PSTORE_TYPE_PMSG:
scnprintf(private->name, sizeof(private->name),
- "pmsg-%s-%lld", psname, id);
+ "pmsg-%s-%lld", record->psi->name, record->id);
break;
case PSTORE_TYPE_UNKNOWN:
scnprintf(private->name, sizeof(private->name),
- "unknown-%s-%lld", psname, id);
+ "unknown-%s-%lld", record->psi->name, record->id);
break;
default:
scnprintf(private->name, sizeof(private->name),
- "type%d-%s-%lld", type, psname, id);
+ "type%d-%s-%lld", record->type, record->psi->name,
+ record->id);
break;
}
- memcpy(private->data, data, size);
+ memcpy(private->data, record->buf, size);
private->size = size;
list_add(&private->list, &allpstore);
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 0a8df1f4e2..6b507e4bd3 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -11,9 +11,7 @@ extern struct pstore_info *psinfo;
extern void pstore_set_kmsg_bytes(int);
extern void pstore_get_records(int);
-extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
- int count, char *data, bool compressed,
- size_t size, struct pstore_info *psi);
+extern int pstore_mkfile(struct pstore_record *record);
extern int pstore_is_mounted(void);
#endif
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 963ecafef8..755363c309 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -25,6 +25,7 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
+#include <console.h>
#include <malloc.h>
#include <printk.h>
#include <module.h>
@@ -43,14 +44,83 @@ void pstore_set_kmsg_bytes(int bytes)
kmsg_bytes = bytes;
}
-static int pstore_write_compat(enum pstore_type_id type,
- enum kmsg_dump_reason reason,
- u64 *id, unsigned int part, int count,
- bool compressed, size_t size,
- struct pstore_info *psi)
+#ifdef CONFIG_FS_PSTORE_CONSOLE
+static void pstore_console_write(const char *s, unsigned c)
{
- return psi->write_buf(type, reason, id, part, psinfo->buf, compressed,
- size, psi);
+ const char *e = s + c;
+
+ while (s < e) {
+ struct pstore_record record = {
+ .type = PSTORE_TYPE_CONSOLE,
+ .psi = psinfo,
+ };
+
+ if (c > psinfo->bufsize)
+ c = psinfo->bufsize;
+
+ record.buf = (char *)s;
+ record.size = c;
+ psinfo->write_buf(PSTORE_TYPE_CONSOLE, 0, &record.id, 0,
+ record.buf, 0, record.size, psinfo);
+ s += c;
+ c = e - s;
+ }
+}
+
+static int pstore_console_puts(struct console_device *cdev, const char *s)
+{
+ pstore_console_write(s, strlen(s));
+ return strlen(s);
+}
+
+static void pstore_console_putc(struct console_device *cdev, char c)
+{
+ const char s[1] = { c };
+
+ pstore_console_write(s, 1);
+}
+
+static void pstore_console_capture_log(void)
+{
+ struct log_entry *log;
+
+ list_for_each_entry(log, &barebox_logbuf, list)
+ pstore_console_write(log->msg, strlen(log->msg));
+}
+
+static struct console_device *pstore_cdev;
+
+static void pstore_register_console(void)
+{
+ struct console_device *cdev;
+ int ret;
+
+ cdev = xzalloc(sizeof(struct console_device));
+ pstore_cdev = cdev;
+
+ cdev->puts = pstore_console_puts;
+ cdev->putc = pstore_console_putc;
+ cdev->devname = "pstore";
+ cdev->devid = DEVICE_ID_SINGLE;
+
+ ret = console_register(cdev);
+ if (ret)
+ pr_err("registering failed with %s\n", strerror(-ret));
+
+ pstore_console_capture_log();
+
+ console_set_active(pstore_cdev, CONSOLE_STDOUT);
+}
+#else
+static void pstore_register_console(void) {}
+#endif
+
+static int pstore_write_compat(struct pstore_record *record)
+{
+ return record->psi->write_buf(record->type, record->reason,
+ &record->id, record->part,
+ psinfo->buf, record->compressed,
+ record->size, record->psi);
}
/*
@@ -81,6 +151,8 @@ int pstore_register(struct pstore_info *psi)
pstore_get_records(0);
+ pstore_register_console();
+
pr_info("Registered %s as persistent store backend\n", psi->name);
return 0;
@@ -96,13 +168,8 @@ EXPORT_SYMBOL_GPL(pstore_register);
void pstore_get_records(int quiet)
{
struct pstore_info *psi = psinfo;
- char *buf = NULL;
- ssize_t size;
- u64 id;
- int count;
- enum pstore_type_id type;
+ struct pstore_record record = { .psi = psi, };
int failed = 0, rc;
- bool compressed;
int unzipped_len = -1;
if (!psi)
@@ -112,22 +179,24 @@ void pstore_get_records(int quiet)
if (psi->open && psi->open(psi))
goto out;
- while ((size = psi->read(&id, &type, &count, &buf, &compressed,
- psi)) > 0) {
- if (compressed && (type == PSTORE_TYPE_DMESG)) {
+ while ((record.size = psi->read(&record)) > 0) {
+ if (record.compressed &&
+ record.type == PSTORE_TYPE_DMESG) {
pr_err("barebox does not have ramoops compression support\n");
continue;
}
- rc = pstore_mkfile(type, psi->name, id, count, buf,
- compressed, (size_t)size, psi);
+ rc = pstore_mkfile(&record);
if (unzipped_len < 0) {
/* Free buffer other than big oops */
- kfree(buf);
- buf = NULL;
+ kfree(record.buf);
+ record.buf = NULL;
} else
unzipped_len = -1;
if (rc && (rc != -EEXIST || !quiet))
failed++;
+
+ memset(&record, 0, sizeof(record));
+ record.psi = psi;
}
if (psi->close)
psi->close(psi);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index fdd92a60a5..734d0c3c1d 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -36,6 +36,8 @@
#include <globalvar.h>
#include <init.h>
#include <common.h>
+#include <of.h>
+#include <of_address.h>
#define RAMOOPS_KERNMSG_HDR "===="
#define MIN_MEM_SIZE 4096UL
@@ -126,27 +128,32 @@ static bool prz_ok(struct persistent_ram_zone *prz)
persistent_ram_ecc_string(prz, NULL, 0));
}
-static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
- int *count, char **buf, bool *compressed,
- struct pstore_info *psi)
+static ssize_t ramoops_pstore_read(struct pstore_record *record)
{
ssize_t size;
ssize_t ecc_notice_size;
- struct ramoops_context *cxt = psi->data;
+ struct ramoops_context *cxt = record->psi->data;
struct persistent_ram_zone *prz;
+ record->compressed = false;
+
prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
- cxt->max_dump_cnt, id, type,
+ cxt->max_dump_cnt, &record->id,
+ &record->type,
PSTORE_TYPE_DMESG, 0);
if (!prz_ok(prz))
prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
- 1, id, type, PSTORE_TYPE_CONSOLE, 0);
+ 1, &record->id, &record->type,
+ PSTORE_TYPE_CONSOLE, 0);
+
if (!prz_ok(prz))
prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
- 1, id, type, PSTORE_TYPE_FTRACE, 0);
+ 1, &record->id, &record->type,
+ PSTORE_TYPE_FTRACE, 0);
if (!prz_ok(prz))
prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
- 1, id, type, PSTORE_TYPE_PMSG, 0);
+ 1, &record->id, &record->type,
+ PSTORE_TYPE_PMSG, 0);
if (!prz_ok(prz))
return 0;
@@ -158,12 +165,12 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
/* ECC correction notice */
ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
- *buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL);
- if (*buf == NULL)
+ record->buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL);
+ if (record->buf == NULL)
return -ENOMEM;
- memcpy(*buf, (char *)persistent_ram_old(prz), size);
- persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);
+ memcpy(record->buf, (char *)persistent_ram_old(prz), size);
+ persistent_ram_ecc_string(prz, record->buf + size, ecc_notice_size + 1);
return size + ecc_notice_size;
}
@@ -272,91 +279,278 @@ static void ramoops_free_przs(struct ramoops_context *cxt)
kfree(cxt->przs);
}
-static int ramoops_init_przs(struct ramoops_context *cxt, phys_addr_t *paddr,
- size_t dump_mem_sz)
+static int ramoops_init_przs(const char *name,
+ struct ramoops_context *cxt,
+ struct persistent_ram_zone ***przs,
+ phys_addr_t *paddr, size_t mem_sz,
+ ssize_t record_size,
+ unsigned int *cnt, u32 sig, u32 flags)
{
int err = -ENOMEM;
int i;
+ size_t zone_sz;
+ struct persistent_ram_zone **prz_ar;
- if (!cxt->record_size)
+ /* Allocate nothing for 0 mem_sz or 0 record_size. */
+ if (mem_sz == 0 || record_size == 0) {
+ *cnt = 0;
return 0;
+ }
- if (*paddr + dump_mem_sz - cxt->phys_addr > cxt->size) {
- pr_err("no room for dumps\n");
- return -ENOMEM;
+ /*
+ * If we have a negative record size, calculate it based on
+ * mem_sz / *cnt. If we have a positive record size, calculate
+ * cnt from mem_sz / record_size.
+ */
+ if (record_size < 0) {
+ if (*cnt == 0)
+ return 0;
+ record_size = mem_sz / *cnt;
+ if (record_size == 0) {
+ pr_err("%s record size == 0 (%zu / %u)\n",
+ name, mem_sz, *cnt);
+ goto fail;
+ }
+ } else {
+ *cnt = mem_sz / record_size;
+ if (*cnt == 0) {
+ pr_err("%s record count == 0 (%zu / %zu)\n",
+ name, mem_sz, record_size);
+ goto fail;
+ }
}
- cxt->max_dump_cnt = dump_mem_sz / cxt->record_size;
- if (!cxt->max_dump_cnt)
- return -ENOMEM;
+ if (*paddr + mem_sz - cxt->phys_addr > cxt->size) {
+ pr_err("no room for %s mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n",
+ name,
+ mem_sz, (unsigned long long)*paddr,
+ cxt->size, (unsigned long long)cxt->phys_addr);
+ goto fail;
+ }
- cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt,
- GFP_KERNEL);
- if (!cxt->przs) {
- pr_err("failed to initialize a prz array for dumps\n");
- goto fail_prz;
+ zone_sz = mem_sz / *cnt;
+ if (!zone_sz) {
+ pr_err("%s zone size == 0\n", name);
+ goto fail;
}
- for (i = 0; i < cxt->max_dump_cnt; i++) {
- size_t sz = cxt->record_size;
-
- cxt->przs[i] = persistent_ram_new(*paddr, sz, 0,
- &cxt->ecc_info,
- cxt->memtype);
- if (IS_ERR(cxt->przs[i])) {
- err = PTR_ERR(cxt->przs[i]);
- pr_err("failed to request mem region (0x%zx@0x%llx): %d\n",
- sz, (unsigned long long)*paddr, err);
- goto fail_prz;
+ prz_ar = kcalloc(*cnt, sizeof(**przs), GFP_KERNEL);
+ if (!prz_ar)
+ goto fail;
+
+ for (i = 0; i < *cnt; i++) {
+ char *label;
+
+ if (*cnt == 1)
+ label = basprintf("ramoops:%s", name);
+ else
+ label = basprintf("ramoops:%s(%d/%d)",
+ name, i, *cnt - 1);
+ prz_ar[i] = persistent_ram_new(*paddr, zone_sz, sig,
+ &cxt->ecc_info,
+ cxt->memtype, label);
+ if (IS_ERR(prz_ar[i])) {
+ err = PTR_ERR(prz_ar[i]);
+ pr_err("failed to request %s mem region (0x%zx@0x%llx): %d\n",
+ name, record_size,
+ (unsigned long long)*paddr, err);
+
+ while (i > 0) {
+ i--;
+ persistent_ram_free(prz_ar[i]);
+ }
+ kfree(prz_ar);
+ goto fail;
}
- *paddr += sz;
+ *paddr += zone_sz;
}
+ *przs = prz_ar;
return 0;
-fail_prz:
- ramoops_free_przs(cxt);
+
+fail:
+ *cnt = 0;
return err;
}
-static int ramoops_init_prz(struct ramoops_context *cxt,
+static int ramoops_init_prz(const char *name,
+ struct ramoops_context *cxt,
struct persistent_ram_zone **prz,
phys_addr_t *paddr, size_t sz, u32 sig)
{
+ char *label;
+
if (!sz)
return 0;
if (*paddr + sz - cxt->phys_addr > cxt->size) {
- pr_err("no room for mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n",
- sz, (unsigned long long)*paddr,
+ pr_err("no room for %s mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n",
+ name, sz, (unsigned long long)*paddr,
cxt->size, (unsigned long long)cxt->phys_addr);
return -ENOMEM;
}
+ label = basprintf("ramoops:%s", name);
*prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info,
- cxt->memtype);
+ cxt->memtype, label);
if (IS_ERR(*prz)) {
int err = PTR_ERR(*prz);
- pr_err("failed to request mem region (0x%zx@0x%llx): %d\n",
- sz, (unsigned long long)*paddr, err);
+ pr_err("failed to request %s mem region (0x%zx@0x%llx): %d\n",
+ name, sz, (unsigned long long)*paddr, err);
return err;
}
+#ifndef CONFIG_FS_PSTORE_RAMOOPS_RO
persistent_ram_zap(*prz);
+#endif /* CONFIG_FS_PSTORE_RAMOOPS_RO */
*paddr += sz;
return 0;
}
-static int ramoops_probe(struct ramoops_platform_data *pdata)
+static int ramoops_parse_dt_size(struct device_d *dev,
+ const char *propname, u32 *value)
+{
+ u32 val32 = 0;
+ int ret;
+
+ ret = of_property_read_u32(dev->device_node, propname, &val32);
+ if (ret < 0 && ret != -EINVAL) {
+ dev_err(dev, "failed to parse property %s: %d\n",
+ propname, ret);
+ return ret;
+ }
+
+ if (val32 > INT_MAX) {
+ dev_err(dev, "%s %u > INT_MAX\n", propname, val32);
+ return -EOVERFLOW;
+ }
+
+ *value = val32;
+ return 0;
+}
+
+static int ramoops_parse_dt(struct device_d *dev,
+ struct ramoops_platform_data *pdata)
+{
+ struct device_node *of_node = dev->device_node;
+ struct resource *res;
+ u32 value;
+ int ret;
+
+ res = dev_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev,
+ "failed to locate DT /reserved-memory resource\n");
+ return -EINVAL;
+ }
+
+ pdata->mem_size = resource_size(res);
+ pdata->mem_address = res->start;
+ pdata->mem_type = of_property_read_bool(of_node, "unbuffered");
+ pdata->dump_oops = !of_property_read_bool(of_node, "no-dump-oops");
+
+#define parse_size(name, field) { \
+ ret = ramoops_parse_dt_size(dev, name, &value); \
+ if (ret < 0) \
+ return ret; \
+ field = value; \
+ }
+
+ parse_size("record-size", pdata->record_size);
+ parse_size("console-size", pdata->console_size);
+ parse_size("ftrace-size", pdata->ftrace_size);
+ parse_size("pmsg-size", pdata->pmsg_size);
+ parse_size("ecc-size", pdata->ecc_info.ecc_size);
+
+#undef parse_size
+
+ return 0;
+}
+
+static int ramoops_of_fixup(struct device_node *root, void *data)
+{
+ struct ramoops_platform_data *pdata = data;
+ struct device_node *node;
+ u32 reg[2];
+ int ret;
+
+ node = of_get_child_by_name(root, "reserved-memory");
+ if (!node) {
+ pr_info("Adding reserved-memory node\n");
+ node = of_create_node(root, "/reserved-memory");
+ if (!node)
+ return -ENOMEM;
+
+ of_property_write_u32(node, "#address-cells", 1);
+ of_property_write_u32(node, "#size-cells", 1);
+ of_new_property(node, "ranges", NULL, 0);
+ }
+
+ node = of_get_child_by_name(node, "ramoops");
+ if (!node) {
+ pr_info("Adding ramoops node\n");
+ node = of_create_node(root, "/reserved-memory/ramoops");
+ if (!node)
+ return -ENOMEM;
+ }
+
+ ret = of_property_write_string(node, "compatible", "ramoops");
+ if (ret)
+ return ret;
+ reg[0] = pdata->mem_address;
+ reg[1] = pdata->mem_size;
+ ret = of_property_write_u32_array(node, "reg", reg, 2);
+ if (ret)
+ return ret;
+
+ ret = of_property_write_bool(node, "unbuffered", pdata->mem_type);
+ if (ret)
+ return ret;
+ ret = of_property_write_bool(node, "no-dump-oops", !pdata->dump_oops);
+ if (ret)
+ return ret;
+
+#define store_size(name, field) { \
+ ret = of_property_write_u32(node, name, field); \
+ if (ret < 0) \
+ return ret; \
+ }
+
+ store_size("record-size", pdata->record_size);
+ store_size("console-size", pdata->console_size);
+ store_size("ftrace-size", pdata->ftrace_size);
+ store_size("pmsg-size", pdata->pmsg_size);
+ store_size("ecc-size", pdata->ecc_info.ecc_size);
+
+#undef store_size
+
+ return 0;
+}
+
+static int ramoops_probe(struct device_d *dev)
{
+ struct ramoops_platform_data *pdata = dummy_data;
struct ramoops_context *cxt = &oops_cxt;
size_t dump_mem_sz;
phys_addr_t paddr;
int err = -EINVAL;
char kernelargs[512];
+ if (IS_ENABLED(CONFIG_OFTREE) && !pdata) {
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ err = -ENOMEM;
+ goto fail_out;
+ }
+
+ err = ramoops_parse_dt(dev, pdata);
+ if (err < 0)
+ goto fail_out;
+ }
+
/* Only a single ramoops area allowed at a time, so fail extra
* probes.
*/
@@ -393,20 +587,24 @@ static int ramoops_probe(struct ramoops_platform_data *pdata)
dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
- cxt->pmsg_size;
- err = ramoops_init_przs(cxt, &paddr, dump_mem_sz);
+ err = ramoops_init_przs("dump", cxt, &cxt->przs, &paddr,
+ dump_mem_sz, cxt->record_size,
+ &cxt->max_dump_cnt, 0, 0);
if (err)
goto fail_out;
- err = ramoops_init_prz(cxt, &cxt->cprz, &paddr,
+ err = ramoops_init_prz("console", cxt, &cxt->cprz, &paddr,
cxt->console_size, 0);
if (err)
goto fail_init_cprz;
- err = ramoops_init_prz(cxt, &cxt->fprz, &paddr, cxt->ftrace_size, 0);
+ err = ramoops_init_prz("ftrace", cxt, &cxt->fprz, &paddr,
+ cxt->ftrace_size, 0);
if (err)
goto fail_init_fprz;
- err = ramoops_init_prz(cxt, &cxt->mprz, &paddr, cxt->pmsg_size, 0);
+ err = ramoops_init_prz("pmsg", cxt, &cxt->mprz, &paddr,
+ cxt->pmsg_size, 0);
if (err)
goto fail_init_mprz;
@@ -438,25 +636,27 @@ static int ramoops_probe(struct ramoops_platform_data *pdata)
cxt->size, (unsigned long long)cxt->phys_addr,
cxt->ecc_info.ecc_size, cxt->ecc_info.block_size);
- scnprintf(kernelargs, sizeof(kernelargs),
- "ramoops.record_size=0x%x "
- "ramoops.console_size=0x%x "
- "ramoops.ftrace_size=0x%x "
- "ramoops.pmsg_size=0x%x "
- "ramoops.mem_address=0x%llx "
- "ramoops.mem_size=0x%lx "
- "ramoops.ecc=%d",
- cxt->record_size,
- cxt->console_size,
- cxt->ftrace_size,
- cxt->pmsg_size,
- (unsigned long long)cxt->phys_addr,
- mem_size,
- ramoops_ecc);
- globalvar_add_simple("linux.bootargs.ramoops", kernelargs);
-
- if (IS_ENABLED(CONFIG_OFTREE))
+ if (!IS_ENABLED(CONFIG_OFTREE)) {
+ scnprintf(kernelargs, sizeof(kernelargs),
+ "ramoops.record_size=0x%x "
+ "ramoops.console_size=0x%x "
+ "ramoops.ftrace_size=0x%x "
+ "ramoops.pmsg_size=0x%x "
+ "ramoops.mem_address=0x%llx "
+ "ramoops.mem_size=0x%lx "
+ "ramoops.ecc=%d",
+ cxt->record_size,
+ cxt->console_size,
+ cxt->ftrace_size,
+ cxt->pmsg_size,
+ (unsigned long long)cxt->phys_addr,
+ mem_size,
+ ramoops_ecc);
+ globalvar_add_simple("linux.bootargs.ramoops", kernelargs);
+ } else {
of_add_reserve_entry(cxt->phys_addr, cxt->phys_addr + mem_size);
+ of_register_fixup(ramoops_of_fixup, pdata);
+ }
return 0;
@@ -472,6 +672,7 @@ fail_init_fprz:
fail_init_cprz:
ramoops_free_przs(cxt);
fail_out:
+ kfree(pdata);
return err;
}
unsigned long arm_mem_ramoops_get(void);
@@ -498,12 +699,39 @@ static void ramoops_register_dummy(void)
*/
dummy_data->ecc_info.ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc;
- ramoops_probe(dummy_data);
+ if (!IS_ENABLED(CONFIG_OFTREE))
+ ramoops_probe(NULL);
}
+static const struct of_device_id ramoops_dt_ids[] = {
+ { .compatible = "ramoops" },
+ { },
+};
+
+static struct driver_d ramoops_driver = {
+ .name = "ramoops",
+ .probe = ramoops_probe,
+ .of_compatible = DRV_OF_COMPAT(ramoops_dt_ids),
+};
+
static int __init ramoops_init(void)
{
+ if (IS_ENABLED(CONFIG_OFTREE)) {
+ struct device_node *node;
+
+ node = of_get_root_node();
+ if (!node)
+ return 0;
+
+ node = of_get_child_by_name(node, "reserved-memory");
+ if (!node)
+ return 0;
+
+ for_each_matching_node(node, ramoops_dt_ids)
+ of_platform_device_create(node, NULL);
+ }
+
ramoops_register_dummy();
- return 0;
+ return platform_driver_register(&ramoops_driver);
}
-postcore_initcall(ramoops_init);
+device_initcall(ramoops_init);
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
index 9de6dc614d..06be47ce53 100644
--- a/fs/pstore/ram_core.c
+++ b/fs/pstore/ram_core.c
@@ -80,24 +80,23 @@ static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
uint8_t *data, size_t len, uint8_t *ecc)
{
int i;
- uint16_t par[prz->ecc_info.ecc_size];
/* Initialize the parity buffer */
- memset(par, 0, sizeof(par));
- encode_rs8(prz->rs_decoder, data, len, par, 0);
+ memset(prz->ecc_info.par, 0,
+ prz->ecc_info.ecc_size * sizeof(prz->ecc_info.par[0]));
+ encode_rs8(prz->rs_decoder, data, len, prz->ecc_info.par, 0);
for (i = 0; i < prz->ecc_info.ecc_size; i++)
- ecc[i] = par[i];
+ ecc[i] = prz->ecc_info.par[i];
}
static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
void *data, size_t len, uint8_t *ecc)
{
int i;
- uint16_t par[prz->ecc_info.ecc_size];
for (i = 0; i < prz->ecc_info.ecc_size; i++)
- par[i] = ecc[i];
- return decode_rs8(prz->rs_decoder, data, par, len,
+ prz->ecc_info.par[i] = ecc[i];
+ return decode_rs8(prz->rs_decoder, data, prz->ecc_info.par, len,
NULL, 0, NULL, 0, NULL);
}
@@ -210,6 +209,15 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
return -EINVAL;
}
+ /* allocate workspace instead of using stack VLA */
+ prz->ecc_info.par = kmalloc_array(prz->ecc_info.ecc_size,
+ sizeof(*prz->ecc_info.par),
+ GFP_KERNEL);
+ if (!prz->ecc_info.par) {
+ pr_err("cannot allocate ECC parity workspace\n");
+ return -ENOMEM;
+ }
+
prz->corrected_bytes = 0;
prz->bad_blocks = 0;
@@ -322,23 +330,17 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz)
prz->old_log_size = 0;
}
-#ifdef CONFIG_FS_PSTORE_RAMOOPS_RO
-void persistent_ram_zap(struct persistent_ram_zone *prz)
-{
-}
-#else
void persistent_ram_zap(struct persistent_ram_zone *prz)
{
prz->buffer->start = 0;
prz->buffer->size = 0;
persistent_ram_update_header_ecc(prz);
}
-#endif /* CONFIG_PSTORE_RAMOOPS_RO */
static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
struct persistent_ram_zone *prz, int memtype)
{
- prz->res = request_sdram_region("persistent ram", start, size);
+ prz->res = request_sdram_region(prz->label ?: "ramoops", start, size);
if (!prz->res)
return -ENOMEM;
@@ -393,14 +395,21 @@ void persistent_ram_free(struct persistent_ram_zone *prz)
release_sdram_region(prz->res);
prz->res = NULL;
}
+ if (prz->rs_decoder) {
+ free_rs(prz->rs_decoder);
+ prz->rs_decoder = NULL;
+ }
+ kfree(prz->ecc_info.par);
+ prz->ecc_info.par = NULL;
persistent_ram_free_old(prz);
+ kfree(prz->label);
kfree(prz);
}
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
u32 sig, struct persistent_ram_ecc_info *ecc_info,
- unsigned int memtype)
+ unsigned int memtype, char *label)
{
struct persistent_ram_zone *prz;
int ret = -ENOMEM;
@@ -411,6 +420,9 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
goto err;
}
+ /* Initialize general buffer state. */
+ prz->label = label;
+
ret = persistent_ram_buffer_map(start, size, prz, memtype);
if (ret)
goto err;