rtc-philips-pcf2123-rtc-spi-driver-updates
[safe/jmp/linux-2.6] / drivers / mtd / chips / cfi_cmdset_0001.c
index 3aa3dca..e7563a9 100644 (file)
@@ -4,10 +4,8 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.186 2005/11/23 22:07:52 nico Exp $
  *
- *
- * 10/10/2000  Nicolas Pitre <nico@cam.org>
+ * 10/10/2000  Nicolas Pitre <nico@fluxnic.net>
  *     - completely revamped method functions so they are aware and
  *       independent of the flash geometry (buswidth, interleave, etc.)
  *     - scalability vs code size is completely set at compile-time
 #define MANUFACTURER_INTEL     0x0089
 #define I82802AB       0x00ad
 #define I82802AC       0x00ac
+#define PF38F4476      0x881c
 #define MANUFACTURER_ST         0x0020
 #define M50LPW080       0x002F
+#define M50FLW080A     0x0080
+#define M50FLW080B     0x0081
+#define AT49BV640D     0x02de
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -57,8 +59,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 *);
@@ -81,10 +83,10 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
 static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
 
 static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
-                    size_t *retlen, u_char **mtdbuf);
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
-                       size_t len);
+                    size_t *retlen, void **virt, resource_size_t *phys);
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
 
+static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
 static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
 #include "fwh_lock.h"
@@ -156,13 +158,54 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
 }
 #endif
 
+/* Atmel chips don't use the same PRI format as Intel chips */
+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+       struct cfi_pri_atmel atmel_pri;
+       uint32_t features = 0;
+
+       /* Reverse byteswapping */
+       extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport);
+       extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask);
+       extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr);
+
+       memcpy(&atmel_pri, extp, sizeof(atmel_pri));
+       memset((char *)extp + 5, 0, sizeof(*extp) - 5);
+
+       printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features);
+
+       if (atmel_pri.Features & 0x01) /* chip erase supported */
+               features |= (1<<0);
+       if (atmel_pri.Features & 0x02) /* erase suspend supported */
+               features |= (1<<1);
+       if (atmel_pri.Features & 0x04) /* program suspend supported */
+               features |= (1<<2);
+       if (atmel_pri.Features & 0x08) /* simultaneous operations supported */
+               features |= (1<<9);
+       if (atmel_pri.Features & 0x20) /* page mode read supported */
+               features |= (1<<7);
+       if (atmel_pri.Features & 0x40) /* queued erase supported */
+               features |= (1<<4);
+       if (atmel_pri.Features & 0x80) /* Protection bits supported */
+               features |= (1<<6);
+
+       extp->FeatureSupport = features;
+
+       /* burst write mode not supported */
+       cfi->cfiq->BufWriteTimeoutTyp = 0;
+       cfi->cfiq->BufWriteTimeoutMax = 0;
+}
+
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
 static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
 
        printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
                            "erase on write disabled.\n");
@@ -226,13 +269,20 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
 /*
  * Some chips power-up with all sectors locked by default.
  */
