f520e6cc7a6bb239973fa74c92d00d75ab3c8506
[openwrt.git] / target / linux / ipq806x / patches / 0049-drivers-of-add-initialization-code-for-static-reserv.patch
1 From 60ee5b21ce14a7d5c269115b0751b904d0e005ed Mon Sep 17 00:00:00 2001
2 From: Marek Szyprowski <m.szyprowski@samsung.com>
3 Date: Fri, 28 Feb 2014 14:42:47 +0100
4 Subject: [PATCH 049/182] drivers: of: add initialization code for static
5  reserved memory
6
7 This patch adds support for static (defined by 'reg' property) reserved
8 memory regions declared in device tree.
9
10 Memory blocks can be reliably reserved only during early boot. This must
11 happen before the whole memory management subsystem is initialized,
12 because we need to ensure that the given contiguous blocks are not yet
13 allocated by kernel. Also it must happen before kernel mappings for the
14 whole low memory are created, to ensure that there will be no mappings
15 (for reserved blocks). Typically, all this happens before device tree
16 structures are unflattened, so we need to get reserved memory layout
17 directly from fdt.
18
19 Based on previous code provided by Josh Cartwright <joshc@codeaurora.org>
20
21 Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
22 Signed-off-by: Grant Likely <grant.likely@linaro.org>
23 ---
24  drivers/of/fdt.c       |  131 ++++++++++++++++++++++++++++++++++++++++++++++++
25  include/linux/of_fdt.h |    4 ++
26  2 files changed, 135 insertions(+)
27
28 diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
29 index 758b4f8..819e112 100644
30 --- a/drivers/of/fdt.c
31 +++ b/drivers/of/fdt.c
32 @@ -15,6 +15,7 @@
33  #include <linux/module.h>
34  #include <linux/of.h>
35  #include <linux/of_fdt.h>
36 +#include <linux/sizes.h>
37  #include <linux/string.h>
38  #include <linux/errno.h>
39  #include <linux/slab.h>
40 @@ -440,6 +441,118 @@ struct boot_param_header *initial_boot_params;
41  #ifdef CONFIG_OF_EARLY_FLATTREE
42  
43  /**
44 + * res_mem_reserve_reg() - reserve all memory described in 'reg' property
45 + */
46 +static int __init __reserved_mem_reserve_reg(unsigned long node,
47 +                                            const char *uname)
48 +{
49 +       int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
50 +       phys_addr_t base, size;
51 +       unsigned long len;
52 +       __be32 *prop;
53 +       int nomap;
54 +
55 +       prop = of_get_flat_dt_prop(node, "reg", &len);
56 +       if (!prop)
57 +               return -ENOENT;
58 +
59 +       if (len && len % t_len != 0) {
60 +               pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
61 +                      uname);
62 +               return -EINVAL;
63 +       }
64 +
65 +       nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
66 +
67 +       while (len >= t_len) {
68 +               base = dt_mem_next_cell(dt_root_addr_cells, &prop);
69 +               size = dt_mem_next_cell(dt_root_size_cells, &prop);
70 +
71 +               if (base && size &&
72 +                   early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
73 +                       pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
74 +                               uname, &base, (unsigned long)size / SZ_1M);
75 +               else
76 +                       pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
77 +                               uname, &base, (unsigned long)size / SZ_1M);
78 +
79 +               len -= t_len;
80 +       }
81 +       return 0;
82 +}
83 +
84 +/**
85 + * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
86 + * in /reserved-memory matches the values supported by the current implementation,
87 + * also check if ranges property has been provided
88 + */
89 +static int __reserved_mem_check_root(unsigned long node)
90 +{
91 +       __be32 *prop;
92 +
93 +       prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
94 +       if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
95 +               return -EINVAL;
96 +
97 +       prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
98 +       if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
99 +               return -EINVAL;
100 +
101 +       prop = of_get_flat_dt_prop(node, "ranges", NULL);
102 +       if (!prop)
103 +               return -EINVAL;
104 +       return 0;
105 +}
106 +
107 +/**
108 + * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
109 + */
110 +static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
111 +                                         int depth, void *data)
112 +{
113 +       static int found;
114 +       const char *status;
115 +
116 +       if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
117 +               if (__reserved_mem_check_root(node) != 0) {
118 +                       pr_err("Reserved memory: unsupported node format, ignoring\n");
119 +                       /* break scan */
120 +                       return 1;
121 +               }
122 +               found = 1;
123 +               /* scan next node */
124 +               return 0;
125 +       } else if (!found) {
126 +               /* scan next node */
127 +               return 0;
128 +       } else if (found && depth < 2) {
129 +               /* scanning of /reserved-memory has been finished */
130 +               return 1;
131 +       }
132 +
133 +       status = of_get_flat_dt_prop(node, "status", NULL);
134 +       if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
135 +               return 0;
136 +
137 +       __reserved_mem_reserve_reg(node, uname);
138 +
139 +       /* scan next node */
140 +       return 0;
141 +}
142 +
143 +/**
144 + * early_init_fdt_scan_reserved_mem() - create reserved memory regions
145 + *
146 + * This function grabs memory from early allocator for device exclusive use
147 + * defined in device tree structures. It should be called by arch specific code
148 + * once the early allocator (i.e. memblock) has been fully activated.
149 + */
150 +void __init early_init_fdt_scan_reserved_mem(void)
151 +{
152 +       of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
153 +}
154 +
155 +/**
156   * of_scan_flat_dt - scan flattened tree blob and call callback on each.
157   * @it: callback function
158   * @data: context data pointer
159 @@ -856,6 +969,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
160         memblock_add(base, size);
161  }
162  
163 +int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
164 +                                       phys_addr_t size, bool nomap)
165 +{
166 +       if (memblock_is_region_reserved(base, size))
167 +               return -EBUSY;
168 +       if (nomap)
169 +               return memblock_remove(base, size);
170 +       return memblock_reserve(base, size);
171 +}
172 +
173  /*
174   * called from unflatten_device_tree() to bootstrap devicetree itself
175   * Architectures can override this definition if memblock isn't used
176 @@ -864,6 +987,14 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
177  {
178         return __va(memblock_alloc(size, align));
179  }
180 +#else
181 +int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
182 +                                       phys_addr_t size, bool nomap)
183 +{
184 +       pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
185 +                 base, size, nomap ? " (nomap)" : "");
186 +       return -ENOSYS;
187 +}
188  #endif
189  
190  bool __init early_init_dt_scan(void *params)
191 diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
192 index 2b77058..ddd7219 100644
193 --- a/include/linux/of_fdt.h
194 +++ b/include/linux/of_fdt.h
195 @@ -98,7 +98,10 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
196                                      int depth, void *data);
197  extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
198                                      int depth, void *data);
199 +extern void early_init_fdt_scan_reserved_mem(void);
200  extern void early_init_dt_add_memory_arch(u64 base, u64 size);
201 +extern int early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size,
202 +                                            bool no_map);
203  extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align);
204  extern u64 dt_mem_next_cell(int s, __be32 **cellp);
205  
206 @@ -118,6 +121,7 @@ extern void unflatten_and_copy_device_tree(void);
207  extern void early_init_devtree(void *);
208  extern void early_get_first_memblock_info(void *, phys_addr_t *);
209  #else /* CONFIG_OF_FLATTREE */
210 +static inline void early_init_fdt_scan_reserved_mem(void) {}
211  static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
212  static inline void unflatten_device_tree(void) {}
213  static inline void unflatten_and_copy_device_tree(void) {}
214 -- 
215 1.7.10.4
216