diff options
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 56 | ||||
| -rw-r--r-- | include/linux/mtd/nand.h | 6 |
2 files changed, 58 insertions, 4 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 94fe4f5dad3b..052e3ad82687 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
| @@ -1410,6 +1410,30 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, | |||
| 1410 | } | 1410 | } |
| 1411 | 1411 | ||
| 1412 | /** | 1412 | /** |
| 1413 | * nand_setup_read_retry - [INTERN] Set the READ RETRY mode | ||
| 1414 | * @mtd: MTD device structure | ||
| 1415 | * @retry_mode: the retry mode to use | ||
| 1416 | * | ||
| 1417 | * Some vendors supply a special command to shift the Vt threshold, to be used | ||
| 1418 | * when there are too many bitflips in a page (i.e., ECC error). After setting | ||
| 1419 | * a new threshold, the host should retry reading the page. | ||
| 1420 | */ | ||
| 1421 | static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) | ||
| 1422 | { | ||
| 1423 | struct nand_chip *chip = mtd->priv; | ||
| 1424 | |||
| 1425 | pr_debug("setting READ RETRY mode %d\n", retry_mode); | ||
| 1426 | |||
| 1427 | if (retry_mode >= chip->read_retries) | ||
| 1428 | return -EINVAL; | ||
| 1429 | |||
| 1430 | if (!chip->setup_read_retry) | ||
| 1431 | return -EOPNOTSUPP; | ||
| 1432 | |||
| 1433 | return chip->setup_read_retry(mtd, retry_mode); | ||
| 1434 | } | ||
| 1435 | |||
| 1436 | /** | ||
| 1413 | * nand_do_read_ops - [INTERN] Read data with ECC | 1437 | * nand_do_read_ops - [INTERN] Read data with ECC |
| 1414 | * @mtd: MTD device structure | 1438 | * @mtd: MTD device structure |
| 1415 | * @from: offset to read from | 1439 | * @from: offset to read from |
| @@ -1430,6 +1454,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1430 | 1454 | ||
| 1431 | uint8_t *bufpoi, *oob, *buf; | 1455 | uint8_t *bufpoi, *oob, *buf; |
| 1432 | unsigned int max_bitflips = 0; | 1456 | unsigned int max_bitflips = 0; |
| 1457 | int retry_mode = 0; | ||
| 1433 | bool ecc_fail = false; | 1458 | bool ecc_fail = false; |
| 1434 | 1459 | ||
| 1435 | chipnr = (int)(from >> chip->chip_shift); | 1460 | chipnr = (int)(from >> chip->chip_shift); |
| @@ -1454,6 +1479,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1454 | if (realpage != chip->pagebuf || oob) { | 1479 | if (realpage != chip->pagebuf || oob) { |
| 1455 | bufpoi = aligned ? buf : chip->buffers->databuf; | 1480 | bufpoi = aligned ? buf : chip->buffers->databuf; |
| 1456 | 1481 | ||
| 1482 | read_retry: | ||
| 1457 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); | 1483 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); |
| 1458 | 1484 | ||
| 1459 | /* | 1485 | /* |
| @@ -1494,8 +1520,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1494 | memcpy(buf, chip->buffers->databuf + col, bytes); | 1520 | memcpy(buf, chip->buffers->databuf + col, bytes); |
| 1495 | } | 1521 | } |
| 1496 | 1522 | ||
| 1497 | buf += bytes; | ||
| 1498 | |||
| 1499 | if (unlikely(oob)) { | 1523 | if (unlikely(oob)) { |
| 1500 | int toread = min(oobreadlen, max_oobsize); | 1524 | int toread = min(oobreadlen, max_oobsize); |
| 1501 | 1525 | ||
| @@ -1514,8 +1538,24 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1514 | nand_wait_ready(mtd); | 1538 | nand_wait_ready(mtd); |
| 1515 | } | 1539 | } |
| 1516 | 1540 | ||
| 1517 | if (mtd->ecc_stats.failed - ecc_failures) | 1541 | if (mtd->ecc_stats.failed - ecc_failures) { |
| 1518 | ecc_fail = true; | 1542 | if (retry_mode + 1 <= chip->read_retries) { |
| 1543 | retry_mode++; | ||
| 1544 | ret = nand_setup_read_retry(mtd, | ||
| 1545 | retry_mode); | ||
| 1546 | if (ret < 0) | ||
| 1547 | break; | ||
| 1548 | |||
| 1549 | /* Reset failures; retry */ | ||
| 1550 | mtd->ecc_stats.failed = ecc_failures; | ||
| 1551 | goto read_retry; | ||
| 1552 | } else { | ||
| 1553 | /* No more retry modes; real failure */ | ||
| 1554 | ecc_fail = true; | ||
| 1555 | } | ||
| 1556 | } | ||
| 1557 | |||
| 1558 | buf += bytes; | ||
| 1519 | } else { | 1559 | } else { |
| 1520 | memcpy(buf, chip->buffers->databuf + col, bytes); | 1560 | memcpy(buf, chip->buffers->databuf + col, bytes); |
| 1521 | buf += bytes; | 1561 | buf += bytes; |
| @@ -1525,6 +1565,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1525 | 1565 | ||
| 1526 | readlen -= bytes; | 1566 | readlen -= bytes; |
| 1527 | 1567 | ||
| 1568 | /* Reset to retry mode 0 */ | ||
| 1569 | if (retry_mode) { | ||
| 1570 | ret = nand_setup_read_retry(mtd, 0); | ||
| 1571 | if (ret < 0) | ||
| 1572 | break; | ||
| 1573 | retry_mode = 0; | ||
| 1574 | } | ||
| 1575 | |||
| 1528 | if (!readlen) | 1576 | if (!readlen) |
| 1529 | break; | 1577 | break; |
| 1530 | 1578 | ||
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 309009b7764b..7fd717010ee2 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
| @@ -472,6 +472,8 @@ struct nand_buffers { | |||
| 472 | * commands to the chip. | 472 | * commands to the chip. |
| 473 | * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on | 473 | * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on |
| 474 | * ready. | 474 | * ready. |
| 475 | * @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for | ||
| 476 | * setting the read-retry mode. Mostly needed for MLC NAND. | ||
| 475 | * @ecc: [BOARDSPECIFIC] ECC control structure | 477 | * @ecc: [BOARDSPECIFIC] ECC control structure |
| 476 | * @buffers: buffer structure for read/write | 478 | * @buffers: buffer structure for read/write |
| 477 | * @hwcontrol: platform-specific hardware control structure | 479 | * @hwcontrol: platform-specific hardware control structure |
| @@ -518,6 +520,7 @@ struct nand_buffers { | |||
| 518 | * non 0 if ONFI supported. | 520 | * non 0 if ONFI supported. |
| 519 | * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is | 521 | * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is |
| 520 | * supported, 0 otherwise. | 522 | * supported, 0 otherwise. |
| 523 | * @read_retries: [INTERN] the number of read retry modes supported | ||
| 521 | * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand | 524 | * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand |
| 522 | * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand | 525 | * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand |
| 523 | * @bbt: [INTERN] bad block table pointer | 526 | * @bbt: [INTERN] bad block table pointer |
| @@ -565,6 +568,7 @@ struct nand_chip { | |||
| 565 | int feature_addr, uint8_t *subfeature_para); | 568 | int feature_addr, uint8_t *subfeature_para); |
| 566 | int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, | 569 | int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, |
| 567 | int feature_addr, uint8_t *subfeature_para); | 570 | int feature_addr, uint8_t *subfeature_para); |
| 571 | int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode); | ||
| 568 | 572 | ||
| 569 | int chip_delay; | 573 | int chip_delay; |
| 570 | unsigned int options; | 574 | unsigned int options; |
| @@ -589,6 +593,8 @@ struct nand_chip { | |||
| 589 | int onfi_version; | 593 | int onfi_version; |
| 590 | struct nand_onfi_params onfi_params; | 594 | struct nand_onfi_params onfi_params; |
| 591 | 595 | ||
| 596 | int read_retries; | ||
| 597 | |||
| 592 | flstate_t state; | 598 | flstate_t state; |
| 593 | 599 | ||
| 594 | uint8_t *oob_poi; | 600 | uint8_t *oob_poi; |
