[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>

authored by Adrian Hunter and committed by Artem Bityutskiy a8de85d5 2fd32d4a

+40 -29
+39 -29
drivers/mtd/onenand/onenand_base.c
··· 727 727 /* TODO handling oob */ 728 728 729 729 stats = mtd->ecc_stats; 730 - while (read < len) { 731 - cond_resched(); 732 730 733 - thislen = min_t(int, mtd->writesize, len - read); 731 + /* Read-while-load method */ 734 732 735 - column = from & (mtd->writesize - 1); 736 - if (column + thislen > mtd->writesize) 737 - thislen = mtd->writesize - column; 733 + /* Do first load to bufferRAM */ 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 + } 738 741 739 - if (!onenand_check_bufferram(mtd, from)) { 740 - this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); 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; 741 746 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 - } 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 + } 746 770 747 - this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); 748 - 749 - if (ret) { 750 - DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret); 751 - goto out; 752 - } 753 - 754 - read += thislen; 755 - 756 - if (read == len) 757 - break; 758 - 759 - from += thislen; 760 - buf += thislen; 761 - } 762 - 763 - out: 764 771 /* Deselect and wake up anyone waiting on the device */ 765 772 onenand_release_device(mtd); 766 773 ··· 780 773 781 774 if (mtd->ecc_stats.failed - stats.failed) 782 775 return -EBADMSG; 776 + 777 + if (ret) 778 + return ret; 783 779 784 780 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; 785 781 }
+1
include/linux/mtd/onenand.h
··· 143 143 #define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) 144 144 #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) 145 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 148 #define ONENAND_GET_SYS_CFG1(this) \ 148 149 (this->read_word(this->base + ONENAND_REG_SYS_CFG1))