Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=49dc08eeda707f59019814fe07a2b17979348002
Commit:     49dc08eeda707f59019814fe07a2b17979348002
Parent:     0bac5111cc00b70460dd8ba8340522e1f0d79f05
Author:     Artem Bityutskiy <[EMAIL PROTECTED]>
AuthorDate: Fri Sep 21 19:35:21 2007 +0300
Committer:  David Woodhouse <[EMAIL PROTECTED]>
CommitDate: Sun Sep 23 19:58:52 2007 +0100

    [MTD] [OneNAND] fix numerous races
    
    This patch make the OneNAND driver much less racy. It fixes
    our "onenand_wait: read timeout!" heisenbugs. The reason of
    these bugs was that the driver did not lock the chip when
    accessing OTP, and it screwed up OneNAND state when the OTP
    was read while JFFS2 was doing FS checking.
    
    This patch also fixes other races I spotted:
    1. BBT was not protected
    2. Access to ecc_stats was not protected
    
    Now the chip is locked when BBT is accessed.
    
    To fix all of these I basically split all interface functions
    on 'function()' and 'function_nolock()' parts.
    
    I tested this patch on N800 hardware - it fixes our problems.
    But I tested a little different version because our OneNAND
    codebase is slightly out-of-date. But it should be OK.
    
    This patch also includes the prin fixes I posted before.
    
    Signed-off-by: Artem Bityutskiy <[EMAIL PROTECTED]>
    Signed-off-by: David Woodhouse <[EMAIL PROTECTED]>
---
 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 40d8d6f..85a9719 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)
        if (interrupt & ONENAND_INT_READ) {
                int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
                if (ecc) {
-                       printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", 
ecc);
                        if (ecc & ONENAND_ECC_2BIT_ALL) {
+                               printk(KERN_ERR "onenand_wait: ECC error = 
0x%04x\n", ecc);
                                mtd->ecc_stats.failed++;
                                return ecc;
-                       } else if (ecc & ONENAND_ECC_1BIT_ALL)
+                       } else if (ecc & ONENAND_ECC_1BIT_ALL) {
+                               printk(KERN_INFO "onenand_wait: correctable ECC 
error = 0x%04x\n", ecc);
                                mtd->ecc_stats.corrected++;
+                       }
                }
        } else if (state == FL_READING) {
                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
 }
 
 /**
- * onenand_read_ops - [OneNAND Interface] OneNAND read main and/or out-of-band
+ * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or 
out-of-band
  * @param mtd          MTD device structure
  * @param from         offset to read from
  * @param ops:         oob operation description structure
  *
  * OneNAND read main and/or out-of-band data
  */
