]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mtd/bcm63xxpart.c
mtd: bcm63xxpart: give width specifier an 'int', not 'size_t'
[karo-tx-linux.git] / drivers / mtd / bcm63xxpart.c
index 44093699859321ce4164ed63d368ec8b72c5d49b..41d1d3149c611777fcd904d12546ed50db739cec 100644 (file)
@@ -24,6 +24,8 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/bcm963xx_nvram.h>
+#include <linux/bcm963xx_tag.h>
 #include <linux/crc32.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/mach-bcm63xx/bcm63xx_nvram.h>
-#include <asm/mach-bcm63xx/bcm963xx_tag.h>
-#include <asm/mach-bcm63xx/board_bcm963xx.h>
+#define BCM963XX_CFE_BLOCK_SIZE                SZ_64K  /* always at least 64KiB */
 
-#define BCM63XX_EXTENDED_SIZE  0xBFC00000      /* Extended flash address */
+#define BCM963XX_CFE_MAGIC_OFFSET      0x4e0
+#define BCM963XX_CFE_VERSION_OFFSET    0x570
+#define BCM963XX_NVRAM_OFFSET          0x580
 
-#define BCM63XX_CFE_BLOCK_SIZE SZ_64K          /* always at least 64KiB */
-
-#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
+/* Ensure strings read from flash structs are null terminated */
+#define STR_NULL_TERMINATE(x) \
+       do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
 
 static int bcm63xx_detect_cfe(struct mtd_info *master)
 {
@@ -60,71 +62,133 @@ static int bcm63xx_detect_cfe(struct mtd_info *master)
                return 0;
 
        /* very old CFE's do not have the cfe-v string, so check for magic */
-       ret = mtd_read(master, BCM63XX_CFE_MAGIC_OFFSET, 8, &retlen,
+       ret = mtd_read(master, BCM963XX_CFE_MAGIC_OFFSET, 8, &retlen,
                       (void *)buf);
        buf[retlen] = 0;
 
        return strncmp("CFE1CFE1", buf, 8);
 }
 
-static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
-                                       const struct mtd_partition **pparts,
-                                       struct mtd_part_parser_data *data)
+static int bcm63xx_read_nvram(struct mtd_info *master,
+       struct bcm963xx_nvram *nvram)
+{
+       u32 actual_crc, expected_crc;
+       size_t retlen;
+       int ret;
+
+       /* extract nvram data */
+       ret = mtd_read(master, BCM963XX_NVRAM_OFFSET, BCM963XX_NVRAM_V5_SIZE,
+                       &retlen, (void *)nvram);
+       if (ret)
+               return ret;
+
+       ret = bcm963xx_nvram_checksum(nvram, &expected_crc, &actual_crc);
+       if (ret)
+               pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
+                       expected_crc, actual_crc);
+
+       if (!nvram->psi_size)
+               nvram->psi_size = BCM963XX_DEFAULT_PSI_SIZE;
+
+       return 0;
+}
+
+static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name,
+       loff_t tag_offset, struct bcm_tag *buf)
+{
+       int ret;
+       size_t retlen;
+       u32 computed_crc;
+
+       ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
+       if (ret)
+               return ret;
+
+       if (retlen != sizeof(*buf))
+               return -EIO;
+
+       computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
+                               offsetof(struct bcm_tag, header_crc));
+       if (computed_crc == buf->header_crc) {
+               STR_NULL_TERMINATE(buf->board_id);
+               STR_NULL_TERMINATE(buf->tag_version);
+
+               pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
+                       name, tag_offset, buf->tag_version, buf->board_id);
+
+               return 0;
+       }
+
+       pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
+               name, tag_offset, buf->header_crc, computed_crc);
+       return 1;
+}
+
+static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
+       const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)
 {
        /* CFE, NVRAM and global Linux are always present */
        int nrparts = 3, curpart = 0;
-       struct bcm_tag *buf;
+       struct bcm_tag *buf = NULL;
        struct mtd_partition *parts;
        int ret;
-       size_t retlen;
        unsigned int rootfsaddr, kerneladdr, spareaddr;
        unsigned int rootfslen, kernellen, sparelen, totallen;
        unsigned int cfelen, nvramlen;
        unsigned int cfe_erasesize;
        int i;
-       u32 computed_crc;
        bool rootfs_first = false;
 
-       if (bcm63xx_detect_cfe(master))
-               return -EINVAL;
-
        cfe_erasesize = max_t(uint32_t, master->erasesize,
-                             BCM63XX_CFE_BLOCK_SIZE);
+                             BCM963XX_CFE_BLOCK_SIZE);
 
        cfelen = cfe_erasesize;
