diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/pstore/Kconfig | 6 | ||||
-rw-r--r-- | fs/pstore/fs.c | 45 | ||||
-rw-r--r-- | fs/pstore/internal.h | 4 | ||||
-rw-r--r-- | fs/pstore/platform.c | 109 | ||||
-rw-r--r-- | fs/pstore/ram.c | 372 | ||||
-rw-r--r-- | fs/pstore/ram_core.c | 42 |
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; |