-static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
+static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
 {
-       printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
-       mtd->flags |= MTD_STUPID_LOCK;
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+
+       if (cfip->FeatureSupport&32) {
+               printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
+               mtd->flags |= MTD_POWERUP_LOCK;
+       }
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+       { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
 #endif
@@ -244,7 +294,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #endif
        { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
        { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-       { MANUFACTURER_INTEL, 0x891c,         fixup_use_powerup_lock, NULL, },
+       { MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
 
@@ -252,6 +302,8 @@ static struct cfi_fixup jedec_fixup_table[] = {
        { MANUFACTURER_INTEL, I82802AB,   fixup_use_fwh_lock, NULL, },
        { MANUFACTURER_INTEL, I82802AC,   fixup_use_fwh_lock, NULL, },
        { MANUFACTURER_ST,    M50LPW080,  fixup_use_fwh_lock, NULL, },
+       { MANUFACTURER_ST,    M50FLW080A, fixup_use_fwh_lock, NULL, },
+       { MANUFACTURER_ST,    M50FLW080B, fixup_use_fwh_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
 static struct cfi_fixup fixup_table[] = {
@@ -264,10 +316,20 @@ static struct cfi_fixup fixup_table[] = {
        { 0, 0, NULL, NULL }
 };
 
+static void cfi_fixup_major_minor(struct cfi_private *cfi,
+                                               struct cfi_pri_intelext *extp)
+{
+       if (cfi->mfr == MANUFACTURER_INTEL &&
+                       cfi->id == PF38F4476 && extp->MinorVersion == '3')
+               extp->MinorVersion = '1';
+}
+
 static inline struct cfi_pri_intelext *
 read_pri_intelext(struct map_info *map, __u16 adr)
 {
+       struct cfi_private *cfi = map->fldrv_priv;
        struct cfi_pri_intelext *extp;
+       unsigned int extra_size = 0;
        unsigned int extp_size = sizeof(*extp);
 
  again:
@@ -275,8 +337,10 @@ read_pri_intelext(struct map_info *map, __u16 adr)
        if (!extp)
                return NULL;
 
+       cfi_fixup_major_minor(cfi, extp);
+
        if (extp->MajorVersion != '1' ||
-           (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
+           (extp->MinorVersion < '0' || extp->MinorVersion > '5')) {
                printk(KERN_ERR "  Unknown Intel/Sharp Extended Query "
                       "version %c.%c.\n",  extp->MajorVersion,
                       extp->MinorVersion);
@@ -289,19 +353,24 @@ read_pri_intelext(struct map_info *map, __u16 adr)
        extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
        extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
 
-       if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') {
-               unsigned int extra_size = 0;
-               int nb_parts, i;
+       if (extp->MinorVersion >= '0') {
+               extra_size = 0;
 
                /* Protection Register info */
                extra_size += (extp->NumProtectionFields - 1) *
                              sizeof(struct cfi_intelext_otpinfo);
+       }
 
+       if (extp->MinorVersion >= '1') {
                /* Burst Read info */
                extra_size += 2;
                if (extp_size < sizeof(*extp) + extra_size)
                        goto need_more;
-               extra_size += extp->extra[extra_size-1];
+               extra_size += extp->extra[extra_size - 1];
+       }
+
+       if (extp->MinorVersion >= '3') {
+               int nb_parts, i;
 
                /* Number of hardware-partitions */
                extra_size += 1;
@@ -334,7 +403,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                        if (extp_size > 4096) {
                                printk(KERN_ERR
                                        "%s: cfi_pri_intelext is too fat\n",
-                                       __FUNCTION__);
+                                       __func__);
                                return NULL;
                        }
                        goto again;
@@ -427,6 +496,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));
        }
@@ -485,8 +576,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);
        }
@@ -569,6 +660,9 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                                  sizeof(struct cfi_intelext_blockinfo);
                }
 
+               if (!numparts)
+                       numparts = 1;
+
                /* Programming Region info */
                if (extp->MinorVersion >= '4') {
                        struct cfi_intelext_programming_regioninfo *prinfo;
@@ -591,7 +685,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                if ((1 << partshift) < mtd->erasesize) {
                        printk( KERN_ERR
                                "%s: bad number of hw partitions (%d)\n",
-                               __FUNCTION__, numparts);
+                               __func__, numparts);
                        return -EINVAL;
                }
 
@@ -641,73 +735,17 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
 /*
  *  *********** CHIP ACCESS FUNCTIONS ***********
  */
-
-static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
+static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct cfi_private *cfi = map->fldrv_priv;
        map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
-       unsigned long timeo;
        struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+       unsigned long timeo = jiffies + HZ;
 
- resettime:
-       timeo = jiffies + HZ;
- retry:
-       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
-               /*
-                * OK. We have possibility for contension on the write/erase
-                * operations which are global to the real chip and not per
-                * partition.  So let's fight it over in the partition which
-                * currently has authority on the operation.
-                *
-                * The rules are as follows:
-                *
-                * - any write operation must own shared->writing.
-                *
-                * - any erase operation must own _both_ shared->writing and
-                *   shared->erasing.
-                *
-                * - contension arbitration is handled in the owner's context.
-                *
-                * The 'shared' struct can be read and/or written only when
-                * its lock is taken.
-                */
-               struct flchip_shared *shared = chip->priv;
-               struct flchip *contender;
-               spin_lock(&shared->lock);
-               contender = shared->writing;
-               if (contender && contender != chip) {
-                       /*
-                        * The engine to perform desired operation on this
-                        * partition is already in use by someone else.
-                        * Let's fight over it in the context of the chip
-                        * currently using it.  If it is possible to suspend,
-                        * that other partition will do just that, otherwise
-                        * it'll happily send us to sleep.  In any case, when
-                        * get_chip returns success we're clear to go ahead.
-                        */
-                       int ret = spin_trylock(contender->mutex);
-                       spin_unlock(&shared->lock);
-                       if (!ret)
-                               goto retry;
-                       spin_unlock(chip->mutex);
-                       ret = get_chip(map, contender, contender->start, mode);
-                       spin_lock(chip->mutex);
-                       if (ret) {
-                               spin_unlock(contender->mutex);
-                               return ret;
-                       }
-                       timeo = jiffies + HZ;
-                       spin_lock(&shared->lock);
-                       spin_unlock(contender->mutex);
-               }
-
-               /* We now own it */
-               shared->writing = chip;
-               if (mode == FL_ERASING)
-                       shared->erasing = chip;
-               spin_unlock(&shared->lock);
-       }
+       /* Prevent setting state FL_SYNCING for chip in suspended state. */
+       if (mode == FL_SYNCING && chip->oldstate != FL_READY)
+               goto sleep;
 
        switch (chip->state) {
 
@@ -722,18 +760,13 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                        if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
                                break;
 
-                       if (time_after(jiffies, timeo)) {
-                               printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n",
-                                      map->name, status.x[0]);
-                               return -EIO;
-                       }
                        spin_unlock(chip->mutex);
                        cfi_udelay(1);
                        spin_lock(chip->mutex);
                        /* Someone else might have been playing with it. */
-                       goto retry;
+                       return -EAGAIN;
                }
-
+               /* Fall through */
        case FL_READY:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
@@ -793,14 +826,14 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                chip->state = FL_READY;
                return 0;
 
+       case FL_SHUTDOWN:
+               /* The machine is rebooting now,so no one can get chip anymore */
+               return -EIO;
        case FL_POINT:
                /* Only if there's no operation suspended... */
                if (mode == FL_READY && chip->oldstate == FL_READY)
                        return 0;
-
-       case FL_SHUTDOWN:
-               /* The machine is rebooting now,so no one can get chip anymore */
-               return -EIO;
+               /* Fall through */
        default:
        sleep:
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -809,8 +842,104 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                schedule();
                remove_wait_queue(&chip->wq, &wait);
                spin_lock(chip->mutex);
-               goto resettime;
+               return -EAGAIN;
+       }
+}
+
+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
+{
+       int ret;
+       DECLARE_WAITQUEUE(wait, current);
+
+ retry:
+       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
+                * partition.  So let's fight it over in the partition which
+                * currently has authority on the operation.
+                *
+                * The rules are as follows:
+                *
+                * - any write operation must own shared->writing.
+                *
+                * - any erase operation must own _both_ shared->writing and
+                *   shared->erasing.
+                *
+                * - contention arbitration is handled in the owner's context.
+                *
+                * The 'shared' struct can be read and/or written only when
+                * its lock is taken.
+                */
+               struct flchip_shared *shared = chip->priv;
+               struct flchip *contender;
+               spin_lock(&shared->lock);
+               contender = shared->writing;
+               if (contender && contender != chip) {
+                       /*
+                        * The engine to perform desired operation on this
+                        * partition is already in use by someone else.
+                        * Let's fight over it in the context of the chip
+                        * currently using it.  If it is possible to suspend,
+                        * that other partition will do just that, otherwise
+                        * it'll happily send us to sleep.  In any case, when
+                        * get_chip returns success we're clear to go ahead.
+                        */
+                       ret = spin_trylock(contender->mutex);
+                       spin_unlock(&shared->lock);
+                       if (!ret)
+                               goto retry;
+                       spin_unlock(chip->mutex);
+                       ret = chip_ready(map, contender, contender->start, mode);
+                       spin_lock(chip->mutex);
+
+                       if (ret == -EAGAIN) {
+                               spin_unlock(contender->mutex);
+                               goto retry;
+                       }
+                       if (ret) {
+                               spin_unlock(contender->mutex);
+                               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);
+               }
+
+               /* Check if we already have suspended erase
+                * on this chip. Sleep. */
+               if (mode == FL_ERASING && shared->erasing
+                   && shared->erasing->oldstate == FL_ERASING) {
+                       spin_unlock(&shared->lock);
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       add_wait_queue(&chip->wq, &wait);
+                       spin_unlock(chip->mutex);
+                       schedule();
+                       remove_wait_queue(&chip->wq, &wait);
+                       spin_lock(chip->mutex);
+                       goto retry;
+               }
+
+               /* We now own it */
+               shared->writing = chip;
+               if (mode == FL_ERASING)
+                       shared->erasing = chip;
+               spin_unlock(&shared->lock);
        }
+       ret = chip_ready(map, chip, adr, mode);
+       if (ret == -EAGAIN)
+               goto retry;
+
+       return ret;
 }
 
 static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