-       nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
+       nvramlen = nvram->psi_size * SZ_1K;
        nvramlen = roundup(nvramlen, cfe_erasesize);
 
-       /* Allocate memory for buffer */
        buf = vmalloc(sizeof(struct bcm_tag));
        if (!buf)
                return -ENOMEM;
 
        /* Get the tag */
-       ret = mtd_read(master, cfelen, sizeof(struct bcm_tag), &retlen,
-                      (void *)buf);
-
-       if (retlen != sizeof(struct bcm_tag)) {
-               vfree(buf);
-               return -EIO;
-       }
+       ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf);
+       if (!ret) {
+               STR_NULL_TERMINATE(buf->flash_image_start);
+               if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
+                               rootfsaddr < BCM963XX_EXTENDED_SIZE) {
+                       pr_err("invalid rootfs address: %*ph\n",
+                               (int)sizeof(buf->flash_image_start),
+                               buf->flash_image_start);
+                       goto invalid_tag;
+               }
 
-       computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
-                               offsetof(struct bcm_tag, header_crc));
-       if (computed_crc == buf->header_crc) {
-               char *boardid = &(buf->board_id[0]);
-               char *tagversion = &(buf->tag_version[0]);
+               STR_NULL_TERMINATE(buf->kernel_address);
+               if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
+                               kerneladdr < BCM963XX_EXTENDED_SIZE) {
+                       pr_err("invalid kernel address: %*ph\n",
+                               (int)sizeof(buf->kernel_address),
+                               buf->kernel_address);
+                       goto invalid_tag;
+               }
 
-               sscanf(buf->flash_image_start, "%u", &rootfsaddr);
-               sscanf(buf->kernel_address, "%u", &kerneladdr);
-               sscanf(buf->kernel_length, "%u", &kernellen);
-               sscanf(buf->total_length, "%u", &totallen);
+               STR_NULL_TERMINATE(buf->kernel_length);
+               if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
+                       pr_err("invalid kernel length: %*ph\n",
+                               (int)sizeof(buf->kernel_length),
+                               buf->kernel_length);
+                       goto invalid_tag;
+               }
 
-               pr_info("CFE boot tag found with version %s and board type %s\n",
-                       tagversion, boardid);
+               STR_NULL_TERMINATE(buf->total_length);
+               if (kstrtouint(buf->total_length, 10, &totallen)) {
+                       pr_err("invalid total length: %*ph\n",
+                               (int)sizeof(buf->total_length),
+                               buf->total_length);
+                       goto invalid_tag;
+               }
 
-               kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
-               rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE;
+               kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE;
+               rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE;
                spareaddr = roundup(totallen, master->erasesize) + cfelen;
 
                if (rootfsaddr < kerneladdr) {
@@ -136,13 +200,14 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                        rootfsaddr = kerneladdr + kernellen;
                        rootfslen = spareaddr - rootfsaddr;
                }
-       } else {
-               pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n",
-                       buf->header_crc, computed_crc);
+       } else if (ret > 0) {
+invalid_tag:
                kernellen = 0;
                rootfslen = 0;
                rootfsaddr = 0;
                spareaddr = cfelen;
+       } else {
+               goto out;
        }
        sparelen = master->size - spareaddr - nvramlen;
 
@@ -153,11 +218,10 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
        if (kernellen > 0)
                nrparts++;
 
-       /* Ask kernel for more memory */
        parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
        if (!parts) {
-               vfree(buf);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
        /* Start building partition list */
@@ -208,9 +272,43 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                sparelen);
 
        *pparts = parts;
+       ret = 0;
+
+out:
        vfree(buf);
 
+       if (ret)
+               return ret;
+
        return nrparts;
+}
+
+static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
+                                       const struct mtd_partition **pparts,
+                                       struct mtd_part_parser_data *data)
+{
+       struct bcm963xx_nvram *nvram = NULL;
+       int ret;
+
+       if (bcm63xx_detect_cfe(master))
+               return -EINVAL;
+
+       nvram = vzalloc(sizeof(*nvram));
+       if (!nvram)
+               return -ENOMEM;
+
+       ret = bcm63xx_read_nvram(master, nvram);
+       if (ret)
+               goto out;
+
+       if (!mtd_type_is_nand(master))
+               ret = bcm63xx_parse_cfe_nor_partitions(master, pparts, nvram);
+       else
+               ret = -EINVAL;
+
+out:
+       vfree(nvram);
+       return ret;
 };
 
 static struct mtd_part_parser bcm63xx_cfe_parser = {