brcm47xx: rename target to bcm47xx
[openwrt/openwrt.git] / target / linux / brcm63xx / patches-4.14 / 121-mtd-bcm63xxpart-move-imagetag-parsing-to-its-own-par.patch
1 From a2b8c7f648e168573905818dbb4cb90ca3957c65 Mon Sep 17 00:00:00 2001
2 From: Jonas Gorski <jonas.gorski@gmail.com>
3 Date: Wed, 28 Jun 2017 18:29:43 +0200
4 Subject: [PATCH] mtd: bcm63xxpart: move imagetag parsing to its own parser
5
6 Move the bcm963xx Image Tag parsing into its own partition parser. This
7 Allows reusing the parser with different full flash parsers.
8
9 While moving it, rename it to bcm963* to better reflect it isn't chip
10 but board specific.
11
12 Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
13 ---
14 I tried to keep the code as-is, to keep the changes as small as
15 possible.
16
17 One side effect is that the partitions get renumbered, which means any
18 root=/dev/mtdblock* will now point to the wrong mtd device. But since
19 bcm963xx boards will require these hardcoded in the kernel commandline
20 anyway this should b a non issue, as it can be easily updated.
21
22 There is no such thing in the mips/bcm63xx defconfig, so nothing to update
23 there.
24
25 drivers/mtd/Kconfig | 1 +
26 drivers/mtd/bcm63xxpart.c | 155 ++----------------------
27 drivers/mtd/parsers/Kconfig | 11 ++
28 drivers/mtd/parsers/Makefile | 1 +
29 drivers/mtd/parsers/parser_imagetag.c | 214 ++++++++++++++++++++++++++++++++++
30 5 files changed, 235 insertions(+), 147 deletions(-)
31 create mode 100644 drivers/mtd/parsers/parser_imagetag.c
32
33 --- a/drivers/mtd/Kconfig
34 +++ b/drivers/mtd/Kconfig
35 @@ -163,6 +163,7 @@ config MTD_BCM63XX_PARTS
36 tristate "BCM63XX CFE partitioning support"
37 depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
38 select CRC32
39 + select MTD_PARSER_IMAGETAG
40 help
41 This provides partions parsing for BCM63xx devices with CFE
42 bootloaders.
43 --- a/drivers/mtd/bcm63xxpart.c
44 +++ b/drivers/mtd/bcm63xxpart.c
45 @@ -93,51 +93,19 @@ static int bcm63xx_read_nvram(struct mtd
46 return 0;
47 }
48
49 -static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name,
50 - loff_t tag_offset, struct bcm_tag *buf)
51 -{
52 - int ret;
53 - size_t retlen;
54 - u32 computed_crc;
55 -
56 - ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
57 - if (ret)
58 - return ret;
59 -
60 - if (retlen != sizeof(*buf))
61 - return -EIO;
62 -
63 - computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
64 - offsetof(struct bcm_tag, header_crc));
65 - if (computed_crc == buf->header_crc) {
66 - STR_NULL_TERMINATE(buf->board_id);
67 - STR_NULL_TERMINATE(buf->tag_version);
68 -
69 - pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
70 - name, tag_offset, buf->tag_version, buf->board_id);
71 -
72 - return 0;
73 - }
74 -
75 - pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
76 - name, tag_offset, buf->header_crc, computed_crc);
77 - return 1;
78 -}
79 +static const char * const bcm63xx_cfe_part_types[] = {
80 + "bcm963xx-imagetag",
81 + NULL,
82 +};
83
84 static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
85 const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)
86 {
87 - /* CFE, NVRAM and global Linux are always present */
88 - int nrparts = 3, curpart = 0;
89 - struct bcm_tag *buf = NULL;
90 struct mtd_partition *parts;
91 - int ret;
92 - unsigned int rootfsaddr, kerneladdr, spareaddr;
93 - unsigned int rootfslen, kernellen, sparelen, totallen;
94 + int nrparts = 3, curpart = 0;
95 unsigned int cfelen, nvramlen;
96 unsigned int cfe_erasesize;
97 int i;
98 - bool rootfs_first = false;
99
100 cfe_erasesize = max_t(uint32_t, master->erasesize,
101 BCM963XX_CFE_BLOCK_SIZE);
102 @@ -146,83 +114,9 @@ static int bcm63xx_parse_cfe_nor_partiti
103 nvramlen = nvram->psi_size * SZ_1K;
104 nvramlen = roundup(nvramlen, cfe_erasesize);
105
106 - buf = vmalloc(sizeof(struct bcm_tag));
107 - if (!buf)
108 - return -ENOMEM;
109 -
110 - /* Get the tag */
111 - ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf);
112 - if (!ret) {
113 - STR_NULL_TERMINATE(buf->flash_image_start);
114 - if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
115 - rootfsaddr < BCM963XX_EXTENDED_SIZE) {
116 - pr_err("invalid rootfs address: %*ph\n",
117 - (int)sizeof(buf->flash_image_start),
118 - buf->flash_image_start);
119 - goto invalid_tag;
120 - }
121 -
122 - STR_NULL_TERMINATE(buf->kernel_address);
123 - if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
124 - kerneladdr < BCM963XX_EXTENDED_SIZE) {
125 - pr_err("invalid kernel address: %*ph\n",
126 - (int)sizeof(buf->kernel_address),
127 - buf->kernel_address);
128 - goto invalid_tag;
129 - }
130 -
131 - STR_NULL_TERMINATE(buf->kernel_length);
132 - if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
133 - pr_err("invalid kernel length: %*ph\n",
134 - (int)sizeof(buf->kernel_length),
135 - buf->kernel_length);
136 - goto invalid_tag;
137 - }
138 -
139 - STR_NULL_TERMINATE(buf->total_length);
140 - if (kstrtouint(buf->total_length, 10, &totallen)) {
141 - pr_err("invalid total length: %*ph\n",
142 - (int)sizeof(buf->total_length),
143 - buf->total_length);
144 - goto invalid_tag;
145 - }
146 -
147 - kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE;
148 - rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE;
149 - spareaddr = roundup(totallen, master->erasesize) + cfelen;
150 -
151 - if (rootfsaddr < kerneladdr) {
152 - /* default Broadcom layout */
153 - rootfslen = kerneladdr - rootfsaddr;
154 - rootfs_first = true;
155 - } else {
156 - /* OpenWrt layout */
157 - rootfsaddr = kerneladdr + kernellen;
158 - rootfslen = spareaddr - rootfsaddr;
159 - }
160 - } else if (ret > 0) {
161 -invalid_tag:
162 - kernellen = 0;
163 - rootfslen = 0;
164 - rootfsaddr = 0;
165 - spareaddr = cfelen;
166 - } else {
167 - goto out;
168 - }
169 - sparelen = master->size - spareaddr - nvramlen;
170 -
171 - /* Determine number of partitions */
172 - if (rootfslen > 0)
173 - nrparts++;
174 -
175 - if (kernellen > 0)
176 - nrparts++;
177 -
178 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
179 - if (!parts) {
180 - ret = -ENOMEM;
181 - goto out;
182 - }
183 + if (!parts)
184 + return -ENOMEM;
185
186 /* Start building partition list */
187 parts[curpart].name = "CFE";
188 @@ -230,30 +124,6 @@ invalid_tag:
189 parts[curpart].size = cfelen;
190 curpart++;
191
192 - if (kernellen > 0) {
193 - int kernelpart = curpart;
194 -
195 - if (rootfslen > 0 && rootfs_first)
196 - kernelpart++;
197 - parts[kernelpart].name = "kernel";
198 - parts[kernelpart].offset = kerneladdr;
199 - parts[kernelpart].size = kernellen;
200 - curpart++;
201 - }
202 -
203 - if (rootfslen > 0) {
204 - int rootfspart = curpart;
205 -
206 - if (kernellen > 0 && rootfs_first)
207 - rootfspart--;
208 - parts[rootfspart].name = "rootfs";
209 - parts[rootfspart].offset = rootfsaddr;
210 - parts[rootfspart].size = rootfslen;
211 - if (sparelen > 0 && !rootfs_first)
212 - parts[rootfspart].size += sparelen;
213 - curpart++;
214 - }
215 -
216 parts[curpart].name = "nvram";
217 parts[curpart].offset = master->size - nvramlen;
218 parts[curpart].size = nvramlen;
219 @@ -263,22 +133,13 @@ invalid_tag:
220 parts[curpart].name = "linux";
221 parts[curpart].offset = cfelen;
222 parts[curpart].size = master->size - cfelen - nvramlen;
223 + parts[curpart].types = bcm63xx_cfe_part_types;
224
225 for (i = 0; i < nrparts; i++)
226 pr_info("Partition %d is %s offset %llx and length %llx\n", i,
227 parts[i].name, parts[i].offset, parts[i].size);
228
229 - pr_info("Spare partition is offset %x and length %x\n", spareaddr,
230 - sparelen);
231 -
232 *pparts = parts;
233 - ret = 0;
234 -
235 -out:
236 - vfree(buf);
237 -
238 - if (ret)
239 - return ret;
240
241 return nrparts;
242 }
243 --- a/drivers/mtd/parsers/Kconfig
244 +++ b/drivers/mtd/parsers/Kconfig
245 @@ -1,3 +1,14 @@
246 +config MTD_PARSER_IMAGETAG
247 + tristate "Parser for BCM963XX Image Tag format partitions"
248 + depends on BCM63XX || BMIPS || COMPILE_TEST
249 + select CRC32
250 + help
251 + Image Tag is the firmware header used by broadcom on their xDSL line
252 + of devices. It is used to describe the offsets and lengths of kernel
253 + and rootfs partitions.
254 + This driver adds support for parsing a partition with an Image Tag
255 + header and creates up to two partitions, kernel and rootfs.
256 +
257 config MTD_PARSER_TRX
258 tristate "Parser for TRX format partitions"
259 depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST)
260 --- a/drivers/mtd/parsers/Makefile
261 +++ b/drivers/mtd/parsers/Makefile
262 @@ -1 +1,2 @@
263 +obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
264 obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
265 --- /dev/null
266 +++ b/drivers/mtd/parsers/parser_imagetag.c
267 @@ -0,0 +1,214 @@
268 +/*
269 + * BCM63XX CFE image tag parser
270 + *
271 + * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org>
272 + * Mike Albon <malbon@openwrt.org>
273 + * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
274 + * Copyright © 2011-2013 Jonas Gorski <jonas.gorski@gmail.com>
275 + *
276 + * This program is free software; you can redistribute it and/or modify
277 + * it under the terms of the GNU General Public License as published by
278 + * the Free Software Foundation; either version 2 of the License, or
279 + * (at your option) any later version.
280 + *
281 + */
282 +
283 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
284 +
285 +#include <linux/bcm963xx_tag.h>
286 +#include <linux/crc32.h>
287 +#include <linux/module.h>
288 +#include <linux/kernel.h>
289 +#include <linux/sizes.h>
290 +#include <linux/slab.h>
291 +#include <linux/vmalloc.h>
292 +#include <linux/mtd/mtd.h>
293 +#include <linux/mtd/partitions.h>
294 +
295 +/* Ensure strings read from flash structs are null terminated */
296 +#define STR_NULL_TERMINATE(x) \
297 + do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
298 +
299 +static int bcm963xx_read_imagetag(struct mtd_info *master, const char *name,
300 + loff_t tag_offset, struct bcm_tag *buf)
301 +{
302 + int ret;
303 + size_t retlen;
304 + u32 computed_crc;
305 +
306 + ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
307 + if (ret)
308 + return ret;
309 +
310 + if (retlen != sizeof(*buf))
311 + return -EIO;
312 +
313 + computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
314 + offsetof(struct bcm_tag, header_crc));
315 + if (computed_crc == buf->header_crc) {
316 + STR_NULL_TERMINATE(buf->board_id);
317 + STR_NULL_TERMINATE(buf->tag_version);
318 +
319 + pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
320 + name, tag_offset, buf->tag_version, buf->board_id);
321 +
322 + return 0;
323 + }
324 +
325 + pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
326 + name, tag_offset, buf->header_crc, computed_crc);
327 + return -EINVAL;
328 +}
329 +
330 +static int bcm963xx_parse_imagetag_partitions(struct mtd_info *master,
331 + const struct mtd_partition **pparts,
332 + struct mtd_part_parser_data *data)
333 +{
334 + /* CFE, NVRAM and global Linux are always present */
335 + int nrparts = 0, curpart = 0;
336 + struct bcm_tag *buf = NULL;
337 + struct mtd_partition *parts;
338 + int ret;
339 + unsigned int rootfsaddr, kerneladdr, spareaddr, offset;
340 + unsigned int rootfslen, kernellen, sparelen, totallen;
341 + int i;
342 + bool rootfs_first = false;
343 +
344 + buf = vmalloc(sizeof(struct bcm_tag));
345 + if (!buf)
346 + return -ENOMEM;
347 +
348 + /* Get the tag */
349 + ret = bcm963xx_read_imagetag(master, "rootfs", 0, buf);
350 + if (!ret) {
351 + STR_NULL_TERMINATE(buf->flash_image_start);
352 + if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
353 + rootfsaddr < BCM963XX_EXTENDED_SIZE) {
354 + pr_err("invalid rootfs address: %*ph\n",
355 + (int)sizeof(buf->flash_image_start),
356 + buf->flash_image_start);
357 + goto out;
358 + }
359 +
360 + STR_NULL_TERMINATE(buf->kernel_address);
361 + if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
362 + kerneladdr < BCM963XX_EXTENDED_SIZE) {
363 + pr_err("invalid kernel address: %*ph\n",
364 + (int)sizeof(buf->kernel_address),
365 + buf->kernel_address);
366 + goto out;
367 + }
368 +
369 + STR_NULL_TERMINATE(buf->kernel_length);
370 + if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
371 + pr_err("invalid kernel length: %*ph\n",
372 + (int)sizeof(buf->kernel_length),
373 + buf->kernel_length);
374 + goto out;
375 + }
376 +
377 + STR_NULL_TERMINATE(buf->total_length);
378 + if (kstrtouint(buf->total_length, 10, &totallen)) {
379 + pr_err("invalid total length: %*ph\n",
380 + (int)sizeof(buf->total_length),
381 + buf->total_length);
382 + goto out;
383 + }
384 +
385 + /*
386 + * Addresses are flash absolute, so convert to partition
387 + * relative addresses. Assume either kernel or rootfs will
388 + * directly follow the image tag.
389 + */
390 + if (rootfsaddr < kerneladdr)
391 + offset = rootfsaddr - sizeof(struct bcm_tag);
392 + else
393 + offset = kerneladdr - sizeof(struct bcm_tag);
394 +
395 + kerneladdr = kerneladdr - offset;
396 + rootfsaddr = rootfsaddr - offset;
397 + spareaddr = roundup(totallen, master->erasesize);
398 +
399 + if (rootfsaddr < kerneladdr) {
400 + /* default Broadcom layout */
401 + rootfslen = kerneladdr - rootfsaddr;
402 + rootfs_first = true;
403 + } else {
404 + /* OpenWrt layout */
405 + rootfsaddr = kerneladdr + kernellen;
406 + rootfslen = spareaddr - rootfsaddr;
407 + }
408 + } else {
409 + goto out;
410 + }
411 + sparelen = master->size - spareaddr;
412 +
413 + /* Determine number of partitions */
414 + if (rootfslen > 0)
415 + nrparts++;
416 +
417 + if (kernellen > 0)
418 + nrparts++;
419 +
420 + parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
421 + if (!parts) {
422 + ret = -ENOMEM;
423 + goto out;
424 + }
425 +
426 + /* Start building partition list */
427 + if (kernellen > 0) {
428 + int kernelpart = curpart;
429 +
430 + if (rootfslen > 0 && rootfs_first)
431 + kernelpart++;
432 + parts[kernelpart].name = "kernel";
433 + parts[kernelpart].offset = kerneladdr;
434 + parts[kernelpart].size = kernellen;
435 + curpart++;
436 + }
437 +
438 + if (rootfslen > 0) {
439 + int rootfspart = curpart;
440 +
441 + if (kernellen > 0 && rootfs_first)
442 + rootfspart--;
443 + parts[rootfspart].name = "rootfs";
444 + parts[rootfspart].offset = rootfsaddr;
445 + parts[rootfspart].size = rootfslen;
446 + if (sparelen > 0 && !rootfs_first)
447 + parts[rootfspart].size += sparelen;
448 + curpart++;
449 + }
450 +
451 + for (i = 0; i < nrparts; i++)
452 + pr_info("Partition %d is %s offset %llx and length %llx\n", i,
453 + parts[i].name, parts[i].offset, parts[i].size);
454 +
455 + pr_info("Spare partition is offset %x and length %x\n", spareaddr,
456 + sparelen);
457 +
458 + *pparts = parts;
459 + ret = 0;
460 +
461 +out:
462 + vfree(buf);
463 +
464 + if (ret)
465 + return ret;
466 +
467 + return nrparts;
468 +}
469 +
470 +static struct mtd_part_parser bcm963xx_imagetag_parser = {
471 + .parse_fn = bcm963xx_parse_imagetag_partitions,
472 + .name = "bcm963xx-imagetag",
473 +};
474 +module_mtd_part_parser(bcm963xx_imagetag_parser);
475 +
476 +MODULE_LICENSE("GPL");
477 +MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
478 +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
479 +MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");
480 +MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com");
481 +MODULE_DESCRIPTION("MTD parser for BCM963XX CFE Image Tag partitions");