Commit a36ed299 authored by Thomas Gleixner's avatar Thomas Gleixner

[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: default avatarThomas Gleixner <tglx@linutronix.de>
parent 819d6a32
...@@ -172,20 +172,12 @@ static void nand_release_device(struct mtd_info *mtd) ...@@ -172,20 +172,12 @@ static void nand_release_device(struct mtd_info *mtd)
/* De-select the NAND device */ /* De-select the NAND device */
this->select_chip(mtd, -1); this->select_chip(mtd, -1);
if (this->controller) { /* Release the controller and the chip */
/* Release the controller and the chip */ spin_lock(&this->controller->lock);
spin_lock(&this->controller->lock); this->controller->active = NULL;
this->controller->active = NULL; this->state = FL_READY;
this->state = FL_READY; wake_up(&this->controller->wq);
wake_up(&this->controller->wq); spin_unlock(&this->controller->lock);
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);
}
} }
/** /**
...@@ -765,25 +757,18 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, ...@@ -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) static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
{ {
struct nand_chip *active; spinlock_t *lock = &this->controller->lock;
spinlock_t *lock; wait_queue_head_t *wq = &this->controller->wq;
wait_queue_head_t *wq;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
wq = (this->controller) ? &this->controller->wq : &this->wq;
retry: retry:
active = this;
spin_lock(lock); spin_lock(lock);
/* Hardware controller shared among independend devices */ /* Hardware controller shared among independend devices */
if (this->controller) { /* Hardware controller shared among independend devices */
if (this->controller->active) if (!this->controller->active)
active = this->controller->active; this->controller->active = this;
else
this->controller->active = this; if (this->controller->active == this && this->state == FL_READY) {
}
if (active == this && this->state == FL_READY) {
this->state = new_state; this->state = new_state;
spin_unlock(lock); spin_unlock(lock);
return 0; return 0;
...@@ -2312,6 +2297,22 @@ static void nand_resume(struct mtd_info *mtd) ...@@ -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 /* 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 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. */ 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,9 +2523,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
len = mtd->oobblock + mtd->oobsize; len = mtd->oobblock + mtd->oobsize;
this->data_buf = kmalloc(len, GFP_KERNEL); this->data_buf = kmalloc(len, GFP_KERNEL);
if (!this->data_buf) { if (!this->data_buf) {
if (this->options & NAND_OOBBUF_ALLOC)
kfree(this->oob_buf);
printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
nand_free_kmem(this);
return -ENOMEM; return -ENOMEM;
} }
this->options |= NAND_DATABUF_ALLOC; this->options |= NAND_DATABUF_ALLOC;
...@@ -2657,8 +2657,17 @@ int nand_scan(struct mtd_info *mtd, int maxchips) ...@@ -2657,8 +2657,17 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
/* Initialize state, waitqueue and spinlock */ /* Initialize state, waitqueue and spinlock */
this->state = FL_READY; this->state = FL_READY;
init_waitqueue_head(&this->wq); if (!this->controller) {
spin_lock_init(&this->chip_lock); 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 */ /* De-select the device */
this->select_chip(mtd, -1); this->select_chip(mtd, -1);
...@@ -2718,12 +2727,8 @@ void nand_release(struct mtd_info *mtd) ...@@ -2718,12 +2727,8 @@ void nand_release(struct mtd_info *mtd)
/* Free bad block table memory */ /* Free bad block table memory */
kfree(this->bbt); kfree(this->bbt);
/* Buffer allocated by nand_scan ? */ /* Free buffers */
if (this->options & NAND_OOBBUF_ALLOC) nand_free_kmem(this);
kfree(this->oob_buf);
/* Buffer allocated by nand_scan ? */
if (this->options & NAND_DATABUF_ALLOC)
kfree(this->data_buf);
} }
EXPORT_SYMBOL_GPL(nand_scan); EXPORT_SYMBOL_GPL(nand_scan);
......
...@@ -227,6 +227,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ ...@@ -227,6 +227,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
#define NAND_SKIP_BBTSCAN 0x00040000 #define NAND_SKIP_BBTSCAN 0x00040000
/* Options set by nand scan */ /* Options set by nand scan */
/* Nand scan has allocated controller struct */
#define NAND_CONTROLLER_ALLOC 0x20000000
/* Nand scan has allocated oob_buf */ /* Nand scan has allocated oob_buf */
#define NAND_OOBBUF_ALLOC 0x40000000 #define NAND_OOBBUF_ALLOC 0x40000000
/* Nand scan has allocated data_buf */ /* Nand scan has allocated data_buf */
...@@ -294,7 +296,6 @@ struct nand_hw_control { ...@@ -294,7 +296,6 @@ struct nand_hw_control {
* @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step
* @eccsteps: [INTERN] number of ecc calculation steps per page * @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_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 * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
* @state: [INTERN] the current state of the NAND device * @state: [INTERN] the current state of the NAND device
* @page_shift: [INTERN] number of address bits in a page (column address bits) * @page_shift: [INTERN] number of address bits in a page (column address bits)
...@@ -317,7 +318,8 @@ struct nand_hw_control { ...@@ -317,7 +318,8 @@ struct nand_hw_control {
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
* @bbt_md: [REPLACEABLE] bad block table mirror descriptor * @bbt_md: [REPLACEABLE] bad block table mirror descriptor
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan * @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 * @priv: [OPTIONAL] pointer to private chip date
* @errstat: [OPTIONAL] hardware specific function to perform additional error status checks * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
* (determine if errors are correctable) * (determine if errors are correctable)
...@@ -352,7 +354,6 @@ struct nand_chip { ...@@ -352,7 +354,6 @@ struct nand_chip {
int eccbytes; int eccbytes;
int eccsteps; int eccsteps;
int chip_delay; int chip_delay;
spinlock_t chip_lock;
wait_queue_head_t wq; wait_queue_head_t wq;
nand_state_t state; nand_state_t state;
int page_shift; int page_shift;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment