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 | |
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>
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 81 | ||||
-rw-r--r-- | 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 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); |
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; |