2015-12-10 23:04:37

by Simon Arlott

[permalink] [raw]
Subject: [PATCH linux-next (v2) 1/3] MIPS: bcm963xx: Add nvram structure

The BCM963xx has multiple nvram variants across different SoCs with
additional checksum fields added whenever the size of the nvram was
extended.

Signed-off-by: Simon Arlott <[email protected]>
---
v2: Use external struct bcm963xx_nvram definition for bcm963268part.

MAINTAINERS | 1 +
include/uapi/linux/bcm963xx_nvram.h | 39 +++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 include/uapi/linux/bcm963xx_nvram.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 1354720..5d2272c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2396,6 +2396,7 @@ F: drivers/irqchip/irq-brcmstb*
F: drivers/power/bcm6358*
F: drivers/reset/bcm/reset-bcm6345*
F: include/linux/bcm63xx_wdt.h
+F: include/uapi/linux/bcm963xx_nvram.h

BROADCOM TG3 GIGABIT ETHERNET DRIVER
M: Prashant Sreedharan <[email protected]>
diff --git a/include/uapi/linux/bcm963xx_nvram.h b/include/uapi/linux/bcm963xx_nvram.h
new file mode 100644
index 0000000..470a4b9
--- /dev/null
+++ b/include/uapi/linux/bcm963xx_nvram.h
@@ -0,0 +1,39 @@
+#ifndef _UAPI__LINUX_BCM963XX_NVRAM_H__
+#define _UAPI__LINUX_BCM963XX_NVRAM_H__
+
+#include <linux/sizes.h>
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+#define BCM963XX_NVRAM_V4_SIZE 300
+#define BCM963XX_NVRAM_V5_SIZE (1 * SZ_1K)
+#define BCM963XX_NVRAM_V6_SIZE BCM963XX_NVRAM_V5_SIZE
+#define BCM963XX_NVRAM_V7_SIZE (3 * SZ_1K)
+
+#define BCM963XX_NVRAM_NR_PARTS 5
+
+struct bcm963xx_nvram {
+ u32 version;
+ char bootline[256];
+ char name[16];
+ u32 main_tp_number;
+ u32 psi_size;
+ u32 mac_addr_count;
+ u8 mac_addr_base[ETH_ALEN];
+ u8 __reserved1[2];
+ u32 checksum_v4;
+
+ u8 __reserved2[292];
+ u32 nand_part_offset[BCM963XX_NVRAM_NR_PARTS];
+ u32 nand_part_size[BCM963XX_NVRAM_NR_PARTS];
+ u8 __reserved3[388];
+ union {
+ u32 checksum_v5;
+ u32 checksum_v6;
+ };
+
+ u8 __reserved4[2044];
+ u32 checksum_v7;
+} __packed;
+
+#endif /* _UAPI__LINUX_BCM963XX_NVRAM_H__ */
--
2.1.4

--
Simon Arlott


2015-12-10 23:06:21

by Simon Arlott

[permalink] [raw]
Subject: [PATCH linux-next (v2) 2/3] MIPS: bcm63xx: Use common nvram structure definition

Use an external common definition of the nvram structure.

Signed-off-by: Simon Arlott <[email protected]>
---
Compile tested only (there is no support for brcmnand on mach-bcm63xx).

v2: Use external struct bcm963xx_nvram definition for bcm963268part.

arch/mips/bcm63xx/nvram.c | 32 ++++++++------------------------
1 file changed, 8 insertions(+), 24 deletions(-)

diff --git a/arch/mips/bcm63xx/nvram.c b/arch/mips/bcm63xx/nvram.c
index 4b50d40..36e74f9 100644
--- a/arch/mips/bcm63xx/nvram.c
+++ b/arch/mips/bcm63xx/nvram.c
@@ -16,25 +16,9 @@
#include <linux/kernel.h>
#include <linux/if_ether.h>

+#include <uapi/linux/bcm963xx_nvram.h>
#include <bcm63xx_nvram.h>

-/*
- * nvram structure
- */
-struct bcm963xx_nvram {
- u32 version;
- u8 reserved1[256];
- u8 name[16];
- u32 main_tp_number;
- u32 psi_size;
- u32 mac_addr_count;
- u8 mac_addr_base[ETH_ALEN];
- u8 reserved2[2];
- u32 checksum_old;
- u8 reserved3[720];
- u32 checksum_high;
-};
-
#define BCM63XX_DEFAULT_PSI_SIZE 64

static struct bcm963xx_nvram nvram;
@@ -47,17 +31,17 @@ void __init bcm63xx_nvram_init(void *addr)
u8 hcs_mac_addr[ETH_ALEN] = { 0x00, 0x10, 0x18, 0xff, 0xff, 0xff };

/* extract nvram data */
- memcpy(&nvram, addr, sizeof(nvram));
+ memcpy(&nvram, addr, BCM963XX_NVRAM_V5_SIZE);

/* check checksum before using data */
if (nvram.version <= 4) {
- check_len = offsetof(struct bcm963xx_nvram, reserved3);
- expected_crc = nvram.checksum_old;
- nvram.checksum_old = 0;
+ check_len = BCM963XX_NVRAM_V4_SIZE;
+ expected_crc = nvram.checksum_v4;
+ nvram.checksum_v4 = 0;
} else {
- check_len = sizeof(nvram);
- expected_crc = nvram.checksum_high;
- nvram.checksum_high = 0;
+ check_len = BCM963XX_NVRAM_V5_SIZE;
+ expected_crc = nvram.checksum_v5;
+ nvram.checksum_v5 = 0;
}

crc = crc32_le(~0, (u8 *)&nvram, check_len);
--
2.1.4

--
Simon Arlott

2015-12-10 23:10:20

by Simon Arlott

[permalink] [raw]
Subject: [PATCH linux-next (v2) 3/3] mtd: part: Add BCM962368 CFE partitioning support

Add partitioning support for BCM963268 boards with CFE bootloaders.
The following partitions are defined:
"boot": CFE and nvram data
"rootfs": Currently selected rootfs
"data": Configuration data
"rootfs1_update": Container for the whole flash area used
for the first rootfs to allow it to be
updated.
"rootfs2_update": Container for the whole flash area used
for the second rootfs to allow it to be
updated.
"rootfs_other": The other (not currently selected) rootfs

Example:
[ 1.904302] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xf1
[ 1.911000] nand: Macronix NAND 128MiB 3,3V 8-bit
[ 1.915855] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
[ 1.923797] bcm6368_nand 10000200.nand: detected 128MiB total, 128KiB blocks, 2KiB pages, 16B OOB, 8-bit, Hamming ECC
[ 1.936994] Bad block table found at page 65472, version 0x01
[ 1.944121] Bad block table found at page 65408, version 0x01
[ 1.951166] nand_read_bbt: bad block at 0x000007480000
[ 1.990043] bcm963268part: rootfs1: CFE boot tag found at 0x20000 with version 6, board type 963168VX and sequence number 2
[ 2.003060] bcm963268part: rootfs2: CFE boot tag found at 0x4000000 with version 6, board type 963168VX and sequence number 1
[ 2.015159] bcm963268part: CFE bootline selected latest image rootfs1
[ 2.022080] 6 bcm963268part partitions found on MTD device brcmnand.0
[ 2.042659] Creating 6 MTD partitions on "brcmnand.0":
[ 2.048025] 0x000000000000-0x000000020000 : "boot"
[ 2.062134] 0x000000040000-0x000001120000 : "rootfs"
[ 2.077632] 0x000007b00000-0x000007f00000 : "data"
[ 2.091363] 0x000000020000-0x000003ac0000 : "rootfs1_update"
[ 2.106228] 0x000004000000-0x000007ac0000 : "rootfs2_update"
[ 2.121093] 0x000004020000-0x000005060000 : "rootfs_other"

The nvram contains the offset and size of the boot, rootfs1, rootfs2
and data partitions. The presence of CFE and nvram is verified by
reading from the boot partition which is assumed to be at offset 0
and the process aborts if the nvram read indicates that this is not
the case.

There is bcm_tag information at the start of each rootfs that is used
to determine which rootfs is newer and what its real offset/size is.

The CFE bootline is used to select a rootfs.

Signed-off-by: Simon Arlott <[email protected]>
---
v2: Use external struct bcm963xx_nvram definition for bcm963268part.

Removed support for the nand partition number field, it's not a
standard Broadcom field (was added by MitraStar Technology Corp.).

drivers/mtd/Kconfig | 21 +++
drivers/mtd/Makefile | 1 +
drivers/mtd/bcm963268part.c | 326 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 348 insertions(+)
create mode 100644 drivers/mtd/bcm963268part.c

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 42cc953..63cb2db 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -148,6 +148,27 @@ config MTD_BCM63XX_PARTS
This provides partions parsing for BCM63xx devices with CFE
bootloaders.

+config MTD_BCM963268_PARTS
+ tristate "BCM963268 CFE partitioning support"
+ depends on BMIPS_GENERIC
+ select CRC32
+ help
+ This provides partitions parsing for BCM963268 boards with CFE
+ bootloaders. The following partitions are defined:
+ "boot": CFE and nvram data
+ "rootfs": Currently selected rootfs
+ "data": Configuration data
+ "rootfs1_update": Container for the whole flash area used
+ for the first rootfs to allow it to be
+ updated.
+ "rootfs2_update": Container for the whole flash area used
+ for the second rootfs to allow it to be
+ updated.
+ "rootfs_other": The other (not currently selected) rootfs
+
+ A decision is made regarding which of the two rootfs is to be
+ used based on the nvram data.
+
config MTD_BCM47XX_PARTS
tristate "BCM47XX partitioning support"
depends on BCM47XX || ARCH_BCM_5301X
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 99bb9a1..f0f4140 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
+obj-$(CONFIG_MTD_BCM963268_PARTS) += bcm963268part.o
obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o

# 'Users' - code which presents functionality to userspace.
diff --git a/drivers/mtd/bcm963268part.c b/drivers/mtd/bcm963268part.c
new file mode 100644
index 0000000..a519499
--- /dev/null
+++ b/drivers/mtd/bcm963268part.c
@@ -0,0 +1,326 @@
+/*
+ * BCM963268 CFE image tag parser
+ * Copyright 2015 Simon Arlott
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Derived from drivers/mtd/bcm63xxpart.c:
+ * Copyright © 2006-2008 Florian Fainelli <[email protected]>
+ * Mike Albon <[email protected]>
+ * Copyright © 2009-2010 Daniel Dickinson <[email protected]>
+ * Copyright © 2011-2013 Jonas Gorski <[email protected]>
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/bcmdrivers/opensource/char/board/bcm963xx/impl1/board.c,
+ * bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/bcm_hwdefs.h:
+ * Copyright (c) 2002 Broadcom Corporation
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/crc32.h>
+#include <linux/if_ether.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-bcm63xx/bcm963xx_tag.h>
+#include <uapi/linux/bcm963xx_nvram.h>
+
+/* Extended flash address, needs to be subtracted from bcm_tag flash offsets */
+#define BCM63XX_EXTENDED_SIZE 0xBFC00000
+
+#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
+#define BCM963XX_CFE_VERSION_OFFSET 0x570
+#define BCM963XX_NVRAM_OFFSET 0x580
+
+enum bcm963268_nvram_part {
+ PART_BOOT = 0,
+ PART_ROOTFS_1,
+ PART_ROOTFS_2,
+ PART_DATA,
+ PART_BBT,
+};
+
+static int bcm963268_detect_cfe(struct mtd_info *master)
+{
+ char buf[9];
+ int ret;
+ size_t retlen;
+
+ ret = mtd_read(master, BCM963XX_CFE_VERSION_OFFSET, 5, &retlen,
+ (void *)buf);
+ buf[retlen] = 0;
+
+ if (ret < 0)
+ return ret;
+
+ if (strncmp("cfe-v", buf, 5) == 0)
+ return 0;
+
+ return -EINVAL;
+}
+
+static int bcm963268_read_nvram(struct mtd_info *master,
+ struct bcm963xx_nvram *nvram)
+{
+ u32 crc, expected_crc;
+ size_t retlen;
+ int ret;
+
+ /* extract nvram data */
+ ret = mtd_read(master, BCM963XX_NVRAM_OFFSET, BCM963XX_NVRAM_V6_SIZE,
+ &retlen, (void *)nvram);
+
+ if (ret < 0)
+ return ret;
+
+ if (nvram->version < 6) {
+ pr_warn("nvram version %d not supported\n", nvram->version);
+ return -EINVAL;
+ }
+
+ /* check checksum before using data */
+ expected_crc = nvram->checksum_v6;
+ nvram->checksum_v6 = 0;
+
+ crc = crc32_le(~0, (u8 *)nvram, BCM963XX_NVRAM_V6_SIZE);
+
+ if (crc != expected_crc)
+ pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
+ expected_crc, crc);
+
+ return 0;
+}
+
+static bool bcm963268_boot_latest(struct bcm963xx_nvram *nvram)
+{
+ char *p;
+
+ /* Ensure bootline is null terminated */
+ nvram->bootline[sizeof(nvram->bootline) - 1] = 0;
+
+ /* Find previous image parameter "p" */
+ if (!strncmp(nvram->bootline, "p=", 2))
+ p = nvram->bootline;
+ else
+ p = strstr(nvram->bootline, " p=");
+
+ if (p == NULL)
+ return true;
+
+ p += 2;
+ if (*p == '\0')
+ return true;
+
+ return *p != '0';
+}
+
+static bool bcm963268_parse_rootfs_tag(struct mtd_info *master,
+ const char *name, loff_t rootfs_part, u64 *rootfs_offset,
+ u64 *rootfs_size, unsigned int *rootfs_sequence)
+{
+ struct bcm_tag *buf;
+ int ret;
+ size_t retlen;
+ u32 computed_crc;
+ bool rootfs_ok = false;
+
+ *rootfs_offset = 0;
+ *rootfs_size = 0;
+ *rootfs_sequence = 0;
+
+ buf = vmalloc(sizeof(struct bcm_tag));
+ if (!buf)
+ goto out;
+
+ ret = mtd_read(master, rootfs_part, sizeof(*buf), &retlen, (void *)buf);
+ if (ret < 0)
+ goto out;
+
+ if (retlen != sizeof(*buf))
+ goto out;
+
+ computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
+ offsetof(struct bcm_tag, header_crc));
+ if (computed_crc == buf->header_crc) {
+ char *board_id = &buf->board_id[0];
+ char *tag_version = &buf->tag_version[0];
+
+ /* Get rootfs offset and size from tag data */
+ kstrtou64(buf->flash_image_start, 10, rootfs_offset);
+ kstrtou64(buf->root_length, 10, rootfs_size);
+ kstrtouint(buf->dual_image, 10, rootfs_sequence);
+
+ pr_info("%s: CFE boot tag found at 0x%llx with version %s, board type %s and sequence number %u\n",
+ name, rootfs_part, tag_version, board_id,
+ *rootfs_sequence);
+
+ /* Adjust for flash offset */
+ *rootfs_offset -= BCM63XX_EXTENDED_SIZE;
+
+ /* Remove bcm_tag data from length */
+ *rootfs_size -= *rootfs_offset - rootfs_part;
+
+ rootfs_ok = true;
+ } else {
+ pr_warn("%s: CFE boot tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
+ name, rootfs_part, buf->header_crc, computed_crc);
+ goto out;
+ }
+
+out:
+ vfree(buf);
+ return rootfs_ok;
+}
+
+static int bcm963268_parse_cfe_partitions(struct mtd_info *master,
+ const struct mtd_partition **pparts, struct mtd_part_parser_data *data)
+{
+ int nrparts, curpart;
+ struct bcm963xx_nvram *nvram = NULL;
+ struct mtd_partition *parts;
+ u64 rootfs1_off, rootfs1_size;
+ unsigned int rootfs1_seq;
+ u64 rootfs2_off, rootfs2_size;
+ unsigned int rootfs2_seq;
+ bool rootfs1, rootfs2;
+ bool use_first;
+ int ret;
+
+ if (bcm963268_detect_cfe(master)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ nvram = vzalloc(sizeof(*nvram));
+ if (!nvram) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (bcm963268_read_nvram(master, nvram)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* We've just read the nvram from offset 0,
+ * so it must be located there.
+ */
+ if (nvram->nand_part_offset[PART_BOOT] != 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Get the rootfs partition locations */
+ rootfs1 = bcm963268_parse_rootfs_tag(master, "rootfs1",
+ nvram->nand_part_offset[PART_ROOTFS_1] * SZ_1K,
+ &rootfs1_off, &rootfs1_size, &rootfs1_seq);
+ rootfs2 = bcm963268_parse_rootfs_tag(master, "rootfs2",
+ nvram->nand_part_offset[PART_ROOTFS_2] * SZ_1K,
+ &rootfs2_off, &rootfs2_size, &rootfs2_seq);
+ if (!rootfs1 && !rootfs2) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Determine primary rootfs partition */
+ if (rootfs1 && rootfs2) {
+ bool use_latest = bcm963268_boot_latest(nvram);
+
+ /* Compare sequence numbers */
+ if (use_latest)
+ use_first = rootfs1_seq > rootfs2_seq;
+ else
+ use_first = rootfs1_seq < rootfs2_seq;
+
+ pr_info("CFE bootline selected %s image rootfs%u\n",
+ use_latest ? "latest" : "previous",
+ use_first ? 1 : 2);
+ } else {
+ use_first = rootfs1;
+ }
+
+ /* Partitions:
+ * 1 boot
+ * 2 rootfs
+ * 3 data
+ * 4 rootfs1_update
+ * 5 rootfs2_update
+ * 6 rootfs_other
+ */
+ nrparts = 6;
+ curpart = 0;
+
+ parts = kcalloc(nrparts, sizeof(*parts), GFP_KERNEL);
+ if (!parts) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ parts[curpart].name = "boot";
+ parts[curpart].offset = nvram->nand_part_offset[PART_BOOT] * SZ_1K;
+ parts[curpart].size = nvram->nand_part_size[PART_BOOT] * SZ_1K;
+ curpart++;
+
+ parts[curpart].name = "rootfs";
+ parts[curpart].offset = use_first ? rootfs1_off : rootfs2_off;
+ parts[curpart].size = use_first ? rootfs1_size : rootfs2_size;
+ curpart++;
+
+ parts[curpart].name = "data";
+ parts[curpart].offset = nvram->nand_part_offset[PART_DATA] * SZ_1K;
+ parts[curpart].size = nvram->nand_part_size[PART_DATA] * SZ_1K;
+ curpart++;
+
+ /* Full rootfs partitions for updates */
+ parts[curpart].name = "rootfs1_update";
+ parts[curpart].offset = nvram->nand_part_offset[PART_ROOTFS_1] * SZ_1K;
+ parts[curpart].size = nvram->nand_part_size[PART_ROOTFS_1] * SZ_1K;
+ curpart++;
+
+ parts[curpart].name = "rootfs2_update";
+ parts[curpart].offset = nvram->nand_part_offset[PART_ROOTFS_2] * SZ_1K;
+ parts[curpart].size = nvram->nand_part_size[PART_ROOTFS_2] * SZ_1K;
+ curpart++;
+
+ /* Other rootfs if both are available */
+ if (rootfs1 && rootfs2) {
+ parts[curpart].name = "rootfs_other";
+ parts[curpart].offset = use_first ? rootfs2_off : rootfs1_off;
+ parts[curpart].size = use_first ? rootfs2_size : rootfs1_size;
+ curpart++;
+ }
+
+ *pparts = parts;
+ ret = 0;
+
+out:
+ vfree(nvram);
+
+ if (ret < 0)
+ return ret;
+
+ return nrparts;
+};
+
+static struct mtd_part_parser bcm963268_cfe_parser = {
+ .name = "bcm963268part",
+ .parse_fn = bcm963268_parse_cfe_partitions,
+};
+module_mtd_part_parser(bcm963268_cfe_parser);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Arlott");
+MODULE_DESCRIPTION("MTD partitioning for BCM963268 CFE bootloaders");
--
2.1.4

--
Simon Arlott

2015-12-11 00:05:50

by Brian Norris

[permalink] [raw]
Subject: Re: [PATCH linux-next (v2) 3/3] mtd: part: Add BCM962368 CFE partitioning support

On Thu, Dec 10, 2015 at 11:10:13PM +0000, Simon Arlott wrote:
> Add partitioning support for BCM963268 boards with CFE bootloaders.
> The following partitions are defined:
> "boot": CFE and nvram data
> "rootfs": Currently selected rootfs
> "data": Configuration data
> "rootfs1_update": Container for the whole flash area used
> for the first rootfs to allow it to be
> updated.
> "rootfs2_update": Container for the whole flash area used
> for the second rootfs to allow it to be
> updated.
> "rootfs_other": The other (not currently selected) rootfs
>
> Example:
> [ 1.904302] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xf1
> [ 1.911000] nand: Macronix NAND 128MiB 3,3V 8-bit
> [ 1.915855] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
> [ 1.923797] bcm6368_nand 10000200.nand: detected 128MiB total, 128KiB blocks, 2KiB pages, 16B OOB, 8-bit, Hamming ECC
> [ 1.936994] Bad block table found at page 65472, version 0x01
> [ 1.944121] Bad block table found at page 65408, version 0x01
> [ 1.951166] nand_read_bbt: bad block at 0x000007480000
> [ 1.990043] bcm963268part: rootfs1: CFE boot tag found at 0x20000 with version 6, board type 963168VX and sequence number 2
> [ 2.003060] bcm963268part: rootfs2: CFE boot tag found at 0x4000000 with version 6, board type 963168VX and sequence number 1
> [ 2.015159] bcm963268part: CFE bootline selected latest image rootfs1
> [ 2.022080] 6 bcm963268part partitions found on MTD device brcmnand.0
> [ 2.042659] Creating 6 MTD partitions on "brcmnand.0":
> [ 2.048025] 0x000000000000-0x000000020000 : "boot"
> [ 2.062134] 0x000000040000-0x000001120000 : "rootfs"
> [ 2.077632] 0x000007b00000-0x000007f00000 : "data"
> [ 2.091363] 0x000000020000-0x000003ac0000 : "rootfs1_update"
> [ 2.106228] 0x000004000000-0x000007ac0000 : "rootfs2_update"
> [ 2.121093] 0x000004020000-0x000005060000 : "rootfs_other"
>
> The nvram contains the offset and size of the boot, rootfs1, rootfs2
> and data partitions. The presence of CFE and nvram is verified by
> reading from the boot partition which is assumed to be at offset 0
> and the process aborts if the nvram read indicates that this is not
> the case.
>
> There is bcm_tag information at the start of each rootfs that is used
> to determine which rootfs is newer and what its real offset/size is.
>
> The CFE bootline is used to select a rootfs.
>
> Signed-off-by: Simon Arlott <[email protected]>
> ---
> v2: Use external struct bcm963xx_nvram definition for bcm963268part.
>
> Removed support for the nand partition number field, it's not a
> standard Broadcom field (was added by MitraStar Technology Corp.).
>
> drivers/mtd/Kconfig | 21 +++
> drivers/mtd/Makefile | 1 +
> drivers/mtd/bcm963268part.c | 326 ++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 348 insertions(+)
> create mode 100644 drivers/mtd/bcm963268part.c
>
> diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
> index 42cc953..63cb2db 100644
> --- a/drivers/mtd/Kconfig
> +++ b/drivers/mtd/Kconfig
> @@ -148,6 +148,27 @@ config MTD_BCM63XX_PARTS
> This provides partions parsing for BCM63xx devices with CFE
> bootloaders.
>
> +config MTD_BCM963268_PARTS
> + tristate "BCM963268 CFE partitioning support"
> + depends on BMIPS_GENERIC

It'd be nice if this didn't hard-depend on MIPS. Can we do COMPILE_TEST?

> + select CRC32
> + help
> + This provides partitions parsing for BCM963268 boards with CFE
> + bootloaders. The following partitions are defined:
> + "boot": CFE and nvram data
> + "rootfs": Currently selected rootfs
> + "data": Configuration data
> + "rootfs1_update": Container for the whole flash area used
> + for the first rootfs to allow it to be
> + updated.
> + "rootfs2_update": Container for the whole flash area used
> + for the second rootfs to allow it to be
> + updated.
> + "rootfs_other": The other (not currently selected) rootfs
> +
> + A decision is made regarding which of the two rootfs is to be
> + used based on the nvram data.
> +
> config MTD_BCM47XX_PARTS
> tristate "BCM47XX partitioning support"
> depends on BCM47XX || ARCH_BCM_5301X
> diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
> index 99bb9a1..f0f4140 100644
> --- a/drivers/mtd/Makefile
> +++ b/drivers/mtd/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
> obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
> obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
> obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
> +obj-$(CONFIG_MTD_BCM963268_PARTS) += bcm963268part.o
> obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
>
> # 'Users' - code which presents functionality to userspace.
> diff --git a/drivers/mtd/bcm963268part.c b/drivers/mtd/bcm963268part.c
> new file mode 100644
> index 0000000..a519499
> --- /dev/null
> +++ b/drivers/mtd/bcm963268part.c
> @@ -0,0 +1,326 @@

...

> +static bool bcm963268_parse_rootfs_tag(struct mtd_info *master,
> + const char *name, loff_t rootfs_part, u64 *rootfs_offset,
> + u64 *rootfs_size, unsigned int *rootfs_sequence)
> +{
> + struct bcm_tag *buf;
> + int ret;
> + size_t retlen;
> + u32 computed_crc;
> + bool rootfs_ok = false;
> +
> + *rootfs_offset = 0;
> + *rootfs_size = 0;
> + *rootfs_sequence = 0;
> +
> + buf = vmalloc(sizeof(struct bcm_tag));
> + if (!buf)
> + goto out;
> +
> + ret = mtd_read(master, rootfs_part, sizeof(*buf), &retlen, (void *)buf);
> + if (ret < 0)
> + goto out;
> +
> + if (retlen != sizeof(*buf))
> + goto out;
> +
> + computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
> + offsetof(struct bcm_tag, header_crc));
> + if (computed_crc == buf->header_crc) {
> + char *board_id = &buf->board_id[0];
> + char *tag_version = &buf->tag_version[0];
> +
> + /* Get rootfs offset and size from tag data */
> + kstrtou64(buf->flash_image_start, 10, rootfs_offset);
> + kstrtou64(buf->root_length, 10, rootfs_size);
> + kstrtouint(buf->dual_image, 10, rootfs_sequence);

drivers/mtd/bcm963268part.c: In function 'bcm963268_parse_rootfs_tag':
drivers/mtd/bcm963268part.c:186:12: warning: ignoring return value of 'kstrtou64', declared with attribute warn_unused_result [-Wunused-result]
drivers/mtd/bcm963268part.c:187:12: warning: ignoring return value of 'kstrtou64', declared with attribute warn_unused_result [-Wunused-result]
drivers/mtd/bcm963268part.c:188:13: warning: ignoring return value of 'kstrtouint', declared with attribute warn_unused_result [-Wunused-result]

Fixing these warnings should improve your robustness against malformed
input.

> +
> + pr_info("%s: CFE boot tag found at 0x%llx with version %s, board type %s and sequence number %u\n",
> + name, rootfs_part, tag_version, board_id,
> + *rootfs_sequence);
> +
> + /* Adjust for flash offset */
> + *rootfs_offset -= BCM63XX_EXTENDED_SIZE;
> +
> + /* Remove bcm_tag data from length */
> + *rootfs_size -= *rootfs_offset - rootfs_part;
> +
> + rootfs_ok = true;
> + } else {
> + pr_warn("%s: CFE boot tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
> + name, rootfs_part, buf->header_crc, computed_crc);
> + goto out;
> + }
> +
> +out:
> + vfree(buf);
> + return rootfs_ok;
> +}

Brian