@@ -936,7 +1065,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;
@@ -945,7 +1074,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;
@@ -999,10 +1128,10 @@ static int __xipram xip_wait_for_operation(
                        chip->state = newstate;
                        map_write(map, CMD(0xff), adr);
                        (void) map_read(map, adr);
-                       asm volatile (".rep 8; nop; .endr");
+                       xip_iprefetch();
                        local_irq_enable();
                        spin_unlock(chip->mutex);
-                       asm volatile (".rep 8; nop; .endr");
+                       xip_iprefetch();
                        cond_resched();
 
                        /*
@@ -1055,8 +1184,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
 
@@ -1068,22 +1197,22 @@ 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);
        int chip_state = chip->state;
-       unsigned int timeo, sleep_time;
+       unsigned int timeo, sleep_time, reset_timeo;
 
        spin_unlock(chip->mutex);
        if (inval_len)
                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;
        sleep_time = chip_op_time / 2;
 
        for (;;) {
@@ -1125,6 +1254,16 @@ static int inval_cache_and_wait_for_operation(
                        remove_wait_queue(&chip->wq, &wait);
                        spin_lock(chip->mutex);
                }
+               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;
+               }
        }
 
        /* Done and happy. */
@@ -1134,8 +1273,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)
@@ -1165,7 +1304,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
        return ret;
 }
 
