aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Korolev <akorolev@pentafluge.infradead.org>2006-06-28 14:22:07 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2006-07-15 08:43:59 -0400
commit46a1652c28fc4f4e9d46ea12b0c36b5b6b600f58 (patch)
tree1efde18ca7addfe8cd3cbb828ad6c44b578265c4
parentc4e7fb313771ac03dfdca26d30e8b721731c562b (diff)
[MTD] Fixes of performance and stability issues in CFI driver.
Fix of performance and stability issues on Intel NOR chips. It fixes: 1. Very low write performance on Sibley (perf tests demonstrated write performance less than 100Kb/sec when it should be over 400Kb/sec). 2. Low erase performance. (perf tests on Sibleuy demonstrated erase performance 246Kb/sec when it should be over 300Kb/sec). 3. Error on JFFS2 tests with CPU loading application when MTD returns "block erase error: (status timeout)" To fix the issue it does the following: 1. Removes the timeout tuning from inval_cache_and_wait_for_operation. 2. Waiting conditions in inval_cache_and_wait_for_operation now is based on timer resolution If timeout is lower than timer resolution then we do in cycle "Checking the status" udelay(1); cond_resched(); If timeout is greater than timer resolution (probably erase operation) We do the following sleep for half of operation timeout and do in cycle the following "Checking the status" sleep for timer resolution Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Alexey Korolev <akorolev@infradead.org> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c87
1 files changed, 43 insertions, 44 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 39edb8250fbc..7ea49a0d5ec3 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -908,7 +908,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
908 908
909static int __xipram xip_wait_for_operation( 909static int __xipram xip_wait_for_operation(
910 struct map_info *map, struct flchip *chip, 910 struct map_info *map, struct flchip *chip,
911 unsigned long adr, int *chip_op_time ) 911 unsigned long adr, unsigned int chip_op_time )
912{ 912{
913 struct cfi_private *cfi = map->fldrv_priv; 913 struct cfi_private *cfi = map->fldrv_priv;
914 struct cfi_pri_intelext *cfip = cfi->cmdset_priv; 914 struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
@@ -917,7 +917,7 @@ static int __xipram xip_wait_for_operation(
917 flstate_t oldstate, newstate; 917 flstate_t oldstate, newstate;
918 918
919 start = xip_currtime(); 919 start = xip_currtime();
920 usec = *chip_op_time * 8; 920 usec = chip_op_time * 8;
921 if (usec == 0) 921 if (usec == 0)
922 usec = 500000; 922 usec = 500000;
923 done = 0; 923 done = 0;
@@ -1027,8 +1027,8 @@ static int __xipram xip_wait_for_operation(
1027#define XIP_INVAL_CACHED_RANGE(map, from, size) \ 1027#define XIP_INVAL_CACHED_RANGE(map, from, size) \
1028 INVALIDATE_CACHED_RANGE(map, from, size) 1028 INVALIDATE_CACHED_RANGE(map, from, size)
1029 1029
1030#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, p_usec) \ 1030#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \
1031 xip_wait_for_operation(map, chip, cmd_adr, p_usec) 1031 xip_wait_for_operation(map, chip, cmd_adr, usec)
1032 1032
1033#else 1033#else
1034 1034
@@ -1040,64 +1040,64 @@ static int __xipram xip_wait_for_operation(
1040static int inval_cache_and_wait_for_operation( 1040static int inval_cache_and_wait_for_operation(
1041 struct map_info *map, struct flchip *chip, 1041 struct map_info *map, struct flchip *chip,
1042 unsigned long cmd_adr, unsigned long inval_adr, int inval_len, 1042 unsigned long cmd_adr, unsigned long inval_adr, int inval_len,
1043 int *chip_op_time ) 1043 unsigned int chip_op_time)
1044{ 1044{
1045 struct cfi_private *cfi = map->fldrv_priv; 1045 struct cfi_private *cfi = map->fldrv_priv;
1046 map_word status, status_OK = CMD(0x80); 1046 map_word status, status_OK = CMD(0x80);
1047 int z, chip_state = chip->state; 1047 int chip_state = chip->state;
1048 unsigned long timeo; 1048 unsigned int timeo, sleep_time;
1049 1049
1050 spin_unlock(chip->mutex); 1050 spin_unlock(chip->mutex);
1051 if (inval_len) 1051 if (inval_len)
1052 INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len); 1052 INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
1053 if (*chip_op_time)
1054 cfi_udelay(*chip_op_time);
1055 spin_lock(chip->mutex); 1053 spin_lock(chip->mutex);
1056 1054
1057 timeo = *chip_op_time * 8 * HZ / 1000000; 1055 /* set our timeout to 8 times the expected delay */
1058 if (timeo < HZ/2) 1056 timeo = chip_op_time * 8;
1059 timeo = HZ/2; 1057 if (!timeo)
1060 timeo += jiffies; 1058 timeo = 500000;
1059 sleep_time = chip_op_time / 2;
1061 1060
1062 z = 0;
1063 for (;;) { 1061 for (;;) {
1064 if (chip->state != chip_state) {
1065 /* Someone's suspended the operation: sleep */
1066 DECLARE_WAITQUEUE(wait, current);
1067
1068 set_current_state(TASK_UNINTERRUPTIBLE);
1069 add_wait_queue(&chip->wq, &wait);
1070 spin_unlock(chip->mutex);
1071 schedule();
1072 remove_wait_queue(&chip->wq, &wait);
1073 timeo = jiffies + (HZ / 2); /* FIXME */
1074 spin_lock(chip->mutex);
1075 continue;
1076 }
1077
1078 status = map_read(map, cmd_adr); 1062 status = map_read(map, cmd_adr);
1079 if (map_word_andequal(map, status, status_OK, status_OK)) 1063 if (map_word_andequal(map, status, status_OK, status_OK))
1080 break; 1064 break;
1081 1065
1082 /* OK Still waiting */ 1066 if (!timeo) {
1083 if (time_after(jiffies, timeo)) {
1084 map_write(map, CMD(0x70), cmd_adr); 1067 map_write(map, CMD(0x70), cmd_adr);
1085 chip->state = FL_STATUS; 1068 chip->state = FL_STATUS;
1086 return -ETIME; 1069 return -ETIME;
1087 } 1070 }
1088 1071
1089 /* Latency issues. Drop the lock, wait a while and retry */ 1072 /* OK Still waiting. Drop the lock, wait a while and retry. */
1090 z++;
1091 spin_unlock(chip->mutex); 1073 spin_unlock(chip->mutex);
1092 cfi_udelay(1); 1074 if (sleep_time >= 1000000/HZ) {
1075 /*
1076 * Half of the normal delay still remaining
1077 * can be performed with a sleeping delay instead
1078 * of busy waiting.
1079 */
1080 msleep(sleep_time/1000);
1081 timeo -= sleep_time;
1082 sleep_time = 1000000/HZ;
1083 } else {
1084 udelay(1);
1085 cond_resched();
1086 timeo--;
1087 }
1093 spin_lock(chip->mutex); 1088 spin_lock(chip->mutex);
1094 }
1095 1089
1096 if (!z) { 1090 if (chip->state != chip_state) {
1097 if (!--(*chip_op_time)) 1091 /* Someone's suspended the operation: sleep */
1098 *chip_op_time = 1; 1092 DECLARE_WAITQUEUE(wait, current);
1099 } else if (z > 1) 1093 set_current_state(TASK_UNINTERRUPTIBLE);
1100 ++(*chip_op_time); 1094 add_wait_queue(&chip->wq, &wait);
1095 spin_unlock(chip->mutex);
1096 schedule();
1097 remove_wait_queue(&chip->wq, &wait);
1098 spin_lock(chip->mutex);
1099 }
1100 }
1101 1101
1102 /* Done and happy. */ 1102 /* Done and happy. */
1103 chip->state = FL_STATUS; 1103 chip->state = FL_STATUS;
@@ -1107,8 +1107,7 @@ static int inval_cache_and_wait_for_operation(
1107#endif 1107#endif
1108 1108
1109#define WAIT_TIMEOUT(map, chip, adr, udelay) \ 1109#define WAIT_TIMEOUT(map, chip, adr, udelay) \
1110 ({ int __udelay = (udelay); \ 1110 INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay);
1111 INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, &__udelay); })
1112 1111
1113 1112
1114static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) 1113static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
@@ -1332,7 +1331,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1332 1331
1333 ret = INVAL_CACHE_AND_WAIT(map, chip, adr, 1332 ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
1334 adr, map_bankwidth(map), 1333 adr, map_bankwidth(map),
1335 &chip->word_write_time); 1334 chip->word_write_time);
1336 if (ret) { 1335 if (ret) {
1337 xip_enable(map, chip, adr); 1336 xip_enable(map, chip, adr);
1338 printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); 1337 printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
@@ -1569,7 +1568,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
1569 1568
1570 ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, 1569 ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
1571 adr, len, 1570 adr, len,
1572 &chip->buffer_write_time); 1571 chip->buffer_write_time);
1573 if (ret) { 1572 if (ret) {
1574 map_write(map, CMD(0x70), cmd_adr); 1573 map_write(map, CMD(0x70), cmd_adr);
1575 chip->state = FL_STATUS; 1574 chip->state = FL_STATUS;
@@ -1704,7 +1703,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
1704 1703
1705 ret = INVAL_CACHE_AND_WAIT(map, chip, adr, 1704 ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
1706 adr, len, 1705 adr, len,
1707 &chip->erase_time); 1706 chip->erase_time);
1708 if (ret) { 1707 if (ret) {
1709 map_write(map, CMD(0x70), adr); 1708 map_write(map, CMD(0x70), adr);
1710 chip->state = FL_STATUS; 1709 chip->state = FL_STATUS;