diff options
author | Adrian Hunter <ext-adrian.hunter@nokia.com> | 2007-01-04 02:51:26 -0500 |
---|---|---|
committer | Artem Bityutskiy <dedekind@infradead.org> | 2007-01-10 07:58:42 -0500 |
commit | a8de85d557004d6d4e4cf79ecd6b97339b986fe9 (patch) | |
tree | 02b3b1dfef5dd1f0e197c2584baff302ca6b6fd6 | |
parent | 2fd32d4af83f4535d12d3f6dd23189352a9596fa (diff) |
[MTD] OneNAND: Implement read-while-load
Read-while-load enables higher performance read operations.
Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 74 | ||||
-rw-r--r-- | include/linux/mtd/onenand.h | 1 |
2 files changed, 43 insertions, 32 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index e80857b3bb83..abbe160b4309 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -727,40 +727,47 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
727 | /* TODO handling oob */ | 727 | /* TODO handling oob */ |
728 | 728 | ||
729 | stats = mtd->ecc_stats; | 729 | stats = mtd->ecc_stats; |
730 | while (read < len) { | ||
731 | cond_resched(); | ||
732 | |||
733 | thislen = min_t(int, mtd->writesize, len - read); | ||
734 | |||
735 | column = from & (mtd->writesize - 1); | ||
736 | if (column + thislen > mtd->writesize) | ||
737 | thislen = mtd->writesize - column; | ||
738 | |||
739 | if (!onenand_check_bufferram(mtd, from)) { | ||
740 | this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); | ||
741 | |||
742 | ret = this->wait(mtd, FL_READING); | ||
743 | /* First copy data and check return value for ECC handling */ | ||
744 | onenand_update_bufferram(mtd, from, !ret); | ||
745 | } | ||
746 | |||
747 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | ||
748 | 730 | ||
749 | if (ret) { | 731 | /* Read-while-load method */ |
750 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret); | 732 | |
751 | goto out; | 733 | /* Do first load to bufferRAM */ |
752 | } | 734 | if (read < len) { |
735 | if (!onenand_check_bufferram(mtd, from)) { | ||
736 | this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); | ||
737 | ret = this->wait(mtd, FL_READING); | ||
738 | onenand_update_bufferram(mtd, from, !ret); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | thislen = min_t(int, mtd->writesize, len - read); | ||
743 | column = from & (mtd->writesize - 1); | ||
744 | if (column + thislen > mtd->writesize) | ||
745 | thislen = mtd->writesize - column; | ||
746 | |||
747 | while (!ret) { | ||
748 | /* If there is more to load then start next load */ | ||
749 | from += thislen; | ||
750 | if (read + thislen < len) { | ||
751 | this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); | ||
752 | ONENAND_SET_PREV_BUFFERRAM(this); | ||
753 | } | ||
754 | /* While load is going, read from last bufferRAM */ | ||
755 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | ||
756 | /* See if we are done */ | ||
757 | read += thislen; | ||
758 | if (read == len) | ||
759 | break; | ||
760 | /* Set up for next read from bufferRAM */ | ||
761 | ONENAND_SET_NEXT_BUFFERRAM(this); | ||
762 | buf += thislen; | ||
763 | thislen = min_t(int, mtd->writesize, len - read); | ||
764 | column = 0; | ||
765 | cond_resched(); | ||
766 | /* Now wait for load */ | ||
767 | ret = this->wait(mtd, FL_READING); | ||
768 | onenand_update_bufferram(mtd, from, !ret); | ||
769 | } | ||
753 | 770 | ||
754 | read += thislen; | ||
755 | |||
756 | if (read == len) | ||
757 | break; | ||
758 | |||
759 | from += thislen; | ||
760 | buf += thislen; | ||
761 | } | ||
762 | |||
763 | out: | ||
764 | /* Deselect and wake up anyone waiting on the device */ | 771 | /* Deselect and wake up anyone waiting on the device */ |
765 | onenand_release_device(mtd); | 772 | onenand_release_device(mtd); |
766 | 773 | ||
@@ -774,6 +781,9 @@ out: | |||
774 | if (mtd->ecc_stats.failed - stats.failed) | 781 | if (mtd->ecc_stats.failed - stats.failed) |
775 | return -EBADMSG; | 782 | return -EBADMSG; |
776 | 783 | ||
784 | if (ret) | ||
785 | return ret; | ||
786 | |||
777 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; | 787 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; |
778 | } | 788 | } |
779 | 789 | ||
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index fe3500d7d4bb..f775a7af3890 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h | |||
@@ -143,6 +143,7 @@ struct onenand_chip { | |||
143 | #define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) | 143 | #define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) |
144 | #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) | 144 | #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) |
145 | #define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) | 145 | #define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) |
146 | #define ONENAND_SET_PREV_BUFFERRAM(this) (this->bufferram_index ^= 1) | ||
146 | 147 | ||
147 | #define ONENAND_GET_SYS_CFG1(this) \ | 148 | #define ONENAND_GET_SYS_CFG1(this) \ |
148 | (this->read_word(this->base + ONENAND_REG_SYS_CFG1)) | 149 | (this->read_word(this->base + ONENAND_REG_SYS_CFG1)) |