From 716ca530e1c4515d8683c9d5be3d56b301758b66 Mon Sep 17 00:00:00 2001 From: James <> Date: Wed, 4 Nov 2015 11:49:21 +0000 Subject: trunk-47381 --- .../425-bcm63xxpart_parse_paritions_from_dt.patch | 357 +++++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 target/linux/brcm63xx/patches-3.18/425-bcm63xxpart_parse_paritions_from_dt.patch (limited to 'target/linux/brcm63xx/patches-3.18/425-bcm63xxpart_parse_paritions_from_dt.patch') diff --git a/target/linux/brcm63xx/patches-3.18/425-bcm63xxpart_parse_paritions_from_dt.patch b/target/linux/brcm63xx/patches-3.18/425-bcm63xxpart_parse_paritions_from_dt.patch new file mode 100644 index 0000000..53fc4c5 --- /dev/null +++ b/target/linux/brcm63xx/patches-3.18/425-bcm63xxpart_parse_paritions_from_dt.patch @@ -0,0 +1,357 @@ +--- a/drivers/mtd/bcm63xxpart.c ++++ b/drivers/mtd/bcm63xxpart.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -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", + }; + -- cgit v1.2.3