]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mtd/chips/cfi_cmdset_0001.c
Merge git://git.infradead.org/mtd-2.6
[linux-2.6-omap-h63xx.git] / drivers / mtd / chips / cfi_cmdset_0001.c
index 5f1b472137a024b96fcff3ea3f9bcd654c7389f8..c240454fd113d757794141a160eaaac60015c036 100644 (file)
@@ -58,8 +58,8 @@ static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t
 static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *);
 static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
 static void cfi_intelext_sync (struct mtd_info *);
-static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
-static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 #ifdef CONFIG_MTD_OTP
 static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
@@ -478,6 +478,28 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
                else
                        cfi->chips[i].erase_time = 2000000;
 
+               if (cfi->cfiq->WordWriteTimeoutTyp &&
+                   cfi->cfiq->WordWriteTimeoutMax)
+                       cfi->chips[i].word_write_time_max =
+                               1<<(cfi->cfiq->WordWriteTimeoutTyp +
+                                   cfi->cfiq->WordWriteTimeoutMax);
+               else
+                       cfi->chips[i].word_write_time_max = 50000 * 8;
+
+               if (cfi->cfiq->BufWriteTimeoutTyp &&
+                   cfi->cfiq->BufWriteTimeoutMax)
+                       cfi->chips[i].buffer_write_time_max =
+                               1<<(cfi->cfiq->BufWriteTimeoutTyp +
+                                   cfi->cfiq->BufWriteTimeoutMax);
+
+               if (cfi->cfiq->BlockEraseTimeoutTyp &&
+                   cfi->cfiq->BlockEraseTimeoutMax)
+                       cfi->chips[i].erase_time_max =
+                               1000<<(cfi->cfiq->BlockEraseTimeoutTyp +
+                                      cfi->cfiq->BlockEraseTimeoutMax);
+               else
+                       cfi->chips[i].erase_time_max = 2000000 * 8;
+
                cfi->chips[i].ref_point_counter = 0;
                init_waitqueue_head(&(cfi->chips[i].wq));
        }
@@ -536,8 +558,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
        }
 
        for (i=0; i<mtd->numeraseregions;i++){
-               printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n",
-                      i,mtd->eraseregions[i].offset,
+               printk(KERN_DEBUG "erase region %d: offset=0x%llx,size=0x%x,blocks=%d\n",
+                      i,(unsigned long long)mtd->eraseregions[i].offset,
                       mtd->eraseregions[i].erasesize,
                       mtd->eraseregions[i].numblocks);
        }
@@ -703,6 +725,10 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
        struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
        unsigned long timeo = jiffies + HZ;
 
