From e14ed7dc08296a52f81d14781dee2f455dd90bbd Mon Sep 17 00:00:00 2001 From: Jane Wan Date: Mon, 30 Apr 2018 14:05:40 -0700 Subject: [PATCH 2/2] mtd: rawnand: fsl_ifc: use bit-wise majority to recover the contents of ONFI parameter Per ONFI specification (Rev. 4.0), if all parameter pages have invalid CRC values, the bit-wise majority may be used to recover the contents of the parameter pages from the parameter page copies present. Signed-off-by: Jane Wan --- drivers/mtd/nand/raw/nand_base.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 72f3a89..464c4fb 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5086,6 +5086,8 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip, return ret; } +#define GET_BIT(bit, val) (((val) >> (bit)) & 0x01) + /* * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ @@ -5094,7 +5096,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) struct mtd_info *mtd = nand_to_mtd(chip); struct nand_onfi_params *p; char id[4]; - int i, ret, val; + int i, ret, val, pagesize; + u8 *buf; /* Try ONFI for unknown chip or LP */ ret = nand_readid_op(chip, 0x20, id, sizeof(id)); @@ -5102,8 +5105,9 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) return 0; /* ONFI chip: allocate a buffer to hold its parameter page */ - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) + pagesize = sizeof(*p); + buf = kzalloc((pagesize * 3), GFP_KERNEL); + if (!buf) return -ENOMEM; ret = nand_read_param_page_op(chip, 0, NULL, 0); @@ -5113,7 +5117,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) } for (i = 0; i < 3; i++) { - ret = nand_read_data_op(chip, p, sizeof(*p), true); + p = (struct nand_onfi_params *)&buf[i*pagesize]; + ret = nand_read_data_op(chip, p, pagesize, true); if (ret) { ret = 0; goto free_onfi_param_page; @@ -5126,8 +5131,27 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) } if (i == 3) { - pr_err("Could not find valid ONFI parameter page; aborting\n"); - goto free_onfi_param_page; + int j, k, l; + u8 v, m; + + pr_err("Could not find valid ONFI parameter page\n"); + pr_info("Recover ONFI params with bit-wise majority\n"); + for (j = 0; j < pagesize; j++) { + v = 0; + for (k = 0; k < 8; k++) { + m = 0; + for (l = 0; l < 3; l++) + m += GET_BIT(k, buf[l*pagesize + j]); + if (m > 1) + v |= BIT(k); + } + ((u8 *)p)[j] = v; + } + if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) != + le16_to_cpu(p->crc)) { + pr_err("ONFI parameter recovery failed, aborting\n"); + goto free_onfi_param_page; + } } /* Check version */ -- 1.7.9.5