mtd/drivers/mtd/nand nand_base.c,1.117,1.118
gleixner at infradead.org
gleixner at infradead.org
Thu Sep 23 19:34:59 EDT 2004
Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv19935
Modified Files:
nand_base.c
Log Message:
add support for hardware controllers shared by multiple independend devices
Index: nand_base.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand_base.c,v
retrieving revision 1.117
retrieving revision 1.118
diff -u -r1.117 -r1.118
--- nand_base.c 23 Sep 2004 22:44:21 -0000 1.117
+++ nand_base.c 23 Sep 2004 23:34:56 -0000 1.118
@@ -24,6 +24,10 @@
*
* 05-19-2004 tglx: Basic support for Renesas AG-AND chips
*
+ * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared
+ * among multiple independend devices. Suggestions and initial patch
+ * from Ben Dooks <ben-mtd at fluff.org>
+ *
* Credits:
* David Woodhouse for adding multichip support
*
@@ -131,25 +135,31 @@
#define nand_verify_pages(...) (0)
#endif
-static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state);
+static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);
/**
- * nand_release_chip - [GENERIC] release chip
+ * nand_release_device - [GENERIC] release chip
* @mtd: MTD device structure
*
* Deselect, release chip lock and wake up anyone waiting on the device
*/
-static void nand_release_chip (struct mtd_info *mtd)
+static void nand_release_device (struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
/* De-select the NAND device */
this->select_chip(mtd, -1);
+ /* Do we have a hardware controller ? */
+ if (this->controller) {
+ spin_lock(&this->controller.lock);
+ active = NULL;
+ spin_unlock(&this->controller.lock);
+ }
/* Release the chip */
- spin_lock_bh (&this->chip_lock);
+ spin_lock (&this->chip_lock);
this->state = FL_READY;
wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
+ spin_unlock (&this->chip_lock);
}
/**
@@ -388,7 +398,7 @@
chipnr = (int)(ofs >> this->chip_shift);
/* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_READING);
+ nand_get_device (this, mtd, FL_READING);
/* Select the NAND device */
this->select_chip(mtd, chipnr);
@@ -410,7 +420,7 @@
if (getchip) {
/* Deselect and wake up anyone waiting on the device */
- nand_release_chip(mtd);
+ nand_release_device(mtd);
}
return res;
@@ -689,15 +699,16 @@
}
/**
- * nand_get_chip - [GENERIC] Get chip for selected access
+ * nand_get_device - [GENERIC] Get chip for selected access
* @this: the nand chip descriptor
* @mtd: MTD device structure
* @new_state: the state which is requested
*
* Get the device and lock it for exclusive access
*/
-static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state)
+static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
{
+ struct nand_chip *active = this;
DECLARE_WAITQUEUE (wait, current);
@@ -705,19 +716,29 @@
* Grab the lock and see if the device is available
*/
retry:
- spin_lock_bh (&this->chip_lock);
-
- if (this->state == FL_READY) {
- this->state = new_state;
- spin_unlock_bh (&this->chip_lock);
- return;
+ /* Hardware controller shared among independend devices */
+ if (this->controller) {
+ spin_lock (&this->controller.lock);
+ if (this->controller.active)
+ active = this->controller.active;
+ else
+ this->controller.active = this;
+ spin_unlock (&this->controller.lock);
}
-
+
+ if (active == this) {
+ spin_lock (&this->chip_lock);
+ if (this->state == FL_READY) {
+ this->state = new_state;
+ spin_unlock (&this->chip_lock);
+ return;
+ }
+ }
set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
+ add_wait_queue (&active->wq, &wait);
+ spin_unlock (&active->chip_lock);
schedule ();
- remove_wait_queue (&this->wq, &wait);
+ remove_wait_queue (&active->wq, &wait);
goto retry;
}
@@ -1045,7 +1066,7 @@
}
/* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd ,FL_READING);
+ nand_get_device (this, mtd ,FL_READING);
/* use userspace supplied oobinfo, if zero */
if (oobsel == NULL)
@@ -1275,7 +1296,7 @@
}
/* Deselect and wake up anyone waiting on the device */
- nand_release_chip(mtd);
+ nand_release_device(mtd);
/*
* Return success, if no ECC failures, else -EBADMSG
@@ -1322,7 +1343,7 @@
}
/* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd , FL_READING);
+ nand_get_device (this, mtd , FL_READING);
/* Select the NAND device */
this->select_chip(mtd, chipnr);
@@ -1373,7 +1394,7 @@
}
/* Deselect and wake up anyone waiting on the device */
- nand_release_chip(mtd);
+ nand_release_device(mtd);
/* Return happy */
*retlen = len;
@@ -1407,7 +1428,7 @@
}
/* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd , FL_READING);
+ nand_get_device (this, mtd , FL_READING);
this->select_chip (mtd, chip);
@@ -1436,7 +1457,7 @@
}
/* Deselect and wake up anyone waiting on the device */
- nand_release_chip(mtd);
+ nand_release_device(mtd);
return 0;
}
@@ -1558,7 +1579,7 @@
}
/* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_WRITING);
+ nand_get_device (this, mtd, FL_WRITING);
/* Calculate chipnr */
chipnr = (int)(to >> this->chip_shift);
@@ -1663,7 +1684,7 @@
out:
/* Deselect and wake up anyone waiting on the device */
- nand_release_chip(mtd);
+ nand_release_device(mtd);
return ret;
}
@@ -1703,7 +1724,7 @@
}
/* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_WRITING);
+ nand_get_device (this, mtd, FL_WRITING);
/* Select the NAND device */
this->select_chip(mtd, chipnr);
@@ -1765,7 +1786,7 @@
ret = 0;
out:
/* Deselect and wake up anyone waiting on the device */
- nand_release_chip(mtd);
+ nand_release_device(mtd);
return ret;
}
@@ -1832,7 +1853,7 @@
}
/* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_WRITING);
+ nand_get_device (this, mtd, FL_WRITING);
/* Get the current chip-nr */
chipnr = (int) (to >> this->chip_shift);
@@ -1946,7 +1967,7 @@
ret = 0;
out:
/* Deselect and wake up anyone waiting on the device */
- nand_release_chip(mtd);
+ nand_release_device(mtd);
*retlen = written;
return ret;
@@ -2035,7 +2056,7 @@
instr->fail_addr = 0xffffffff;
/* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_ERASING);
+ nand_get_device (this, mtd, FL_ERASING);
/* Shift to get first page */
page = (int) (instr->addr >> this->page_shift);
@@ -2106,7 +2127,7 @@
mtd_erase_callback(instr);
/* Deselect and wake up anyone waiting on the device */
- nand_release_chip(mtd);
+ nand_release_device(mtd);
/* Return more or less happy */
return ret;
@@ -2121,43 +2142,13 @@
static void nand_sync (struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE (wait, current);
DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
-retry:
- /* Grab the spinlock */
- spin_lock_bh (&this->chip_lock);
-
- /* See what's going on */
- switch (this->state) {
- case FL_READY:
- case FL_SYNCING:
- this->state = FL_SYNCING;
- spin_unlock_bh (&this->chip_lock);
- break;
-
- default:
- /* Not an idle state */
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule ();
-
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- }
-
- /* Lock the device */
- spin_lock_bh (&this->chip_lock);
-
- /* Set the device to be ready again */
- if (this->state == FL_SYNCING) {
- this->state = FL_READY;
- wake_up (&this->wq);
- }
-
- /* Unlock the device */
- spin_unlock_bh (&this->chip_lock);
+ /* Grab the lock and see if the device is available */
+ nand_get_device (this, mtd, FL_SYNCING);
+ /* Release it and go back */
+ nand_release_device (mtd);
}
More information about the linux-mtd-cvs
mailing list