]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mtd: rawnand: toshiba: Support reading the number of bitflips for BENAND (Built-in...
authorYoshio Furuyama <ytc-mb-yfuruyama7@kioxia.com>
Wed, 25 Mar 2020 08:22:52 +0000 (17:22 +0900)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Wed, 25 Mar 2020 21:13:04 +0000 (22:13 +0100)
Add support vendor specific commands for KIOXIA CORPORATION BENAND.
The actual bitflips number can be retrieved by this command.

Signed-off-by: Yoshio Furuyama <ytc-mb-yfuruyama7@kioxia.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/1585124572-4693-1-git-send-email-ytc-mb-yfuruyama7@kioxia.com
drivers/mtd/nand/raw/nand_toshiba.c

index 9c03fbb1f47dc41ca901304e501f9830a895b9ec..f3dcd695b5dbfb66c006330c242c67c673aa4637 100644 (file)
 /* Recommended to rewrite for BENAND */
 #define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED        BIT(3)
 
+/* ECC Status Read Command for BENAND */
+#define TOSHIBA_NAND_CMD_ECC_STATUS_READ       0x7A
+
+/* ECC Status Mask for BENAND */
+#define TOSHIBA_NAND_ECC_STATUS_MASK           0x0F
+
+/* Uncorrectable Error for BENAND */
+#define TOSHIBA_NAND_ECC_STATUS_UNCORR         0x0F
+
+/* Max ECC Steps for BENAND */
+#define TOSHIBA_NAND_MAX_ECC_STEPS             8
+
+static int toshiba_nand_benand_read_eccstatus_op(struct nand_chip *chip,
+                                                u8 *buf)
+{
+       u8 *ecc_status = buf;
+
+       if (nand_has_exec_op(chip)) {
+               const struct nand_sdr_timings *sdr =
+                       nand_get_sdr_timings(&chip->data_interface);
+               struct nand_op_instr instrs[] = {
+                       NAND_OP_CMD(TOSHIBA_NAND_CMD_ECC_STATUS_READ,
+                                   PSEC_TO_NSEC(sdr->tADL_min)),
+                       NAND_OP_8BIT_DATA_IN(chip->ecc.steps, ecc_status, 0),
+               };
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+
+               return nand_exec_op(chip, &op);
+       }
+
+       return -ENOTSUPP;
+}
+
 static int toshiba_nand_benand_eccstatus(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
        unsigned int max_bitflips = 0;
-       u8 status;
+       u8 status, ecc_status[TOSHIBA_NAND_MAX_ECC_STEPS];
 
        /* Check Status */
+       ret = toshiba_nand_benand_read_eccstatus_op(chip, ecc_status);
+       if (!ret) {
+               unsigned int i, bitflips = 0;
+
+               for (i = 0; i < chip->ecc.steps; i++) {
+                       bitflips = ecc_status[i] & TOSHIBA_NAND_ECC_STATUS_MASK;
+                       if (bitflips == TOSHIBA_NAND_ECC_STATUS_UNCORR) {
+                               mtd->ecc_stats.failed++;
+                       } else {
+                               mtd->ecc_stats.corrected += bitflips;
+                               max_bitflips = max(max_bitflips, bitflips);
+                       }
+               }
+
+               return max_bitflips;
+       }
+
+       /*
+        * Fallback to regular status check if
+        * toshiba_nand_benand_read_eccstatus_op() failed.
+        */
        ret = nand_status_op(chip, &status);
        if (ret)
                return ret;
@@ -108,7 +162,7 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
         */
        if (chip->id.len >= 6 && nand_is_slc(chip) &&
            (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
-           !(chip->id.data[4] & 0x80) /* !BENAND */) {
+           !(chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND) /* !BENAND */) {
                memorg->oobsize = 32 * memorg->pagesize >> 9;
                mtd->oobsize = memorg->oobsize;
        }