diff options
author | Grant Likely <grant.likely@linaro.org> | 2014-03-19 11:01:53 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@linaro.org> | 2014-03-19 11:01:53 -0400 |
commit | ca3992bc0c12e381deb84cd47ec1181a6d34660d (patch) | |
tree | 162006e862b9d856fdce1b19f0ba117dafb6ca58 /drivers/of/fdt.c | |
parent | 0829f6d1f69e4f2fae4062987ae6531a9af1a2e3 (diff) | |
parent | 2040b52768ebab6e7bd73af0dc63703269c62f17 (diff) |
Merge branch 'devicetree/next-reserved-mem' into devicetree/next
Diffstat (limited to 'drivers/of/fdt.c')
-rw-r--r-- | drivers/of/fdt.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 70ccc36513e7..fa16a912a927 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c | |||
@@ -15,6 +15,8 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/of.h> | 16 | #include <linux/of.h> |
17 | #include <linux/of_fdt.h> | 17 | #include <linux/of_fdt.h> |
18 | #include <linux/of_reserved_mem.h> | ||
19 | #include <linux/sizes.h> | ||
18 | #include <linux/string.h> | 20 | #include <linux/string.h> |
19 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
20 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
@@ -440,6 +442,129 @@ struct boot_param_header *initial_boot_params; | |||
440 | #ifdef CONFIG_OF_EARLY_FLATTREE | 442 | #ifdef CONFIG_OF_EARLY_FLATTREE |
441 | 443 | ||
442 | /** | 444 | /** |
445 | * res_mem_reserve_reg() - reserve all memory described in 'reg' property | ||
446 | */ | ||
447 | static int __init __reserved_mem_reserve_reg(unsigned long node, | ||
448 | const char *uname) | ||
449 | { | ||
450 | int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); | ||
451 | phys_addr_t base, size; | ||
452 | unsigned long len; | ||
453 | __be32 *prop; | ||
454 | int nomap, first = 1; | ||
455 | |||
456 | prop = of_get_flat_dt_prop(node, "reg", &len); | ||
457 | if (!prop) | ||
458 | return -ENOENT; | ||
459 | |||
460 | if (len && len % t_len != 0) { | ||
461 | pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", | ||
462 | uname); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | |||
466 | nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; | ||
467 | |||
468 | while (len >= t_len) { | ||
469 | base = dt_mem_next_cell(dt_root_addr_cells, &prop); | ||
470 | size = dt_mem_next_cell(dt_root_size_cells, &prop); | ||
471 | |||
472 | if (base && size && | ||
473 | early_init_dt_reserve_memory_arch(base, size, nomap) == 0) | ||
474 | pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n", | ||
475 | uname, &base, (unsigned long)size / SZ_1M); | ||
476 | else | ||
477 | pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n", | ||
478 | uname, &base, (unsigned long)size / SZ_1M); | ||
479 | |||
480 | len -= t_len; | ||
481 | if (first) { | ||
482 | fdt_reserved_mem_save_node(node, uname, base, size); | ||
483 | first = 0; | ||
484 | } | ||
485 | } | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | /** | ||
490 | * __reserved_mem_check_root() - check if #size-cells, #address-cells provided | ||
491 | * in /reserved-memory matches the values supported by the current implementation, | ||
492 | * also check if ranges property has been provided | ||
493 | */ | ||
494 | static int __reserved_mem_check_root(unsigned long node) | ||
495 | { | ||
496 | __be32 *prop; | ||
497 | |||
498 | prop = of_get_flat_dt_prop(node, "#size-cells", NULL); | ||
499 | if (!prop || be32_to_cpup(prop) != dt_root_size_cells) | ||
500 | return -EINVAL; | ||
501 | |||
502 | prop = of_get_flat_dt_prop(node, "#address-cells", NULL); | ||
503 | if (!prop || be32_to_cpup(prop) != dt_root_addr_cells) | ||
504 | return -EINVAL; | ||
505 | |||
506 | prop = of_get_flat_dt_prop(node, "ranges", NULL); | ||
507 | if (!prop) | ||
508 | return -EINVAL; | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | /** | ||
513 | * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory | ||
514 | */ | ||
515 | static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, | ||
516 | int depth, void *data) | ||
517 | { | ||
518 | static int found; | ||
519 | const char *status; | ||
520 | int err; | ||
521 | |||
522 | if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) { | ||
523 | if (__reserved_mem_check_root(node) != 0) { | ||
524 | pr_err("Reserved memory: unsupported node format, ignoring\n"); | ||
525 | /* break scan */ | ||
526 | return 1; | ||
527 | } | ||
528 | found = 1; | ||
529 | /* scan next node */ | ||
530 | return 0; | ||
531 | } else if (!found) { | ||
532 | /* scan next node */ | ||
533 | return 0; | ||
534 | } else if (found && depth < 2) { | ||
535 | /* scanning of /reserved-memory has been finished */ | ||
536 | return 1; | ||
537 | } | ||
538 | |||
539 | status = of_get_flat_dt_prop(node, "status", NULL); | ||
540 | if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0) | ||
541 | return 0; | ||
542 | |||
543 | err = __reserved_mem_reserve_reg(node, uname); | ||
544 | if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL)) | ||
545 | fdt_reserved_mem_save_node(node, uname, 0, 0); | ||
546 | |||
547 | /* scan next node */ | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | /** | ||
552 | * early_init_fdt_scan_reserved_mem() - create reserved memory regions | ||
553 | * | ||
554 | * This function grabs memory from early allocator for device exclusive use | ||
555 | * defined in device tree structures. It should be called by arch specific code | ||
556 | * once the early allocator (i.e. memblock) has been fully activated. | ||
557 | */ | ||
558 | void __init early_init_fdt_scan_reserved_mem(void) | ||
559 | { | ||
560 | if (!initial_boot_params) | ||
561 | return; | ||
562 | |||
563 | of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); | ||
564 | fdt_init_reserved_mem(); | ||
565 | } | ||
566 | |||
567 | /** | ||
443 | * of_scan_flat_dt - scan flattened tree blob and call callback on each. | 568 | * of_scan_flat_dt - scan flattened tree blob and call callback on each. |
444 | * @it: callback function | 569 | * @it: callback function |
445 | * @data: context data pointer | 570 | * @data: context data pointer |
@@ -856,6 +981,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) | |||
856 | memblock_add(base, size); | 981 | memblock_add(base, size); |
857 | } | 982 | } |
858 | 983 | ||
984 | int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, | ||
985 | phys_addr_t size, bool nomap) | ||
986 | { | ||
987 | if (memblock_is_region_reserved(base, size)) | ||
988 | return -EBUSY; | ||
989 | if (nomap) | ||
990 | return memblock_remove(base, size); | ||
991 | return memblock_reserve(base, size); | ||
992 | } | ||
993 | |||
859 | /* | 994 | /* |
860 | * called from unflatten_device_tree() to bootstrap devicetree itself | 995 | * called from unflatten_device_tree() to bootstrap devicetree itself |
861 | * Architectures can override this definition if memblock isn't used | 996 | * Architectures can override this definition if memblock isn't used |
@@ -864,6 +999,14 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) | |||
864 | { | 999 | { |
865 | return __va(memblock_alloc(size, align)); | 1000 | return __va(memblock_alloc(size, align)); |
866 | } | 1001 | } |
1002 | #else | ||
1003 | int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, | ||
1004 | phys_addr_t size, bool nomap) | ||
1005 | { | ||
1006 | pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n", | ||
1007 | base, size, nomap ? " (nomap)" : ""); | ||
1008 | return -ENOSYS; | ||
1009 | } | ||
867 | #endif | 1010 | #endif |
868 | 1011 | ||
869 | bool __init early_init_dt_scan(void *params) | 1012 | bool __init early_init_dt_scan(void *params) |