Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Greg Hackmann and committed by
Kees Cook
35da6094 cae73167

+145 -4
+48
Documentation/devicetree/bindings/misc/ramoops.txt
··· 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)
+4 -2
Documentation/ramoops.txt
··· 45 45 46 46 2. Setting the parameters 47 47 48 - Setting the ramoops parameters can be done in 2 different manners: 48 + Setting the ramoops parameters can be done in 3 different manners: 49 49 1. Use the module parameters (which have the names of the variables described 50 50 as before). 51 51 For quick debugging, you can also reserve parts of memory during boot ··· 54 54 kernel to use only the first 128 MB of memory, and place ECC-protected ramoops 55 55 region at 128 MB boundary: 56 56 "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 58 60 be set through that platform data. An example of doing that is: 59 61 60 62 #include <linux/pstore_ram.h>
+93 -2
fs/pstore/ram.c
··· 34 34 #include <linux/slab.h> 35 35 #include <linux/compiler.h> 36 36 #include <linux/pstore_ram.h> 37 + #include <linux/of.h> 38 + #include <linux/of_address.h> 37 39 38 40 #define RAMOOPS_KERNMSG_HDR "====" 39 41 #define MIN_MEM_SIZE 4096UL ··· 460 458 return 0; 461 459 } 462 460 461 + static int ramoops_parse_dt_size(struct platform_device *pdev, 462 + const char *propname, u32 *value) 463 + { 464 + u32 val32 = 0; 465 + int ret; 466 + 467 + ret = of_property_read_u32(pdev->dev.of_node, propname, &val32); 468 + if (ret < 0 && ret != -EINVAL) { 469 + dev_err(&pdev->dev, "failed to parse property %s: %d\n", 470 + propname, ret); 471 + return ret; 472 + } 473 + 474 + if (val32 > INT_MAX) { 475 + dev_err(&pdev->dev, "%s %u > INT_MAX\n", propname, val32); 476 + return -EOVERFLOW; 477 + } 478 + 479 + *value = val32; 480 + return 0; 481 + } 482 + 483 + static int ramoops_parse_dt(struct platform_device *pdev, 484 + struct ramoops_platform_data *pdata) 485 + { 486 + struct device_node *of_node = pdev->dev.of_node; 487 + struct device_node *mem_region; 488 + struct resource res; 489 + u32 value; 490 + int ret; 491 + 492 + dev_dbg(&pdev->dev, "using Device Tree\n"); 493 + 494 + mem_region = of_parse_phandle(of_node, "memory-region", 0); 495 + if (!mem_region) { 496 + dev_err(&pdev->dev, "no memory-region phandle\n"); 497 + return -ENODEV; 498 + } 499 + 500 + ret = of_address_to_resource(mem_region, 0, &res); 501 + of_node_put(mem_region); 502 + if (ret) { 503 + dev_err(&pdev->dev, 504 + "failed to translate memory-region to resource: %d\n", 505 + ret); 506 + return ret; 507 + } 508 + 509 + pdata->mem_size = resource_size(&res); 510 + pdata->mem_address = res.start; 511 + pdata->mem_type = of_property_read_bool(of_node, "unbuffered"); 512 + pdata->dump_oops = !of_property_read_bool(of_node, "no-dump-oops"); 513 + 514 + #define parse_size(name, field) { \ 515 + ret = ramoops_parse_dt_size(pdev, name, &value); \ 516 + if (ret < 0) \ 517 + return ret; \ 518 + field = value; \ 519 + } 520 + 521 + parse_size("record-size", pdata->record_size); 522 + parse_size("console-size", pdata->console_size); 523 + parse_size("ftrace-size", pdata->ftrace_size); 524 + parse_size("pmsg-size", pdata->pmsg_size); 525 + parse_size("ecc-size", pdata->ecc_info.ecc_size); 526 + 527 + #undef parse_size 528 + 529 + return 0; 530 + } 531 + 463 532 static int ramoops_probe(struct platform_device *pdev) 464 533 { 465 534 struct device *dev = &pdev->dev; 466 - struct ramoops_platform_data *pdata = pdev->dev.platform_data; 535 + struct ramoops_platform_data *pdata = dev->platform_data; 467 536 struct ramoops_context *cxt = &oops_cxt; 468 537 size_t dump_mem_sz; 469 538 phys_addr_t paddr; 470 539 int err = -EINVAL; 540 + 541 + if (dev_of_node(dev) && !pdata) { 542 + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 543 + if (!pdata) { 544 + err = -ENOMEM; 545 + goto fail_out; 546 + } 547 + 548 + err = ramoops_parse_dt(pdev, pdata); 549 + if (err < 0) 550 + goto fail_out; 551 + } 471 552 472 553 /* Only a single ramoops area allowed at a time, so fail extra 473 554 * probes. ··· 681 596 return 0; 682 597 } 683 598 599 + static const struct of_device_id dt_match[] = { 600 + { .compatible = "ramoops" }, 601 + {} 602 + }; 603 + 684 604 static struct platform_driver ramoops_driver = { 685 605 .probe = ramoops_probe, 686 606 .remove = ramoops_remove, 687 607 .driver = { 688 - .name = "ramoops", 608 + .name = "ramoops", 609 + .of_match_table = dt_match, 689 610 }, 690 611 }; 691 612