aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Szyprowski2014-02-28 07:42:47 -0600
committerMark Brown2014-08-12 06:42:35 -0500
commit04ac7b666de39c05eef566cd80358c16ea8c69a0 (patch)
tree40f8ae09f864c0c2a80a460cfe637ca98dfd6055
parent455c6fdbd219161bd09b1165f11699d6d73de11c (diff)
downloadkernel-video-04ac7b666de39c05eef566cd80358c16ea8c69a0.tar.gz
kernel-video-04ac7b666de39c05eef566cd80358c16ea8c69a0.tar.xz
kernel-video-04ac7b666de39c05eef566cd80358c16ea8c69a0.zip
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> (cherry picked from commit e8d9d1f5485b52ec3c4d7af839e6914438f6c285) Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--drivers/of/fdt.c131
-rw-r--r--include/linux/of_fdt.h4
2 files changed, 135 insertions, 0 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 758b4f8b30b..819e1120971 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)
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 2b77058a733..ddd7219af8a 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -98,7 +98,10 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
98 int depth, void *data); 98 int depth, void *data);
99extern int early_init_dt_scan_memory(unsigned long node, const char *uname, 99extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
100 int depth, void *data); 100 int depth, void *data);
101extern void early_init_fdt_scan_reserved_mem(void);
101extern void early_init_dt_add_memory_arch(u64 base, u64 size); 102extern void early_init_dt_add_memory_arch(u64 base, u64 size);
103extern int early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size,
104 bool no_map);
102extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align); 105extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align);
103extern u64 dt_mem_next_cell(int s, __be32 **cellp); 106extern u64 dt_mem_next_cell(int s, __be32 **cellp);
104 107
@@ -118,6 +121,7 @@ extern void unflatten_and_copy_device_tree(void);
118extern void early_init_devtree(void *); 121extern void early_init_devtree(void *);
119extern void early_get_first_memblock_info(void *, phys_addr_t *); 122extern void early_get_first_memblock_info(void *, phys_addr_t *);
120#else /* CONFIG_OF_FLATTREE */ 123#else /* CONFIG_OF_FLATTREE */
124static inline void early_init_fdt_scan_reserved_mem(void) {}
121static inline const char *of_flat_dt_get_machine_name(void) { return NULL; } 125static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
122static inline void unflatten_device_tree(void) {} 126static inline void unflatten_device_tree(void) {}
123static inline void unflatten_and_copy_device_tree(void) {} 127static inline void unflatten_and_copy_device_tree(void) {}