X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fmtd%2Fchips%2Fcfi_cmdset_0001.c;h=1c074d63ff3af865d52acf29d59aa1be824c41bf;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=7ea49a0d5ec32490633e27a3219e9b2335c3024b;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 7ea49a0d5..1c074d63f 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -331,6 +331,13 @@ read_pri_intelext(struct map_info *map, __u16 adr) return extp; } +/* This routine is made available to other mtd code via + * inter_module_register. It must only be accessed through + * inter_module_get which will bump the use count of this module. The + * addresses passed back in cfi are valid as long as the use count of + * this module is non-zero, i.e. between inter_module_get and + * inter_module_put. Keith Owens 29 Oct 2000. + */ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; @@ -357,7 +364,6 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) mtd->resume = cfi_intelext_resume; mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; - mtd->writesize = 1; mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; @@ -400,7 +406,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) for (i=0; i< cfi->numchips; i++) { cfi->chips[i].word_write_time = 1<cfiq->WordWriteTimeoutTyp; cfi->chips[i].buffer_write_time = 1<cfiq->BufWriteTimeoutTyp; - cfi->chips[i].erase_time = 1000<cfiq->BlockEraseTimeoutTyp; + cfi->chips[i].erase_time = 1<cfiq->BlockEraseTimeoutTyp; cfi->chips[i].ref_point_counter = 0; init_waitqueue_head(&(cfi->chips[i].wq)); } @@ -409,11 +415,6 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) return cfi_intelext_setup(mtd); } -struct mtd_info *cfi_cmdset_0003(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0001"))); -struct mtd_info *cfi_cmdset_0200(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0001"))); -EXPORT_SYMBOL_GPL(cfi_cmdset_0001); -EXPORT_SYMBOL_GPL(cfi_cmdset_0003); -EXPORT_SYMBOL_GPL(cfi_cmdset_0200); static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) { @@ -546,12 +547,12 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, if (extp->MinorVersion >= '4') { struct cfi_intelext_programming_regioninfo *prinfo; prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs]; - mtd->writesize = cfi->interleave << prinfo->ProgRegShift; + MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift; MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid; MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid; - mtd->flags &= ~MTD_BIT_WRITEABLE; + mtd->flags |= MTD_PROGRAM_REGIONS; printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n", - map->name, mtd->writesize, + map->name, MTD_PROGREGION_SIZE(mtd), MTD_PROGREGION_CTRLMODE_VALID(mtd), MTD_PROGREGION_CTRLMODE_INVALID(mtd)); } @@ -895,33 +896,26 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, /* * When a delay is required for the flash operation to complete, the - * xip_wait_for_operation() function is polling for both the given timeout - * and pending (but still masked) hardware interrupts. Whenever there is an - * interrupt pending then the flash erase or write operation is suspended, - * array mode restored and interrupts unmasked. Task scheduling might also - * happen at that point. The CPU eventually returns from the interrupt or - * the call to schedule() and the suspended flash operation is resumed for - * the remaining of the delay period. + * xip_udelay() function is polling for both the given timeout and pending + * (but still masked) hardware interrupts. Whenever there is an interrupt + * pending then the flash erase or write operation is suspended, array mode + * restored and interrupts unmasked. Task scheduling might also happen at that + * point. The CPU eventually returns from the interrupt or the call to + * schedule() and the suspended flash operation is resumed for the remaining + * of the delay period. * * Warning: this function _will_ fool interrupt latency tracing tools. */ -static int __xipram xip_wait_for_operation( - struct map_info *map, struct flchip *chip, - unsigned long adr, unsigned int chip_op_time ) +static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, + unsigned long adr, int usec) { struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *cfip = cfi->cmdset_priv; map_word status, OK = CMD(0x80); - unsigned long usec, suspended, start, done; + unsigned long suspended, start = xip_currtime(); flstate_t oldstate, newstate; - start = xip_currtime(); - usec = chip_op_time * 8; - if (usec == 0) - usec = 500000; - done = 0; - do { cpu_relax(); if (xip_irqpending() && cfip && @@ -938,9 +932,9 @@ static int __xipram xip_wait_for_operation( * we resume the whole thing at once). Yes, it * can happen! */ - usec -= done; map_write(map, CMD(0xb0), adr); map_write(map, CMD(0x70), adr); + usec -= xip_elapsed_since(start); suspended = xip_currtime(); do { if (xip_elapsed_since(suspended) > 100000) { @@ -950,7 +944,7 @@ static int __xipram xip_wait_for_operation( * This is a critical error but there * is not much we can do here. */ - return -EIO; + return; } status = map_read(map, adr); } while (!map_word_andequal(map, status, OK, OK)); @@ -1010,106 +1004,65 @@ static int __xipram xip_wait_for_operation( xip_cpu_idle(); } status = map_read(map, adr); - done = xip_elapsed_since(start); } while (!map_word_andequal(map, status, OK, OK) - && done < usec); - - return (done >= usec) ? -ETIME : 0; + && xip_elapsed_since(start) < usec); } +#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec) + /* * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while * the flash is actively programming or erasing since we have to poll for * the operation to complete anyway. We can't do that in a generic way with * a XIP setup so do it before the actual flash operation in this case - * and stub it out from INVAL_CACHE_AND_WAIT. + * and stub it out from INVALIDATE_CACHE_UDELAY. */ #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 INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \ + UDELAY(map, chip, cmd_adr, usec) + +/* + * Extra notes: + * + * Activating this XIP support changes the way the code works a bit. For + * example the code to suspend the current process when concurrent access + * happens is never executed because xip_udelay() will always return with the + * same chip state as it was entered with. This is why there is no care for + * the presence of add_wait_queue() or schedule() calls from within a couple + * xip_disable()'d areas of code, like in do_erase_oneblock for example. + * The queueing and scheduling are always happening within xip_udelay(). + * + * Similarly, get_chip() and put_chip() just happen to always be executed + * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state + * is in array mode, therefore never executing many cases therein and not + * causing any problem with XIP. + */ #else #define xip_disable(map, chip, adr) #define xip_enable(map, chip, adr) #define XIP_INVAL_CACHED_RANGE(x...) -#define INVAL_CACHE_AND_WAIT inval_cache_and_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) -{ - struct cfi_private *cfi = map->fldrv_priv; - map_word status, status_OK = CMD(0x80); - int chip_state = chip->state; - unsigned int timeo, sleep_time; - - 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; - if (!timeo) - timeo = 500000; - sleep_time = chip_op_time / 2; - - for (;;) { - status = map_read(map, cmd_adr); - if (map_word_andequal(map, status, status_OK, status_OK)) - break; - - if (!timeo) { - map_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; - return -ETIME; - } - /* OK Still waiting. Drop the lock, wait a while and retry. */ - spin_unlock(chip->mutex); - if (sleep_time >= 1000000/HZ) { - /* - * Half of the normal delay still remaining - * can be performed with a sleeping delay instead - * of busy waiting. - */ - msleep(sleep_time/1000); - timeo -= sleep_time; - sleep_time = 1000000/HZ; - } else { - udelay(1); - cond_resched(); - timeo--; - } - spin_lock(chip->mutex); - - if (chip->state != chip_state) { - /* Someone's suspended the operation: sleep */ - DECLARE_WAITQUEUE(wait, current); - 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); - } - } - - /* Done and happy. */ - chip->state = FL_STATUS; - return 0; -} +#define UDELAY(map, chip, adr, usec) \ +do { \ + spin_unlock(chip->mutex); \ + cfi_udelay(usec); \ + spin_lock(chip->mutex); \ +} while (0) + +#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \ +do { \ + spin_unlock(chip->mutex); \ + INVALIDATE_CACHED_RANGE(map, adr, len); \ + cfi_udelay(usec); \ + spin_lock(chip->mutex); \ +} while (0) #endif -#define WAIT_TIMEOUT(map, chip, adr, udelay) \ - INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay); - - static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) { unsigned long cmd_addr; @@ -1299,11 +1252,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum, int mode) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, write_cmd; - int ret=0; + map_word status, status_OK, write_cmd; + unsigned long timeo; + int z, ret=0; adr += chip->start; + /* Let's determine those according to the interleave only once */ + status_OK = CMD(0x80); switch (mode) { case FL_WRITING: write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); @@ -1329,17 +1285,57 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, map_write(map, datum, adr); chip->state = mode; - ret = INVAL_CACHE_AND_WAIT(map, chip, adr, - adr, map_bankwidth(map), - chip->word_write_time); - if (ret) { - xip_enable(map, chip, adr); - printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); - goto out; + INVALIDATE_CACHE_UDELAY(map, chip, adr, + adr, map_bankwidth(map), + chip->word_write_time); + + timeo = jiffies + (HZ/2); + z = 0; + for (;;) { + if (chip->state != mode) { + /* Someone's suspended the write. Sleep */ + DECLARE_WAITQUEUE(wait, current); + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + (HZ / 2); /* FIXME */ + spin_lock(chip->mutex); + continue; + } + + status = map_read(map, adr); + if (map_word_andequal(map, status, status_OK, status_OK)) + break; + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + map_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + xip_enable(map, chip, adr); + printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); + ret = -EIO; + goto out; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + z++; + UDELAY(map, chip, adr, 1); + } + if (!z) { + chip->word_write_time--; + if (!chip->word_write_time) + chip->word_write_time = 1; } + if (z > 1) + chip->word_write_time++; + + /* Done and happy. */ + chip->state = FL_STATUS; /* check for errors */ - status = map_read(map, adr); if (map_word_bitsset(map, status, CMD(0x1a))) { unsigned long chipstatus = MERGESTATUS(status); @@ -1456,9 +1452,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long *pvec_seek, int len) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, write_cmd, datum; - unsigned long cmd_adr; - int ret, wbufsize, word_gap, words; + map_word status, status_OK, write_cmd, datum; + unsigned long cmd_adr, timeo; + int wbufsize, z, ret=0, word_gap, words; const struct kvec *vec; unsigned long vec_seek; @@ -1467,6 +1463,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, cmd_adr = adr & ~(wbufsize-1); /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); spin_lock(chip->mutex); @@ -1480,14 +1477,12 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ENABLE_VPP(map); xip_disable(map, chip, cmd_adr); - /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set + /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set [...], the device will not accept any more Write to Buffer commands". So we must check here and reset those bits if they're set. Otherwise we're just pissing in the wind */ - if (chip->state != FL_STATUS) { + if (chip->state != FL_STATUS) map_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; - } status = map_read(map, cmd_adr); if (map_word_bitsset(map, status, CMD(0x30))) { xip_enable(map, chip, cmd_adr); @@ -1498,20 +1493,32 @@ 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); - if (ret) { - /* Argh. Not ready for write to buffer */ - map_word Xstatus = map_read(map, cmd_adr); - map_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; + + z = 0; + for (;;) { + map_write(map, write_cmd, cmd_adr); + status = map_read(map, cmd_adr); - map_write(map, CMD(0x50), cmd_adr); - map_write(map, CMD(0x70), cmd_adr); - xip_enable(map, chip, cmd_adr); - printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n", - map->name, Xstatus.x[0], status.x[0]); - goto out; + if (map_word_andequal(map, status, status_OK, status_OK)) + break; + + UDELAY(map, chip, cmd_adr, 1); + + if (++z > 20) { + /* Argh. Not ready for write to buffer */ + map_word Xstatus; + map_write(map, CMD(0x70), cmd_adr); + chip->state = FL_STATUS; + Xstatus = map_read(map, cmd_adr); + /* Odd. Clear status bits */ + map_write(map, CMD(0x50), cmd_adr); + map_write(map, CMD(0x70), cmd_adr); + xip_enable(map, chip, cmd_adr); + printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", + map->name, status.x[0], Xstatus.x[0]); + ret = -EIO; + goto out; + } } /* Figure out the number of words to write */ @@ -1566,19 +1573,56 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, map_write(map, CMD(0xd0), cmd_adr); chip->state = FL_WRITING; - ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, - adr, len, - chip->buffer_write_time); - if (ret) { - map_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; - xip_enable(map, chip, cmd_adr); - printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); - goto out; + INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, + adr, len, + chip->buffer_write_time); + + timeo = jiffies + (HZ/2); + z = 0; + for (;;) { + if (chip->state != FL_WRITING) { + /* Someone's suspended the write. Sleep */ + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + (HZ / 2); /* FIXME */ + spin_lock(chip->mutex); + continue; + } + + status = map_read(map, cmd_adr); + if (map_word_andequal(map, status, status_OK, status_OK)) + break; + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + map_write(map, CMD(0x70), cmd_adr); + chip->state = FL_STATUS; + xip_enable(map, chip, cmd_adr); + printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); + ret = -EIO; + goto out; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + z++; + UDELAY(map, chip, cmd_adr, 1); } + if (!z) { + chip->buffer_write_time--; + if (!chip->buffer_write_time) + chip->buffer_write_time = 1; + } + if (z > 1) + chip->buffer_write_time++; + + /* Done and happy. */ + chip->state = FL_STATUS; /* check for errors */ - status = map_read(map, cmd_adr); if (map_word_bitsset(map, status, CMD(0x1a))) { unsigned long chipstatus = MERGESTATUS(status); @@ -1649,11 +1693,6 @@ static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs, if (chipnum == cfi->numchips) return 0; } - - /* Be nice and reschedule with the chip in a usable state for other - processes. */ - cond_resched(); - } while (len); return 0; @@ -1674,12 +1713,17 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; - map_word status; + map_word status, status_OK; + unsigned long timeo; int retries = 3; - int ret; + DECLARE_WAITQUEUE(wait, current); + int ret = 0; adr += chip->start; + /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); + retry: spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_ERASING); @@ -1701,15 +1745,48 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->state = FL_ERASING; chip->erase_suspended = 0; - ret = INVAL_CACHE_AND_WAIT(map, chip, adr, - adr, len, - chip->erase_time); - if (ret) { - map_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - xip_enable(map, chip, adr); - printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); - goto out; + INVALIDATE_CACHE_UDELAY(map, chip, adr, + adr, len, + chip->erase_time*1000/2); + + /* FIXME. Use a timer to check this, and return immediately. */ + /* Once the state machine's known to be working I'll do that */ + + timeo = jiffies + (HZ*20); + for (;;) { + if (chip->state != FL_ERASING) { + /* Someone's suspended the erase. Sleep */ + 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); + continue; + } + if (chip->erase_suspended) { + /* This erase was suspended and resumed. + Adjust the timeout */ + timeo = jiffies + (HZ*20); /* FIXME */ + chip->erase_suspended = 0; + } + + status = map_read(map, adr); + if (map_word_andequal(map, status, status_OK, status_OK)) + break; + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + map_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + xip_enable(map, chip, adr); + printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); + ret = -EIO; + goto out; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + UDELAY(map, chip, adr, 1000000/HZ); } /* We've broken this before. It doesn't hurt to be safe */ @@ -1738,6 +1815,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ret = -EIO; } else if (chipstatus & 0x20 && retries--) { printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); + timeo = jiffies + HZ; put_chip(map, chip, adr); spin_unlock(chip->mutex); goto retry; @@ -1843,11 +1921,15 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip { struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv; - int udelay; + map_word status, status_OK; + unsigned long timeo = jiffies + HZ; int ret; adr += chip->start; + /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { @@ -1872,21 +1954,41 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip * If Instant Individual Block Locking supported then no need * to delay. */ - udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; - ret = WAIT_TIMEOUT(map, chip, adr, udelay); - if (ret) { - map_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - xip_enable(map, chip, adr); - printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); - goto out; + if (!extp || !(extp->FeatureSupport & (1 << 5))) + UDELAY(map, chip, adr, 1000000/HZ); + + /* FIXME. Use a timer to check this, and return immediately. */ + /* Once the state machine's known to be working I'll do that */ + + timeo = jiffies + (HZ*20); + for (;;) { + + status = map_read(map, adr); + if (map_word_andequal(map, status, status_OK, status_OK)) + break; + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + map_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + xip_enable(map, chip, adr); + printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); + put_chip(map, chip, adr); + spin_unlock(chip->mutex); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + UDELAY(map, chip, adr, 1); } + /* Done and happy. */ + chip->state = FL_STATUS; xip_enable(map, chip, adr); -out: put_chip(map, chip, adr); + put_chip(map, chip, adr); spin_unlock(chip->mutex); - return ret; + return 0; } static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) @@ -2343,8 +2445,28 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) kfree(mtd->eraseregions); } +static char im_name_0001[] = "cfi_cmdset_0001"; +static char im_name_0003[] = "cfi_cmdset_0003"; +static char im_name_0200[] = "cfi_cmdset_0200"; + +static int __init cfi_intelext_init(void) +{ + inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001); + inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001); + inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001); + return 0; +} + +static void __exit cfi_intelext_exit(void) +{ + inter_module_unregister(im_name_0001); + inter_module_unregister(im_name_0003); + inter_module_unregister(im_name_0200); +} + +module_init(cfi_intelext_init); +module_exit(cfi_intelext_exit); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse et al."); MODULE_DESCRIPTION("MTD chip driver for Intel/Sharp flash chips"); -MODULE_ALIAS("cfi_cmdset_0003"); -MODULE_ALIAS("cfi_cmdset_0200");