aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-23 05:37:03 -0400
committerThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-23 05:37:03 -0400
commita36ed2995c56d4f858ecb524a78837473e7115ae (patch)
tree510f31485713ae5be63a20fe29b3809f0fafbbb8
parent819d6a32c397534c819d3c72a3947b7e7e4bec4b (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>
-rw-r--r--drivers/mtd/nand/nand_base.c81
-rw-r--r--include/linux/mtd/nand.h7
2 files changed, 47 insertions, 41 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 */
766static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state) 758static 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 */
2303static 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
2729EXPORT_SYMBOL_GPL(nand_scan); 2734EXPORT_SYMBOL_GPL(nand_scan);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index da5e67b3fc70..b8792be3c4e0 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -227,6 +227,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
227#define NAND_SKIP_BBTSCAN 0x00040000 227#define NAND_SKIP_BBTSCAN 0x00040000
228 228
229/* Options set by nand scan */ 229/* Options set by nand scan */
230/* Nand scan has allocated controller struct */
231#define NAND_CONTROLLER_ALLOC 0x20000000
230/* Nand scan has allocated oob_buf */ 232/* Nand scan has allocated oob_buf */
231#define NAND_OOBBUF_ALLOC 0x40000000 233#define NAND_OOBBUF_ALLOC 0x40000000
232/* Nand scan has allocated data_buf */ 234/* Nand scan has allocated data_buf */
@@ -294,7 +296,6 @@ struct nand_hw_control {
294 * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step 296 * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step
295 * @eccsteps: [INTERN] number of ecc calculation steps per page 297 * @eccsteps: [INTERN] number of ecc calculation steps per page
296 * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) 298 * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
297 * @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip
298 * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress 299 * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
299 * @state: [INTERN] the current state of the NAND device 300 * @state: [INTERN] the current state of the NAND device
300 * @page_shift: [INTERN] number of address bits in a page (column address bits) 301 * @page_shift: [INTERN] number of address bits in a page (column address bits)
@@ -317,7 +318,8 @@ struct nand_hw_control {
317 * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup 318 * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
318 * @bbt_md: [REPLACEABLE] bad block table mirror descriptor 319 * @bbt_md: [REPLACEABLE] bad block table mirror descriptor
319 * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan 320 * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
320 * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices 321 * @controller: [REPLACEABLE] a pointer to a hardware controller structure
322 * which is shared among multiple independend devices
321 * @priv: [OPTIONAL] pointer to private chip date 323 * @priv: [OPTIONAL] pointer to private chip date
322 * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks 324 * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
323 * (determine if errors are correctable) 325 * (determine if errors are correctable)
@@ -352,7 +354,6 @@ struct nand_chip {
352 int eccbytes; 354 int eccbytes;
353 int eccsteps; 355 int eccsteps;
354 int chip_delay; 356 int chip_delay;
355 spinlock_t chip_lock;
356 wait_queue_head_t wq; 357 wait_queue_head_t wq;
357 nand_state_t state; 358 nand_state_t state;
358 int page_shift; 359 int page_shift;