diff options
Diffstat (limited to 'drivers/mtd/devices/docg3.c')
-rw-r--r-- | drivers/mtd/devices/docg3.c | 40 |
1 files changed, 27 insertions, 13 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 50aa90aa7a7f..f70854d728fe 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c | |||
@@ -227,7 +227,7 @@ static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, | |||
227 | u8 data8, *dst8; | 227 | u8 data8, *dst8; |
228 | 228 | ||
229 | doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); | 229 | doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); |
230 | cdr = len & 0x3; | 230 | cdr = len & 0x1; |
231 | len4 = len - cdr; | 231 | len4 = len - cdr; |
232 | 232 | ||
233 | if (first) | 233 | if (first) |
@@ -732,12 +732,24 @@ err: | |||
732 | * @len: the number of bytes to be read (must be a multiple of 4) | 732 | * @len: the number of bytes to be read (must be a multiple of 4) |
733 | * @buf: the buffer to be filled in (or NULL is forget bytes) | 733 | * @buf: the buffer to be filled in (or NULL is forget bytes) |
734 | * @first: 1 if first time read, DOC_READADDRESS should be set | 734 | * @first: 1 if first time read, DOC_READADDRESS should be set |
735 | * @last_odd: 1 if last read ended up on an odd byte | ||
736 | * | ||
737 | * Reads bytes from a prepared page. There is a trickery here : if the last read | ||
738 | * ended up on an odd offset in the 1024 bytes double page, ie. between the 2 | ||
739 | * planes, the first byte must be read apart. If a word (16bit) read was used, | ||
740 | * the read would return the byte of plane 2 as low *and* high endian, which | ||
741 | * will mess the read. | ||
735 | * | 742 | * |
736 | */ | 743 | */ |
737 | static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, | 744 | static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, |
738 | int first) | 745 | int first, int last_odd) |
739 | { | 746 | { |
740 | doc_read_data_area(docg3, buf, len, first); | 747 | if (last_odd && len > 0) { |
748 | doc_read_data_area(docg3, buf, 1, first); | ||
749 | doc_read_data_area(docg3, buf ? buf + 1 : buf, len - 1, 0); | ||
750 | } else { | ||
751 | doc_read_data_area(docg3, buf, len, first); | ||
752 | } | ||
741 | doc_delay(docg3, 2); | 753 | doc_delay(docg3, 2); |
742 | return len; | 754 | return len; |
743 | } | 755 | } |
@@ -850,6 +862,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
850 | u8 *buf = ops->datbuf; | 862 | u8 *buf = ops->datbuf; |
851 | size_t len, ooblen, nbdata, nboob; | 863 | size_t len, ooblen, nbdata, nboob; |
852 | u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; | 864 | u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; |
865 | int max_bitflips = 0; | ||
853 | 866 | ||
854 | if (buf) | 867 | if (buf) |
855 | len = ops->len; | 868 | len = ops->len; |
@@ -876,7 +889,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
876 | ret = 0; | 889 | ret = 0; |
877 | skip = from % DOC_LAYOUT_PAGE_SIZE; | 890 | skip = from % DOC_LAYOUT_PAGE_SIZE; |
878 | mutex_lock(&docg3->cascade->lock); | 891 | mutex_lock(&docg3->cascade->lock); |
879 | while (!ret && (len > 0 || ooblen > 0)) { | 892 | while (ret >= 0 && (len > 0 || ooblen > 0)) { |
880 | calc_block_sector(from - skip, &block0, &block1, &page, &ofs, | 893 | calc_block_sector(from - skip, &block0, &block1, &page, &ofs, |
881 | docg3->reliable); | 894 | docg3->reliable); |
882 | nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); | 895 | nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); |
@@ -887,20 +900,20 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
887 | ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); | 900 | ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); |
888 | if (ret < 0) | 901 | if (ret < 0) |
889 | goto err_in_read; | 902 | goto err_in_read; |
890 | ret = doc_read_page_getbytes(docg3, skip, NULL, 1); | 903 | ret = doc_read_page_getbytes(docg3, skip, NULL, 1, 0); |
891 | if (ret < skip) | 904 | if (ret < skip) |
892 | goto err_in_read; | 905 | goto err_in_read; |
893 | ret = doc_read_page_getbytes(docg3, nbdata, buf, 0); | 906 | ret = doc_read_page_getbytes(docg3, nbdata, buf, 0, skip % 2); |
894 | if (ret < nbdata) | 907 | if (ret < nbdata) |
895 | goto err_in_read; | 908 | goto err_in_read; |
896 | doc_read_page_getbytes(docg3, | 909 | doc_read_page_getbytes(docg3, |
897 | DOC_LAYOUT_PAGE_SIZE - nbdata - skip, | 910 | DOC_LAYOUT_PAGE_SIZE - nbdata - skip, |
898 | NULL, 0); | 911 | NULL, 0, (skip + nbdata) % 2); |
899 | ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); | 912 | ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0, 0); |
900 | if (ret < nboob) | 913 | if (ret < nboob) |
901 | goto err_in_read; | 914 | goto err_in_read; |
902 | doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, | 915 | doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, |
903 | NULL, 0); | 916 | NULL, 0, nboob % 2); |
904 | 917 | ||
905 | doc_get_bch_hw_ecc(docg3, hwecc); | 918 | doc_get_bch_hw_ecc(docg3, hwecc); |
906 | eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); | 919 | eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); |
@@ -936,7 +949,8 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
936 | } | 949 | } |
937 | if (ret > 0) { | 950 | if (ret > 0) { |
938 | mtd->ecc_stats.corrected += ret; | 951 | mtd->ecc_stats.corrected += ret; |
939 | ret = -EUCLEAN; | 952 | max_bitflips = max(max_bitflips, ret); |
953 | ret = max_bitflips; | ||
940 | } | 954 | } |
941 | } | 955 | } |
942 | 956 | ||
@@ -1004,7 +1018,7 @@ static int doc_reload_bbt(struct docg3 *docg3) | |||
1004 | DOC_LAYOUT_PAGE_SIZE); | 1018 | DOC_LAYOUT_PAGE_SIZE); |
1005 | if (!ret) | 1019 | if (!ret) |
1006 | doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, | 1020 | doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, |
1007 | buf, 1); | 1021 | buf, 1, 0); |
1008 | buf += DOC_LAYOUT_PAGE_SIZE; | 1022 | buf += DOC_LAYOUT_PAGE_SIZE; |
1009 | } | 1023 | } |
1010 | doc_read_page_finish(docg3); | 1024 | doc_read_page_finish(docg3); |
@@ -1064,10 +1078,10 @@ static int doc_get_erase_count(struct docg3 *docg3, loff_t from) | |||
1064 | ret = doc_reset_seq(docg3); | 1078 | ret = doc_reset_seq(docg3); |
1065 | if (!ret) | 1079 | if (!ret) |
1066 | ret = doc_read_page_prepare(docg3, block0, block1, page, | 1080 | ret = doc_read_page_prepare(docg3, block0, block1, page, |
1067 | ofs + DOC_LAYOUT_WEAR_OFFSET); | 1081 | ofs + DOC_LAYOUT_WEAR_OFFSET, 0); |
1068 | if (!ret) | 1082 | if (!ret) |
1069 | ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, | 1083 | ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, |
1070 | buf, 1); | 1084 | buf, 1, 0); |
1071 | doc_read_page_finish(docg3); | 1085 | doc_read_page_finish(docg3); |
1072 | 1086 | ||
1073 | if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) | 1087 | if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) |