diff options
author | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-23 11:37:03 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-23 11:37:03 +0200 |
commit | a36ed2995c56d4f858ecb524a78837473e7115ae (patch) | |
tree | 510f31485713ae5be63a20fe29b3809f0fafbbb8 /drivers | |
parent | [MTD] Improve software ECC calculation (diff) | |
download | linux-a36ed2995c56d4f858ecb524a78837473e7115ae.tar.xz linux-a36ed2995c56d4f858ecb524a78837473e7115ae.zip |
[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@linutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 81 |
1 files changed, 43 insertions, 38 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 08dffb7a9389..7933ca273c95 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 mtd_info *mtd) /* 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_info *mtd, unsigned command, int column, */ 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 *mtd) } +/* + * 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 maxchips) 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 maxchips) /* 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 @@ void nand_release(struct mtd_info *mtd) /* 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); |