]> err.no Git - linux-2.6/blobdiff - drivers/mtd/nand/nand_base.c
AUDIT: Reduce contention in audit_serial()
[linux-2.6] / drivers / mtd / nand / nand_base.c
index 4d7c916c74fce5212f100aff62025e06b45dc4e9..1bd71a598c798f845a1331ec8655a796903972bc 100644 (file)
@@ -59,7 +59,7 @@
  *     The AG-AND chips have nice features for speed improvement,
  *     which are not supported yet. Read / program 4 pages in one go.
  *
- * $Id: nand_base.c,v 1.134 2005/02/22 21:56:46 gleixner Exp $
+ * $Id: nand_base.c,v 1.146 2005/06/17 15:02:06 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -167,17 +167,21 @@ static void nand_release_device (struct mtd_info *mtd)
 
        /* De-select the NAND device */
        this->select_chip(mtd, -1);
-       /* Do we have a hardware controller ? */
+
        if (this->controller) {
+               /* Release the controller and the chip */
                spin_lock(&this->controller->lock);
                this->controller->active = NULL;
+               this->state = FL_READY;
+               wake_up(&this->controller->wq);
                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);
        }
-       /* Release the chip */
-       spin_lock (&this->chip_lock);
-       this->state = FL_READY;
-       wake_up (&this->wq);
-       spin_unlock (&this->chip_lock);
 }
 
 /**
@@ -753,37 +757,34 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
  */
 static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
 {
-       struct nand_chip *active = this;
-
+       struct nand_chip *active;
+       spinlock_t *lock;
+       wait_queue_head_t *wq;
        DECLARE_WAITQUEUE (wait, current);
 
-       /* 
-        * Grab the lock and see if the device is available 
-       */
+       lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
+       wq = (this->controller) ? &this->controller->wq : &this->wq;
 retry:
+       active = this;
+       spin_lock(lock);
+
        /* 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 (&active->wq, &wait);
-       spin_unlock (&active->chip_lock);
-       schedule ();
-       remove_wait_queue (&active->wq, &wait);
+       if (active == this && this->state == FL_READY) {
+               this->state = new_state;
+               spin_unlock(lock);
+               return;
+       }
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       add_wait_queue(wq, &wait);
+       spin_unlock(lock);
+       schedule();
+       remove_wait_queue(wq, &wait);
        goto retry;
 }
 
@@ -830,7 +831,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
                        if (this->read_byte(mtd) & NAND_STATUS_READY)
                                break;
                }
-               msleep(1);
+               cond_resched();
        }
        status = (int) this->read_byte(mtd);
        return status;
@@ -1060,8 +1061,8 @@ out:
  */
 static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
 {
-       return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
-}                         
+       return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
+}
 
 
 /**
@@ -1079,6 +1080,9 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                          size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
 {
+       /* use userspace supplied oobinfo, if zero */
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
        return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
 }
 
@@ -1090,7 +1094,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
  * @len:       number of bytes to read
  * @retlen:    pointer to variable to store the number of read bytes
  * @buf:       the databuffer to put data
- * @oob_buf:   filesystem supplied oob data buffer
+ * @oob_buf:   filesystem supplied oob data buffer (can be NULL)
  * @oobsel:    oob selection structure
  * @flags:     flag to indicate if nand_get_device/nand_release_device should be preformed
  *             and how many corrected error bits are acceptable:
@@ -1103,6 +1107,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                             size_t * retlen, u_char * buf, u_char * oob_buf, 
                             struct nand_oobinfo *oobsel, int flags)
 {
+
        int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
        int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
        struct nand_chip *this = mtd->priv;
@@ -1130,10 +1135,6 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        if (flags & NAND_GET_DEVICE)
                nand_get_device (this, mtd, FL_READING);
 
-       /* use userspace supplied oobinfo, if zero */
-       if (oobsel == NULL)
-               oobsel = &mtd->oobinfo;
-       
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
                oobsel = this->autooob;
@@ -1195,7 +1196,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                }       
 
                /* get oob area, if we have no oob buffer from fs-driver */
-               if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE)
+               if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
+                       oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                        oob_data = &this->data_buf[end];
 
                eccsteps = this->eccsteps;
@@ -1284,14 +1286,14 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                        /* without autoplace. Legacy mode used by YAFFS1 */
                        switch(oobsel->useecc) {
                        case MTD_NANDECC_AUTOPLACE:
+                       case MTD_NANDECC_AUTOPL_USR:
                                /* Walk through the autoplace chunks */
-                               for (i = 0, j = 0; j < mtd->oobavail; i++) {
+                               for (i = 0; oobsel->oobfree[i][1]; i++) {
                                        int from = oobsel->oobfree[i][0];
                                        int num = oobsel->oobfree[i][1];
                                        memcpy(&oob_buf[oob], &oob_data[from], num);
-                                       j+= num;
+                                       oob += num;
                                }
-                               oob += mtd->oobavail;
                                break;
                        case MTD_NANDECC_PLACE:
                                /* YAFFS1 legacy mode */
@@ -1646,6 +1648,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                oobsel = this->autooob;
                autoplace = 1;
        }       
+       if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+               autoplace = 1;
 
        /* Setup variables and oob buffer */
        totalpages = len >> this->page_shift;
@@ -1920,6 +1924,8 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                oobsel = this->autooob;
                autoplace = 1;
        }       
+       if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+               autoplace = 1;
 
        /* Setup start page */
        page = (int) (to >> this->page_shift);
@@ -2291,7 +2297,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
  */
 int nand_scan (struct mtd_info *mtd, int maxchips)
 {
-       int i, j, nand_maf_id, nand_dev_id, busw, maf_id;
+       int i, nand_maf_id, nand_dev_id, busw, maf_id;
        struct nand_chip *this = mtd->priv;
 
        /* Get buswidth to select the correct functions*/
@@ -2512,12 +2518,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        
        /* The number of bytes available for the filesystem to place fs dependend
         * oob data */
-       if (this->options & NAND_BUSWIDTH_16) {
-               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
-               if (this->autooob->eccbytes & 0x01)
-                       mtd->oobavail--;
-       } else
-               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
+       mtd->oobavail = 0;
+       for (i = 0; this->autooob->oobfree[i][1]; i++)
+               mtd->oobavail += this->autooob->oobfree[i][1];
 
        /* 
         * check ECC mode, default to software
@@ -2683,8 +2686,8 @@ void nand_release (struct mtd_info *mtd)
                kfree (this->data_buf);
 }
 
-EXPORT_SYMBOL (nand_scan);
-EXPORT_SYMBOL (nand_release);
+EXPORT_SYMBOL_GPL (nand_scan);
+EXPORT_SYMBOL_GPL (nand_release);
 
 MODULE_LICENSE ("GPL");
 MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");