aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r--drivers/mtd/nand/nand_base.c51
1 files changed, 35 insertions, 16 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8df36e2c9a53..5dcb2e066ce7 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -897,12 +897,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
897 * @chip: nand chip structure 897 * @chip: nand chip structure
898 * @oob: oob destination address 898 * @oob: oob destination address
899 * @ops: oob ops structure 899 * @ops: oob ops structure
900 * @len: size of oob to transfer
900 */ 901 */
901static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, 902static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
902 struct mtd_oob_ops *ops) 903 struct mtd_oob_ops *ops, size_t len)
903{ 904{
904 size_t len = ops->ooblen;
905
906 switch(ops->mode) { 905 switch(ops->mode) {
907 906
908 case MTD_OOB_PLACE: 907 case MTD_OOB_PLACE:
@@ -960,6 +959,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
960 int sndcmd = 1; 959 int sndcmd = 1;
961 int ret = 0; 960 int ret = 0;
962 uint32_t readlen = ops->len; 961 uint32_t readlen = ops->len;
962 uint32_t oobreadlen = ops->ooblen;
963 uint8_t *bufpoi, *oob, *buf; 963 uint8_t *bufpoi, *oob, *buf;
964 964
965 stats = mtd->ecc_stats; 965 stats = mtd->ecc_stats;
@@ -1006,10 +1006,17 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1006 1006
1007 if (unlikely(oob)) { 1007 if (unlikely(oob)) {
1008 /* Raw mode does data:oob:data:oob */ 1008 /* Raw mode does data:oob:data:oob */
1009 if (ops->mode != MTD_OOB_RAW) 1009 if (ops->mode != MTD_OOB_RAW) {
1010 oob = nand_transfer_oob(chip, oob, ops); 1010 int toread = min(oobreadlen,
1011 else 1011 chip->ecc.layout->oobavail);
1012 buf = nand_transfer_oob(chip, buf, ops); 1012 if (toread) {
1013 oob = nand_transfer_oob(chip,
1014 oob, ops, toread);
1015 oobreadlen -= toread;
1016 }
1017 } else
1018 buf = nand_transfer_oob(chip,
1019 buf, ops, mtd->oobsize);
1013 } 1020 }
1014 1021
1015 if (!(chip->options & NAND_NO_READRDY)) { 1022 if (!(chip->options & NAND_NO_READRDY)) {
@@ -1056,6 +1063,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1056 } 1063 }
1057 1064
1058 ops->retlen = ops->len - (size_t) readlen; 1065 ops->retlen = ops->len - (size_t) readlen;
1066 if (oob)
1067 ops->oobretlen = ops->ooblen - oobreadlen;
1059 1068
1060 if (ret) 1069 if (ret)
1061 return ret; 1070 return ret;
@@ -1256,12 +1265,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1256 int page, realpage, chipnr, sndcmd = 1; 1265 int page, realpage, chipnr, sndcmd = 1;
1257 struct nand_chip *chip = mtd->priv; 1266 struct nand_chip *chip = mtd->priv;
1258 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; 1267 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
1259 int readlen = ops->len; 1268 int readlen = ops->ooblen;
1269 int len;
1260 uint8_t *buf = ops->oobbuf; 1270 uint8_t *buf = ops->oobbuf;
1261 1271
1262 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", 1272 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
1263 (unsigned long long)from, readlen); 1273 (unsigned long long)from, readlen);
1264 1274
1275 if (ops->mode == MTD_OOB_RAW)
1276 len = mtd->oobsize;
1277 else
1278 len = chip->ecc.layout->oobavail;
1279
1265 chipnr = (int)(from >> chip->chip_shift); 1280 chipnr = (int)(from >> chip->chip_shift);
1266 chip->select_chip(mtd, chipnr); 1281 chip->select_chip(mtd, chipnr);
1267 1282
@@ -1271,7 +1286,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1271 1286
1272 while(1) { 1287 while(1) {
1273 sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); 1288 sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
1274 buf = nand_transfer_oob(chip, buf, ops); 1289
1290 len = min(len, readlen);
1291 buf = nand_transfer_oob(chip, buf, ops, len);
1275 1292
1276 if (!(chip->options & NAND_NO_READRDY)) { 1293 if (!(chip->options & NAND_NO_READRDY)) {
1277 /* 1294 /*
@@ -1286,7 +1303,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1286 nand_wait_ready(mtd); 1303 nand_wait_ready(mtd);
1287 } 1304 }
1288 1305
1289 readlen -= ops->ooblen; 1306 readlen -= len;
1290 if (!readlen) 1307 if (!readlen)
1291 break; 1308 break;
1292 1309
@@ -1308,7 +1325,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1308 sndcmd = 1; 1325 sndcmd = 1;
1309 } 1326 }
1310 1327
1311 ops->retlen = ops->len; 1328 ops->oobretlen = ops->ooblen;
1312 return 0; 1329 return 0;
1313} 1330}
1314 1331
@@ -1329,7 +1346,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
1329 ops->retlen = 0; 1346 ops->retlen = 0;
1330 1347
1331 /* Do not allow reads past end of device */ 1348 /* Do not allow reads past end of device */
1332 if ((from + ops->len) > mtd->size) { 1349 if (ops->datbuf && (from + ops->len) > mtd->size) {
1333 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " 1350 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1334 "Attempt read beyond end of device\n"); 1351 "Attempt read beyond end of device\n");
1335 return -EINVAL; 1352 return -EINVAL;
@@ -1654,6 +1671,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1654 } 1671 }
1655 1672
1656 ops->retlen = ops->len - writelen; 1673 ops->retlen = ops->len - writelen;
1674 if (unlikely(oob))
1675 ops->oobretlen = ops->ooblen;
1657 return ret; 1676 return ret;
1658} 1677}
1659 1678
@@ -1709,10 +1728,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
1709 struct nand_chip *chip = mtd->priv; 1728 struct nand_chip *chip = mtd->priv;
1710 1729
1711 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", 1730 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
1712 (unsigned int)to, (int)ops->len); 1731 (unsigned int)to, (int)ops->ooblen);
1713 1732
1714 /* Do not allow write past end of page */ 1733 /* Do not allow write past end of page */
1715 if ((ops->ooboffs + ops->len) > mtd->oobsize) { 1734 if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) {
1716 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " 1735 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1717 "Attempt to write past end of page\n"); 1736 "Attempt to write past end of page\n");
1718 return -EINVAL; 1737 return -EINVAL;
@@ -1748,7 +1767,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
1748 if (status) 1767 if (status)
1749 return status; 1768 return status;
1750 1769
1751 ops->retlen = ops->len; 1770 ops->oobretlen = ops->ooblen;
1752 1771
1753 return 0; 1772 return 0;
1754} 1773}
@@ -1768,7 +1787,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
1768 ops->retlen = 0; 1787 ops->retlen = 0;
1769 1788
1770 /* Do not allow writes past end of device */ 1789 /* Do not allow writes past end of device */
1771 if ((to + ops->len) > mtd->size) { 1790 if (ops->datbuf && (to + ops->len) > mtd->size) {
1772 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " 1791 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1773 "Attempt read beyond end of device\n"); 1792 "Attempt read beyond end of device\n");
1774 return -EINVAL; 1793 return -EINVAL;