12
12
#define pr_fmt (fmt ) "OF: reserved mem: " fmt
13
13
14
14
#include <linux/err.h>
15
+ #include <linux/libfdt.h>
15
16
#include <linux/of.h>
16
17
#include <linux/of_fdt.h>
17
18
#include <linux/of_platform.h>
@@ -58,8 +59,8 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
58
59
/*
59
60
* fdt_reserved_mem_save_node() - save fdt node for second pass initialization
60
61
*/
61
- void __init fdt_reserved_mem_save_node (unsigned long node , const char * uname ,
62
- phys_addr_t base , phys_addr_t size )
62
+ static void __init fdt_reserved_mem_save_node (unsigned long node , const char * uname ,
63
+ phys_addr_t base , phys_addr_t size )
63
64
{
64
65
struct reserved_mem * rmem = & reserved_mem [reserved_mem_count ];
65
66
@@ -77,6 +78,126 @@ void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
77
78
return ;
78
79
}
79
80
81
+ static int __init early_init_dt_reserve_memory (phys_addr_t base ,
82
+ phys_addr_t size , bool nomap )
83
+ {
84
+ if (nomap ) {
85
+ /*
86
+ * If the memory is already reserved (by another region), we
87
+ * should not allow it to be marked nomap, but don't worry
88
+ * if the region isn't memory as it won't be mapped.
89
+ */
90
+ if (memblock_overlaps_region (& memblock .memory , base , size ) &&
91
+ memblock_is_region_reserved (base , size ))
92
+ return - EBUSY ;
93
+
94
+ return memblock_mark_nomap (base , size );
95
+ }
96
+ return memblock_reserve (base , size );
97
+ }
98
+
99
+ /*
100
+ * __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property
101
+ */
102
+ static int __init __reserved_mem_reserve_reg (unsigned long node ,
103
+ const char * uname )
104
+ {
105
+ int t_len = (dt_root_addr_cells + dt_root_size_cells ) * sizeof (__be32 );
106
+ phys_addr_t base , size ;
107
+ int len ;
108
+ const __be32 * prop ;
109
+ int first = 1 ;
110
+ bool nomap ;
111
+
112
+ prop = of_get_flat_dt_prop (node , "reg" , & len );
113
+ if (!prop )
114
+ return - ENOENT ;
115
+
116
+ if (len && len % t_len != 0 ) {
117
+ pr_err ("Reserved memory: invalid reg property in '%s', skipping node.\n" ,
118
+ uname );
119
+ return - EINVAL ;
120
+ }
121
+
122
+ nomap = of_get_flat_dt_prop (node , "no-map" , NULL ) != NULL ;
123
+
124
+ while (len >= t_len ) {
125
+ base = dt_mem_next_cell (dt_root_addr_cells , & prop );
126
+ size = dt_mem_next_cell (dt_root_size_cells , & prop );
127
+
128
+ if (size &&
129
+ early_init_dt_reserve_memory (base , size , nomap ) == 0 )
130
+ pr_debug ("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n" ,
131
+ uname , & base , (unsigned long )(size / SZ_1M ));
132
+ else
133
+ pr_err ("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n" ,
134
+ uname , & base , (unsigned long )(size / SZ_1M ));
135
+
136
+ len -= t_len ;
137
+ if (first ) {
138
+ fdt_reserved_mem_save_node (node , uname , base , size );
139
+ first = 0 ;
140
+ }
141
+ }
142
+ return 0 ;
143
+ }
144
+
145
+ /*
146
+ * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
147
+ * in /reserved-memory matches the values supported by the current implementation,
148
+ * also check if ranges property has been provided
149
+ */
150
+ static int __init __reserved_mem_check_root (unsigned long node )
151
+ {
152
+ const __be32 * prop ;
153
+
154
+ prop = of_get_flat_dt_prop (node , "#size-cells" , NULL );
155
+ if (!prop || be32_to_cpup (prop ) != dt_root_size_cells )
156
+ return - EINVAL ;
157
+
158
+ prop = of_get_flat_dt_prop (node , "#address-cells" , NULL );
159
+ if (!prop || be32_to_cpup (prop ) != dt_root_addr_cells )
160
+ return - EINVAL ;
161
+
162
+ prop = of_get_flat_dt_prop (node , "ranges" , NULL );
163
+ if (!prop )
164
+ return - EINVAL ;
165
+ return 0 ;
166
+ }
167
+
168
+ /*
169
+ * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
170
+ */
171
+ int __init fdt_scan_reserved_mem (void )
172
+ {
173
+ int node , child ;
174
+ const void * fdt = initial_boot_params ;
175
+
176
+ node = fdt_path_offset (fdt , "/reserved-memory" );
177
+ if (node < 0 )
178
+ return - ENODEV ;
179
+
180
+ if (__reserved_mem_check_root (node ) != 0 ) {
181
+ pr_err ("Reserved memory: unsupported node format, ignoring\n" );
182
+ return - EINVAL ;
183
+ }
184
+
185
+ fdt_for_each_subnode (child , fdt , node ) {
186
+ const char * uname ;
187
+ int err ;
188
+
189
+ if (!of_fdt_device_is_available (fdt , child ))
190
+ continue ;
191
+
192
+ uname = fdt_get_name (fdt , child , NULL );
193
+
194
+ err = __reserved_mem_reserve_reg (child , uname );
195
+ if (err == - ENOENT && of_get_flat_dt_prop (child , "size" , NULL ))
196
+ fdt_reserved_mem_save_node (child , uname , 0 , 0 );
197
+ }
198
+ return 0 ;
199
+ }
200
+
80
201
/*
81
202
* __reserved_mem_alloc_in_range() - allocate reserved memory described with
82
203
* 'alloc-ranges'. Choose bottom-up/top-down depending on nearby existing
0 commit comments