aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of/fdt.c
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2014-02-28 08:42:47 -0500
committerGrant Likely <grant.likely@linaro.org>2014-03-11 13:26:47 -0400
commite8d9d1f5485b52ec3c4d7af839e6914438f6c285 (patch)
tree40ee498612d54b3983a96406b1897dd875376cf5 /drivers/of/fdt.c
parentf08ad1deaaf83b7e7369716949b34dadc530be01 (diff)
drivers: of: add initialization code for static reserved memory
This patch adds support for static (defined by 'reg' property) reserved memory regions declared in device tree. Memory blocks can be reliably reserved only during early boot. This must happen before the whole memory management subsystem is initialized, because we need to ensure that the given contiguous blocks are not yet allocated by kernel. Also it must happen before kernel mappings for the whole low memory are created, to ensure that there will be no mappings (for reserved blocks). Typically, all this happens before device tree structures are unflattened, so we need to get reserved memory layout directly from fdt. Based on previous code provided by Josh Cartwright <joshc@codeaurora.org> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Grant Likely <grant.likely@linaro.org>
Diffstat (limited to 'drivers/of/fdt.c')
-rw-r--r--drivers/of/fdt.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 758b4f8b30b7..819e11209718 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -15,6 +15,7 @@
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/sizes.h>
18#include <linux/string.h> 19#include <linux/string.h>
19#include <linux/errno.h> 20#include <linux/errno.h>
20#include <linux/slab.h> 21#include <linux/slab.h>
@@ -440,6 +441,118 @@ struct boot_param_header *initial_boot_params;
440#ifdef CONFIG_OF_EARLY_FLATTREE 441#ifdef CONFIG_OF_EARLY_FLATTREE
441 442
442/** 443/**
444 * res_mem_reserve_reg() - reserve all memory described in 'reg' property
445 */
446static int __init __reserved_mem_reserve_reg(unsigned long node,
447 const char *uname)
448{
449 int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
450 phys_addr_t base, size;
451 unsigned long len;
452 __be32 *prop;
453 int nomap;
454
455 prop = of_get_flat_dt_prop(node, "reg", &len);
456 if (!prop)
457 return -ENOENT;
458
459 if (len && len % t_len != 0) {
460 pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
461 uname);
462 return -EINVAL;
463 }
464
465 nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
466
467 while (len >= t_len) {
468 base = dt_mem_next_cell(dt_root_addr_cells, &prop);
469 size = dt_mem_next_cell(dt_root_size_cells, &prop);
470
471 if (base && size &&
472 early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
473 pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
474 uname, &base, (unsigned long)size / SZ_1M);
475 else
476 pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
477 uname, &base, (unsigned long)size / SZ_1M);
478
479 len -= t_len;
480 }
481 return 0;
482}
483
484/**
485 * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
486 * in /reserved-memory matches the values supported by the current implementation,
487 * also check if ranges property has been provided
488 */
489static int __reserved_mem_check_root(unsigned long node)
490{
491 __be32 *prop;
492
493 prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
494 if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
495 return -EINVAL;
496
497 prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
498 if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
499 return -EINVAL;
500
501 prop = of_get_flat_dt_prop(node, "ranges", NULL);
502 if (!prop)
503 return -EINVAL;
504 return 0;
505}
506
507/**
508 * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
509 */
510static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
511 int depth, void *data)
512{
513 static int found;
514 const char *status;
515
516 if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
517 if (__reserved_mem_check_root(node) != 0) {
518 pr_err("Reserved memory: unsupported node format, ignoring\n");
519 /* break scan */
520 return 1;
521 }
522 found = 1;
523 /* scan next node */
524 return 0;
525 } else if (!found) {
526 /* scan next node */
527 return 0;
528 } else if (found && depth < 2) {
529 /* scanning of /reserved-memory has been finished */
530 return 1;
531 }
532
533 status = of_get_flat_dt_prop(node, "status", NULL);
534 if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
535 return 0;
536
537 __reserved_mem_reserve_reg(node, uname);
538
539 /* scan next node */
540 return 0;
541}
542
543/**
544 * early_init_fdt_scan_reserved_mem() - create reserved memory regions
545 *
546 * This function grabs memory from early allocator for device exclusive use
547 * defined in device tree structures. It should be called by arch specific code
548 * once the early allocator (i.e. memblock) has been fully activated.
549 */
550void __init early_init_fdt_scan_reserved_mem(void)
551{
552 of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
553}
554
555/**
443 * of_scan_flat_dt - scan flattened tree blob and call callback on each. 556 * of_scan_flat_dt - scan flattened tree blob and call callback on each.
444 * @it: callback function 557 * @it: callback function
445 * @data: context data pointer 558 * @data: context data pointer
@@ -856,6 +969,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
856 memblock_add(base, size); 969 memblock_add(base, size);
857} 970}
858 971
972int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
973 phys_addr_t size, bool nomap)
974{
975 if (memblock_is_region_reserved(base, size))
976 return -EBUSY;
977 if (nomap)
978 return memblock_remove(base, size);
979 return memblock_reserve(base, size);
980}
981
859/* 982/*
860 * called from unflatten_device_tree() to bootstrap devicetree itself 983 * called from unflatten_device_tree() to bootstrap devicetree itself
861 * Architectures can override this definition if memblock isn't used 984 * Architectures can override this definition if memblock isn't used
@@ -864,6 +987,14 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
864{ 987{
865 return __va(memblock_alloc(size, align)); 988 return __va(memblock_alloc(size, align));
866} 989}
990#else
991int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
992 phys_addr_t size, bool nomap)
993{
994 pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
995 base, size, nomap ? " (nomap)" : "");
996 return -ENOSYS;
997}
867#endif 998#endif
868 999
869bool __init early_init_dt_scan(void *params) 1000bool __init early_init_dt_scan(void *params)