123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- --- a/drivers/mtd/bcm63xxpart.c
- +++ b/drivers/mtd/bcm63xxpart.c
- @@ -32,6 +32,7 @@
- #include <linux/vmalloc.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
- +#include <linux/of.h>
-
- #include <asm/mach-bcm63xx/bcm63xx_nvram.h>
- #include <asm/mach-bcm63xx/bcm963xx_tag.h>
- @@ -43,66 +44,35 @@
-
- #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
-
- -static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
- - struct mtd_partition **pparts,
- - struct mtd_part_parser_data *data)
- +static bool node_has_compatible(struct device_node *pp)
- +{
- + return of_get_property(pp, "compatible", NULL);
- +}
- +
- +static int parse_bcmtag(struct mtd_info *master, struct mtd_partition *pparts,
- + int next_part, size_t offset, size_t size)
- {
- - /* CFE, NVRAM and global Linux are always present */
- - int nrparts = 3, curpart = 0;
- struct bcm_tag *buf;
- - struct mtd_partition *parts;
- + u32 computed_crc;
- int ret;
- size_t retlen;
- - unsigned int rootfsaddr, kerneladdr, spareaddr, nvramaddr;
- - unsigned int rootfslen, kernellen, sparelen, totallen;
- - unsigned int cfelen, nvramlen;
- - unsigned int cfe_erasesize;
- - unsigned int caldatalen1 = 0, caldataaddr1 = 0;
- - unsigned int caldatalen2 = 0, caldataaddr2 = 0;
- - int i;
- - u32 computed_crc;
- + unsigned int rootfsaddr, kerneladdr;
- + unsigned int rootfslen, kernellen, totallen;
- bool rootfs_first = false;
- -
- - if (!bcm63xx_is_cfe_present())
- - return -EINVAL;
- -
- - cfe_erasesize = max_t(uint32_t, master->erasesize,
- - BCM63XX_CFE_BLOCK_SIZE);
- -
- - cfelen = cfe_erasesize;
- - nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
- - nvramlen = roundup(nvramlen, cfe_erasesize);
- - nvramaddr = master->size - nvramlen;
- -
- - if (data) {
- - if (data->caldata[0]) {
- - caldatalen1 = cfe_erasesize;
- - caldataaddr1 = rounddown(data->caldata[0],
- - cfe_erasesize);
- - }
- - if (data->caldata[1]) {
- - caldatalen2 = cfe_erasesize;
- - caldataaddr2 = rounddown(data->caldata[1],
- - cfe_erasesize);
- - }
- - if (caldataaddr1 == caldataaddr2) {
- - caldataaddr2 = 0;
- - caldatalen2 = 0;
- - }
- - }
- + int curr_part = next_part;
-
- /* Allocate memory for buffer */
- - buf = vmalloc(sizeof(struct bcm_tag));
- + buf = vmalloc(sizeof(*buf));
- if (!buf)
- return -ENOMEM;
-
- /* Get the tag */
- - ret = mtd_read(master, cfelen, sizeof(struct bcm_tag), &retlen,
- + ret = mtd_read(master, offset, sizeof(*buf), &retlen,
- (void *)buf);
-
- - if (retlen != sizeof(struct bcm_tag)) {
- + if (retlen != sizeof(*buf)) {
- vfree(buf);
- - return -EIO;
- + return 0;
- }
-
- computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
- @@ -121,7 +91,6 @@ static int bcm63xx_parse_cfe_partitions(
-
- kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
- rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE;
- - spareaddr = roundup(totallen, master->erasesize) + cfelen;
-
- if (rootfsaddr < kerneladdr) {
- /* default Broadcom layout */
- @@ -130,8 +99,8 @@ static int bcm63xx_parse_cfe_partitions(
- } else {
- /* OpenWrt layout */
- rootfsaddr = kerneladdr + kernellen;
- - rootfslen = buf->real_rootfs_length;
- - spareaddr = rootfsaddr + rootfslen;
- + rootfslen = size - kernellen -
- + sizeof(*buf);
- }
- } else {
- pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n",
- @@ -139,16 +108,153 @@ static int bcm63xx_parse_cfe_partitions(
- kernellen = 0;
- rootfslen = 0;
- rootfsaddr = 0;
- - spareaddr = cfelen;
- }
- - sparelen = min_not_zero(nvramaddr, caldataaddr1) - spareaddr;
-
- - /* Determine number of partitions */
- - if (rootfslen > 0)
- - nrparts++;
- + if (kernellen > 0) {
- + int kernelpart = curr_part;
-
- - if (kernellen > 0)
- - nrparts++;
- + if (rootfslen > 0 && rootfs_first)
- + kernelpart++;
- + pparts[kernelpart].name = "kernel";
- + pparts[kernelpart].offset = kerneladdr;
- + pparts[kernelpart].size = kernellen;
- + curr_part++;
- + }
- +
- + if (rootfslen > 0) {
- + int rootfspart = curr_part;
- +
- + if (kernellen > 0 && rootfs_first)
- + rootfspart--;
- + pparts[rootfspart].name = "rootfs";
- + pparts[rootfspart].offset = rootfsaddr;
- + pparts[rootfspart].size = rootfslen;
- +
- + curr_part++;
- + }
- +
- + vfree(buf);
- +
- + return curr_part - next_part;
- +}
- +
- +
- +static int bcm63xx_parse_cfe_partitions_of(struct mtd_info *master,
- + struct mtd_partition **pparts,
- + struct mtd_part_parser_data *data)
- +{
- + struct device_node *dp = data->of_node;
- + struct device_node *pp;
- + int i, nr_parts = 0;
- + const char *partname;
- + int len;
- +
- + for_each_child_of_node(dp, pp) {
- + if (node_has_compatible(pp))
- + continue;
- +
- + if (!of_get_property(pp, "reg", &len))
- + continue;
- +
- + partname = of_get_property(pp, "label", &len);
- + if (!partname)
- + partname = of_get_property(pp, "name", &len);
- +
- + if (!strcmp(partname, "linux"))
- + nr_parts += 2;
- +
- + nr_parts++;
- + }
- +
- + *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
- + if (!*pparts)
- + return -ENOMEM;
- +
- + i = 0;
- + for_each_child_of_node(dp, pp) {
- + const __be32 *reg;
- + int a_cells, s_cells;
- + size_t size, offset;
- +
- + if (node_has_compatible(pp))
- + continue;
- +
- + reg = of_get_property(pp, "reg", &len);
- + if (!reg)
- + continue;
- +
- + a_cells = of_n_addr_cells(pp);
- + s_cells = of_n_size_cells(pp);
- + offset = of_read_number(reg, a_cells);
- + size = of_read_number(reg + a_cells, s_cells);
- + partname = of_get_property(pp, "label", &len);
- + if (!partname)
- + partname = of_get_property(pp, "name", &len);
- +
- + if (!strcmp(partname, "linux"))
- + i += parse_bcmtag(master, *pparts, i, offset, size);
- +
- + if (of_get_property(pp, "read-only", &len))
- + (*pparts)[i].mask_flags |= MTD_WRITEABLE;
- +
- + if (of_get_property(pp, "lock", &len))
- + (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
- +
- + (*pparts)[i].offset = offset;
- + (*pparts)[i].size = size;
- + (*pparts)[i].name = partname;
- +
- + i++;
- + }
- +
- + return i;
- +}
- +
- +static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
- + struct mtd_partition **pparts,
- + struct mtd_part_parser_data *data)
- +{
- + /* CFE, NVRAM and global Linux are always present */
- + int nrparts = 5, curpart = 0;
- + struct mtd_partition *parts;
- + unsigned int nvramaddr;
- + unsigned int cfelen, nvramlen;
- + unsigned int cfe_erasesize;
- + unsigned int caldatalen1 = 0, caldataaddr1 = 0;
- + unsigned int caldatalen2 = 0, caldataaddr2 = 0;
- + unsigned int imageaddr, imagelen;
- + int i;
- +
- + if (!bcm63xx_is_cfe_present())
- + return -EINVAL;
- +
- + cfe_erasesize = max_t(uint32_t, master->erasesize,
- + BCM63XX_CFE_BLOCK_SIZE);
- +
- + cfelen = cfe_erasesize;
- + nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
- + nvramlen = roundup(nvramlen, cfe_erasesize);
- + nvramaddr = master->size - nvramlen;
- +
- + if (data) {
- + if (data->caldata[0]) {
- + caldatalen1 = cfe_erasesize;
- + caldataaddr1 = rounddown(data->caldata[0],
- + cfe_erasesize);
- + }
- + if (data->caldata[1]) {
- + caldatalen2 = cfe_erasesize;
- + caldataaddr2 = rounddown(data->caldata[1],
- + cfe_erasesize);
- + }
- + if (caldataaddr1 == caldataaddr2) {
- + caldataaddr2 = 0;
- + caldatalen2 = 0;
- + }
- + }
- +
- + imageaddr = cfelen;
- + imagelen = min_not_zero(nvramaddr, caldataaddr1) - imageaddr;
-
- if (caldatalen1 > 0)
- nrparts++;
- @@ -158,10 +264,8 @@ static int bcm63xx_parse_cfe_partitions(
-
- /* Ask kernel for more memory */
- parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
- - if (!parts) {
- - vfree(buf);
- + if (!parts)
- return -ENOMEM;
- - }
-
- /* Start building partition list */
- parts[curpart].name = "CFE";
- @@ -169,29 +273,7 @@ static int bcm63xx_parse_cfe_partitions(
- parts[curpart].size = cfelen;
- curpart++;
-
- - if (kernellen > 0) {
- - int kernelpart = curpart;
- -
- - if (rootfslen > 0 && rootfs_first)
- - kernelpart++;
- - parts[kernelpart].name = "kernel";
- - parts[kernelpart].offset = kerneladdr;
- - parts[kernelpart].size = kernellen;
- - curpart++;
- - }
- -
- - if (rootfslen > 0) {
- - int rootfspart = curpart;
- -
- - if (kernellen > 0 && rootfs_first)
- - rootfspart--;
- - parts[rootfspart].name = "rootfs";
- - parts[rootfspart].offset = rootfsaddr;
- - parts[rootfspart].size = rootfslen;
- - if (sparelen > 0 && !rootfs_first)
- - parts[rootfspart].size += sparelen;
- - curpart++;
- - }
- + curpart += parse_bcmtag(master, parts, curpart, imageaddr, imagelen);
-
- if (caldatalen1 > 0) {
- if (caldatalen2 > 0)
- @@ -217,25 +299,33 @@ static int bcm63xx_parse_cfe_partitions(
-
- /* Global partition "linux" to make easy firmware upgrade */
- parts[curpart].name = "linux";
- - parts[curpart].offset = cfelen;
- - parts[curpart].size = min_not_zero(nvramaddr, caldataaddr1) - cfelen;
- + parts[curpart].offset = imageaddr;
- + parts[curpart].size = imagelen;
- + curpart++;
-
- - for (i = 0; i < nrparts; i++)
- + for (i = 0; i < curpart; i++)
- pr_info("Partition %d is %s offset %llx and length %llx\n", i,
- parts[i].name, parts[i].offset, parts[i].size);
-
- - pr_info("Spare partition is offset %x and length %x\n", spareaddr,
- - sparelen);
- -
- *pparts = parts;
- - vfree(buf);
-
- return nrparts;
- };
-
- +
- +static int bcm63xx_parse_partitions(struct mtd_info *master,
- + struct mtd_partition **pparts,
- + struct mtd_part_parser_data *data)
- +{
- + if (data && data->of_node)
- + return bcm63xx_parse_cfe_partitions_of(master, pparts, data);
- + else
- + return bcm63xx_parse_cfe_partitions(master, pparts, data);
- +}
- +
- static struct mtd_part_parser bcm63xx_cfe_parser = {
- .owner = THIS_MODULE,
- - .parse_fn = bcm63xx_parse_cfe_partitions,
- + .parse_fn = bcm63xx_parse_partitions,
- .name = "bcm63xxpart",
- };
-
|