aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 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)
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 2b77058a7335..ddd7219af8ac 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) {}