mtd/drivers/mtd/nand nand.c,1.72,1.73

gleixner at infradead.org gleixner at infradead.org
Mon Mar 29 11:04:00 EST 2004


Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv15178

Modified Files:
	nand.c 
Log Message:
change handling of block_bad function, implement mtd interface for bad block management, use a common release_chip function, merge block_bad and block_bad16

Index: nand.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand.c,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -r1.72 -r1.73
--- nand.c	29 Mar 2004 09:49:34 -0000	1.72
+++ nand.c	29 Mar 2004 16:03:58 -0000	1.73
@@ -181,7 +181,24 @@
 			unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
 static void nand_sync (struct mtd_info *mtd);
+
+/* Some internal functions */
 static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,  struct nand_oobinfo *oobsel, int chipnr);
+static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state);
+
+/* Deselect and wake up anyone waiting on the device */
+static void nand_release_chip (struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+
+	/* De-select the NAND device */
+	this->select_chip(mtd, -1);
+	/* Release the chip */
+	spin_lock_bh (&this->chip_lock);
+	this->state = FL_READY;
+	wake_up (&this->wq);
+	spin_unlock_bh (&this->chip_lock);
+}
 
 static u_char nand_read_byte(struct mtd_info *mtd)
 {
@@ -302,34 +319,53 @@
 	return 0;
 }
 
-/* Appropriate chip should already be selected */
-static int nand_block_bad(struct mtd_info *mtd, unsigned long page)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
+	int page, chipnr, res = 0;
 	struct nand_chip *this = mtd->priv;
-	
-	this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page);
-	if (this->read_byte(mtd) != 0xff)
-		return 1;
+	u16 bad;
 
-	return 0;
+	/* Shift to get page */
+	page = ((int) ofs) >> this->page_shift;
+	chipnr = (int)((unsigned long) ofs / this->chipsize);
+
+	/* Grab the lock and see if the device is available */
+	nand_get_chip (this, mtd, FL_READING, NULL);
+
+	/* Select the NAND device */
+	this->select_chip(mtd, chipnr);
+
+	if (this->options & NAND_BUSWIDTH_16) {
+		this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
+		bad = cpu_to_le16(this->read_word(mtd));
+		if (this->badblockpos & 0x1)
+			bad >>= 1;
+		if ((bad & 0xFF) != 0xff)
+			res = 1;
+	} else {
+		this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask);
+		if (this->read_byte(mtd) != 0xff)
+			res = 1;
+	}	
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_chip(mtd);
+	
+	return res;
 }
 
-/* Appropriate chip should already be selected */
-static int nand_block_bad16(struct mtd_info *mtd, unsigned long page)
+/* This is the default implementation, which can be overridden by
+ * a hardware specific driver.
+*/
+static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
 	struct nand_chip *this = mtd->priv;
-	u16 bad;
+	u_char buf[2] = {0, 0};
+	size_t	retlen;
 	
-	this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page);
-
-	bad = cpu_to_le16(this->read_word(mtd));
-	if (this->badblockpos & 0x1)
-		bad >>= 1;
-
-	if ((bad & 0xFF) != 0xff)
-		return 1;
-
-	return 0;
+	ofs += mtd->oobsize + (this->badblockpos & ~0x01);
+	
+	/* We write two bytes, so we dont have to mess with 16 bit access */
+	return nand_write_oob (mtd, ofs , 2, &retlen, buf);
 }
 
 /*
@@ -522,7 +558,7 @@
 /*
  *	Get chip for selected access
  */
-static inline void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
+static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
 {
 
 	DECLARE_WAITQUEUE (wait, current);
@@ -944,14 +980,8 @@
 		}
 	}
 
-	/* De-select the NAND device */
-	this->select_chip(mtd, -1);
-
-	/* Wake up anyone waiting on the device */
-	spin_lock_bh (&this->chip_lock);
-	this->state = FL_READY;
-	wake_up (&this->wq);
-	spin_unlock_bh (&this->chip_lock);
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_chip(mtd);
 
 	/*
 	 * Return success, if no ECC failures, else -EIO
@@ -1041,14 +1071,9 @@
 			} 
 		}
 	}
-	/* De-select the NAND device */
-	this->select_chip(mtd, -1);
 
