mtd: nand: switch `check_pattern()' to standard `memcmp()'
[firefly-linux-kernel-4.4.55.git] / drivers / mtd / nand / nand_bbt.c
index e962167c9b712a1c5458d9afa83da544922313b7..5c9c0b2f09d4ad81b762059eb4795197fafc711e 100644 (file)
@@ -107,10 +107,8 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
        p += end;
 
        /* Compare the pattern */
-       for (i = 0; i < td->len; i++) {
-               if (p[i] != td->pattern[i])
-                       return -1;
-       }
+       if (memcmp(p, td->pattern, td->len))
+               return -1;
 
        if (td->options & NAND_BBT_SCANEMPTY) {
                p += td->len;
@@ -178,7 +176,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
 static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                struct nand_bbt_descr *td, int offs)
 {
-       int res, i, j, act = 0;
+       int res, ret = 0, i, j, act = 0;
        struct nand_chip *this = mtd->priv;
        size_t retlen, len, totlen;
        loff_t from;
@@ -204,11 +202,18 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                }
                res = mtd->read(mtd, from, len, &retlen, buf);
                if (res < 0) {
-                       if (retlen != len) {
-                               pr_info("nand_bbt: error reading bad block table\n");
+                       if (mtd_is_eccerr(res)) {
+                               pr_info("nand_bbt: ECC error in BBT at "
+                                       "0x%012llx\n", from & ~mtd->writesize);
+                               return res;
+                       } else if (mtd_is_bitflip(res)) {
+                               pr_info("nand_bbt: corrected error in BBT at "
+                                       "0x%012llx\n", from & ~mtd->writesize);
+                               ret = res;
+                       } else {
+                               pr_info("nand_bbt: error reading BBT\n");
                                return res;
                        }
-                       pr_warn("nand_bbt: ECC error while reading bad block table\n");
                }
 
                /* Analyse data */
@@ -242,7 +247,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                totlen -= len;
                from += len;
        }
-       return 0;
+       return ret;
 }
 
 /**
@@ -400,7 +405,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 
        ret = scan_read_raw_oob(mtd, buf, offs, readlen);
        /* Ignore ECC errors when checking for BBM */
