]> err.no Git - linux-2.6/commitdiff
[MTD] OneNAND: Implement read-while-load
authorAdrian Hunter <ext-adrian.hunter@nokia.com>
Thu, 4 Jan 2007 07:51:26 +0000 (09:51 +0200)
committerArtem Bityutskiy <dedekind@infradead.org>
Wed, 10 Jan 2007 12:58:42 +0000 (14:58 +0200)
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>
drivers/mtd/onenand/onenand_base.c
include/linux/mtd/onenand.h

index e80857b3bb83dde457e93961016ae60f8a657027..abbe160b43092fff9623b4e72e4e56ee2aa16d4c 100644 (file)
@@ -727,40 +727,47 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
        /* TODO handling oob */
 
        stats = mtd->ecc_stats;
-       while (read < len) {
-               cond_resched();
-
-               thislen = min_t(int, mtd->writesize, len - read);
-
-               column = from & (mtd->writesize - 1);
-               if (column + thislen > mtd->writesize)
-                       thislen = mtd->writesize - column;
-
-               if (!onenand_check_bufferram(mtd, from)) {
-                       this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
-
-                       ret = this->wait(mtd, FL_READING);
-                       /* First copy data and check return value for ECC handling */
-                       onenand_update_bufferram(mtd, from, !ret);
-               }
-
-               this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
 
-               if (ret) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret);
-                       goto out;
-               }
+       /* Read-while-load method */
+
+       /* Do first load to bufferRAM */
+       if (read < len) {
+               if (!onenand_check_bufferram(mtd, from)) {
+                       this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+                       ret = this->wait(mtd, FL_READING);
+                       onenand_update_bufferram(mtd, from, !ret);
+               }
+       }
+
+       thislen = min_t(int, mtd->writesize, len - read);
+       column = from & (mtd->writesize - 1);
+       if (column + thislen > mtd->writesize)
+               thislen = mtd->writesize - column;
+
+       while (!ret) {
+               /* If there is more to load then start next load */
+               from += thislen;
+               if (read + thislen < len) {
+                       this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+                       ONENAND_SET_PREV_BUFFERRAM(this);
+               }
+               /* While load is going, read from last bufferRAM */
+               this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+               /* See if we are done */
+               read += thislen;
+               if (read == len)
+                       break;
+               /* Set up for next read from bufferRAM */
+               ONENAND_SET_NEXT_BUFFERRAM(this);
+               buf += thislen;
+               thislen = min_t(int, mtd->writesize, len - read);
+               column = 0;
+               cond_resched();
+               /* Now wait for load */
+               ret = this->wait(mtd, FL_READING);
+               onenand_update_bufferram(mtd, from, !ret);
+       }
 
-               read += thislen;
-
-               if (read == len)
-                       break;
-
-               from += thislen;
-               buf += thislen;
-       }
-
-out:
        /* Deselect and wake up anyone waiting on the device */
        onenand_release_device(mtd);
 
@@ -774,6 +781,9 @@ out:
        if (mtd->ecc_stats.failed - stats.failed)
                return -EBADMSG;
 
+       if (ret)
+               return ret;
+
        return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
index fe3500d7d4bbc27c29b30f11f27d61233e014ace..f775a7af3890087215ce16504a8da68f513310dd 100644 (file)
@@ -143,6 +143,7 @@ struct onenand_chip {
 #define ONENAND_CURRENT_BUFFERRAM(this)                (this->bufferram_index)
 #define ONENAND_NEXT_BUFFERRAM(this)           (this->bufferram_index ^ 1)
 #define ONENAND_SET_NEXT_BUFFERRAM(this)       (this->bufferram_index ^= 1)
+#define ONENAND_SET_PREV_BUFFERRAM(this)       (this->bufferram_index ^= 1)
 
 #define ONENAND_GET_SYS_CFG1(this)                                     \
        (this->read_word(this->base + ONENAND_REG_SYS_CFG1))