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
6 Move the bcm963xx Image Tag parsing into its own partition parser. This
7 Allows reusing the parser with different full flash parsers.
9 While moving it, rename it to bcm963* to better reflect it isn't chip
12 Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
14 I tried to keep the code as-is, to keep the changes as small as
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.
22 There is no such thing in the mips/bcm63xx defconfig, so nothing to update
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
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
39 + select MTD_PARSER_IMAGETAG
41 This provides partions parsing for BCM63xx devices with CFE
43 --- a/drivers/mtd/bcm63xxpart.c
44 +++ b/drivers/mtd/bcm63xxpart.c
45 @@ -93,51 +93,19 @@ static int bcm63xx_read_nvram(struct mtd
49 -static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name,
50 - loff_t tag_offset, struct bcm_tag *buf)
56 - ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
60 - if (retlen != sizeof(*buf))
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);
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);
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);
79 +static const char * const bcm63xx_cfe_part_types[] = {
80 + "bcm963xx-imagetag",
84 static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
85 const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)
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;
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;
98 - bool rootfs_first = false;
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);
106 - buf = vmalloc(sizeof(struct bcm_tag));
111 - ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf);
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);
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);
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);
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);
147 - kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE;
148 - rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE;
149 - spareaddr = roundup(totallen, master->erasesize) + cfelen;
151 - if (rootfsaddr < kerneladdr) {
152 - /* default Broadcom layout */
153 - rootfslen = kerneladdr - rootfsaddr;
154 - rootfs_first = true;
156 - /* OpenWrt layout */
157 - rootfsaddr = kerneladdr + kernellen;
158 - rootfslen = spareaddr - rootfsaddr;
160 - } else if (ret > 0) {
165 - spareaddr = cfelen;
169 - sparelen = master->size - spareaddr - nvramlen;
171 - /* Determine number of partitions */
178 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
186 /* Start building partition list */
187 parts[curpart].name = "CFE";
188 @@ -230,30 +124,6 @@ invalid_tag:
189 parts[curpart].size = cfelen;
192 - if (kernellen > 0) {
193 - int kernelpart = curpart;
195 - if (rootfslen > 0 && rootfs_first)
197 - parts[kernelpart].name = "kernel";
198 - parts[kernelpart].offset = kerneladdr;
199 - parts[kernelpart].size = kernellen;
203 - if (rootfslen > 0) {
204 - int rootfspart = curpart;
206 - if (kernellen > 0 && rootfs_first)
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;
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;
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);
229 - pr_info("Spare partition is offset %x and length %x\n", spareaddr,
243 --- a/drivers/mtd/parsers/Kconfig
244 +++ b/drivers/mtd/parsers/Kconfig
246 +config MTD_PARSER_IMAGETAG
247 + tristate "Parser for BCM963XX Image Tag format partitions"
248 + depends on BCM63XX || BMIPS || COMPILE_TEST
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.
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
263 +obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
264 obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
266 +++ b/drivers/mtd/parsers/parser_imagetag.c
269 + * BCM63XX CFE image tag parser
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>
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.
283 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
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)
299 +static int bcm963xx_read_imagetag(struct mtd_info *master, const char *name,
300 + loff_t tag_offset, struct bcm_tag *buf)
306 + ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
310 + if (retlen != sizeof(*buf))
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);
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);
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);
330 +static int bcm963xx_parse_imagetag_partitions(struct mtd_info *master,
331 + const struct mtd_partition **pparts,
332 + struct mtd_part_parser_data *data)
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;
339 + unsigned int rootfsaddr, kerneladdr, spareaddr, offset;
340 + unsigned int rootfslen, kernellen, sparelen, totallen;
342 + bool rootfs_first = false;
344 + buf = vmalloc(sizeof(struct bcm_tag));
349 + ret = bcm963xx_read_imagetag(master, "rootfs", 0, buf);
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);
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);
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);
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);
386 + * Addresses are flash absolute, so convert to partition
387 + * relative addresses. Assume either kernel or rootfs will
388 + * directly follow the image tag.
390 + if (rootfsaddr < kerneladdr)
391 + offset = rootfsaddr - sizeof(struct bcm_tag);
393 + offset = kerneladdr - sizeof(struct bcm_tag);
395 + kerneladdr = kerneladdr - offset;
396 + rootfsaddr = rootfsaddr - offset;
397 + spareaddr = roundup(totallen, master->erasesize);
399 + if (rootfsaddr < kerneladdr) {
400 + /* default Broadcom layout */
401 + rootfslen = kerneladdr - rootfsaddr;
402 + rootfs_first = true;
404 + /* OpenWrt layout */
405 + rootfsaddr = kerneladdr + kernellen;
406 + rootfslen = spareaddr - rootfsaddr;
411 + sparelen = master->size - spareaddr;
413 + /* Determine number of partitions */
420 + parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
426 + /* Start building partition list */
427 + if (kernellen > 0) {
428 + int kernelpart = curpart;
430 + if (rootfslen > 0 && rootfs_first)
432 + parts[kernelpart].name = "kernel";
433 + parts[kernelpart].offset = kerneladdr;
434 + parts[kernelpart].size = kernellen;
438 + if (rootfslen > 0) {
439 + int rootfspart = curpart;
441 + if (kernellen > 0 && rootfs_first)
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;
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);
455 + pr_info("Spare partition is offset %x and length %x\n", spareaddr,
470 +static struct mtd_part_parser bcm963xx_imagetag_parser = {
471 + .parse_fn = bcm963xx_parse_imagetag_partitions,
472 + .name = "bcm963xx-imagetag",
474 +module_mtd_part_parser(bcm963xx_imagetag_parser);
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");