-	/* Wake up anyone waiting on the device */
-	spin_lock_bh (&this->chip_lock);
-	this->state = FL_READY;
-	wake_up (&this->wq);
-	spin_unlock_bh (&this->chip_lock);
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_chip(mtd);
 
 	/* Return happy */
 	*retlen = len;
@@ -1137,14 +1162,8 @@
 	}
 
 out:
-	/* De-select the NAND device */
-	this->select_chip(mtd, -1);
-
-	/* Wake up anyone waiting on the device */
-	spin_lock_bh (&this->chip_lock);
-	this->state = FL_READY;
-	wake_up (&this->wq);
-	spin_unlock_bh (&this->chip_lock);
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_chip(mtd);
 
 	*retlen = written;
 	return ret;
@@ -1249,14 +1268,8 @@
 #endif
 
 out:
-	/* De-select the NAND device */
-	this->select_chip(mtd, -1);
-
-	/* Wake up anyone waiting on the device */
-	spin_lock_bh (&this->chip_lock);
-	this->state = FL_READY;
-	wake_up (&this->wq);
-	spin_unlock_bh (&this->chip_lock);
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_chip(mtd);
 
 	return ret;
 }
@@ -1377,14 +1390,8 @@
 	}
 
 out:
-	/* De-select the NAND device */
-	this->select_chip(mtd, -1);
-
-	/* Wake up anyone waiting on the device */
-	spin_lock_bh (&this->chip_lock);
-	this->state = FL_READY;
-	wake_up (&this->wq);
-	spin_unlock_bh (&this->chip_lock);
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_chip(mtd);
 
 	*retlen = written;
 	return ret;
@@ -1480,19 +1487,14 @@
 	instr->state = MTD_ERASE_DONE;
 
 erase_exit:
-	/* De-select the NAND device */
-	this->select_chip(mtd, -1);
 
 	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;;
 	/* Do call back function */
 	if (!ret && instr->callback)
 		instr->callback (instr);
 
-	/* The device is ready */
-	spin_lock_bh (&this->chip_lock);
-	this->state = FL_READY;
-	wake_up (&this->wq);
-	spin_unlock_bh (&this->chip_lock);
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_chip(mtd);
 
 	/* Return more or less happy */
 	return ret;
@@ -1544,6 +1546,34 @@
 }
 
 /*
+ * Check whether the block at the given offset is bad
+ */
+static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *this = mtd->priv;
+	
+	/* Check for invalid offset */
+	if (ofs > mtd->size) 
+		return -EINVAL;
+
+	return this->block_bad(mtd, ofs);
+}
+
+/*
+ * Mark the block at the given offset as bad
+ */
+static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *this = mtd->priv;
+		
+	/* Check for invalid offset */
+	if (ofs > mtd->size) 
+		return -EINVAL;
+
+	return this->block_markbad(mtd, ofs);
+}
+
+/*
  * Scan for the NAND device
  */
 int nand_scan (struct mtd_info *mtd, int maxchips)
@@ -1577,7 +1607,9 @@
 	if (!this->read_word)
 		this->read_word = nand_read_word;
 	if (!this->block_bad)
-		this->block_bad = busw ? nand_block_bad16 : nand_block_bad;
+		this->block_bad = nand_block_bad;
+	if (!this->block_markbad)
+		this->block_markbad = nand_default_block_markbad;
 	if (!this->write_buf)
 		this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
 	if (!this->read_buf)
@@ -1764,6 +1796,8 @@
 	mtd->unlock = NULL;
 	mtd->suspend = NULL;
 	mtd->resume = NULL;
+	mtd->block_isbad = nand_block_isbad;
+	mtd->block_markbad = nand_block_markbad;
 	mtd->owner = THIS_MODULE;
 
 	/* Return happy */




More information about the linux-mtd-cvs mailing list