0050-drivers-of-add-initialization-code-for-dynamic-reser.patch 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. From 968b497e1027ec78e986370976c76e1652aa0459 Mon Sep 17 00:00:00 2001
  2. From: Marek Szyprowski <[email protected]>
  3. Date: Fri, 28 Feb 2014 14:42:48 +0100
  4. Subject: [PATCH 050/182] drivers: of: add initialization code for dynamic
  5. reserved memory
  6. This patch adds support for dynamically allocated reserved memory regions
  7. declared in device tree. Such regions are defined by 'size', 'alignment'
  8. and 'alloc-ranges' properties.
  9. Based on previous code provided by Josh Cartwright <[email protected]>
  10. Signed-off-by: Marek Szyprowski <[email protected]>
  11. Signed-off-by: Grant Likely <[email protected]>
  12. ---
  13. drivers/of/Kconfig | 6 ++
  14. drivers/of/Makefile | 1 +
  15. drivers/of/fdt.c | 13 ++-
  16. drivers/of/of_reserved_mem.c | 188 +++++++++++++++++++++++++++++++++++++++
  17. include/linux/of_reserved_mem.h | 21 +++++
  18. 5 files changed, 227 insertions(+), 2 deletions(-)
  19. create mode 100644 drivers/of/of_reserved_mem.c
  20. create mode 100644 include/linux/of_reserved_mem.h
  21. --- a/drivers/of/Kconfig
  22. +++ b/drivers/of/Kconfig
  23. @@ -75,4 +75,10 @@ config OF_MTD
  24. depends on MTD
  25. def_bool y
  26. +config OF_RESERVED_MEM
  27. + depends on OF_EARLY_FLATTREE
  28. + bool
  29. + help
  30. + Helpers to allow for reservation of memory regions
  31. +
  32. endmenu # OF
  33. --- a/drivers/of/Makefile
  34. +++ b/drivers/of/Makefile
  35. @@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
  36. obj-$(CONFIG_OF_PCI) += of_pci.o
  37. obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
  38. obj-$(CONFIG_OF_MTD) += of_mtd.o
  39. +obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
  40. --- a/drivers/of/fdt.c
  41. +++ b/drivers/of/fdt.c
  42. @@ -15,6 +15,7 @@
  43. #include <linux/module.h>
  44. #include <linux/of.h>
  45. #include <linux/of_fdt.h>
  46. +#include <linux/of_reserved_mem.h>
  47. #include <linux/sizes.h>
  48. #include <linux/string.h>
  49. #include <linux/errno.h>
  50. @@ -450,7 +451,7 @@ static int __init __reserved_mem_reserve
  51. phys_addr_t base, size;
  52. unsigned long len;
  53. __be32 *prop;
  54. - int nomap;
  55. + int nomap, first = 1;
  56. prop = of_get_flat_dt_prop(node, "reg", &len);
  57. if (!prop)
  58. @@ -477,6 +478,10 @@ static int __init __reserved_mem_reserve
  59. uname, &base, (unsigned long)size / SZ_1M);
  60. len -= t_len;
  61. + if (first) {
  62. + fdt_reserved_mem_save_node(node, uname, base, size);
  63. + first = 0;
  64. + }
  65. }
  66. return 0;
  67. }
  68. @@ -512,6 +517,7 @@ static int __init __fdt_scan_reserved_me
  69. {
  70. static int found;
  71. const char *status;
  72. + int err;
  73. if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
  74. if (__reserved_mem_check_root(node) != 0) {
  75. @@ -534,7 +540,9 @@ static int __init __fdt_scan_reserved_me
  76. if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
  77. return 0;
  78. - __reserved_mem_reserve_reg(node, uname);
  79. + err = __reserved_mem_reserve_reg(node, uname);
  80. + if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
  81. + fdt_reserved_mem_save_node(node, uname, 0, 0);
  82. /* scan next node */
  83. return 0;
  84. @@ -550,6 +558,7 @@ static int __init __fdt_scan_reserved_me
  85. void __init early_init_fdt_scan_reserved_mem(void)
  86. {
  87. of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
  88. + fdt_init_reserved_mem();
  89. }
  90. /**
  91. --- /dev/null
  92. +++ b/drivers/of/of_reserved_mem.c
  93. @@ -0,0 +1,188 @@
  94. +/*
  95. + * Device tree based initialization code for reserved memory.
  96. + *
  97. + * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
  98. + * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
  99. + * http://www.samsung.com
  100. + * Author: Marek Szyprowski <[email protected]>
  101. + * Author: Josh Cartwright <[email protected]>
  102. + *
  103. + * This program is free software; you can redistribute it and/or
  104. + * modify it under the terms of the GNU General Public License as
  105. + * published by the Free Software Foundation; either version 2 of the
  106. + * License or (at your optional) any later version of the license.
  107. + */
  108. +
  109. +#include <linux/err.h>
  110. +#include <linux/of.h>
  111. +#include <linux/of_fdt.h>
  112. +#include <linux/of_platform.h>
  113. +#include <linux/mm.h>
  114. +#include <linux/sizes.h>
  115. +#include <linux/of_reserved_mem.h>
  116. +
  117. +#define MAX_RESERVED_REGIONS 16
  118. +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
  119. +static int reserved_mem_count;
  120. +
  121. +#if defined(CONFIG_HAVE_MEMBLOCK)
  122. +#include <linux/memblock.h>
  123. +int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
  124. + phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
  125. + phys_addr_t *res_base)
  126. +{
  127. + /*
  128. + * We use __memblock_alloc_base() because memblock_alloc_base()
  129. + * panic()s on allocation failure.
  130. + */
  131. + phys_addr_t base = __memblock_alloc_base(size, align, end);
  132. + if (!base)
  133. + return -ENOMEM;
  134. +
  135. + /*
  136. + * Check if the allocated region fits in to start..end window
  137. + */
  138. + if (base < start) {
  139. + memblock_free(base, size);
  140. + return -ENOMEM;
  141. + }
  142. +
  143. + *res_base = base;
  144. + if (nomap)
  145. + return memblock_remove(base, size);
  146. + return 0;
  147. +}
  148. +#else
  149. +int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
  150. + phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
  151. + phys_addr_t *res_base)
  152. +{
  153. + pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
  154. + size, nomap ? " (nomap)" : "");
  155. + return -ENOSYS;
  156. +}
  157. +#endif
  158. +
  159. +/**
  160. + * res_mem_save_node() - save fdt node for second pass initialization
  161. + */
  162. +void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
  163. + phys_addr_t base, phys_addr_t size)
  164. +{
  165. + struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
  166. +
  167. + if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
  168. + pr_err("Reserved memory: not enough space all defined regions.\n");
  169. + return;
  170. + }
  171. +
  172. + rmem->fdt_node = node;
  173. + rmem->name = uname;
  174. + rmem->base = base;
  175. + rmem->size = size;
  176. +
  177. + reserved_mem_count++;
  178. + return;
  179. +}
  180. +
  181. +/**
  182. + * res_mem_alloc_size() - allocate reserved memory described by 'size', 'align'
  183. + * and 'alloc-ranges' properties
  184. + */
  185. +static int __init __reserved_mem_alloc_size(unsigned long node,
  186. + const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
  187. +{
  188. + int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
  189. + phys_addr_t start = 0, end = 0;
  190. + phys_addr_t base = 0, align = 0, size;
  191. + unsigned long len;
  192. + __be32 *prop;
  193. + int nomap;
  194. + int ret;
  195. +
  196. + prop = of_get_flat_dt_prop(node, "size", &len);
  197. + if (!prop)
  198. + return -EINVAL;
  199. +
  200. + if (len != dt_root_size_cells * sizeof(__be32)) {
  201. + pr_err("Reserved memory: invalid size property in '%s' node.\n",
  202. + uname);
  203. + return -EINVAL;
  204. + }
  205. + size = dt_mem_next_cell(dt_root_size_cells, &prop);
  206. +
  207. + nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
  208. +
  209. + prop = of_get_flat_dt_prop(node, "alignment", &len);
  210. + if (prop) {
  211. + if (len != dt_root_addr_cells * sizeof(__be32)) {
  212. + pr_err("Reserved memory: invalid alignment property in '%s' node.\n",
  213. + uname);
  214. + return -EINVAL;
  215. + }
  216. + align = dt_mem_next_cell(dt_root_addr_cells, &prop);
  217. + }
  218. +
  219. + prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
  220. + if (prop) {
  221. +
  222. + if (len % t_len != 0) {
  223. + pr_err("Reserved memory: invalid alloc-ranges property in '%s', skipping node.\n",
  224. + uname);
  225. + return -EINVAL;
  226. + }
  227. +
  228. + base = 0;
  229. +
  230. + while (len > 0) {
  231. + start = dt_mem_next_cell(dt_root_addr_cells, &prop);
  232. + end = start + dt_mem_next_cell(dt_root_size_cells,
  233. + &prop);
  234. +
  235. + ret = early_init_dt_alloc_reserved_memory_arch(size,
  236. + align, start, end, nomap, &base);
  237. + if (ret == 0) {
  238. + pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
  239. + uname, &base,
  240. + (unsigned long)size / SZ_1M);
  241. + break;
  242. + }
  243. + len -= t_len;
  244. + }
  245. +
  246. + } else {
  247. + ret = early_init_dt_alloc_reserved_memory_arch(size, align,
  248. + 0, 0, nomap, &base);
  249. + if (ret == 0)
  250. + pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
  251. + uname, &base, (unsigned long)size / SZ_1M);
  252. + }
  253. +
  254. + if (base == 0) {
  255. + pr_info("Reserved memory: failed to allocate memory for node '%s'\n",
  256. + uname);
  257. + return -ENOMEM;
  258. + }
  259. +
  260. + *res_base = base;
  261. + *res_size = size;
  262. +
  263. + return 0;
  264. +}
  265. +
  266. +/**
  267. + * fdt_init_reserved_mem - allocate and init all saved reserved memory regions
  268. + */
  269. +void __init fdt_init_reserved_mem(void)
  270. +{
  271. + int i;
  272. + for (i = 0; i < reserved_mem_count; i++) {
  273. + struct reserved_mem *rmem = &reserved_mem[i];
  274. + unsigned long node = rmem->fdt_node;
  275. + int err = 0;
  276. +
  277. + if (rmem->size == 0)
  278. + err = __reserved_mem_alloc_size(node, rmem->name,
  279. + &rmem->base, &rmem->size);
  280. + }
  281. +}
  282. --- /dev/null
  283. +++ b/include/linux/of_reserved_mem.h
  284. @@ -0,0 +1,21 @@
  285. +#ifndef __OF_RESERVED_MEM_H
  286. +#define __OF_RESERVED_MEM_H
  287. +
  288. +struct reserved_mem {
  289. + const char *name;
  290. + unsigned long fdt_node;
  291. + phys_addr_t base;
  292. + phys_addr_t size;
  293. +};
  294. +
  295. +#ifdef CONFIG_OF_RESERVED_MEM
  296. +void fdt_init_reserved_mem(void);
  297. +void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
  298. + phys_addr_t base, phys_addr_t size);
  299. +#else
  300. +static inline void fdt_init_reserved_mem(void) { }
  301. +static inline void fdt_reserved_mem_save_node(unsigned long node,
  302. + const char *uname, phys_addr_t base, phys_addr_t size) { }
  303. +#endif
  304. +
  305. +#endif /* __OF_RESERVED_MEM_H */