[MTD] Simplify NAND locking

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Tue May 23 06:59:02 EDT 2006


Commit:     a36ed2995c56d4f858ecb524a78837473e7115ae
Parent:     819d6a32c397534c819d3c72a3947b7e7e4bec4b
Author:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
AuthorDate: Tue May 23 11:37:03 2006 +0200
Commit:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
CommitDate: Tue May 23 11:37:03 2006 +0200

    [MTD] Simplify NAND locking
    
    Replace the chip lock by a the controller lock. For simple drivers a
    dummy controller structure is created by the scan code.
    This simplifies the locking algorithm in nand_get/release_chip().
    
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>

 drivers/mtd/nand/nand_base.c |   81 ++++++++++++++++++++++--------------------
 include/linux/mtd/nand.h     |    7 ++--
 2 files changed, 47 insertions(+), 41 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 08dffb7..7933ca2 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -172,20 +172,12 @@ static void nand_release_device(struct m
 	/* De-select the NAND device */
 	this->select_chip(mtd, -1);
 
-	if (this->controller) {
-		/* Release the controller and the chip */
-		spin_lock(&this->controller->lock);
-		this->controller->active = NULL;
-		this->state = FL_READY;
-		wake_up(&this->controller->wq);
-		spin_unlock(&this->controller->lock);
-	} else {
-		/* Release the chip */
-		spin_lock(&this->chip_lock);
-		this->state = FL_READY;
-		wake_up(&this->wq);
-		spin_unlock(&this->chip_lock);
-	}
+	/* Release the controller and the chip */
+	spin_lock(&this->controller->lock);
+	this->controller->active = NULL;
+	this->state = FL_READY;
+	wake_up(&this->controller->wq);
+	spin_unlock(&this->controller->lock);
 }
 
 /**
@@ -765,25 +757,18 @@ static void nand_command_lp(struct mtd_i
  */
 static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
 {
-	struct nand_chip *active;
-	spinlock_t *lock;
-	wait_queue_head_t *wq;
+	spinlock_t *lock = &this->controller->lock;
+	wait_queue_head_t *wq = &this->controller->wq;
 	DECLARE_WAITQUEUE(wait, current);
-
-	lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
-	wq = (this->controller) ? &this->controller->wq : &this->wq;
  retry:
-	active = this;
 	spin_lock(lock);
 
 	/* Hardware controller shared among independend devices */
-	if (this->controller) {
-		if (this->controller->active)
-			active = this->controller->active;
-		else
-			this->controller->active = this;
-	}
-	if (active == this && this->state == FL_READY) {
+	/* Hardware controller shared among independend devices */
+	if (!this->controller->active)
+		this->controller->active = this;
+
+	if (this->controller->active == this && this->state == FL_READY) {
 		this->state = new_state;
 		spin_unlock(lock);
 		return 0;
@@ -2312,6 +2297,22 @@ static void nand_resume(struct mtd_info 
 
 }
 
+/*
+ * Free allocated data structures
+ */
+static void nand_free_kmem(struct nand_chip *this)
+{
+	/* Buffer allocated by nand_scan ? */
+	if (this->options & NAND_OOBBUF_ALLOC)
+		kfree(this->oob_buf);
+	/* Buffer allocated by nand_scan ? */
+	if (this->options & NAND_DATABUF_ALLOC)
+		kfree(this->data_buf);
+	/* Controller allocated by nand_scan ? */
+	if (this->options & NAND_CONTROLLER_ALLOC)
+		kfree(this->controller);
+}
+
 /* module_text_address() isn't exported, and it's mostly a pointless
    test if this is a module _anyway_ -- they'd have to try _really_ hard
    to call us from in-kernel code if the core NAND support is modular. */
@@ -2522,9 +2523,8 @@ int nand_scan(struct mtd_info *mtd, int 
 		len = mtd->oobblock + mtd->oobsize;
 		this->data_buf = kmalloc(len, GFP_KERNEL);
 		if (!this->data_buf) {
-			if (this->options & NAND_OOBBUF_ALLOC)
-				kfree(this->oob_buf);
 			printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
+			nand_free_kmem(this);
 			return -ENOMEM;
 		}
 		this->options |= NAND_DATABUF_ALLOC;
@@ -2657,8 +2657,17 @@ int nand_scan(struct mtd_info *mtd, int 
 
 	/* Initialize state, waitqueue and spinlock */
 	this->state = FL_READY;
-	init_waitqueue_head(&this->wq);
-	spin_lock_init(&this->chip_lock);
+	if (!this->controller) {
+		this->controller = kzalloc(sizeof(struct nand_hw_control),
+					   GFP_KERNEL);
+		if (!this->controller) {
+			nand_free_kmem(this);
+			return -ENOMEM;
+		}
+		this->options |= NAND_CONTROLLER_ALLOC;
+	}
+	init_waitqueue_head(&this->controller->wq);
+	spin_lock_init(&this->controller->lock);
 
 	/* De-select the device */
 	this->select_chip(mtd, -1);
@@ -2718,12 +2727,8 @@ #endif
 
 	/* Free bad block table memory */
 	kfree(this->bbt);
-	/* Buffer allocated by nand_scan ? */
-	if (this->options & NAND_OOBBUF_ALLOC)
-		kfree(this->oob_buf);
-	/* Buffer allocated by nand_scan ? */
-	if (this->options & NAND_DATABUF_ALLOC)
-		kfree(this->data_buf);
+	/* Free buffers */
+	nand_free_kmem(this);
 }
 
 EXPORT_SYMBOL_GPL(nand_scan);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index da5e67b..b8792be 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -227,6 +227,8 @@ #define NAND_HWECC_SYNDROME	0x00020000
 #define NAND_SKIP_BBTSCAN	0x00040000
 
 /* Options set by nand scan */
+/* Nand scan has allocated controller struct */
+#define NAND_CONTROLLER_ALLOC	0x20000000
 /* Nand scan has allocated oob_buf */
 #define NAND_OOBBUF_ALLOC	0x40000000
 /* Nand scan has allocated data_buf */
@@ -294,7 +296,6 @@ struct nand_hw_control {
  * @eccbytes: 		[INTERN] number of ecc bytes per ecc-calculation step
  * @eccsteps:		[INTERN] number of ecc calculation steps per page
  * @chip_delay:		[BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
- * @chip_lock:		[INTERN] spinlock used to protect access to this structure and the chip
  * @wq:			[INTERN] wait queue to sleep on if a NAND operation is in progress
  * @state: 		[INTERN] the current state of the NAND device
  * @page_shift:		[INTERN] number of address bits in a page (column address bits)
@@ -317,7 +318,8 @@ struct nand_hw_control {
  * @bbt_td:		[REPLACEABLE] bad block table descriptor for flash lookup
  * @bbt_md:		[REPLACEABLE] bad block table mirror descriptor
  * @badblock_pattern:	[REPLACEABLE] bad block scan pattern used for initial bad block scan
- * @controller:		[OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
+ * @controller:		[REPLACEABLE] a pointer to a hardware controller structure
+ *			which is shared among multiple independend devices
  * @priv:		[OPTIONAL] pointer to private chip date
  * @errstat:		[OPTIONAL] hardware specific function to perform additional error status checks
  *			(determine if errors are correctable)
@@ -352,7 +354,6 @@ struct nand_chip {
 	int		eccbytes;
 	int		eccsteps;
 	int 		chip_delay;
-	spinlock_t	chip_lock;
 	wait_queue_head_t wq;
 	nand_state_t 	state;
 	int 		page_shift;



More information about the linux-mtd-cvs mailing list