-       if (ret && ret != -EUCLEAN && ret != -EBADMSG)
+       if (ret && !mtd_is_bitflip_or_eccerr(ret))
                return ret;
 
        for (j = 0; j < len; j++, buf += scanlen) {
@@ -430,7 +435,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
                 */
                ret = mtd->read_oob(mtd, offs, &ops);
                /* Ignore ECC errors when checking for BBM */
-               if (ret && ret != -EUCLEAN && ret != -EBADMSG)
+               if (ret && !mtd_is_bitflip_or_eccerr(ret))
                        return ret;
 
                if (check_short_pattern(buf, bd))
@@ -875,7 +880,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
  */
 static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
 {
-       int i, chips, writeops, chipsel, res;
+       int i, chips, writeops, create, chipsel, res, res2;
        struct nand_chip *this = mtd->priv;
        struct nand_bbt_descr *td = this->bbt_td;
        struct nand_bbt_descr *md = this->bbt_md;
@@ -889,77 +894,89 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
        for (i = 0; i < chips; i++) {
                writeops = 0;
+               create = 0;
                rd = NULL;
                rd2 = NULL;
+               res = res2 = 0;
                /* Per chip or per device? */
                chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
                /* Mirrored table available? */
                if (md) {
                        if (td->pages[i] == -1 && md->pages[i] == -1) {
+                               create = 1;
                                writeops = 0x03;
-                               goto create;
-                       }
-
-                       if (td->pages[i] == -1) {
+                       } else if (td->pages[i] == -1) {
                                rd = md;
-                               td->version[i] = md->version[i];
                                writeops = 0x01;
-                               goto writecheck;
-                       }
-
-                       if (md->pages[i] == -1) {
+                       } else if (md->pages[i] == -1) {
                                rd = td;
-                               md->version[i] = td->version[i];
                                writeops = 0x02;
-                               goto writecheck;
-                       }
-
-                       if (td->version[i] == md->version[i]) {
+                       } else if (td->version[i] == md->version[i]) {
                                rd = td;
                                if (!(td->options & NAND_BBT_VERSION))
                                        rd2 = md;
-                               goto writecheck;
-                       }
-
-                       if (((int8_t)(td->version[i] - md->version[i])) > 0) {
+                       } else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
                                rd = td;
-                               md->version[i] = td->version[i];
                                writeops = 0x02;
                        } else {
                                rd = md;
-                               td->version[i] = md->version[i];
                                writeops = 0x01;
                        }
-
-                       goto writecheck;
-
                } else {
                        if (td->pages[i] == -1) {
+                               create = 1;
                                writeops = 0x01;
-                               goto create;
+                       } else {
+                               rd = td;
                        }
-                       rd = td;
-                       goto writecheck;
                }
-       create:
-               /* Create the bad block table by scanning the device? */
-               if (!(td->options & NAND_BBT_CREATE))
-                       continue;
 
-               /* Create the table in memory by scanning the chip(s) */
-               if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
-                       create_bbt(mtd, buf, bd, chipsel);
+               if (create) {
+                       /* Create the bad block table by scanning the device? */
+                       if (!(td->options & NAND_BBT_CREATE))
+                               continue;
+
+                       /* Create the table in memory by scanning the chip(s) */
+                       if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
+                               create_bbt(mtd, buf, bd, chipsel);
+
+                       td->version[i] = 1;
+                       if (md)
+                               md->version[i] = 1;
+               }
 
-               td->version[i] = 1;
-               if (md)
-                       md->version[i] = 1;
-       writecheck:
                /* Read back first? */
-               if (rd)
-                       read_abs_bbt(mtd, buf, rd, chipsel);
+               if (rd) {
+                       res = read_abs_bbt(mtd, buf, rd, chipsel);
+                       if (mtd_is_eccerr(res)) {
+                               /* Mark table as invalid */
+                               rd->pages[i] = -1;
+                               rd->version[i] = 0;
+                               i--;
+                               continue;
+                       }
+               }
                /* If they weren't versioned, read both */
-               if (rd2)
-                       read_abs_bbt(mtd, buf, rd2, chipsel);
+               if (rd2) {
+                       res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+                       if (mtd_is_eccerr(res2)) {
+                               /* Mark table as invalid */
+                               rd2->pages[i] = -1;
+                               rd2->version[i] = 0;
+                               i--;
+                               continue;
+                       }
+               }
+
+               /* Scrub the flash table(s)? */
+               if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
+                       writeops = 0x03;
+
+               /* Update version numbers before writing */
+               if (md) {
+                       td->version[i] = max(td->version[i], md->version[i]);
+                       md->version[i] = td->version[i];
+               }
 
                /* Write the bad block table to the device? */
                if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
@@ -1275,26 +1292,27 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
        .pattern = mirror_pattern
 };
 
+#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
 /**
- * nand_create_default_bbt_descr - [INTERN] Creates a BBT descriptor structure
+ * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
  * @this: NAND chip to create descriptor for
  *
  * This function allocates and initializes a nand_bbt_descr for BBM detection
- * based on the properties of "this". The new descriptor is stored in
+ * based on the properties of @this. The new descriptor is stored in
  * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
  * passed to this function.
  */
-static int nand_create_default_bbt_descr(struct nand_chip *this)
+static int nand_create_badblock_pattern(struct nand_chip *this)
 {
        struct nand_bbt_descr *bd;
        if (this->badblock_pattern) {
-               pr_warn("BBT descr already allocated; not replacing\n");
+               pr_warn("Bad block pattern already allocated; not replacing\n");
                return -EINVAL;
        }
        bd = kzalloc(sizeof(*bd), GFP_KERNEL);
        if (!bd)
                return -ENOMEM;
-       bd->options = this->bbt_options;
+       bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
        bd->offs = this->badblockpos;
        bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
        bd->pattern = scan_ff_pattern;
@@ -1348,7 +1366,7 @@ int nand_default_bbt(struct mtd_info *mtd)
        }
 
        if (!this->badblock_pattern)
-               nand_create_default_bbt_descr(this);
+               nand_create_badblock_pattern(this);
 
        return nand_scan_bbt(mtd, this->badblock_pattern);
 }