diff options
author | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-23 05:37:03 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-23 05:37:03 -0400 |
commit | a36ed2995c56d4f858ecb524a78837473e7115ae (patch) | |
tree | 510f31485713ae5be63a20fe29b3809f0fafbbb8 /drivers/mtd/nand/nand_base.c | |
parent | 819d6a32c397534c819d3c72a3947b7e7e4bec4b (diff) |
[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/mtd/nand/nand_base.c')
-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) | |||
172 | /* De-select the NAND device */ | 172 | /* De-select the NAND device */ |
173 | this->select_chip(mtd, -1); | 173 | this->select_chip(mtd, -1); |
174 | 174 | ||
175 | if (this->controller) { | 175 | /* Release the controller and the chip */ |
176 | /* Release the controller and the chip */ | 176 | spin_lock(&this->controller->lock); |
177 | spin_lock(&this->controller->lock); | 177 | this->controller->active = NULL; |
178 | this->controller->active = NULL; | 178 | this->state = FL_READY; |
179 | this->state = FL_READY; | 179 | wake_up(&this->controller->wq); |
180 | wake_up(&this->controller->wq); | 180 | spin_unlock(&this->controller->lock); |
181 | spin_unlock(&this->controller->lock); | ||
182 | } else { | ||
183 | /* Release the chip */ | ||
184 | spin_lock(&this->chip_lock); | ||
185 | this->state = FL_READY; | ||
186 | wake_up(&this->wq); | ||
187 | spin_unlock(&this->chip_lock); | ||
188 | } | ||
189 | } | 181 | } |
190 | 182 | ||
191 | /** | 183 | /** |
@@ -765,25 +757,18 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, | |||
765 | */ | 757 | */ |
766 | static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state) | 758 | static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state) |
767 | { | 759 | { |
768 | struct nand_chip *active; | 760 | spinlock_t *lock = &this->controller->lock; |
769 | spinlock_t *lock; | 761 | wait_queue_head_t *wq = &this->controller->wq; |
770 | wait_queue_head_t *wq; | ||
771 | DECLARE_WAITQUEUE(wait, current); | 762 | DECLARE_WAITQUEUE(wait, current); |
772 | |||
773 | lock = (this->controller) ? &this->controller->lock : &this->chip_lock; | ||
774 | wq = (this->controller) ? &this->controller->wq : &this->wq; | ||
775 | retry: | 763 | retry: |
776 | active = this; | ||
777 | spin_lock(lock); | 764 | spin_lock(lock); |
778 | 765 | ||
779 | /* Hardware controller shared among independend devices */ | 766 | /* Hardware controller shared among independend devices */ |
780 | if (this->controller) { | 767 | /* Hardware controller shared among independend devices */ |
781 | if (this->controller->active) | 768 | if (!this->controller->active) |
782 | active = this->controller->active; | 769 | this->controller->active = this; |
783 | else | 770 | |
784 | this->controller->active = this; | 771 | if (this->controller->active == this && this->state == FL_READY) { |
785 | } | ||
786 | if (active == this && this->state == FL_READY) { | ||
787 | this->state = new_state; | 772 | this->state = new_state; |
788 | spin_unlock(lock); | 773 | spin_unlock(lock); |
789 | return 0; | 774 | return 0; |
@@ -2312,6 +2297,22 @@ static void nand_resume(struct mtd_info *mtd) | |||
2312 | 2297 | ||
2313 | } | 2298 | } |
2314 | 2299 | ||
2300 | /* | ||
2301 | * Free allocated data structures | ||
2302 | */ | ||
2303 | static void nand_free_kmem(struct nand_chip *this) | ||
2304 | { | ||
2305 | /* Buffer allocated by nand_scan ? */ | ||
2306 | if (this->options & NAND_OOBBUF_ALLOC) | ||
2307 | kfree(this->oob_buf); | ||
2308 | /* Buffer allocated by nand_scan ? */ | ||
2309 | if (this->options & NAND_DATABUF_ALLOC) | ||
2310 | kfree(this->data_buf); | ||
2311 | /* Controller allocated by nand_scan ? */ | ||
2312 | if (this->options & NAND_CONTROLLER_ALLOC) | ||
2313 | kfree(this->controller); | ||
2314 | } | ||
2315 | |||
2315 | /* module_text_address() isn't exported, and it's mostly a pointless | 2316 | /* module_text_address() isn't exported, and it's mostly a pointless |
2316 | test if this is a module _anyway_ -- they'd have to try _really_ hard | 2317 | test if this is a module _anyway_ -- they'd have to try _really_ hard |
2317 | to call us from in-kernel code if the core NAND support is modular. */ | 2318 | 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) | |||
2522 | len = mtd->oobblock + mtd->oobsize; | 2523 | len = mtd->oobblock + mtd->oobsize; |
2523 | this->data_buf = kmalloc(len, GFP_KERNEL); | 2524 | this->data_buf = kmalloc(len, GFP_KERNEL); |
2524 | if (!this->data_buf) { | 2525 | if (!this->data_buf) { |
2525 | if (this->options & NAND_OOBBUF_ALLOC) | ||
2526 | kfree(this->oob_buf); | ||
2527 | printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); | 2526 | printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); |
2527 | nand_free_kmem(this); | ||
2528 | return -ENOMEM; | 2528 | return -ENOMEM; |
2529 | } | 2529 | } |
2530 | this->options |= NAND_DATABUF_ALLOC; | 2530 | this->options |= NAND_DATABUF_ALLOC; |
@@ -2657,8 +2657,17 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
2657 | 2657 | ||
2658 | /* Initialize state, waitqueue and spinlock */ | 2658 | /* Initialize state, waitqueue and spinlock */ |
2659 | this->state = FL_READY; | 2659 | this->state = FL_READY; |
2660 | init_waitqueue_head(&this->wq); | 2660 | if (!this->controller) { |
2661 | spin_lock_init(&this->chip_lock); | 2661 | this->controller = kzalloc(sizeof(struct nand_hw_control), |
2662 | GFP_KERNEL); | ||
2663 | if (!this->controller) { | ||
2664 | nand_free_kmem(this); | ||
2665 | return -ENOMEM; | ||
2666 | } | ||
2667 | this->options |= NAND_CONTROLLER_ALLOC; | ||
2668 | } | ||
2669 | init_waitqueue_head(&this->controller->wq); | ||
2670 | spin_lock_init(&this->controller->lock); | ||
2662 | 2671 | ||
2663 | /* De-select the device */ | 2672 | /* De-select the device */ |
2664 | this->select_chip(mtd, -1); | 2673 | this->select_chip(mtd, -1); |
@@ -2718,12 +2727,8 @@ void nand_release(struct mtd_info *mtd) | |||
2718 | 2727 | ||
2719 | /* Free bad block table memory */ | 2728 | /* Free bad block table memory */ |
2720 | kfree(this->bbt); | 2729 | kfree(this->bbt); |
2721 | /* Buffer allocated by nand_scan ? */ | 2730 | /* Free buffers */ |
2722 | if (this->options & NAND_OOBBUF_ALLOC) | 2731 | nand_free_kmem(this); |
2723 | kfree(this->oob_buf); | ||
2724 | /* Buffer allocated by nand_scan ? */ | ||
2725 | if (this->options & NAND_DATABUF_ALLOC) | ||
2726 | kfree(this->data_buf); | ||
2727 | } | 2732 | } |
2728 | 2733 | ||
2729 | EXPORT_SYMBOL_GPL(nand_scan); | 2734 | EXPORT_SYMBOL_GPL(nand_scan); |