diff options
Diffstat (limited to 'drivers/mtd/onenand/onenand_base.c')
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 170 |
1 files changed, 95 insertions, 75 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 40d8d6ff626b..85a97198bee3 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -333,12 +333,14 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
333 | if (interrupt & ONENAND_INT_READ) { | 333 | if (interrupt & ONENAND_INT_READ) { |
334 | int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); | 334 | int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); |
335 | if (ecc) { | 335 | if (ecc) { |
336 | printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); | ||
337 | if (ecc & ONENAND_ECC_2BIT_ALL) { | 336 | if (ecc & ONENAND_ECC_2BIT_ALL) { |
337 | printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); | ||
338 | mtd->ecc_stats.failed++; | 338 | mtd->ecc_stats.failed++; |
339 | return ecc; | 339 | return ecc; |
340 | } else if (ecc & ONENAND_ECC_1BIT_ALL) | 340 | } else if (ecc & ONENAND_ECC_1BIT_ALL) { |
341 | printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc); | ||
341 | mtd->ecc_stats.corrected++; | 342 | mtd->ecc_stats.corrected++; |
343 | } | ||
342 | } | 344 | } |
343 | } else if (state == FL_READING) { | 345 | } else if (state == FL_READING) { |
344 | printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); | 346 | printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); |
@@ -805,14 +807,14 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col | |||
805 | } | 807 | } |
806 | 808 | ||
807 | /** | 809 | /** |
808 | * onenand_read_ops - [OneNAND Interface] OneNAND read main and/or out-of-band | 810 | * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band |
809 | * @param mtd MTD device structure | 811 | * @param mtd MTD device structure |
810 | * @param from offset to read from | 812 | * @param from offset to read from |
811 | * @param ops: oob operation description structure | 813 | * @param ops: oob operation description structure |
812 | * | 814 | * |
813 | * OneNAND read main and/or out-of-band data | 815 | * OneNAND read main and/or out-of-band data |
814 | */ | 816 | */ |
815 | static int onenand_read_ops(struct mtd_info *mtd, loff_t from, | 817 | static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, |
816 | struct mtd_oob_ops *ops) | 818 | struct mtd_oob_ops *ops) |
817 | { | 819 | { |
818 | struct onenand_chip *this = mtd->priv; | 820 | struct onenand_chip *this = mtd->priv; |
@@ -826,7 +828,7 @@ static int onenand_read_ops(struct mtd_info *mtd, loff_t from, | |||
826 | int ret = 0, boundary = 0; | 828 | int ret = 0, boundary = 0; |
827 | int writesize = this->writesize; | 829 | int writesize = this->writesize; |
828 | 830 | ||
829 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | 831 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
830 | 832 | ||
831 | if (ops->mode == MTD_OOB_AUTO) | 833 | if (ops->mode == MTD_OOB_AUTO) |
832 | oobsize = this->ecclayout->oobavail; | 834 | oobsize = this->ecclayout->oobavail; |
@@ -837,15 +839,12 @@ static int onenand_read_ops(struct mtd_info *mtd, loff_t from, | |||
837 | 839 | ||
838 | /* Do not allow reads past end of device */ | 840 | /* Do not allow reads past end of device */ |
839 | if ((from + len) > mtd->size) { | 841 | if ((from + len) > mtd->size) { |
840 | printk(KERN_ERR "onenand_read_ops: Attempt read beyond end of device\n"); | 842 | printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n"); |
841 | ops->retlen = 0; | 843 | ops->retlen = 0; |
842 | ops->oobretlen = 0; | 844 | ops->oobretlen = 0; |
843 | return -EINVAL; | 845 | return -EINVAL; |
844 | } | 846 | } |
845 | 847 | ||
846 | /* Grab the lock and see if the device is available */ | ||
847 | onenand_get_device(mtd, FL_READING); | ||
848 | |||
849 | stats = mtd->ecc_stats; | 848 | stats = mtd->ecc_stats; |
850 | 849 | ||
851 | /* Read-while-load method */ | 850 | /* Read-while-load method */ |
@@ -916,9 +915,6 @@ static int onenand_read_ops(struct mtd_info *mtd, loff_t from, | |||
916 | onenand_update_bufferram(mtd, from, !ret); | 915 | onenand_update_bufferram(mtd, from, !ret); |
917 | } | 916 | } |
918 | 917 | ||
919 | /* Deselect and wake up anyone waiting on the device */ | ||
920 | onenand_release_device(mtd); | ||
921 | |||
922 | /* | 918 | /* |
923 | * Return success, if no ECC failures, else -EBADMSG | 919 | * Return success, if no ECC failures, else -EBADMSG |
924 | * fs driver will take care of that, because | 920 | * fs driver will take care of that, because |
@@ -937,14 +933,14 @@ static int onenand_read_ops(struct mtd_info *mtd, loff_t from, | |||
937 | } | 933 | } |
938 | 934 | ||
939 | /** | 935 | /** |
940 | * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band | 936 | * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band |
941 | * @param mtd MTD device structure | 937 | * @param mtd MTD device structure |
942 | * @param from offset to read from | 938 | * @param from offset to read from |
943 | * @param ops: oob operation description structure | 939 | * @param ops: oob operation description structure |
944 | * | 940 | * |
945 | * OneNAND read out-of-band data from the spare area | 941 | * OneNAND read out-of-band data from the spare area |
946 | */ | 942 | */ |
947 | static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, | 943 | static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, |
948 | struct mtd_oob_ops *ops) | 944 | struct mtd_oob_ops *ops) |
949 | { | 945 | { |
950 | struct onenand_chip *this = mtd->priv; | 946 | struct onenand_chip *this = mtd->priv; |
@@ -956,7 +952,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
956 | 952 | ||
957 | from += ops->ooboffs; | 953 | from += ops->ooboffs; |
958 | 954 | ||
959 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | 955 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
960 | 956 | ||
961 | /* Initialize return length value */ | 957 | /* Initialize return length value */ |
962 | ops->oobretlen = 0; | 958 | ops->oobretlen = 0; |
@@ -969,7 +965,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
969 | column = from & (mtd->oobsize - 1); | 965 | column = from & (mtd->oobsize - 1); |
970 | 966 | ||
971 | if (unlikely(column >= oobsize)) { | 967 | if (unlikely(column >= oobsize)) { |
972 | printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n"); | 968 | printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n"); |
973 | return -EINVAL; | 969 | return -EINVAL; |
974 | } | 970 | } |
975 | 971 | ||
@@ -977,13 +973,10 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
977 | if (unlikely(from >= mtd->size || | 973 | if (unlikely(from >= mtd->size || |
978 | column + len > ((mtd->size >> this->page_shift) - | 974 | column + len > ((mtd->size >> this->page_shift) - |
979 | (from >> this->page_shift)) * oobsize)) { | 975 | (from >> this->page_shift)) * oobsize)) { |
980 | printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n"); | 976 | printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n"); |
981 | return -EINVAL; | 977 | return -EINVAL; |
982 | } | 978 | } |
983 | 979 | ||
984 | /* Grab the lock and see if the device is available */ | ||
985 | onenand_get_device(mtd, FL_READING); | ||
986 | |||
987 | while (read < len) { | 980 | while (read < len) { |
988 | cond_resched(); | 981 | cond_resched(); |
989 | 982 | ||
@@ -1003,7 +996,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1003 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | 996 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); |
1004 | 997 | ||
1005 | if (ret) { | 998 | if (ret) { |
1006 | printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret); | 999 | printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret); |
1007 | break; | 1000 | break; |
1008 | } | 1001 | } |
1009 | 1002 | ||
@@ -1022,9 +1015,6 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1022 | } | 1015 | } |
1023 | } | 1016 | } |
1024 | 1017 | ||
1025 | /* Deselect and wake up anyone waiting on the device */ | ||
1026 | onenand_release_device(mtd); | ||
1027 | |||
1028 | ops->oobretlen = read; | 1018 | ops->oobretlen = read; |
1029 | return ret; | 1019 | return ret; |
1030 | } | 1020 | } |
@@ -1050,9 +1040,11 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
1050 | }; | 1040 | }; |
1051 | int ret; | 1041 | int ret; |
1052 | 1042 | ||
1053 | ret = onenand_read_ops(mtd, from, &ops); | 1043 | onenand_get_device(mtd, FL_READING); |
1054 | *retlen = ops.retlen; | 1044 | ret = onenand_read_ops_nolock(mtd, from, &ops); |
1045 | onenand_release_device(mtd); | ||
1055 | 1046 | ||
1047 | *retlen = ops.retlen; | ||
1056 | return ret; | 1048 | return ret; |
1057 | } | 1049 | } |
1058 | 1050 | ||
@@ -1067,6 +1059,8 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
1067 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | 1059 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, |
1068 | struct mtd_oob_ops *ops) | 1060 | struct mtd_oob_ops *ops) |
1069 | { | 1061 | { |
1062 | int ret; | ||
1063 | |||
1070 | switch (ops->mode) { | 1064 | switch (ops->mode) { |
1071 | case MTD_OOB_PLACE: | 1065 | case MTD_OOB_PLACE: |
1072 | case MTD_OOB_AUTO: | 1066 | case MTD_OOB_AUTO: |
@@ -1077,10 +1071,14 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | |||
1077 | return -EINVAL; | 1071 | return -EINVAL; |
1078 | } | 1072 | } |
1079 | 1073 | ||
1074 | onenand_get_device(mtd, FL_READING); | ||
1080 | if (ops->datbuf) | 1075 | if (ops->datbuf) |
1081 | return onenand_read_ops(mtd, from, ops); | 1076 | ret = onenand_read_ops_nolock(mtd, from, ops); |
1077 | else | ||
1078 | ret = onenand_read_oob_nolock(mtd, from, ops); | ||
1079 | onenand_release_device(mtd); | ||
1082 | 1080 | ||
1083 | return onenand_do_read_oob(mtd, from, ops); | 1081 | return ret; |
1084 | } | 1082 | } |
1085 | 1083 | ||
1086 | /** | 1084 | /** |
@@ -1317,14 +1315,14 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, | |||
1317 | } | 1315 | } |
1318 | 1316 | ||
1319 | /** | 1317 | /** |
1320 | * onenand_write_ops - [OneNAND Interface] write main and/or out-of-band | 1318 | * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band |
1321 | * @param mtd MTD device structure | 1319 | * @param mtd MTD device structure |
1322 | * @param to offset to write to | 1320 | * @param to offset to write to |
1323 | * @param ops oob operation description structure | 1321 | * @param ops oob operation description structure |
1324 | * | 1322 | * |
1325 | * Write main and/or oob with ECC | 1323 | * Write main and/or oob with ECC |
1326 | */ | 1324 | */ |
1327 | static int onenand_write_ops(struct mtd_info *mtd, loff_t to, | 1325 | static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, |
1328 | struct mtd_oob_ops *ops) | 1326 | struct mtd_oob_ops *ops) |
1329 | { | 1327 | { |
1330 | struct onenand_chip *this = mtd->priv; | 1328 | struct onenand_chip *this = mtd->priv; |
@@ -1337,7 +1335,7 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t to, | |||
1337 | u_char *oobbuf; | 1335 | u_char *oobbuf; |
1338 | int ret = 0; | 1336 | int ret = 0; |
1339 | 1337 | ||
1340 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 1338 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
1341 | 1339 | ||
1342 | /* Initialize retlen, in case of early exit */ | 1340 | /* Initialize retlen, in case of early exit */ |
1343 | ops->retlen = 0; | 1341 | ops->retlen = 0; |
@@ -1345,13 +1343,13 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t to, | |||
1345 | 1343 | ||
1346 | /* Do not allow writes past end of device */ | 1344 | /* Do not allow writes past end of device */ |
1347 | if (unlikely((to + len) > mtd->size)) { | 1345 | if (unlikely((to + len) > mtd->size)) { |
1348 | printk(KERN_ERR "onenand_write: Attempt write to past end of device\n"); | 1346 | printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n"); |
1349 | return -EINVAL; | 1347 | return -EINVAL; |
1350 | } | 1348 | } |
1351 | 1349 | ||
1352 | /* Reject writes, which are not page aligned */ | 1350 | /* Reject writes, which are not page aligned */ |
1353 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | 1351 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { |
1354 | printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n"); | 1352 | printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n"); |
1355 | return -EINVAL; | 1353 | return -EINVAL; |
1356 | } | 1354 | } |
1357 | 1355 | ||
@@ -1364,9 +1362,6 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t to, | |||
1364 | 1362 | ||
1365 | column = to & (mtd->writesize - 1); | 1363 | column = to & (mtd->writesize - 1); |
1366 | 1364 | ||
1367 | /* Grab the lock and see if the device is available */ | ||
1368 | onenand_get_device(mtd, FL_WRITING); | ||
1369 | |||
1370 | /* Loop until all data write */ | 1365 | /* Loop until all data write */ |
1371 | while (written < len) { | 1366 | while (written < len) { |
1372 | u_char *wbuf = (u_char *) buf; | 1367 | u_char *wbuf = (u_char *) buf; |
@@ -1419,14 +1414,14 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t to, | |||
1419 | } | 1414 | } |
1420 | 1415 | ||
1421 | if (ret) { | 1416 | if (ret) { |
1422 | printk(KERN_ERR "onenand_write: write filaed %d\n", ret); | 1417 | printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret); |
1423 | break; | 1418 | break; |
1424 | } | 1419 | } |
1425 | 1420 | ||
1426 | /* Only check verify write turn on */ | 1421 | /* Only check verify write turn on */ |
1427 | ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); | 1422 | ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); |
1428 | if (ret) { | 1423 | if (ret) { |
1429 | printk(KERN_ERR "onenand_write: verify failed %d\n", ret); | 1424 | printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); |
1430 | break; | 1425 | break; |
1431 | } | 1426 | } |
1432 | 1427 | ||
@@ -1450,7 +1445,7 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t to, | |||
1450 | 1445 | ||
1451 | 1446 | ||
1452 | /** | 1447 | /** |
1453 | * onenand_do_write_oob - [Internal] OneNAND write out-of-band | 1448 | * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band |
1454 | * @param mtd MTD device structure | 1449 | * @param mtd MTD device structure |
1455 | * @param to offset to write to | 1450 | * @param to offset to write to |
1456 | * @param len number of bytes to write | 1451 | * @param len number of bytes to write |
@@ -1460,8 +1455,8 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t to, | |||
1460 | * | 1455 | * |
1461 | * OneNAND write out-of-band | 1456 | * OneNAND write out-of-band |
1462 | */ | 1457 | */ |
1463 | static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, | 1458 | static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, |
1464 | struct mtd_oob_ops *ops) | 1459 | struct mtd_oob_ops *ops) |
1465 | { | 1460 | { |
1466 | struct onenand_chip *this = mtd->priv; | 1461 | struct onenand_chip *this = mtd->priv; |
1467 | int column, ret = 0, oobsize; | 1462 | int column, ret = 0, oobsize; |
@@ -1473,7 +1468,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1473 | 1468 | ||
1474 | to += ops->ooboffs; | 1469 | to += ops->ooboffs; |
1475 | 1470 | ||
1476 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 1471 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
1477 | 1472 | ||
1478 | /* Initialize retlen, in case of early exit */ | 1473 | /* Initialize retlen, in case of early exit */ |
1479 | ops->oobretlen = 0; | 1474 | ops->oobretlen = 0; |
@@ -1486,13 +1481,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1486 | column = to & (mtd->oobsize - 1); | 1481 | column = to & (mtd->oobsize - 1); |
1487 | 1482 | ||
1488 | if (unlikely(column >= oobsize)) { | 1483 | if (unlikely(column >= oobsize)) { |
1489 | printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n"); | 1484 | printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n"); |
1490 | return -EINVAL; | 1485 | return -EINVAL; |
1491 | } | 1486 | } |
1492 | 1487 | ||
1493 | /* For compatibility with NAND: Do not allow write past end of page */ | 1488 | /* For compatibility with NAND: Do not allow write past end of page */ |
1494 | if (unlikely(column + len > oobsize)) { | 1489 | if (unlikely(column + len > oobsize)) { |
1495 | printk(KERN_ERR "onenand_write_oob: " | 1490 | printk(KERN_ERR "onenand_write_oob_nolock: " |
1496 | "Attempt to write past end of page\n"); | 1491 | "Attempt to write past end of page\n"); |
1497 | return -EINVAL; | 1492 | return -EINVAL; |
1498 | } | 1493 | } |
@@ -1501,13 +1496,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1501 | if (unlikely(to >= mtd->size || | 1496 | if (unlikely(to >= mtd->size || |
1502 | column + len > ((mtd->size >> this->page_shift) - | 1497 | column + len > ((mtd->size >> this->page_shift) - |
1503 | (to >> this->page_shift)) * oobsize)) { | 1498 | (to >> this->page_shift)) * oobsize)) { |
1504 | printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n"); | 1499 | printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n"); |
1505 | return -EINVAL; | 1500 | return -EINVAL; |
1506 | } | 1501 | } |
1507 | 1502 | ||
1508 | /* Grab the lock and see if the device is available */ | ||
1509 | onenand_get_device(mtd, FL_WRITING); | ||
1510 | |||
1511 | oobbuf = this->oob_buf; | 1503 | oobbuf = this->oob_buf; |
1512 | 1504 | ||
1513 | /* Loop until all data write */ | 1505 | /* Loop until all data write */ |
@@ -1537,13 +1529,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1537 | 1529 | ||
1538 | ret = this->wait(mtd, FL_WRITING); | 1530 | ret = this->wait(mtd, FL_WRITING); |
1539 | if (ret) { | 1531 | if (ret) { |
1540 | printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret); | 1532 | printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret); |
1541 | break; | 1533 | break; |
1542 | } | 1534 | } |
1543 | 1535 | ||
1544 | ret = onenand_verify_oob(mtd, oobbuf, to); | 1536 | ret = onenand_verify_oob(mtd, oobbuf, to); |
1545 | if (ret) { | 1537 | if (ret) { |
1546 | printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret); | 1538 | printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret); |
1547 | break; | 1539 | break; |
1548 | } | 1540 | } |
1549 | 1541 | ||
@@ -1556,9 +1548,6 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1556 | column = 0; | 1548 | column = 0; |
1557 | } | 1549 | } |
1558 | 1550 | ||
1559 | /* Deselect and wake up anyone waiting on the device */ | ||
1560 | onenand_release_device(mtd); | ||
1561 | |||
1562 | ops->oobretlen = written; | 1551 | ops->oobretlen = written; |
1563 | 1552 | ||
1564 | return ret; | 1553 | return ret; |
@@ -1585,9 +1574,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1585 | }; | 1574 | }; |
1586 | int ret; | 1575 | int ret; |
1587 | 1576 | ||
1588 | ret = onenand_write_ops(mtd, to, &ops); | 1577 | onenand_get_device(mtd, FL_WRITING); |
1589 | *retlen = ops.retlen; | 1578 | ret = onenand_write_ops_nolock(mtd, to, &ops); |
1579 | onenand_release_device(mtd); | ||
1590 | 1580 | ||
1581 | *retlen = ops.retlen; | ||
1591 | return ret; | 1582 | return ret; |
1592 | } | 1583 | } |
1593 | 1584 | ||
@@ -1600,6 +1591,8 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1600 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, | 1591 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, |
1601 | struct mtd_oob_ops *ops) | 1592 | struct mtd_oob_ops *ops) |
1602 | { | 1593 | { |
1594 | int ret; | ||
1595 | |||
1603 | switch (ops->mode) { | 1596 | switch (ops->mode) { |
1604 | case MTD_OOB_PLACE: | 1597 | case MTD_OOB_PLACE: |
1605 | case MTD_OOB_AUTO: | 1598 | case MTD_OOB_AUTO: |
@@ -1610,23 +1603,26 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, | |||
1610 | return -EINVAL; | 1603 | return -EINVAL; |
1611 | } | 1604 | } |
1612 | 1605 | ||
1606 | onenand_get_device(mtd, FL_WRITING); | ||
1613 | if (ops->datbuf) | 1607 | if (ops->datbuf) |
1614 | return onenand_write_ops(mtd, to, ops); | 1608 | ret = onenand_write_ops_nolock(mtd, to, ops); |
1609 | else | ||
1610 | ret = onenand_write_oob_nolock(mtd, to, ops); | ||
1611 | onenand_release_device(mtd); | ||
1615 | 1612 | ||
1616 | return onenand_do_write_oob(mtd, to, ops); | 1613 | return ret; |
1617 | } | 1614 | } |
1618 | 1615 | ||
1619 | /** | 1616 | /** |
1620 | * onenand_block_checkbad - [GENERIC] Check if a block is marked bad | 1617 | * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad |
1621 | * @param mtd MTD device structure | 1618 | * @param mtd MTD device structure |
1622 | * @param ofs offset from device start | 1619 | * @param ofs offset from device start |
1623 | * @param getchip 0, if the chip is already selected | ||
1624 | * @param allowbbt 1, if its allowed to access the bbt area | 1620 | * @param allowbbt 1, if its allowed to access the bbt area |
1625 | * | 1621 | * |
1626 | * Check, if the block is bad. Either by reading the bad block table or | 1622 | * Check, if the block is bad. Either by reading the bad block table or |
1627 | * calling of the scan function. | 1623 | * calling of the scan function. |
1628 | */ | 1624 | */ |
1629 | static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) | 1625 | static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt) |
1630 | { | 1626 | { |
1631 | struct onenand_chip *this = mtd->priv; | 1627 | struct onenand_chip *this = mtd->priv; |
1632 | struct bbm_info *bbm = this->bbm; | 1628 | struct bbm_info *bbm = this->bbm; |
@@ -1687,7 +1683,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1687 | cond_resched(); | 1683 | cond_resched(); |
1688 | 1684 | ||
1689 | /* Check if we have a bad block, we do not erase bad blocks */ | 1685 | /* Check if we have a bad block, we do not erase bad blocks */ |
1690 | if (onenand_block_checkbad(mtd, addr, 0, 0)) { | 1686 | if (onenand_block_isbad_nolock(mtd, addr, 0)) { |
1691 | printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); | 1687 | printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); |
1692 | instr->state = MTD_ERASE_FAILED; | 1688 | instr->state = MTD_ERASE_FAILED; |
1693 | goto erase_exit; | 1689 | goto erase_exit; |
@@ -1751,11 +1747,16 @@ static void onenand_sync(struct mtd_info *mtd) | |||
1751 | */ | 1747 | */ |
1752 | static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) | 1748 | static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) |
1753 | { | 1749 | { |
1750 | int ret; | ||
1751 | |||
1754 | /* Check for invalid offset */ | 1752 | /* Check for invalid offset */ |
1755 | if (ofs > mtd->size) | 1753 | if (ofs > mtd->size) |
1756 | return -EINVAL; | 1754 | return -EINVAL; |
1757 | 1755 | ||
1758 | return onenand_block_checkbad(mtd, ofs, 1, 0); | 1756 | onenand_get_device(mtd, FL_READING); |
1757 | ret = onenand_block_isbad_nolock(mtd, ofs, 0); | ||
1758 | onenand_release_device(mtd); | ||
1759 | return ret; | ||
1759 | } | 1760 | } |
1760 | 1761 | ||
1761 | /** | 1762 | /** |
@@ -1786,7 +1787,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1786 | 1787 | ||
1787 | /* We write two bytes, so we dont have to mess with 16 bit access */ | 1788 | /* We write two bytes, so we dont have to mess with 16 bit access */ |
1788 | ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); | 1789 | ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); |
1789 | return onenand_do_write_oob(mtd, ofs, &ops); | 1790 | return onenand_write_oob_nolock(mtd, ofs, &ops); |
1790 | } | 1791 | } |
1791 | 1792 | ||
1792 | /** | 1793 | /** |
@@ -1809,7 +1810,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1809 | return ret; | 1810 | return ret; |
1810 | } | 1811 | } |
1811 | 1812 | ||
1812 | return this->block_markbad(mtd, ofs); | 1813 | onenand_get_device(mtd, FL_WRITING); |
1814 | ret = this->block_markbad(mtd, ofs); | ||
1815 | onenand_release_device(mtd); | ||
1816 | return ret; | ||
1813 | } | 1817 | } |
1814 | 1818 | ||
1815 | /** | 1819 | /** |
@@ -2008,13 +2012,19 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
2008 | size_t *retlen, u_char *buf) | 2012 | size_t *retlen, u_char *buf) |
2009 | { | 2013 | { |
2010 | struct onenand_chip *this = mtd->priv; | 2014 | struct onenand_chip *this = mtd->priv; |
2015 | struct mtd_oob_ops ops = { | ||
2016 | .len = len, | ||
2017 | .ooblen = 0, | ||
2018 | .datbuf = buf, | ||
2019 | .oobbuf = NULL, | ||
2020 | }; | ||
2011 | int ret; | 2021 | int ret; |
2012 | 2022 | ||
2013 | /* Enter OTP access mode */ | 2023 | /* Enter OTP access mode */ |
2014 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | 2024 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); |
2015 | this->wait(mtd, FL_OTPING); | 2025 | this->wait(mtd, FL_OTPING); |
2016 | 2026 | ||
2017 | ret = mtd->read(mtd, from, len, retlen, buf); | 2027 | ret = onenand_read_ops_nolock(mtd, from, &ops); |
2018 | 2028 | ||
2019 | /* Exit OTP access mode */ | 2029 | /* Exit OTP access mode */ |
2020 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); | 2030 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); |
@@ -2026,19 +2036,20 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
2026 | /** | 2036 | /** |
2027 | * do_otp_write - [DEFAULT] Write OTP block area | 2037 | * do_otp_write - [DEFAULT] Write OTP block area |
2028 | * @param mtd MTD device structure | 2038 | * @param mtd MTD device structure |
2029 | * @param from The offset to write | 2039 | * @param to The offset to write |
2030 | * @param len number of bytes to write | 2040 | * @param len number of bytes to write |
2031 | * @param retlen pointer to variable to store the number of write bytes | 2041 | * @param retlen pointer to variable to store the number of write bytes |
2032 | * @param buf the databuffer to put/get data | 2042 | * @param buf the databuffer to put/get data |
2033 | * | 2043 | * |
2034 | * Write OTP block area. | 2044 | * Write OTP block area. |
2035 | */ | 2045 | */ |
2036 | static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, | 2046 | static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len, |
2037 | size_t *retlen, u_char *buf) | 2047 | size_t *retlen, u_char *buf) |
2038 | { | 2048 | { |
2039 | struct onenand_chip *this = mtd->priv; | 2049 | struct onenand_chip *this = mtd->priv; |
2040 | unsigned char *pbuf = buf; | 2050 | unsigned char *pbuf = buf; |
2041 | int ret; | 2051 | int ret; |
2052 | struct mtd_oob_ops ops; | ||
2042 | 2053 | ||
2043 | /* Force buffer page aligned */ | 2054 | /* Force buffer page aligned */ |
2044 | if (len < mtd->writesize) { | 2055 | if (len < mtd->writesize) { |
@@ -2052,7 +2063,12 @@ static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, | |||
2052 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | 2063 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); |
2053 | this->wait(mtd, FL_OTPING); | 2064 | this->wait(mtd, FL_OTPING); |
2054 | 2065 | ||
2055 | ret = mtd->write(mtd, from, len, retlen, pbuf); | 2066 | ops.len = len; |
2067 | ops.ooblen = 0; | ||
2068 | ops.databuf = pbuf; | ||
2069 | ops.oobbuf = NULL; | ||
2070 | ret = onenand_write_ops_nolock(mtd, to, &ops); | ||
2071 | *retlen = ops.retlen; | ||
2056 | 2072 | ||
2057 | /* Exit OTP access mode */ | 2073 | /* Exit OTP access mode */ |
2058 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); | 2074 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); |
@@ -2087,7 +2103,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, | |||
2087 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | 2103 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); |
2088 | this->wait(mtd, FL_OTPING); | 2104 | this->wait(mtd, FL_OTPING); |
2089 | 2105 | ||
2090 | ret = onenand_do_write_oob(mtd, from, &ops); | 2106 | ret = onenand_write_oob_nolock(mtd, from, &ops); |
2091 | 2107 | ||
2092 | *retlen = ops.oobretlen; | 2108 | *retlen = ops.oobretlen; |
2093 | 2109 | ||
@@ -2136,13 +2152,16 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, | |||
2136 | if (((mtd->writesize * otp_pages) - (from + len)) < 0) | 2152 | if (((mtd->writesize * otp_pages) - (from + len)) < 0) |
2137 | return 0; | 2153 | return 0; |
2138 | 2154 | ||
2155 | onenand_get_device(mtd, FL_OTPING); | ||
2139 | while (len > 0 && otp_pages > 0) { | 2156 | while (len > 0 && otp_pages > 0) { |
2140 | if (!action) { /* OTP Info functions */ | 2157 | if (!action) { /* OTP Info functions */ |
2141 | struct otp_info *otpinfo; | 2158 | struct otp_info *otpinfo; |
2142 | 2159 | ||
2143 | len -= sizeof(struct otp_info); | 2160 | len -= sizeof(struct otp_info); |
2144 | if (len <= 0) | 2161 | if (len <= 0) { |
2145 | return -ENOSPC; | 2162 | ret = -ENOSPC; |
2163 | break; | ||
2164 | } | ||
2146 | 2165 | ||
2147 | otpinfo = (struct otp_info *) buf; | 2166 | otpinfo = (struct otp_info *) buf; |
2148 | otpinfo->start = from; | 2167 | otpinfo->start = from; |
@@ -2162,13 +2181,14 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, | |||
2162 | len -= size; | 2181 | len -= size; |
2163 | *retlen += size; | 2182 | *retlen += size; |
2164 | 2183 | ||
2165 | if (ret < 0) | 2184 | if (ret) |
2166 | return ret; | 2185 | break; |
2167 | } | 2186 | } |
2168 | otp_pages--; | 2187 | otp_pages--; |
2169 | } | 2188 | } |
2189 | onenand_release_device(mtd); | ||
2170 | 2190 | ||
2171 | return 0; | 2191 | return ret; |
2172 | } | 2192 | } |
2173 | 2193 | ||
2174 | /** | 2194 | /** |
@@ -2364,7 +2384,7 @@ static void onenand_print_device_info(int device, int version) | |||
2364 | (16 << density), | 2384 | (16 << density), |
2365 | vcc ? "2.65/3.3" : "1.8", | 2385 | vcc ? "2.65/3.3" : "1.8", |
2366 | device); | 2386 | device); |
2367 | printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version); | 2387 | printk(KERN_INFO "OneNAND version = 0x%04x\n", version); |
2368 | } | 2388 | } |
2369 | 2389 | ||
2370 | static const struct onenand_manufacturers onenand_manuf_ids[] = { | 2390 | static const struct onenand_manufacturers onenand_manuf_ids[] = { |