-static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, void **virt, resource_size_t *phys)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
@@ -1182,8 +1322,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
        chipnum = (from >> cfi->chipshift);
        ofs = from - (chipnum << cfi->chipshift);
 
-       *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+       *virt = map->virt + cfi->chips[chipnum].start + ofs;
        *retlen = 0;
+       if (phys)
+               *phys = map->phys + cfi->chips[chipnum].start + ofs;
 
        while (len) {
                unsigned long thislen;
@@ -1216,7 +1358,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
        return 0;
 }
 
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
@@ -1366,7 +1508,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);
@@ -1496,9 +1639,12 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        int ret, wbufsize, word_gap, words;
        const struct kvec *vec;
        unsigned long vec_seek;
+       unsigned long initial_adr;
+       int initial_len = len;
 
        wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        adr += chip->start;
+       initial_adr = adr;
        cmd_adr = adr & ~(wbufsize-1);
 
        /* Let's determine this according to the interleave only once */
@@ -1511,7 +1657,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                return ret;
        }
 
-       XIP_INVAL_CACHED_RANGE(map, adr, len);
+       XIP_INVAL_CACHED_RANGE(map, initial_adr, initial_len);
        ENABLE_VPP(map);
        xip_disable(map, chip, cmd_adr);
 
@@ -1534,7 +1680,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);
@@ -1551,7 +1697,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 {
@@ -1602,8 +1748,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        chip->state = FL_WRITING;
 
        ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
-                                  adr, len,
-                                  chip->buffer_write_time);
+                                  initial_adr, initial_len,
+                                  chip->buffer_write_time,
+                                  chip->buffer_write_time_max);
        if (ret) {
                map_write(map, CMD(0x70), cmd_adr);
                chip->state = FL_STATUS;
@@ -1738,7 +1885,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;
@@ -1917,7 +2065,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;
@@ -1932,13 +2080,13 @@ 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;
 
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
-              __FUNCTION__, ofs, len);
+              __func__, ofs, len);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, NULL);
 #endif
@@ -1948,7 +2096,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
-              __FUNCTION__, ret);
+              __func__, ret);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, NULL);
 #endif
@@ -1956,13 +2104,13 @@ 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;
 
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
-              __FUNCTION__, ofs, len);
+              __func__, ofs, len);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, NULL);
 #endif
@@ -1972,7 +2120,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
-              __FUNCTION__, ret);
+              __func__, ret);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, NULL);
 #endif
@@ -2283,7 +2431,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
        struct flchip *chip;
        int ret = 0;
 
-       if ((mtd->flags & MTD_STUPID_LOCK)
+       if ((mtd->flags & MTD_POWERUP_LOCK)
            && extp && (extp->FeatureSupport & (1 << 5)))
                cfi_intelext_save_locks(mtd);
 
@@ -2394,7 +2542,7 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
                spin_unlock(chip->mutex);
        }
 
-       if ((mtd->flags & MTD_STUPID_LOCK)
+       if ((mtd->flags & MTD_POWERUP_LOCK)
            && extp && (extp->FeatureSupport & (1 << 5)))
                cfi_intelext_restore_locks(mtd);
 }