changeset 2975:7050b2f79b6e

NAND bbt: fix internal race
author Ross Younger <wry@ecoscentric.com>
date Tue, 10 Nov 2009 15:44:43 +0000
parents 54682dd5e6fe
children 758f9d488949
files packages/io/nand/current/ChangeLog packages/io/nand/current/src/nand.c packages/io/nand/current/src/nand_bbt.c packages/io/nand/current/src/nand_bbt.h
diffstat 4 files changed, 28 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/packages/io/nand/current/ChangeLog
+++ b/packages/io/nand/current/ChangeLog
@@ -10,7 +10,7 @@ 2009-11-09  Ross Younger  <wry@eCosCentr
 	* tests: Update for interface tweak.
 	* nand_bbt.c: Rationalise BBT finding into one place and fix to 
 	  better cope with the situation where only one BBT block had
-	  been written.
+	  been written. Cure an internal race.
 	* nand_ecc_mtd_fast.c: Speed up checking phase.
 
 2009-11-06  Ross Younger  <wry@eCosCentric.com>
--- a/packages/io/nand/current/src/nand.c
+++ b/packages/io/nand/current/src/nand.c
@@ -262,7 +262,7 @@ static int valid_page_addr(cyg_nand_part
 int cyg_nand_read_page(cyg_nand_partition *prt, cyg_nand_page_addr page,
                 void * dest, void * spare, size_t spare_size)
 {
-    int rv;
+    int rv, locked=0;
     PARTITION_CHECK(prt);
     cyg_nand_device *dev = prt->dev;
     DEV_INIT_CHECK(dev);
@@ -279,9 +279,12 @@ int cyg_nand_read_page(cyg_nand_partitio
     }
 #endif
 
+    LOCK_DEV(dev);
+    locked = 1;
     EG(nandi_read_whole_page_raw(dev, page, dest, spare, spare_size, 1));
 
 err_exit:
+    if (locked) UNLOCK_DEV(dev);
     return rv;
 }
 
@@ -297,7 +300,7 @@ int cyg_nand_read_part_page(cyg_nand_par
     cyg_nand_device *dev = prt->dev;
     DEV_INIT_CHECK(dev);
     CYG_BYTE *pagebuffer;
-    int got_pagebuf = 0;
+    int got_pagebuf = 0, locked = 0;
 
     if (offset + length > NAND_BYTES_PER_PAGE(dev)) return -EFBIG;
 
@@ -311,6 +314,9 @@ int cyg_nand_read_part_page(cyg_nand_par
     }
 #endif
 
+    LOCK_DEV(dev);
+    locked = 1;
+
     if (dev->fns->read_part_page && !check_ecc) {
         EG(dev->fns->read_part_page(dev, dest, page, offset, length));
     } else {
@@ -323,11 +329,13 @@ int cyg_nand_read_part_page(cyg_nand_par
 
 err_exit:
     if (got_pagebuf) nandi_release_pagebuf();
+    if (locked) UNLOCK_DEV(dev);
     return rv;
 }
 
 
-/* Internal, mostly-unchecked interface to read a page. */
+/* Internal, mostly-unchecked interface to read a page. 
+ * Caller must hold the devlock! */
 int nandi_read_whole_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
             CYG_BYTE * dest, CYG_BYTE * spare, size_t spare_size,
             int check_ecc)
@@ -353,8 +361,6 @@ int nandi_read_whole_page_raw(cyg_nand_d
 
     CYG_ASSERTC(NAND_BYTES_PER_PAGE(dev) % ecc_data_stride == 0);
 
-    LOCK_DEV(dev);
-
     do {
         CYG_BYTE *data_dest = dest;
         CYG_BYTE *ecc_dest = ecc_calc;
@@ -456,7 +462,6 @@ int nandi_read_whole_page_raw(cyg_nand_d
             break;
     }
 err_exit:
-    UNLOCK_DEV(dev);
     return rv;
 }
 
@@ -465,7 +470,7 @@ err_exit:
 int cyg_nand_write_page(cyg_nand_partition *prt, cyg_nand_page_addr page,
         const void * src, const void * spare, size_t spare_size)
 {
-    int rv;
+    int rv, locked = 0;
     PARTITION_CHECK(prt);
     cyg_nand_device *dev = prt->dev;
     DEV_INIT_CHECK(dev);
@@ -479,9 +484,12 @@ int cyg_nand_write_page(cyg_nand_partiti
         EG(-EINVAL);
     }
 #endif
+    LOCK_DEV(dev);
+    locked = 1;
     EG(nandi_write_page_raw(dev, page, src, spare, spare_size));
 
 err_exit:
+    if (locked) UNLOCK_DEV(dev);
     return rv;
 }
 
@@ -525,7 +533,6 @@ int nandi_write_page_raw(cyg_nand_device
         }
     }
 
-    LOCK_DEV(dev);
     EG(dev->fns->write_begin(dev, page));
     if (src) {
         remain = NAND_BYTES_PER_PAGE(dev);
@@ -553,7 +560,6 @@ int nandi_write_page_raw(cyg_nand_device
      * if ECC is being used. */
 
 err_exit:
-    UNLOCK_DEV(dev);
     return rv;
 #endif
 }
--- a/packages/io/nand/current/src/nand_bbt.c
+++ b/packages/io/nand/current/src/nand_bbt.c
@@ -656,7 +656,8 @@ err_exit:
 }
 
 
-/* Increments the BBT version, then writes out _both_ tables*/
+/* Increments the BBT version, then writes out _both_ tables. 
+ * Caller must have the devlock. */
 static int cyg_nand_bbti_write_tables(cyg_nand_device *dev, int is_initial)
 {
     int rv, retries=-1;
--- a/packages/io/nand/current/src/nand_bbt.h
+++ b/packages/io/nand/current/src/nand_bbt.h
@@ -80,16 +80,20 @@ typedef enum {
  * or -ve error code. */
 int cyg_nand_bbti_query(cyg_nand_device *dev, cyg_nand_block_addr blk);
 
-/* Marks a block as bad. Returns 0 for success, or -ve error code. */
+/* Marks a block as bad. Returns 0 for success, or -ve error code.
+ * Caller must have locked the devlock. */
 int cyg_nand_bbti_markbad(cyg_nand_device *dev, cyg_nand_block_addr blk);
 
 /* Marks a block arbitrarily. Normal applications should never use this.
- * Returns 0 for success, or -ve error code. */
+ * Returns 0 for success, or -ve error code.
+ * Caller must have locked the devlock. */
 int cyg_nand_bbti_markany(cyg_nand_device *dev, cyg_nand_block_addr blk,
                           cyg_nand_bbt_status_t st);
 
 /* Looks to find the bad block table(s) on the chip and read them in.
  * Updates dev->bbt.* as appropriate.
+ * Caller must have locked the devlock or (more likely) the device not 
+ * be accessible to callers yet (as we're running from nand_lookup).
  *
  * Returns: 0 if either or both were found;
  *          -ENOENT if neither; 
@@ -99,6 +103,8 @@ int cyg_nand_bbti_find_tables(cyg_nand_d
 
 /* Creates the initial BBTs by running a scan for factory bad blocks.
  * Returns: 0 if OK, else a -ve error code.
+ * Caller must have locked the devlock or (more likely) the device not 
+ * be accessible to callers yet (as we're running from nand_lookup).
  */
 int cyg_nand_bbti_build_tables(cyg_nand_device *dev);
 
@@ -116,11 +122,13 @@ int cyg_nand_bbti_build_tables(cyg_nand_
 
 /* Raw unchecked NAND access, for use by the BBT ===================== */
 
+/* Caller must hold the devlock! */
 int nandi_read_whole_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
                               CYG_BYTE * dest,
                               CYG_BYTE * spare, size_t spare_size,
                               int check_ecc);
 
+/* Caller must hold the devlock! */
 int nandi_write_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
                          const CYG_BYTE * src,
                          const CYG_BYTE * spare, size_t spare_size);