-static int onenand_read_ops(struct mtd_info *mtd, loff_t from,
+static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                                struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
@@ -826,7 +828,7 @@ static int onenand_read_ops(struct mtd_info *mtd, loff_t 
from,
        int ret = 0, boundary = 0;
        int writesize = this->writesize;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops: from = 0x%08x, len = %i\n", 
(unsigned int) from, (int) len);
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = 
%i\n", (unsigned int) from, (int) len);
 
        if (ops->mode == MTD_OOB_AUTO)
                oobsize = this->ecclayout->oobavail;
@@ -837,15 +839,12 @@ static int onenand_read_ops(struct mtd_info *mtd, loff_t 
from,
 
        /* Do not allow reads past end of device */
        if ((from + len) > mtd->size) {
-               printk(KERN_ERR "onenand_read_ops: Attempt read beyond end of 
device\n");
+               printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond 
end of device\n");
                ops->retlen = 0;
                ops->oobretlen = 0;
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_READING);
-
        stats = mtd->ecc_stats;
 
        /* Read-while-load method */
@@ -916,9 +915,6 @@ static int onenand_read_ops(struct mtd_info *mtd, loff_t 
from,
                onenand_update_bufferram(mtd, from, !ret);
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
-
        /*
         * Return success, if no ECC failures, else -EBADMSG
         * fs driver will take care of that, because
@@ -937,14 +933,14 @@ static int onenand_read_ops(struct mtd_info *mtd, loff_t 
from,
 }
 
 /**
- * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band
+ * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
  * @param mtd          MTD device structure
  * @param from         offset to read from
  * @param ops:         oob operation description structure
  *
  * OneNAND read out-of-band data from the spare area
  */
-static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from,
+static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                        struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
@@ -956,7 +952,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t 
from,
 
        from += ops->ooboffs;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", 
(unsigned int) from, (int) len);
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = 
%i\n", (unsigned int) from, (int) len);
 
        /* Initialize return length value */
        ops->oobretlen = 0;
@@ -969,7 +965,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t 
from,
        column = from & (mtd->oobsize - 1);
 
        if (unlikely(column >= oobsize)) {
-               printk(KERN_ERR "onenand_read_oob: Attempted to start read 
outside oob\n");
+               printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start 
read outside oob\n");
                return -EINVAL;
        }
 
@@ -977,13 +973,10 @@ static int onenand_do_read_oob(struct mtd_info *mtd, 
loff_t from,
        if (unlikely(from >= mtd->size ||
                     column + len > ((mtd->size >> this->page_shift) -
                                     (from >> this->page_shift)) * oobsize)) {
-               printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end 
of device\n");
+               printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read 
beyond end of device\n");
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_READING);
-
        while (read < len) {
                cond_resched();
 
@@ -1003,7 +996,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, 
loff_t from,
                        this->read_bufferram(mtd, ONENAND_SPARERAM, buf, 
column, thislen);
 
                if (ret) {
-                       printk(KERN_ERR "onenand_read_oob: read failed = 
0x%x\n", ret);
+                       printk(KERN_ERR "onenand_read_oob_nolock: read failed = 
0x%x\n", ret);
                        break;
                }
 
@@ -1022,9 +1015,6 @@ static int onenand_do_read_oob(struct mtd_info *mtd, 
loff_t from,
                }
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
-
        ops->oobretlen = read;
        return ret;
 }
@@ -1050,9 +1040,11 @@ static int onenand_read(struct mtd_info *mtd, loff_t 
from, size_t len,
        };
        int ret;
 
-       ret = onenand_read_ops(mtd, from, &ops);
-       *retlen = ops.retlen;
+       onenand_get_device(mtd, FL_READING);
+       ret = onenand_read_ops_nolock(mtd, from, &ops);
+       onenand_release_device(mtd);
 
+       *retlen = ops.retlen;
        return ret;
 }
 
@@ -1067,6 +1059,8 @@ static int onenand_read(struct mtd_info *mtd, loff_t 
from, size_t len,
 static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
                            struct mtd_oob_ops *ops)
 {
+       int ret;
+
        switch (ops->mode) {
        case MTD_OOB_PLACE:
        case MTD_OOB_AUTO:
@@ -1077,10 +1071,14 @@ static int onenand_read_oob(struct mtd_info *mtd, 
loff_t from,
                return -EINVAL;
        }
 
+       onenand_get_device(mtd, FL_READING);
        if (ops->datbuf)
-               return onenand_read_ops(mtd, from, ops);
+               ret = onenand_read_ops_nolock(mtd, from, ops);
+       else
+               ret = onenand_read_oob_nolock(mtd, from, ops);
+       onenand_release_device(mtd);
 
-       return onenand_do_read_oob(mtd, from, ops);
+       return ret;
 }
 
 /**
@@ -1317,14 +1315,14 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, 
u_char *oob_buf,
 }
 
 /**
- * onenand_write_ops - [OneNAND Interface] write main and/or out-of-band
+ * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
  * @param mtd          MTD device structure
  * @param to           offset to write to
  * @param ops          oob operation description structure
  *
  * Write main and/or oob with ECC
  */
-static int onenand_write_ops(struct mtd_info *mtd, loff_t to,
+static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
                                struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
@@ -1337,7 +1335,7 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t 
to,
        u_char *oobbuf;
        int ret = 0;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", 
(unsigned int) to, (int) len);
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = 
%i\n", (unsigned int) to, (int) len);
 
        /* Initialize retlen, in case of early exit */
        ops->retlen = 0;
@@ -1345,13 +1343,13 @@ static int onenand_write_ops(struct mtd_info *mtd, 
loff_t to,
 
        /* Do not allow writes past end of device */
        if (unlikely((to + len) > mtd->size)) {
-               printk(KERN_ERR "onenand_write: Attempt write to past end of 
device\n");
+               printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to 
past end of device\n");
                return -EINVAL;
        }
 
        /* Reject writes, which are not page aligned */
         if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
-                printk(KERN_ERR "onenand_write: Attempt to write not page 
aligned data\n");
+                printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write 
not page aligned data\n");
                 return -EINVAL;
         }
 
@@ -1364,9 +1362,6 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t 
to,
 
        column = to & (mtd->writesize - 1);
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_WRITING);
-
        /* Loop until all data write */
        while (written < len) {
                u_char *wbuf = (u_char *) buf;
@@ -1419,14 +1414,14 @@ static int onenand_write_ops(struct mtd_info *mtd, 
loff_t to,
                }
 
                if (ret) {
-                       printk(KERN_ERR "onenand_write: write filaed %d\n", 
ret);
+                       printk(KERN_ERR "onenand_write_ops_nolock: write filaed 
%d\n", ret);
                        break;
                }
 
                /* Only check verify write turn on */
                ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
                if (ret) {
-                       printk(KERN_ERR "onenand_write: verify failed %d\n", 
ret);
+                       printk(KERN_ERR "onenand_write_ops_nolock: verify 
failed %d\n", ret);
                        break;
                }
 
@@ -1450,7 +1445,7 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t 
to,
 
 
 /**
- * onenand_do_write_oob - [Internal] OneNAND write out-of-band
+ * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
  * @param mtd          MTD device structure
  * @param to           offset to write to
  * @param len          number of bytes to write
@@ -1460,8 +1455,8 @@ static int onenand_write_ops(struct mtd_info *mtd, loff_t 
to,
  *
  * OneNAND write out-of-band
  */
-static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to,
-                               struct mtd_oob_ops *ops)
+static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
+                                   struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
        int column, ret = 0, oobsize;
@@ -1473,7 +1468,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, 
loff_t to,
 
        to += ops->ooboffs;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", 
(unsigned int) to, (int) len);
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = 
%i\n", (unsigned int) to, (int) len);
 
        /* Initialize retlen, in case of early exit */
        ops->oobretlen = 0;
@@ -1486,13 +1481,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, 
loff_t to,
        column = to & (mtd->oobsize - 1);
 
        if (unlikely(column >= oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: Attempted to start write 
outside oob\n");
+               printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start 
write outside oob\n");
                return -EINVAL;
        }
 
        /* For compatibility with NAND: Do not allow write past end of page */
        if (unlikely(column + len > oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: "
+               printk(KERN_ERR "onenand_write_oob_nolock: "
                      "Attempt to write past end of page\n");
                return -EINVAL;
        }
@@ -1501,13 +1496,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, 
loff_t to,
        if (unlikely(to >= mtd->size ||
                     column + len > ((mtd->size >> this->page_shift) -
                                     (to >> this->page_shift)) * oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: Attempted to write past end 
of device\n");
+               printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write 
past end of device\n");
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_WRITING);
-
        oobbuf = this->oob_buf;
 
        /* Loop until all data write */
@@ -1537,13 +1529,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, 
loff_t to,
 
                ret = this->wait(mtd, FL_WRITING);
                if (ret) {
-                       printk(KERN_ERR "onenand_write_oob: write failed %d\n", 
ret);
+                       printk(KERN_ERR "onenand_write_oob_nolock: write failed 
%d\n", ret);
                        break;
                }
 
                ret = onenand_verify_oob(mtd, oobbuf, to);
                if (ret) {
-                       printk(KERN_ERR "onenand_write_oob: verify failed 
%d\n", ret);
+                       printk(KERN_ERR "onenand_write_oob_nolock: verify 
failed %d\n", ret);
                        break;
                }
 
@@ -1556,9 +1548,6 @@ static int onenand_do_write_oob(struct mtd_info *mtd, 
loff_t to,
                column = 0;
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
-
        ops->oobretlen = written;
 
        return ret;
@@ -1585,9 +1574,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t 
to, size_t len,
        };
        int ret;
 
-       ret = onenand_write_ops(mtd, to, &ops);
-       *retlen = ops.retlen;
+       onenand_get_device(mtd, FL_WRITING);
+       ret = onenand_write_ops_nolock(mtd, to, &ops);
+       onenand_release_device(mtd);
 
+       *retlen = ops.retlen;
        return ret;
 }
 
@@ -1600,6 +1591,8 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, 
size_t len,
 static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops)
 {
+       int ret;
+
        switch (ops->mode) {
        case MTD_OOB_PLACE:
        case MTD_OOB_AUTO:
@@ -1610,23 +1603,26 @@ static int onenand_write_oob(struct mtd_info *mtd, 
loff_t to,
                return -EINVAL;
        }
 
+       onenand_get_device(mtd, FL_WRITING);
        if (ops->datbuf)
-               return onenand_write_ops(mtd, to, ops);
+               ret = onenand_write_ops_nolock(mtd, to, ops);
+       else
+               ret = onenand_write_oob_nolock(mtd, to, ops);
+       onenand_release_device(mtd);
 
-       return onenand_do_write_oob(mtd, to, ops);
+       return ret;
 }
 
 /**
- * onenand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
  * @param mtd          MTD device structure
  * @param ofs          offset from device start
- * @param getchip      0, if the chip is already selected
  * @param allowbbt     1, if its allowed to access the bbt area
  *
  * Check, if the block is bad. Either by reading the bad block table or
  * calling of the scan function.
  */
-static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int 
getchip, int allowbbt)
+static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int 
allowbbt)
 {
        struct onenand_chip *this = mtd->priv;
        struct bbm_info *bbm = this->bbm;
@@ -1687,7 +1683,7 @@ static int onenand_erase(struct mtd_info *mtd, struct 
erase_info *instr)
                cond_resched();
 
                /* Check if we have a bad block, we do not erase bad blocks */
-               if (onenand_block_checkbad(mtd, addr, 0, 0)) {
+               if (onenand_block_isbad_nolock(mtd, addr, 0)) {
                        printk (KERN_WARNING "onenand_erase: attempt to erase a 
bad block at addr 0x%08x\n", (unsigned int) addr);
                        instr->state = MTD_ERASE_FAILED;
                        goto erase_exit;
@@ -1751,11 +1747,16 @@ static void onenand_sync(struct mtd_info *mtd)
  */
 static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
 {
+       int ret;
+
        /* Check for invalid offset */
        if (ofs > mtd->size)
                return -EINVAL;
 
-       return onenand_block_checkbad(mtd, ofs, 1, 0);
+       onenand_get_device(mtd, FL_READING);
+       ret = onenand_block_isbad_nolock(mtd, ofs, 0);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1786,7 +1787,7 @@ static int onenand_default_block_markbad(struct mtd_info 
*mtd, loff_t ofs)
 
         /* We write two bytes, so we dont have to mess with 16 bit access */
         ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
-        return onenand_do_write_oob(mtd, ofs, &ops);
+        return onenand_write_oob_nolock(mtd, ofs, &ops);
 }
 
 /**
@@ -1809,7 +1810,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, 
loff_t ofs)
                return ret;
        }
 
-       return this->block_markbad(mtd, ofs);
+       onenand_get_device(mtd, FL_WRITING);
+       ret = this->block_markbad(mtd, ofs);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -2008,13 +2012,19 @@ static int do_otp_read(struct mtd_info *mtd, loff_t 
from, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct onenand_chip *this = mtd->priv;
+       struct mtd_oob_ops ops = {
+               .len    = len,
+               .ooblen = 0,
+               .datbuf = buf,
+               .oobbuf = NULL,
+       };
        int ret;
 
        /* Enter OTP access mode */
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = mtd->read(mtd, from, len, retlen, buf);
+       ret = onenand_read_ops_nolock(mtd, from, &ops);
 
        /* Exit OTP access mode */
        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,
 /**
  * do_otp_write - [DEFAULT] Write OTP block area
  * @param mtd          MTD device structure
- * @param from         The offset to write
+ * @param to           The offset to write
  * @param len          number of bytes to write
  * @param retlen       pointer to variable to store the number of write bytes
  * @param buf          the databuffer to put/get data
  *
  * Write OTP block area.
  */
-static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
+static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct onenand_chip *this = mtd->priv;
        unsigned char *pbuf = buf;
        int ret;
+       struct mtd_oob_ops ops;
 
        /* Force buffer page aligned */
        if (len < mtd->writesize) {
@@ -2052,7 +2063,12 @@ static int do_otp_write(struct mtd_info *mtd, loff_t 
from, size_t len,
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = mtd->write(mtd, from, len, retlen, pbuf);
+       ops.len = len;
+       ops.ooblen = 0;
+       ops.databuf = pbuf;
+       ops.oobbuf = NULL;
+       ret = onenand_write_ops_nolock(mtd, to, &ops);
+       *retlen = ops.retlen;
 
        /* Exit OTP access mode */
        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,
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = onenand_do_write_oob(mtd, from, &ops);
+       ret = onenand_write_oob_nolock(mtd, from, &ops);
 
        *retlen = ops.oobretlen;
 
@@ -2136,13 +2152,16 @@ static int onenand_otp_walk(struct mtd_info *mtd, 
loff_t from, size_t len,
        if (((mtd->writesize * otp_pages) - (from + len)) < 0)
                return 0;
 
+       onenand_get_device(mtd, FL_OTPING);
        while (len > 0 && otp_pages > 0) {
                if (!action) {  /* OTP Info functions */
                        struct otp_info *otpinfo;
 
                        len -= sizeof(struct otp_info);
-                       if (len <= 0)
-                               return -ENOSPC;
+                       if (len <= 0) {
+                               ret = -ENOSPC;
+                               break;
+                       }
 
                        otpinfo = (struct otp_info *) buf;
                        otpinfo->start = from;
@@ -2162,13 +2181,14 @@ static int onenand_otp_walk(struct mtd_info *mtd, 
loff_t from, size_t len,
                        len -= size;
                        *retlen += size;
 
-                       if (ret < 0)
-                               return ret;
+                       if (ret)
+                               break;
                }
                otp_pages--;
        }
+       onenand_release_device(mtd);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -2364,7 +2384,7 @@ static void onenand_print_device_info(int device, int 
version)
                 (16 << density),
                 vcc ? "2.65/3.3" : "1.8",
                 device);
-       printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
+       printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
 }
 
 static const struct onenand_manufacturers onenand_manuf_ids[] = {
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to