diff options
author | Mike Dunn <mikedunn@newsguy.com> | 2012-07-11 14:08:19 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-09-29 09:53:46 -0400 |
commit | aa6d01fa435a6f701128829f8d9d04208fd53176 (patch) | |
tree | 93deac9767a7613a5c0e081b08bb29cfa10e6f67 | |
parent | 036a1ac1f4ac8cdfed4574738c63aba2e81a13e4 (diff) |
mtd: docg4: fix oob reads
This patch does two closely related things:
(1) Currently the ecc.read_page() method does not fill the nand->oob_poi buffer
with the oob data, but instead reads oob into a local buffer. Fix this by
filling the oob_poi buffer instead of a local buffer. The 'oob_required'
argument is quietly ignored; the device must always read oob after the page
data, and it is presumed that there's no harm in filling oob_poi, even when not
explicitly requested.
(2) Always read oob from the device in ecc.read_oob(), instead of copying it
from a local buffer under some circumstances.
Signed-off-by: Mike Dunn <mikedunn@newsguy.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r-- | drivers/mtd/nand/docg4.c | 33 |
1 files changed, 6 insertions, 27 deletions
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 0f2ffd7b6c82..793921e56f8e 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c | |||
@@ -378,9 +378,9 @@ static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page) | |||
378 | * bit flips(s) are not reported in stats. | 378 | * bit flips(s) are not reported in stats. |
379 | */ | 379 | */ |
380 | 380 | ||
381 | if (doc->oob_buf[15]) { | 381 | if (nand->oob_poi[15]) { |
382 | int bit, numsetbits = 0; | 382 | int bit, numsetbits = 0; |
383 | unsigned long written_flag = doc->oob_buf[15]; | 383 | unsigned long written_flag = nand->oob_poi[15]; |
384 | for_each_set_bit(bit, &written_flag, 8) | 384 | for_each_set_bit(bit, &written_flag, 8) |
385 | numsetbits++; | 385 | numsetbits++; |
386 | if (numsetbits > 4) { /* assume blank */ | 386 | if (numsetbits > 4) { /* assume blank */ |
@@ -428,7 +428,7 @@ static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page) | |||
428 | /* if error within oob area preceeding ecc bytes... */ | 428 | /* if error within oob area preceeding ecc bytes... */ |
429 | if (errpos[i] > DOCG4_PAGE_SIZE * 8) | 429 | if (errpos[i] > DOCG4_PAGE_SIZE * 8) |
430 | change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8, | 430 | change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8, |
431 | (unsigned long *)doc->oob_buf); | 431 | (unsigned long *)nand->oob_poi); |
432 | 432 | ||
433 | else /* error in page data */ | 433 | else /* error in page data */ |
434 | change_bit(errpos[i], (unsigned long *)buf); | 434 | change_bit(errpos[i], (unsigned long *)buf); |
@@ -748,18 +748,12 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, | |||
748 | 748 | ||
749 | docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */ | 749 | docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */ |
750 | 750 | ||
751 | /* | 751 | /* this device always reads oob after page data */ |
752 | * Diskonchips read oob immediately after a page read. Mtd | ||
753 | * infrastructure issues a separate command for reading oob after the | ||
754 | * page is read. So we save the oob bytes in a local buffer and just | ||
755 | * copy it if the next command reads oob from the same page. | ||
756 | */ | ||
757 | |||
758 | /* first 14 oob bytes read from I/O reg */ | 752 | /* first 14 oob bytes read from I/O reg */ |
759 | docg4_read_buf(mtd, doc->oob_buf, 14); | 753 | docg4_read_buf(mtd, nand->oob_poi, 14); |
760 | 754 | ||
761 | /* last 2 read from another reg */ | 755 | /* last 2 read from another reg */ |
762 | buf16 = (uint16_t *)(doc->oob_buf + 14); | 756 | buf16 = (uint16_t *)(nand->oob_poi + 14); |
763 | *buf16 = readw(docptr + DOCG4_MYSTERY_REG); | 757 | *buf16 = readw(docptr + DOCG4_MYSTERY_REG); |
764 | 758 | ||
765 | write_nop(docptr); | 759 | write_nop(docptr); |
@@ -807,21 +801,6 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, | |||
807 | 801 | ||
808 | dev_dbg(doc->dev, "%s: page %x\n", __func__, page); | 802 | dev_dbg(doc->dev, "%s: page %x\n", __func__, page); |
809 | 803 | ||
810 | /* | ||
811 | * Oob bytes are read as part of a normal page read. If the previous | ||
812 | * nand command was a read of the page whose oob is now being read, just | ||
813 | * copy the oob bytes that we saved in a local buffer and avoid a | ||
814 | * separate oob read. | ||
815 | */ | ||
816 | if (doc->last_command.command == NAND_CMD_READ0 && | ||
817 | doc->last_command.page == page) { | ||
818 | memcpy(nand->oob_poi, doc->oob_buf, 16); | ||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | /* | ||
823 | * Separate read of oob data only. | ||
824 | */ | ||
825 | docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page); | 804 | docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page); |
826 | 805 | ||
827 | writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0); | 806 | writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0); |