--- linux.old/drivers/mtd/chips/cfi_cmdset_0001.c 2007-02-13 02:41:50.816650352 +0100 +++ linux.dev/drivers/mtd/chips/cfi_cmdset_0001.c 2007-02-13 02:42:13.782159064 +0100 @@ -908,7 +908,7 @@ 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, int *chip_op_time ) { struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *cfip = cfi->cmdset_priv; @@ -917,7 +917,7 @@ flstate_t oldstate, newstate; start = xip_currtime(); - usec = chip_op_time * 8; + usec = *chip_op_time * 8; if (usec == 0) usec = 500000; done = 0; @@ -1027,8 +1027,8 @@ #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, p_usec) \ + xip_wait_for_operation(map, chip, cmd_adr, p_usec) #else @@ -1040,65 +1040,65 @@ 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) + 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; + 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); - /* set our timeout to 8 times the expected delay */ - timeo = chip_op_time * 8; - if (!timeo) - timeo = 500000; - sleep_time = chip_op_time / 2; + 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; - if (!timeo) { + /* OK Still waiting */ + if (time_after(jiffies, 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. */ + /* Latency issues. Drop the lock, wait a while and retry */ + z++; 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--; - } + cfi_udelay(1); spin_lock(chip->mutex); - - while (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); - } } + if (!z) { + if (!--(*chip_op_time)) + *chip_op_time = 1; + } else if (z > 1) + ++(*chip_op_time); + /* Done and happy. */ chip->state = FL_STATUS; return 0; @@ -1107,7 +1107,8 @@ #endif #define WAIT_TIMEOUT(map, chip, adr, udelay) \ - INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, 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) @@ -1331,7 +1332,7 @@ ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, map_bankwidth(map), - chip->word_write_time); + &chip->word_write_time); if (ret) { xip_enable(map, chip, adr); printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); @@ -1568,7 +1569,7 @@ ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, adr, len, - chip->buffer_write_time); + &chip->buffer_write_time); if (ret) { map_write(map, CMD(0x70), cmd_adr); chip->state = FL_STATUS; @@ -1703,7 +1704,7 @@ ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, len, - chip->erase_time); + &chip->erase_time); if (ret) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS;