Skip to content

Commit 35da609

Browse files
greghackmannkees
authored andcommitted
pstore/ram: add Device Tree bindings
ramoops is one of the remaining places where ARM vendors still rely on board-specific shims. Device Tree lets us replace those shims with generic code. These bindings mirror the ramoops module parameters, with two small differences: (1) dump_oops becomes an optional "no-dump-oops" property, since ramoops sets dump_oops=1 by default. (2) mem_type=1 becomes the more self-explanatory "unbuffered" property. Signed-off-by: Greg Hackmann <ghackmann@google.com> [fixed platform_get_drvdata() crash, thanks to Brian Norris] [switched from u64 to u32 to simplify code, various whitespace fixes] [use dev_of_node() to gain code-elimination for CONFIG_OF=n] Signed-off-by: Kees Cook <keescook@chromium.org>
1 parent cae7316 commit 35da609

File tree

3 files changed

+145
-4
lines changed

3 files changed

+145
-4
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Ramoops oops/panic logger
2+
=========================
3+
4+
ramoops provides persistent RAM storage for oops and panics, so they can be
5+
recovered after a reboot. It is a backend to pstore, so this node is named
6+
"ramoops" after the backend, rather than "pstore" which is the subsystem.
7+
8+
Parts of this storage may be set aside for other persistent log buffers, such
9+
as kernel log messages, or for optional ECC error-correction data. The total
10+
size of these optional buffers must fit in the reserved region.
11+
12+
Any remaining space will be used for a circular buffer of oops and panic
13+
records. These records have a configurable size, with a size of 0 indicating
14+
that they should be disabled.
15+
16+
At least one of "record-size", "console-size", "ftrace-size", or "pmsg-size"
17+
must be set non-zero, but are otherwise optional as listed below.
18+
19+
20+
Required properties:
21+
22+
- compatible: must be "ramoops"
23+
24+
- memory-region: phandle to a region of memory that is preserved between
25+
reboots
26+
27+
28+
Optional properties:
29+
30+
- ecc-size: enables ECC support and specifies ECC buffer size in bytes
31+
(defaults to 0: no ECC)
32+
33+
- record-size: maximum size in bytes of each dump done on oops/panic
34+
(defaults to 0: disabled)
35+
36+
- console-size: size in bytes of log buffer reserved for kernel messages
37+
(defaults to 0: disabled)
38+
39+
- ftrace-size: size in bytes of log buffer reserved for function tracing and
40+
profiling (defaults to 0: disabled)
41+
42+
- pmsg-size: size in bytes of log buffer reserved for userspace messages
43+
(defaults to 0: disabled)
44+
45+
- unbuffered: if present, use unbuffered mappings to map the reserved region
46+
(defaults to buffered mappings)
47+
48+
- no-dump-oops: if present, only dump panics (defaults to panics and oops)

Documentation/ramoops.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ corrupt, but usually it is restorable.
4545

4646
2. Setting the parameters
4747

48-
Setting the ramoops parameters can be done in 2 different manners:
48+
Setting the ramoops parameters can be done in 3 different manners:
4949
1. Use the module parameters (which have the names of the variables described
5050
as before).
5151
For quick debugging, you can also reserve parts of memory during boot
@@ -54,7 +54,9 @@ Setting the ramoops parameters can be done in 2 different manners:
5454
kernel to use only the first 128 MB of memory, and place ECC-protected ramoops
5555
region at 128 MB boundary:
5656
"mem=128M ramoops.mem_address=0x8000000 ramoops.ecc=1"
57-
2. Use a platform device and set the platform data. The parameters can then
57+
2. Use Device Tree bindings, as described in
58+
Documentation/device-tree/bindings/misc/ramoops.txt.
59+
3. Use a platform device and set the platform data. The parameters can then
5860
be set through that platform data. An example of doing that is:
5961

6062
#include <linux/pstore_ram.h>

fs/pstore/ram.c

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include <linux/slab.h>
3535
#include <linux/compiler.h>
3636
#include <linux/pstore_ram.h>
37+
#include <linux/of.h>
38+
#include <linux/of_address.h>
3739

