Commit c172471b authored by Nicolas Pitre's avatar Nicolas Pitre Committed by David Woodhouse

cfi_cmdset_0001: factorize code to wait for flash status

This allows for much better abstraction and separation of the XIP and
non-XIP cases with their own specific implementations.  This fixes the
case where a timeout was tripped on in the XIP case by the code that
was meant for the non-XIP case only.

This also makes for a nice code reduction.
Signed-off-by: default avatarNicolas Pitre <nico@cam.org>
CC: "Alexey, Korolev" <alexey.korolev@intel.com>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent 6e7a6809
...@@ -399,7 +399,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) ...@@ -399,7 +399,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
for (i=0; i< cfi->numchips; i++) { for (i=0; i< cfi->numchips; i++) {
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; cfi->chips[i].erase_time = 1000<<cfi->cfiq->BlockEraseTimeoutTyp;
cfi->chips[i].ref_point_counter = 0; cfi->chips[i].ref_point_counter = 0;
init_waitqueue_head(&(cfi->chips[i].wq)); init_waitqueue_head(&(cfi->chips[i].wq));
} }
...@@ -894,26 +894,33 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, ...@@ -894,26 +894,33 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
/* /*
* When a delay is required for the flash operation to complete, the * When a delay is required for the flash operation to complete, the
* xip_udelay() function is polling for both the given timeout and pending * xip_wait_for_operation() function is polling for both the given timeout
* (but still masked) hardware interrupts. Whenever there is an interrupt * and pending (but still masked) hardware interrupts. Whenever there is an
* pending then the flash erase or write operation is suspended, array mode * interrupt pending then the flash erase or write operation is suspended,
* restored and interrupts unmasked. Task scheduling might also happen at that * array mode restored and interrupts unmasked. Task scheduling might also
* point. The CPU eventually returns from the interrupt or the call to * happen at that point. The CPU eventually returns from the interrupt or
* schedule() and the suspended flash operation is resumed for the remaining * the call to schedule() and the suspended flash operation is resumed for
* of the delay period. * the remaining of the delay period.
* *
* Warning: this function _will_ fool interrupt latency tracing tools. * Warning: this function _will_ fool interrupt latency tracing tools.
*/ */
static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, static int __xipram xip_wait_for_operation(
unsigned long adr, int usec) struct map_info *map, struct flchip *chip,
unsigned long adr, int *chip_op_time )
{ {
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *cfip = cfi->cmdset_priv; struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
map_word status, OK = CMD(0x80); map_word status, OK = CMD(0x80);
unsigned long suspended, start = xip_currtime(); unsigned long usec, suspended, start, done;
flstate_t oldstate, newstate; flstate_t oldstate, newstate;
start = xip_currtime();
usec = *chip_op_time * 8;
if (usec == 0)
usec = 500000;
done = 0;
do { do {
cpu_relax(); cpu_relax();
if (xip_irqpending() && cfip && if (xip_irqpending() && cfip &&
...@@ -930,9 +937,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, ...@@ -930,9 +937,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* we resume the whole thing at once). Yes, it * we resume the whole thing at once). Yes, it
* can happen! * can happen!
*/ */
usec -= done;
map_write(map, CMD(0xb0), adr); map_write(map, CMD(0xb0), adr);
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), adr);
usec -= xip_elapsed_since(start);
suspended = xip_currtime(); suspended = xip_currtime();
do { do {
if (xip_elapsed_since(suspended) > 100000) { if (xip_elapsed_since(suspended) > 100000) {
...@@ -942,7 +949,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, ...@@ -942,7 +949,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* This is a critical error but there * This is a critical error but there
* is not much we can do here. * is not much we can do here.
*/ */
return; return -EIO;
} }
status = map_read(map, adr); status = map_read(map, adr);
} while (!map_word_andequal(map, status, OK, OK)); } while (!map_word_andequal(map, status, OK, OK));
...@@ -1002,65 +1009,107 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, ...@@ -1002,65 +1009,107 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
xip_cpu_idle(); xip_cpu_idle();
} }
status = map_read(map, adr); status = map_read(map, adr);
done = xip_elapsed_since(start);
} while (!map_word_andequal(map, status, OK, OK) } while (!map_word_andequal(map, status, OK, OK)
&& xip_elapsed_since(start) < usec); && done < usec);
}
#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec) return (done >= usec) ? -ETIME : 0;
}
/* /*
* The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while * 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 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 * 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 * a XIP setup so do it before the actual flash operation in this case
* and stub it out from INVALIDATE_CACHE_UDELAY. * and stub it out from INVAL_CACHE_AND_WAIT.
*/ */
#define XIP_INVAL_CACHED_RANGE(map, from, size) \ #define XIP_INVAL_CACHED_RANGE(map, from, size) \
INVALIDATE_CACHED_RANGE(map, from, size) INVALIDATE_CACHED_RANGE(map, from, size)
#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \ #define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, p_usec) \
UDELAY(map, chip, cmd_adr, usec) xip_wait_for_operation(map, chip, cmd_adr, p_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 #else
#define xip_disable(map, chip, adr) #define xip_disable(map, chip, adr)
#define xip_enable(map, chip, adr) #define xip_enable(map, chip, adr)
#define XIP_INVAL_CACHED_RANGE(x...) #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,
int *chip_op_time )
{
struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK = CMD(0x80);
int z, chip_state = chip->state;
unsigned long timeo;
spin_unlock(chip->mutex);
if (inval_len)
INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
if (*chip_op_time)
cfi_udelay(*chip_op_time);
spin_lock(chip->mutex);
timeo = *chip_op_time * 8 * HZ / 1000000;
if (timeo < HZ/2)
timeo = HZ/2;
timeo += jiffies;
z = 0;
for (;;) {
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);
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;
return -ETIME;
}
/* Latency issues. Drop the lock, wait a while and retry */
z++;
spin_unlock(chip->mutex);
cfi_udelay(1);
spin_lock(chip->mutex);
}
if (!z) {
if (!--(*chip_op_time))
*chip_op_time = 1;
} else if (z > 1)
++(*chip_op_time);
#define UDELAY(map, chip, adr, usec) \ /* Done and happy. */
do { \ chip->state = FL_STATUS;
spin_unlock(chip->mutex); \ return 0;
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 #endif
#define WAIT_TIMEOUT(map, chip, adr, udelay) \
({ int __udelay = (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) static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
{ {
unsigned long cmd_addr; unsigned long cmd_addr;
...@@ -1250,14 +1299,11 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, ...@@ -1250,14 +1299,11 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
unsigned long adr, map_word datum, int mode) unsigned long adr, map_word datum, int mode)
{ {
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK, write_cmd; map_word status, write_cmd;
unsigned long timeo; int ret=0;
int z, ret=0;
adr += chip->start; adr += chip->start;
/* Let's determine those according to the interleave only once */
status_OK = CMD(0x80);
switch (mode) { switch (mode) {
case FL_WRITING: case FL_WRITING:
write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
...@@ -1283,57 +1329,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, ...@@ -1283,57 +1329,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
map_write(map, datum, adr); map_write(map, datum, adr);
chip->state = mode; chip->state = mode;
INVALIDATE_CACHE_UDELAY(map, chip, adr, ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
adr, map_bankwidth(map), adr, map_bankwidth(map),
chip->word_write_time); &chip->word_write_time);
if (ret) {
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); xip_enable(map, chip, adr);
printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
ret = -EIO;
goto out; 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 */ /* check for errors */
status = map_read(map, adr);
if (map_word_bitsset(map, status, CMD(0x1a))) { if (map_word_bitsset(map, status, CMD(0x1a))) {
unsigned long chipstatus = MERGESTATUS(status); unsigned long chipstatus = MERGESTATUS(status);
...@@ -1450,9 +1456,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ...@@ -1450,9 +1456,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
unsigned long *pvec_seek, int len) unsigned long *pvec_seek, int len)
{ {
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK, write_cmd, datum; map_word status, write_cmd, datum;
unsigned long cmd_adr, timeo; unsigned long cmd_adr;
int wbufsize, z, ret=0, word_gap, words; int ret, wbufsize, word_gap, words;
const struct kvec *vec; const struct kvec *vec;
unsigned long vec_seek; unsigned long vec_seek;
...@@ -1461,7 +1467,6 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ...@@ -1461,7 +1467,6 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
cmd_adr = adr & ~(wbufsize-1); cmd_adr = adr & ~(wbufsize-1);
/* Let's determine this according to the interleave only once */ /* 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); write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
spin_lock(chip->mutex); spin_lock(chip->mutex);
...@@ -1493,33 +1498,21 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ...@@ -1493,33 +1498,21 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
} }
chip->state = FL_WRITING_TO_BUFFER; chip->state = FL_WRITING_TO_BUFFER;
z = 0;
for (;;) {
map_write(map, write_cmd, cmd_adr); map_write(map, write_cmd, cmd_adr);
ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0);
status = map_read(map, cmd_adr); if (ret) {
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 */ /* Argh. Not ready for write to buffer */
map_word Xstatus; map_word Xstatus = map_read(map, cmd_adr);
map_write(map, CMD(0x70), cmd_adr); map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS; chip->state = FL_STATUS;
Xstatus = map_read(map, cmd_adr); status = map_read(map, cmd_adr);
/* Odd. Clear status bits */
map_write(map, CMD(0x50), cmd_adr); map_write(map, CMD(0x50), cmd_adr);
map_write(map, CMD(0x70), cmd_adr); map_write(map, CMD(0x70), cmd_adr);
xip_enable(map, chip, cmd_adr); xip_enable(map, chip, cmd_adr);
printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
map->name, status.x[0], Xstatus.x[0]); map->name, Xstatus.x[0], status.x[0]);
ret = -EIO;
goto out; goto out;
} }
}
/* Figure out the number of words to write */ /* Figure out the number of words to write */
word_gap = (-adr & (map_bankwidth(map)-1)); word_gap = (-adr & (map_bankwidth(map)-1));
...@@ -1573,56 +1566,19 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ...@@ -1573,56 +1566,19 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xd0), cmd_adr); map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING; chip->state = FL_WRITING;
INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
adr, len, adr, len,
chip->buffer_write_time); &chip->buffer_write_time);
if (ret) {
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); map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS; chip->state = FL_STATUS;
xip_enable(map, chip, cmd_adr); xip_enable(map, chip, cmd_adr);
printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
ret = -EIO;
goto out; 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 */ /* check for errors */
status = map_read(map, cmd_adr);
if (map_word_bitsset(map, status, CMD(0x1a))) { if (map_word_bitsset(map, status, CMD(0x1a))) {
unsigned long chipstatus = MERGESTATUS(status); unsigned long chipstatus = MERGESTATUS(status);
...@@ -1718,17 +1674,12 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1718,17 +1674,12 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
unsigned long adr, int len, void *thunk) unsigned long adr, int len, void *thunk)
{ {
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK; map_word status;
unsigned long timeo;
int retries = 3; int retries = 3;
DECLARE_WAITQUEUE(wait, current); int ret;
int ret = 0;
adr += chip->start; adr += chip->start;
/* Let's determine this according to the interleave only once */
status_OK = CMD(0x80);
retry: retry:
spin_lock(chip->mutex); spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_ERASING); ret = get_chip(map, chip, adr, FL_ERASING);
...@@ -1750,50 +1701,17 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1750,50 +1701,17 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->state = FL_ERASING; chip->state = FL_ERASING;
chip->erase_suspended = 0; chip->erase_suspended = 0;
INVALIDATE_CACHE_UDELAY(map, chip, adr, ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
adr, len, adr, len,
chip->erase_time*1000/2); &chip->erase_time);
if (ret) {
/* 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); map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS; chip->state = FL_STATUS;
xip_enable(map, chip, adr); xip_enable(map, chip, adr);
printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
ret = -EIO;
goto out; 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 */ /* We've broken this before. It doesn't hurt to be safe */
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS; chip->state = FL_STATUS;
...@@ -1820,7 +1738,6 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1820,7 +1738,6 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
ret = -EIO; ret = -EIO;
} else if (chipstatus & 0x20 && retries--) { } else if (chipstatus & 0x20 && retries--) {
printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
timeo = jiffies + HZ;
put_chip(map, chip, adr); put_chip(map, chip, adr);
spin_unlock(chip->mutex); spin_unlock(chip->mutex);
goto retry; goto retry;
...@@ -1926,15 +1843,11 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip ...@@ -1926,15 +1843,11 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
{ {
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *extp = cfi->cmdset_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv;
map_word status, status_OK; int udelay;
unsigned long timeo = jiffies + HZ;
int ret; int ret;
adr += chip->start; adr += chip->start;
/* Let's determine this according to the interleave only once */
status_OK = CMD(0x80);
spin_lock(chip->mutex); spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_LOCKING); ret = get_chip(map, chip, adr, FL_LOCKING);
if (ret) { if (ret) {
...@@ -1959,41 +1872,21 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip ...@@ -1959,41 +1872,21 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
* If Instant Individual Block Locking supported then no need * If Instant Individual Block Locking supported then no need
* to delay. * to delay.
*/ */
udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
if (!extp || !(extp->FeatureSupport & (1 << 5))) ret = WAIT_TIMEOUT(map, chip, adr, udelay);
UDELAY(map, chip, adr, 1000000/HZ); if (ret) {
/* 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); map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS; chip->state = FL_STATUS;
xip_enable(map, chip, adr); xip_enable(map, chip, adr);
printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
put_chip(map, chip, adr); goto out;
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); xip_enable(map, chip, adr);
put_chip(map, chip, adr); out: put_chip(map, chip, adr);
spin_unlock(chip->mutex); spin_unlock(chip->mutex);
return 0; 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, size_t len)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment