brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · 6e7b1ae Raw
172 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * BCM63XX CFE image tag parser4 *5 * Copyright © 2006-2008  Florian Fainelli <florian@openwrt.org>6 *			  Mike Albon <malbon@openwrt.org>7 * Copyright © 2009-2010  Daniel Dickinson <openwrt@cshore.neomailbox.net>8 * Copyright © 2011-2013  Jonas Gorski <jonas.gorski@gmail.com>9 */10 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt12 13#include <linux/bcm963xx_nvram.h>14#include <linux/bcm963xx_tag.h>15#include <linux/crc32.h>16#include <linux/module.h>17#include <linux/kernel.h>18#include <linux/sizes.h>19#include <linux/slab.h>20#include <linux/vmalloc.h>21#include <linux/mtd/mtd.h>22#include <linux/mtd/partitions.h>23#include <linux/of.h>24 25#ifdef CONFIG_MIPS26#include <asm/bootinfo.h>27#include <asm/fw/cfe/cfe_api.h>28#endif /* CONFIG_MIPS */29 30#define BCM963XX_CFE_BLOCK_SIZE		SZ_64K	/* always at least 64KiB */31 32#define BCM963XX_CFE_MAGIC_OFFSET	0x4e033#define BCM963XX_CFE_VERSION_OFFSET	0x57034#define BCM963XX_NVRAM_OFFSET		0x58035 36/* Ensure strings read from flash structs are null terminated */37#define STR_NULL_TERMINATE(x) \38	do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)39 40static inline int bcm63xx_detect_cfe(void)41{42	int ret = 0;43 44#ifdef CONFIG_MIPS45	ret = (fw_arg3 == CFE_EPTSEAL);46#endif /* CONFIG_MIPS */47 48	return ret;49}50 51static int bcm63xx_read_nvram(struct mtd_info *master,52	struct bcm963xx_nvram *nvram)53{54	u32 actual_crc, expected_crc;55	size_t retlen;56	int ret;57 58	/* extract nvram data */59	ret = mtd_read(master, BCM963XX_NVRAM_OFFSET, BCM963XX_NVRAM_V5_SIZE,60			&retlen, (void *)nvram);61	if (ret)62		return ret;63 64	ret = bcm963xx_nvram_checksum(nvram, &expected_crc, &actual_crc);65	if (ret)66		pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",67			expected_crc, actual_crc);68 69	if (!nvram->psi_size)70		nvram->psi_size = BCM963XX_DEFAULT_PSI_SIZE;71 72	return 0;73}74 75static const char * const bcm63xx_cfe_part_types[] = {76	"bcm963xx-imagetag",77	NULL,78};79 80static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,81	const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)82{83	struct mtd_partition *parts;84	int nrparts = 3, curpart = 0;85	unsigned int cfelen, nvramlen;86	unsigned int cfe_erasesize;87	int i;88 89	cfe_erasesize = max_t(uint32_t, master->erasesize,90			      BCM963XX_CFE_BLOCK_SIZE);91 92	cfelen = cfe_erasesize;93	nvramlen = nvram->psi_size * SZ_1K;94	nvramlen = roundup(nvramlen, cfe_erasesize);95 96	parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);97	if (!parts)98		return -ENOMEM;99 100	/* Start building partition list */101	parts[curpart].name = "CFE";102	parts[curpart].offset = 0;103	parts[curpart].size = cfelen;104	curpart++;105 106	parts[curpart].name = "nvram";107	parts[curpart].offset = master->size - nvramlen;108	parts[curpart].size = nvramlen;109	curpart++;110 111	/* Global partition "linux" to make easy firmware upgrade */112	parts[curpart].name = "linux";113	parts[curpart].offset = cfelen;114	parts[curpart].size = master->size - cfelen - nvramlen;115	parts[curpart].types = bcm63xx_cfe_part_types;116 117	for (i = 0; i < nrparts; i++)118		pr_info("Partition %d is %s offset %llx and length %llx\n", i,119			parts[i].name, parts[i].offset,	parts[i].size);120 121	*pparts = parts;122 123	return nrparts;124}125 126static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,127					const struct mtd_partition **pparts,128					struct mtd_part_parser_data *data)129{130	struct bcm963xx_nvram *nvram = NULL;131	int ret;132 133	if (!bcm63xx_detect_cfe())134		return -EINVAL;135 136	nvram = vzalloc(sizeof(*nvram));137	if (!nvram)138		return -ENOMEM;139 140	ret = bcm63xx_read_nvram(master, nvram);141	if (ret)142		goto out;143 144	if (!mtd_type_is_nand(master))145		ret = bcm63xx_parse_cfe_nor_partitions(master, pparts, nvram);146	else147		ret = -EINVAL;148 149out:150	vfree(nvram);151	return ret;152};153 154static const struct of_device_id parse_bcm63xx_cfe_match_table[] = {155	{ .compatible = "brcm,bcm963xx-cfe-nor-partitions" },156	{},157};158MODULE_DEVICE_TABLE(of, parse_bcm63xx_cfe_match_table);159 160static struct mtd_part_parser bcm63xx_cfe_parser = {161	.parse_fn = bcm63xx_parse_cfe_partitions,162	.name = "bcm63xxpart",163	.of_match_table = parse_bcm63xx_cfe_match_table,164};165module_mtd_part_parser(bcm63xx_cfe_parser);166 167MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");168MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");169MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");170MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com");171MODULE_DESCRIPTION("MTD partitioning for BCM63XX CFE bootloaders");172