aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt133
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/mm/init.c2
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/mm/init.c1
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/kernel/prom.c3
-rw-r--r--drivers/of/Kconfig6
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/fdt.c143
-rw-r--r--drivers/of/of_reserved_mem.c217
-rw-r--r--include/asm-generic/vmlinux.lds.h11
-rw-r--r--include/linux/of_fdt.h4
-rw-r--r--include/linux/of_reserved_mem.h53
14 files changed, 577 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
new file mode 100644
index 000000000000..3da0ebdba8d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
@@ -0,0 +1,133 @@
1*** Reserved memory regions ***
2
3Reserved memory is specified as a node under the /reserved-memory node.
4The operating system shall exclude reserved memory from normal usage
5one can create child nodes describing particular reserved (excluded from
6normal use) memory regions. Such memory regions are usually designed for
7the special usage by various device drivers.
8
9Parameters for each memory region can be encoded into the device tree
10with the following nodes:
11
12/reserved-memory node
13---------------------
14#address-cells, #size-cells (required) - standard definition
15 - Should use the same values as the root node
16ranges (required) - standard definition
17 - Should be empty
18
19/reserved-memory/ child nodes
20-----------------------------
21Each child of the reserved-memory node specifies one or more regions of
22reserved memory. Each child node may either use a 'reg' property to
23specify a specific range of reserved memory, or a 'size' property with
24optional constraints to request a dynamically allocated block of memory.
25
26Following the generic-names recommended practice, node names should
27reflect the purpose of the node (ie. "framebuffer" or "dma-pool"). Unit
28address (@<address>) should be appended to the name if the node is a
29static allocation.
30
31Properties:
32Requires either a) or b) below.
33a) static allocation
34 reg (required) - standard definition
35b) dynamic allocation
36 size (required) - length based on parent's #size-cells
37 - Size in bytes of memory to reserve.
38 alignment (optional) - length based on parent's #size-cells
39 - Address boundary for alignment of allocation.
40 alloc-ranges (optional) - prop-encoded-array (address, length pairs).
41 - Specifies regions of memory that are
42 acceptable to allocate from.
43
44If both reg and size are present, then the reg property takes precedence
45and size is ignored.
46
47Additional properties:
48compatible (optional) - standard definition
49 - may contain the following strings:
50 - shared-dma-pool: This indicates a region of memory meant to be
51 used as a shared pool of DMA buffers for a set of devices. It can
52 be used by an operating system to instanciate the necessary pool
53 management subsystem if necessary.
54 - vendor specific string in the form <vendor>,[<device>-]<usage>
55no-map (optional) - empty property
56 - Indicates the operating system must not create a virtual mapping
57 of the region as part of its standard mapping of system memory,
58 nor permit speculative access to it under any circumstances other
59 than under the control of the device driver using the region.
60reusable (optional) - empty property
61 - The operating system can use the memory in this region with the
62 limitation that the device driver(s) owning the region need to be
63 able to reclaim it back. Typically that means that the operating
64 system can use that region to store volatile or cached data that
65 can be otherwise regenerated or migrated elsewhere.
66
67Linux implementation note:
68- If a "linux,cma-default" property is present, then Linux will use the
69 region for the default pool of the contiguous memory allocator.
70
71Device node references to reserved memory
72-----------------------------------------
73Regions in the /reserved-memory node may be referenced by other device
74nodes by adding a memory-region property to the device node.
75
76memory-region (optional) - phandle, specifier pairs to children of /reserved-memory
77
78Example
79-------
80This example defines 3 contiguous regions are defined for Linux kernel:
81one default of all device drivers (named linux,cma@72000000 and 64MiB in size),
82one dedicated to the framebuffer device (named framebuffer@78000000, 8MiB), and
83one for multimedia processing (named multimedia-memory@77000000, 64MiB).
84
85/ {
86 #address-cells = <1>;
87 #size-cells = <1>;
88
89 memory {
90 reg = <0x40000000 0x40000000>;
91 };
92
93 reserved-memory {
94 #address-cells = <1>;
95 #size-cells = <1>;
96 ranges;
97
98 /* global autoconfigured region for contiguous allocations */
99 linux,cma {
100 compatible = "shared-dma-pool";
101 reusable;
102 size = <0x4000000>;
103 alignment = <0x2000>;
104 linux,cma-default;
105 };
106
107 display_reserved: framebuffer@78000000 {
108 reg = <0x78000000 0x800000>;
109 };
110
111 multimedia_reserved: multimedia@77000000 {
112 compatible = "acme,multimedia-memory";
113 reg = <0x77000000 0x4000000>;
114 };
115 };
116
117 /* ... */
118
119 fb0: video@12300000 {
120 memory-region = <&display_reserved>;
121 /* ... */
122 };
123
124 scaler: scaler@12500000 {
125 memory-region = <&multimedia_reserved>;
126 /* ... */
127 };
128
129 codec: codec@12600000 {
130 memory-region = <&multimedia_reserved>;
131 /* ... */
132 };
133};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e25419817791..d0262bea8020 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1918,6 +1918,7 @@ config USE_OF
1918 select IRQ_DOMAIN 1918 select IRQ_DOMAIN
1919 select OF 1919 select OF
1920 select OF_EARLY_FLATTREE 1920 select OF_EARLY_FLATTREE
1921 select OF_RESERVED_MEM
1921 help 1922 help
1922 Include support for flattened device tree machine descriptions. 1923 Include support for flattened device tree machine descriptions.
1923 1924
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 804d61566a53..2a77ba8796ae 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -323,6 +323,8 @@ void __init arm_memblock_init(struct meminfo *mi,
323 if (mdesc->reserve) 323 if (mdesc->reserve)
324 mdesc->reserve(); 324 mdesc->reserve();
325 325
326 early_init_fdt_scan_reserved_mem();
327
326 /* 328 /*
327 * reserve memory for DMA contigouos allocations, 329 * reserve memory for DMA contigouos allocations,
328 * must come from DMA area inside low memory 330 * must come from DMA area inside low memory
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 27bbcfc7202a..6abf15407dca 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -43,6 +43,7 @@ config ARM64
43 select NO_BOOTMEM 43 select NO_BOOTMEM
44 select OF 44 select OF
45 select OF_EARLY_FLATTREE 45 select OF_EARLY_FLATTREE
46 select OF_RESERVED_MEM
46 select PERF_USE_VMALLOC 47 select PERF_USE_VMALLOC
47 select POWER_RESET 48 select POWER_RESET
48 select POWER_SUPPLY 49 select POWER_SUPPLY
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index d0b4c2efda90..3fb8d50dfdaa 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -160,6 +160,7 @@ void __init arm64_memblock_init(void)
160 memblock_reserve(base, size); 160 memblock_reserve(base, size);
161 } 161 }
162 162
163 early_init_fdt_scan_reserved_mem();
163 dma_contiguous_reserve(0); 164 dma_contiguous_reserve(0);
164 165
165 memblock_allow_resize(); 166 memblock_allow_resize();
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 957bf344c0f5..3b6617fed8fc 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -90,6 +90,7 @@ config PPC
90 select BINFMT_ELF 90 select BINFMT_ELF
91 select OF 91 select OF
92 select OF_EARLY_FLATTREE 92 select OF_EARLY_FLATTREE
93 select OF_RESERVED_MEM
93 select HAVE_FTRACE_MCOUNT_RECORD 94 select HAVE_FTRACE_MCOUNT_RECORD
94 select HAVE_DYNAMIC_FTRACE 95 select HAVE_DYNAMIC_FTRACE
95 select HAVE_FUNCTION_TRACER 96 select HAVE_FUNCTION_TRACER
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index f58c0d3aaeb4..591986215801 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -33,6 +33,7 @@
33#include <linux/irq.h> 33#include <linux/irq.h>
34#include <linux/memblock.h> 34#include <linux/memblock.h>
35#include <linux/of.h> 35#include <linux/of.h>
36#include <linux/of_fdt.h>
36 37
37#include <asm/prom.h> 38#include <asm/prom.h>
38#include <asm/rtas.h> 39#include <asm/rtas.h>
@@ -588,6 +589,8 @@ static void __init early_reserve_mem_dt(void)
588 memblock_reserve(base, size); 589 memblock_reserve(base, size);
589 } 590 }
590 } 591 }
592
593 early_init_fdt_scan_reserved_mem();
591} 594}
592 595
593static void __init early_reserve_mem(void) 596static void __init early_reserve_mem(void)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index a46ac1b00032..889005fa4d04 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -71,4 +71,10 @@ config OF_MTD
71 depends on MTD 71 depends on MTD
72 def_bool y 72 def_bool y
73 73
74config OF_RESERVED_MEM
75 depends on OF_EARLY_FLATTREE
76 bool
77 help
78 Helpers to allow for reservation of memory regions
79
74endmenu # OF 80endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index efd05102c405..ed9660adad77 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
9obj-$(CONFIG_OF_PCI) += of_pci.o 9obj-$(CONFIG_OF_PCI) += of_pci.o
10obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o 10obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
11obj-$(CONFIG_OF_MTD) += of_mtd.o 11obj-$(CONFIG_OF_MTD) += of_mtd.o
12obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
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 */
447static 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 */
494static 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 */
515static 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 */
558void __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
984int __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
1003int __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
869bool __init early_init_dt_scan(void *params) 1012bool __init early_init_dt_scan(void *params)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
new file mode 100644
index 000000000000..daaaf935911d
--- /dev/null
+++ b/drivers/of/of_reserved_mem.c
@@ -0,0 +1,217 @@
1/*
2 * Device tree based initialization code for reserved memory.
3 *
4 * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
5 * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
6 * http://www.samsung.com
7 * Author: Marek Szyprowski <m.szyprowski@samsung.com>
8 * Author: Josh Cartwright <joshc@codeaurora.org>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License or (at your optional) any later version of the license.
14 */
15
16#include <linux/err.h>
17#include <linux/of.h>
18#include <linux/of_fdt.h>
19#include <linux/of_platform.h>
20#include <linux/mm.h>
21#include <linux/sizes.h>
22#include <linux/of_reserved_mem.h>
23
24#define MAX_RESERVED_REGIONS 16
25static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
26static int reserved_mem_count;
27
28#if defined(CONFIG_HAVE_MEMBLOCK)
29#include <linux/memblock.h>
30int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
31 phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
32 phys_addr_t *res_base)
33{
34 /*
35 * We use __memblock_alloc_base() because memblock_alloc_base()
36 * panic()s on allocation failure.
37 */
38 phys_addr_t base = __memblock_alloc_base(size, align, end);
39 if (!base)
40 return -ENOMEM;
41
42 /*
43 * Check if the allocated region fits in to start..end window
44 */
45 if (base < start) {
46 memblock_free(base, size);
47 return -ENOMEM;
48 }
49
50 *res_base = base;
51 if (nomap)
52 return memblock_remove(base, size);
53 return 0;
54}
55#else
56int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
57 phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
58 phys_addr_t *res_base)
59{
60 pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
61 size, nomap ? " (nomap)" : "");
62 return -ENOSYS;
63}
64#endif
65
66/**
67 * res_mem_save_node() - save fdt node for second pass initialization
68 */
69void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
70 phys_addr_t base, phys_addr_t size)
71{
72 struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
73
74 if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
75 pr_err("Reserved memory: not enough space all defined regions.\n");
76 return;
77 }
78
79 rmem->fdt_node = node;
80 rmem->name = uname;
81 rmem->base = base;
82 rmem->size = size;
83
84 reserved_mem_count++;
85 return;
86}
87
88/**
89 * res_mem_alloc_size() - allocate reserved memory described by 'size', 'align'
90 * and 'alloc-ranges' properties
91 */
92static int __init __reserved_mem_alloc_size(unsigned long node,
93 const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
94{
95 int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
96 phys_addr_t start = 0, end = 0;
97 phys_addr_t base = 0, align = 0, size;
98 unsigned long len;
99 __be32 *prop;
100 int nomap;
101 int ret;
102
103 prop = of_get_flat_dt_prop(node, "size", &len);
104 if (!prop)
105 return -EINVAL;
106
107 if (len != dt_root_size_cells * sizeof(__be32)) {
108 pr_err("Reserved memory: invalid size property in '%s' node.\n",
109 uname);
110 return -EINVAL;
111 }
112 size = dt_mem_next_cell(dt_root_size_cells, &prop);
113
114 nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
115
116 prop = of_get_flat_dt_prop(node, "alignment", &len);
117 if (prop) {
118 if (len != dt_root_addr_cells * sizeof(__be32)) {
119 pr_err("Reserved memory: invalid alignment property in '%s' node.\n",
120 uname);
121 return -EINVAL;
122 }
123 align = dt_mem_next_cell(dt_root_addr_cells, &prop);
124 }
125
126 prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
127 if (prop) {
128
129 if (len % t_len != 0) {
130 pr_err("Reserved memory: invalid alloc-ranges property in '%s', skipping node.\n",
131 uname);
132 return -EINVAL;
133 }
134
135 base = 0;
136
137 while (len > 0) {
138 start = dt_mem_next_cell(dt_root_addr_cells, &prop);
139 end = start + dt_mem_next_cell(dt_root_size_cells,
140 &prop);
141
142 ret = early_init_dt_alloc_reserved_memory_arch(size,
143 align, start, end, nomap, &base);
144 if (ret == 0) {
145 pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
146 uname, &base,
147 (unsigned long)size / SZ_1M);
148 break;
149 }
150 len -= t_len;
151 }
152
153 } else {
154 ret = early_init_dt_alloc_reserved_memory_arch(size, align,
155 0, 0, nomap, &base);
156 if (ret == 0)
157 pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
158 uname, &base, (unsigned long)size / SZ_1M);
159 }
160
161 if (base == 0) {
162 pr_info("Reserved memory: failed to allocate memory for node '%s'\n",
163 uname);
164 return -ENOMEM;
165 }
166
167 *res_base = base;
168 *res_size = size;
169
170 return 0;
171}
172
173static const struct of_device_id __rmem_of_table_sentinel
174 __used __section(__reservedmem_of_table_end);
175
176/**
177 * res_mem_init_node() - call region specific reserved memory init code
178 */
179static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
180{
181 extern const struct of_device_id __reservedmem_of_table[];
182 const struct of_device_id *i;
183
184 for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
185 reservedmem_of_init_fn initfn = i->data;
186 const char *compat = i->compatible;
187
188 if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
189 continue;
190
191 if (initfn(rmem, rmem->fdt_node, rmem->name) == 0) {
192 pr_info("Reserved memory: initialized node %s, compatible id %s\n",
193 rmem->name, compat);
194 return 0;
195 }
196 }
197 return -ENOENT;
198}
199
200/**
201 * fdt_init_reserved_mem - allocate and init all saved reserved memory regions
202 */
203void __init fdt_init_reserved_mem(void)
204{
205 int i;
206 for (i = 0; i < reserved_mem_count; i++) {
207 struct reserved_mem *rmem = &reserved_mem[i];
208 unsigned long node = rmem->fdt_node;
209 int err = 0;
210
211 if (rmem->size == 0)
212 err = __reserved_mem_alloc_size(node, rmem->name,
213 &rmem->base, &rmem->size);
214 if (err == 0)
215 __reserved_mem_init_node(rmem);
216 }
217}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index bc2121fa9132..f10f64fcc815 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -167,6 +167,16 @@
167#define CLK_OF_TABLES() 167#define CLK_OF_TABLES()
168#endif 168#endif
169 169
170#ifdef CONFIG_OF_RESERVED_MEM
171#define RESERVEDMEM_OF_TABLES() \
172 . = ALIGN(8); \
173 VMLINUX_SYMBOL(__reservedmem_of_table) = .; \
174 *(__reservedmem_of_table) \
175 *(__reservedmem_of_table_end)
176#else
177#define RESERVEDMEM_OF_TABLES()
178#endif
179
170#define KERNEL_DTB() \ 180#define KERNEL_DTB() \
171 STRUCT_ALIGN(); \ 181 STRUCT_ALIGN(); \
172 VMLINUX_SYMBOL(__dtb_start) = .; \ 182 VMLINUX_SYMBOL(__dtb_start) = .; \
@@ -490,6 +500,7 @@
490 TRACE_SYSCALLS() \ 500 TRACE_SYSCALLS() \
491 MEM_DISCARD(init.rodata) \ 501 MEM_DISCARD(init.rodata) \
492 CLK_OF_TABLES() \ 502 CLK_OF_TABLES() \
503 RESERVEDMEM_OF_TABLES() \
493 CLKSRC_OF_TABLES() \ 504 CLKSRC_OF_TABLES() \
494 KERNEL_DTB() \ 505 KERNEL_DTB() \
495 IRQCHIP_OF_MATCH_TABLE() 506 IRQCHIP_OF_MATCH_TABLE()
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) {}
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
new file mode 100644
index 000000000000..9b1fbb7f29fc
--- /dev/null
+++ b/include/linux/of_reserved_mem.h
@@ -0,0 +1,53 @@
1#ifndef __OF_RESERVED_MEM_H
2#define __OF_RESERVED_MEM_H
3
4struct device;
5struct of_phandle_args;
6struct reserved_mem_ops;
7
8struct reserved_mem {
9 const char *name;
10 unsigned long fdt_node;
11 const struct reserved_mem_ops *ops;
12 phys_addr_t base;
13 phys_addr_t size;
14 void *priv;
15};
16
17struct reserved_mem_ops {
18 void (*device_init)(struct reserved_mem *rmem,
19 struct device *dev);
20 void (*device_release)(struct reserved_mem *rmem,
21 struct device *dev);
22};
23
24typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem,
25 unsigned long node, const char *uname);
26
27#ifdef CONFIG_OF_RESERVED_MEM
28void fdt_init_reserved_mem(void);
29void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
30 phys_addr_t base, phys_addr_t size);
31
32#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
33 static const struct of_device_id __reservedmem_of_table_##name \
34 __used __section(__reservedmem_of_table) \
35 = { .compatible = compat, \
36 .data = (init == (reservedmem_of_init_fn)NULL) ? \
37 init : init }
38
39#else
40static inline void fdt_init_reserved_mem(void) { }
41static inline void fdt_reserved_mem_save_node(unsigned long node,
42 const char *uname, phys_addr_t base, phys_addr_t size) { }
43
44#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
45 static const struct of_device_id __reservedmem_of_table_##name \
46 __attribute__((unused)) \
47 = { .compatible = compat, \
48 .data = (init == (reservedmem_of_init_fn)NULL) ? \
49 init : init }
50
51#endif
52
53#endif /* __OF_RESERVED_MEM_H */