400-mtd-mtdsplit-support.patch 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. --- a/drivers/mtd/Kconfig
  2. +++ b/drivers/mtd/Kconfig
  3. @@ -12,6 +12,25 @@ menuconfig MTD
  4. if MTD
  5. +menu "OpenWrt specific MTD options"
  6. +
  7. +config MTD_ROOTFS_ROOT_DEV
  8. + bool "Automatically set 'rootfs' partition to be root filesystem"
  9. + default y
  10. +
  11. +config MTD_SPLIT_FIRMWARE
  12. + bool "Automatically split firmware partition for kernel+rootfs"
  13. + default y
  14. +
  15. +config MTD_SPLIT_FIRMWARE_NAME
  16. + string "Firmware partition name"
  17. + depends on MTD_SPLIT_FIRMWARE
  18. + default "firmware"
  19. +
  20. +source "drivers/mtd/mtdsplit/Kconfig"
  21. +
  22. +endmenu
  23. +
  24. config MTD_TESTS
  25. tristate "MTD tests support (DANGEROUS)"
  26. depends on m
  27. --- a/drivers/mtd/mtdpart.c
  28. +++ b/drivers/mtd/mtdpart.c
  29. @@ -15,11 +15,13 @@
  30. #include <linux/kmod.h>
  31. #include <linux/mtd/mtd.h>
  32. #include <linux/mtd/partitions.h>
  33. +#include <linux/magic.h>
  34. #include <linux/err.h>
  35. #include <linux/of.h>
  36. #include <linux/of_platform.h>
  37. #include "mtdcore.h"
  38. +#include "mtdsplit/mtdsplit.h"
  39. /*
  40. * MTD methods which simply translate the effective address and pass through
  41. @@ -236,6 +238,146 @@ static int mtd_add_partition_attrs(struc
  42. return ret;
  43. }
  44. +static DEFINE_SPINLOCK(part_parser_lock);
  45. +static LIST_HEAD(part_parsers);
  46. +
  47. +static struct mtd_part_parser *mtd_part_parser_get(const char *name)
  48. +{
  49. + struct mtd_part_parser *p, *ret = NULL;
  50. +
  51. + spin_lock(&part_parser_lock);
  52. +
  53. + list_for_each_entry(p, &part_parsers, list)
  54. + if (!strcmp(p->name, name) && try_module_get(p->owner)) {
  55. + ret = p;
  56. + break;
  57. + }
  58. +
  59. + spin_unlock(&part_parser_lock);
  60. +
  61. + return ret;
  62. +}
  63. +
  64. +static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
  65. +{
  66. + module_put(p->owner);
  67. +}
  68. +
  69. +static struct mtd_part_parser *
  70. +get_partition_parser_by_type(enum mtd_parser_type type,
  71. + struct mtd_part_parser *start)
  72. +{
  73. + struct mtd_part_parser *p, *ret = NULL;
  74. +
  75. + spin_lock(&part_parser_lock);
  76. +
  77. + p = list_prepare_entry(start, &part_parsers, list);
  78. + if (start)
  79. + mtd_part_parser_put(start);
  80. +
  81. + list_for_each_entry_continue(p, &part_parsers, list) {
  82. + if (p->type == type && try_module_get(p->owner)) {
  83. + ret = p;
  84. + break;
  85. + }
  86. + }
  87. +
  88. + spin_unlock(&part_parser_lock);
  89. +
  90. + return ret;
  91. +}
  92. +
  93. +static int parse_mtd_partitions_by_type(struct mtd_info *master,
  94. + enum mtd_parser_type type,
  95. + const struct mtd_partition **pparts,
  96. + struct mtd_part_parser_data *data)
  97. +{
  98. + struct mtd_part_parser *prev = NULL;
  99. + int ret = 0;
  100. +
  101. + while (1) {
  102. + struct mtd_part_parser *parser;
  103. +
  104. + parser = get_partition_parser_by_type(type, prev);
  105. + if (!parser)
  106. + break;
  107. +
  108. + ret = (*parser->parse_fn)(master, pparts, data);
  109. +
  110. + if (ret > 0) {
  111. + mtd_part_parser_put(parser);
  112. + printk(KERN_NOTICE
  113. + "%d %s partitions found on MTD device %s\n",
  114. + ret, parser->name, master->name);
  115. + break;
  116. + }
  117. +
  118. + prev = parser;
  119. + }
  120. +
  121. + return ret;
  122. +}
  123. +
  124. +static int
  125. +run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
  126. +{
  127. + struct mtd_partition *parts;
  128. + int nr_parts;
  129. + int i;
  130. +
  131. + nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts,
  132. + NULL);
  133. + if (nr_parts <= 0)
  134. + return nr_parts;
  135. +
  136. + if (WARN_ON(!parts))
  137. + return 0;
  138. +
  139. + for (i = 0; i < nr_parts; i++) {
  140. + /* adjust partition offsets */
  141. + parts[i].offset += child->part.offset;
  142. +
  143. + mtd_add_partition(child->parent,
  144. + parts[i].name,
  145. + parts[i].offset,
  146. + parts[i].size);
  147. + }
  148. +
  149. + kfree(parts);
  150. +
  151. + return nr_parts;
  152. +}
  153. +
  154. +#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
  155. +#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
  156. +#else
  157. +#define SPLIT_FIRMWARE_NAME "unused"
  158. +#endif
  159. +
  160. +static void split_firmware(struct mtd_info *master, struct mtd_info *part)
  161. +{
  162. + run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
  163. +}
  164. +
  165. +static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
  166. +{
  167. + static int rootfs_found = 0;
  168. +
  169. + if (rootfs_found)
  170. + return;
  171. +
  172. + if (!strcmp(part->name, "rootfs")) {
  173. + run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
  174. +
  175. + rootfs_found = 1;
  176. + }
  177. +
  178. + if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
  179. + !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
  180. + !of_find_property(mtd_get_of_node(part), "compatible", NULL))
  181. + split_firmware(master, part);
  182. +}
  183. +
  184. int mtd_add_partition(struct mtd_info *parent, const char *name,
  185. long long offset, long long length)
  186. {
  187. @@ -274,6 +416,7 @@ int mtd_add_partition(struct mtd_info *p
  188. if (ret)
  189. goto err_remove_part;
  190. + mtd_partition_split(parent, child);
  191. mtd_add_partition_attrs(child);
  192. return 0;
  193. @@ -422,6 +565,7 @@ int add_mtd_partitions(struct mtd_info *
  194. goto err_del_partitions;
  195. }
  196. + mtd_partition_split(master, child);
  197. mtd_add_partition_attrs(child);
  198. /* Look for subpartitions */
  199. @@ -438,31 +582,6 @@ err_del_partitions:
  200. return ret;
  201. }
  202. -static DEFINE_SPINLOCK(part_parser_lock);
  203. -static LIST_HEAD(part_parsers);
  204. -
  205. -static struct mtd_part_parser *mtd_part_parser_get(const char *name)
  206. -{
  207. - struct mtd_part_parser *p, *ret = NULL;
  208. -
  209. - spin_lock(&part_parser_lock);
  210. -
  211. - list_for_each_entry(p, &part_parsers, list)
  212. - if (!strcmp(p->name, name) && try_module_get(p->owner)) {
  213. - ret = p;
  214. - break;
  215. - }
  216. -
  217. - spin_unlock(&part_parser_lock);
  218. -
  219. - return ret;
  220. -}
  221. -
  222. -static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
  223. -{
  224. - module_put(p->owner);
  225. -}
  226. -
  227. /*
  228. * Many partition parsers just expected the core to kfree() all their data in
  229. * one chunk. Do that by default.
  230. --- a/include/linux/mtd/partitions.h
  231. +++ b/include/linux/mtd/partitions.h
  232. @@ -75,6 +75,12 @@ struct mtd_part_parser_data {
  233. * Functions dealing with the various ways of partitioning the space
  234. */
  235. +enum mtd_parser_type {
  236. + MTD_PARSER_TYPE_DEVICE = 0,
  237. + MTD_PARSER_TYPE_ROOTFS,
  238. + MTD_PARSER_TYPE_FIRMWARE,
  239. +};
  240. +
  241. struct mtd_part_parser {
  242. struct list_head list;
  243. struct module *owner;
  244. @@ -83,6 +89,7 @@ struct mtd_part_parser {
  245. int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
  246. struct mtd_part_parser_data *);
  247. void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
  248. + enum mtd_parser_type type;
  249. };
  250. /* Container for passing around a set of parsed partitions */
  251. --- a/drivers/mtd/Makefile
  252. +++ b/drivers/mtd/Makefile
  253. @@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc
  254. obj-y += parsers/
  255. +obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
  256. +
  257. # 'Users' - code which presents functionality to userspace.
  258. obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
  259. obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
  260. --- a/include/linux/mtd/mtd.h
  261. +++ b/include/linux/mtd/mtd.h
  262. @@ -613,6 +613,24 @@ static inline void mtd_align_erase_req(s
  263. req->len += mtd->erasesize - mod;
  264. }
  265. +static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
  266. +{
  267. + if (mtd_mod_by_eb(sz, mtd) == 0)
  268. + return sz;
  269. +
  270. + /* Round up to next erase block */
  271. + return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
  272. +}
  273. +
  274. +static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
  275. +{
  276. + if (mtd_mod_by_eb(sz, mtd) == 0)
  277. + return sz;
  278. +
  279. + /* Round down to the start of the current erase block */
  280. + return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
  281. +}
  282. +
  283. static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
  284. {
  285. if (mtd->writesize_shift)
  286. @@ -685,6 +703,13 @@ extern void __put_mtd_device(struct mtd_
  287. extern struct mtd_info *get_mtd_device_nm(const char *name);
  288. extern void put_mtd_device(struct mtd_info *mtd);
  289. +static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
  290. +{
  291. + if (!mtd_is_partition(mtd))
  292. + return 0;
  293. +
  294. + return mtd->part.offset;
  295. +}
  296. struct mtd_notifier {
  297. void (*add)(struct mtd_info *mtd);