3840
#define RAMOOPS_KERNMSG_HDR "===="
3941
#define MIN_MEM_SIZE 4096UL
@@ -458,15 +460,98 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
458460
return 0;
459461
}
460462

463+
static int ramoops_parse_dt_size(struct platform_device *pdev,
464+
const char *propname, u32 *value)
465+
{
466+
u32 val32 = 0;
467+
int ret;
468+
469+
ret = of_property_read_u32(pdev->dev.of_node, propname, &val32);
470+
if (ret < 0 && ret != -EINVAL) {
471+
dev_err(&pdev->dev, "failed to parse property %s: %d\n",
472+
propname, ret);
473+
return ret;
474+
}
475+
476+
if (val32 > INT_MAX) {
477+
dev_err(&pdev->dev, "%s %u > INT_MAX\n", propname, val32);
478+
return -EOVERFLOW;
479+
}
480+
481+
*value = val32;
482+
return 0;
483+
}
484+
485+
static int ramoops_parse_dt(struct platform_device *pdev,
486+
struct ramoops_platform_data *pdata)
487+
{
488+
struct device_node *of_node = pdev->dev.of_node;
489+
struct device_node *mem_region;
490+
struct resource res;
491+
u32 value;
492+
int ret;
493+
494+
dev_dbg(&pdev->dev, "using Device Tree\n");
495+
496+
mem_region = of_parse_phandle(of_node, "memory-region", 0);
497+
if (!mem_region) {
498+
dev_err(&pdev->dev, "no memory-region phandle\n");
499+
return -ENODEV;
500+
}
501+
502+
ret = of_address_to_resource(mem_region, 0, &res);
503+
of_node_put(mem_region);
504+
if (ret) {
505+
dev_err(&pdev->dev,
506+
"failed to translate memory-region to resource: %d\n",
507+
ret);
508+
return ret;
509+
}
510+
511+
pdata->mem_size = resource_size(&res);
512+
pdata->mem_address = res.start;
513+
pdata->mem_type = of_property_read_bool(of_node, "unbuffered");
514+
pdata->dump_oops = !of_property_read_bool(of_node, "no-dump-oops");
515+
516+
#define parse_size(name, field) { \
517+
ret = ramoops_parse_dt_size(pdev, name, &value); \
518+
if (ret < 0) \
519+
return ret; \
520+
field = value; \
521+
}
522+
523+
parse_size("record-size", pdata->record_size);
524+
parse_size("console-size", pdata->console_size);
525+
parse_size("ftrace-size", pdata->ftrace_size);
526+
parse_size("pmsg-size", pdata->pmsg_size);
527+
parse_size("ecc-size", pdata->ecc_info.ecc_size);
528+
529+
#undef parse_size
530+
531+
return 0;
532+
}
533+
461534
static int ramoops_probe(struct platform_device *pdev)
462535
{
463536
struct device *dev = &pdev->dev;
464-
struct ramoops_platform_data *pdata = pdev->dev.platform_data;
537+
struct ramoops_platform_data *pdata = dev->platform_data;
465538
struct ramoops_context *cxt = &oops_cxt;
466539
size_t dump_mem_sz;
467540
phys_addr_t paddr;
468541
int err = -EINVAL;
469542

543+
if (dev_of_node(dev) && !pdata) {
544+
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
545+
if (!pdata) {
546+
err = -ENOMEM;
547+
goto fail_out;
548+
}
549+
550+
err = ramoops_parse_dt(pdev, pdata);
551+
if (err < 0)
552+
goto fail_out;
553+
}
554+
470555
/* Only a single ramoops area allowed at a time, so fail extra
471556
* probes.
472557
*/
@@ -596,11 +681,17 @@ static int ramoops_remove(struct platform_device *pdev)
596681
return 0;
597682
}
598683

684+
static const struct of_device_id dt_match[] = {
685+
{ .compatible = "ramoops" },
686+
{}
687+
};
688+
599689
static struct platform_driver ramoops_driver = {
600690
.probe = ramoops_probe,
601691
.remove = ramoops_remove,
602692
.driver = {
603-
.name = "ramoops",
693+
.name = "ramoops",
694+
.of_match_table = dt_match,
604695
},
605696
};
606697

0 commit comments

Comments
 (0)