+       /* Prevent setting state FL_SYNCING for chip in suspended state. */
+       if (mode == FL_SYNCING && chip->oldstate != FL_READY)
+               goto sleep;
+
        switch (chip->state) {
 
        case FL_STATUS:
@@ -808,8 +834,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
        DECLARE_WAITQUEUE(wait, current);
 
  retry:
-       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
-                          || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
+       if (chip->priv &&
+           (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE
+           || mode == FL_SHUTDOWN) && chip->state != FL_SYNCING) {
                /*
                 * OK. We have possibility for contention on the write/erase
                 * operations which are global to the real chip and not per
@@ -859,6 +886,14 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                                return ret;
                        }
                        spin_lock(&shared->lock);
+
+                       /* We should not own chip if it is already
+                        * in FL_SYNCING state. Put contender and retry. */
+                       if (chip->state == FL_SYNCING) {
+                               put_chip(map, contender, contender->start);
+                               spin_unlock(contender->mutex);
+                               goto retry;
+                       }
                        spin_unlock(contender->mutex);
                }
 
@@ -1012,7 +1047,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
 
 static int __xipram xip_wait_for_operation(
                struct map_info *map, struct flchip *chip,
-               unsigned long adr, unsigned int chip_op_time )
+               unsigned long adr, unsigned int chip_op_time_max)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
@@ -1021,7 +1056,7 @@ static int __xipram xip_wait_for_operation(
        flstate_t oldstate, newstate;
 
                start = xip_currtime();
-       usec = chip_op_time * 8;
+       usec = chip_op_time_max;
        if (usec == 0)
                usec = 500000;
        done = 0;
@@ -1131,8 +1166,8 @@ static int __xipram xip_wait_for_operation(
 #define XIP_INVAL_CACHED_RANGE(map, from, size)  \
        INVALIDATE_CACHED_RANGE(map, from, size)
 
-#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \
-       xip_wait_for_operation(map, chip, cmd_adr, usec)
+#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec, usec_max) \
+       xip_wait_for_operation(map, chip, cmd_adr, usec_max)
 
 #else
 
@@ -1144,7 +1179,7 @@ static int __xipram xip_wait_for_operation(
 static int inval_cache_and_wait_for_operation(
                struct map_info *map, struct flchip *chip,
                unsigned long cmd_adr, unsigned long inval_adr, int inval_len,
-               unsigned int chip_op_time)
+               unsigned int chip_op_time, unsigned int chip_op_time_max)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        map_word status, status_OK = CMD(0x80);
@@ -1156,8 +1191,7 @@ static int inval_cache_and_wait_for_operation(
                INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
        spin_lock(chip->mutex);
 
-       /* set our timeout to 8 times the expected delay */
-       timeo = chip_op_time * 8;
+       timeo = chip_op_time_max;
        if (!timeo)
                timeo = 500000;
        reset_timeo = timeo;
@@ -1202,10 +1236,14 @@ static int inval_cache_and_wait_for_operation(
                        remove_wait_queue(&chip->wq, &wait);
                        spin_lock(chip->mutex);
                }
-               if (chip->erase_suspended || chip->write_suspended)  {
-                       /* Suspend has occured while sleep: reset timeout */
+               if (chip->erase_suspended && chip_state == FL_ERASING)  {
+                       /* Erase suspend occured while sleep: reset timeout */
                        timeo = reset_timeo;
                        chip->erase_suspended = 0;
+               }
+               if (chip->write_suspended && chip_state == FL_WRITING)  {
+                       /* Write suspend occured while sleep: reset timeout */
+                       timeo = reset_timeo;
                        chip->write_suspended = 0;
                }
        }
@@ -1217,8 +1255,8 @@ static int inval_cache_and_wait_for_operation(
 
 #endif
 
-#define WAIT_TIMEOUT(map, chip, adr, udelay) \
-       INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay);
+#define WAIT_TIMEOUT(map, chip, adr, udelay, udelay_max) \
+       INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay, udelay_max);
 
 
 static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
@@ -1452,7 +1490,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 
        ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
                                   adr, map_bankwidth(map),
-                                  chip->word_write_time);
+                                  chip->word_write_time,
+                                  chip->word_write_time_max);
        if (ret) {
                xip_enable(map, chip, adr);
                printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
@@ -1623,7 +1662,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 
        chip->state = FL_WRITING_TO_BUFFER;
        map_write(map, write_cmd, cmd_adr);
-       ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0);
+       ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0, 0);
        if (ret) {
                /* Argh. Not ready for write to buffer */
                map_word Xstatus = map_read(map, cmd_adr);
@@ -1640,7 +1679,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 
        /* Figure out the number of words to write */
        word_gap = (-adr & (map_bankwidth(map)-1));
-       words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
+       words = DIV_ROUND_UP(len - word_gap, map_bankwidth(map));
        if (!word_gap) {
                words--;
        } else {
@@ -1692,7 +1731,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 
        ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
                                   initial_adr, initial_len,
-                                  chip->buffer_write_time);
+                                  chip->buffer_write_time,
+                                  chip->buffer_write_time_max);
        if (ret) {
                map_write(map, CMD(0x70), cmd_adr);
                chip->state = FL_STATUS;
@@ -1827,7 +1867,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 
        ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
                                   adr, len,
-                                  chip->erase_time);
+                                  chip->erase_time,
+                                  chip->erase_time_max);
        if (ret) {
                map_write(map, CMD(0x70), adr);
                chip->state = FL_STATUS;
@@ -2006,7 +2047,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
         */
        udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
 
-       ret = WAIT_TIMEOUT(map, chip, adr, udelay);
+       ret = WAIT_TIMEOUT(map, chip, adr, udelay, udelay * 100);
        if (ret) {
                map_write(map, CMD(0x70), adr);
                chip->state = FL_STATUS;
@@ -2021,7 +2062,7 @@ out:      put_chip(map, chip, adr);
        return ret;
 }
 
-static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        int ret;
 
@@ -2045,7 +2086,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
        return ret;
 }
 
-static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        int ret;