summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/chips
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/chips')
-rw-r--r--drivers/mtd/chips/Kconfig1
-rw-r--r--drivers/mtd/chips/Makefile7
-rw-r--r--drivers/mtd/chips/amd_flash.c8
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c474
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c22
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c22
-rw-r--r--drivers/mtd/chips/cfi_probe.c8
-rw-r--r--drivers/mtd/chips/gen_probe.c45
-rw-r--r--drivers/mtd/chips/map_ram.c2
-rw-r--r--drivers/mtd/chips/map_rom.c4
-rw-r--r--drivers/mtd/chips/sharp.c1
11 files changed, 217 insertions, 377 deletions
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index a7ec5954caf5..6d8f30deb868 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -30,7 +30,6 @@ config MTD_JEDECPROBE
config MTD_GEN_PROBE
tristate
- select OBSOLETE_INTERMODULE
config MTD_CFI_ADV_OPTIONS
bool "Flash chip driver advanced configuration options"
diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile
index 8afe3092c4e3..75bc1c2a0f43 100644
--- a/drivers/mtd/chips/Makefile
+++ b/drivers/mtd/chips/Makefile
@@ -3,13 +3,6 @@
#
# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $
-# *** BIG UGLY NOTE ***
-#
-# The removal of get_module_symbol() and replacement with
-# inter_module_register() et al has introduced a link order dependency
-# here where previously there was none. We now have to ensure that
-# the CFI command set drivers are linked before gen_probe.o
-
obj-$(CONFIG_MTD) += chipreg.o
obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
obj-$(CONFIG_MTD_CFI) += cfi_probe.o
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
index 57115618c496..16eaca69fb5a 100644
--- a/drivers/mtd/chips/amd_flash.c
+++ b/drivers/mtd/chips/amd_flash.c
@@ -97,7 +97,6 @@ struct amd_flash_private {
int interleave;
int numchips;
unsigned long chipshift;
-// const char *im_name;
struct flchip chips[0];
};
@@ -131,12 +130,6 @@ static struct mtd_chip_driver amd_flash_chipdrv = {
.module = THIS_MODULE
};
-
-
-static const char im_name[] = "amd_flash";
-
-
-
static inline __u32 wide_read(struct map_info *map, __u32 addr)
{
if (map->buswidth == 1) {
@@ -737,6 +730,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
offset += dev_size;
}
mtd->type = MTD_NORFLASH;
+ mtd->writesize = 1;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->erase = amd_flash_erase;
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 1c074d63ff3a..0d435814aaa1 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -331,13 +331,6 @@ 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 <kaos@ocs.com.au> 29 Oct 2000.
- */
struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
@@ -406,7 +399,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<<cfi->cfiq->WordWriteTimeoutTyp;
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;
init_waitqueue_head(&(cfi->chips[i].wq));
}
@@ -415,6 +408,11 @@ 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)
{
@@ -547,12 +545,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_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift;
+ mtd->writesize = 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_PROGRAM_REGIONS;
+ mtd->flags &= ~MTD_BIT_WRITEABLE;
printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
- map->name, MTD_PROGREGION_SIZE(mtd),
+ map->name, mtd->writesize,
MTD_PROGREGION_CTRLMODE_VALID(mtd),
MTD_PROGREGION_CTRLMODE_INVALID(mtd));
}
@@ -896,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
- * 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.
+ * 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.
*
* Warning: this function _will_ fool interrupt latency tracing tools.
*/
-static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
- unsigned long adr, int usec)
+static int __xipram xip_wait_for_operation(
+ struct map_info *map, struct flchip *chip,
+ unsigned long adr, int *chip_op_time )
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
map_word status, OK = CMD(0x80);
- unsigned long suspended, start = xip_currtime();
+ unsigned long usec, suspended, start, done;
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 &&
@@ -932,9 +937,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* 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) {
@@ -944,7 +949,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* This is a critical error but there
* is not much we can do here.
*/
- return;
+ return -EIO;
}
status = map_read(map, adr);
} while (!map_word_andequal(map, status, OK, OK));
@@ -1004,65 +1009,107 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
xip_cpu_idle();
}
status = map_read(map, adr);
+ done = xip_elapsed_since(start);
} 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 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 INVALIDATE_CACHE_UDELAY.
+ * and stub it out from INVAL_CACHE_AND_WAIT.
*/
#define XIP_INVAL_CACHED_RANGE(map, from, size) \
INVALIDATE_CACHED_RANGE(map, from, size)
-#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.
- */
+#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
#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,
+ 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;
+ }
-#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)
+ 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);
+
+ /* Done and happy. */
+ chip->state = FL_STATUS;
+ return 0;
+}
#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)
{
unsigned long cmd_addr;
@@ -1252,14 +1299,11 @@ 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, status_OK, write_cmd;
- unsigned long timeo;
- int z, ret=0;
+ map_word status, write_cmd;
+ int 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);
@@ -1285,57 +1329,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
map_write(map, datum, adr);
chip->state = mode;
- 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;
+ 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;
}
- 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);
@@ -1452,9 +1456,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, status_OK, write_cmd, datum;
- unsigned long cmd_adr, timeo;
- int wbufsize, z, ret=0, word_gap, words;
+ map_word status, write_cmd, datum;
+ unsigned long cmd_adr;
+ int ret, wbufsize, word_gap, words;
const struct kvec *vec;
unsigned long vec_seek;
@@ -1463,7 +1467,6 @@ 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);
@@ -1477,12 +1480,14 @@ 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);
@@ -1493,32 +1498,20 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
}
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);
+ 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;
status = map_read(map, cmd_adr);
- 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;
- }
+ 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;
}
/* Figure out the number of words to write */
@@ -1573,56 +1566,19 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
- 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;
+ 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;
}
- 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);
@@ -1693,6 +1649,11 @@ 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;
@@ -1713,17 +1674,12 @@ 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, status_OK;
- unsigned long timeo;
+ map_word status;
int retries = 3;
- DECLARE_WAITQUEUE(wait, current);
- int ret = 0;
+ int ret;
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);
@@ -1745,48 +1701,15 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->state = FL_ERASING;
chip->erase_suspended = 0;
- 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);
+ 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;
}
/* We've broken this before. It doesn't hurt to be safe */
@@ -1815,7 +1738,6 @@ 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;
@@ -1921,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_pri_intelext *extp = cfi->cmdset_priv;
- map_word status, status_OK;
- unsigned long timeo = jiffies + HZ;
+ int udelay;
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) {
@@ -1954,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
* to delay.
*/
+ udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
- 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);
+ 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;
}
- /* Done and happy. */
- chip->state = FL_STATUS;
xip_enable(map, chip, adr);
- put_chip(map, chip, adr);
+out: put_chip(map, chip, adr);
spin_unlock(chip->mutex);
- return 0;
+ return ret;
}
static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
@@ -2445,28 +2343,8 @@ 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 <dwmw2@infradead.org> et al.");
MODULE_DESCRIPTION("MTD chip driver for Intel/Sharp flash chips");
+MODULE_ALIAS("cfi_cmdset_0003");
+MODULE_ALIAS("cfi_cmdset_0200");
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index aed10bd5c3c3..1e01ad38b26e 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -236,6 +236,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
mtd->resume = cfi_amdstd_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
+ mtd->writesize = 1;
if (cfi->cfi_mode==CFI_MODE_CFI){
unsigned char bootloc;
@@ -326,7 +327,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
return cfi_amdstd_setup(mtd);
}
-
+EXPORT_SYMBOL_GPL(cfi_cmdset_0002);
static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
{
@@ -1758,25 +1759,6 @@ static void cfi_amdstd_destroy(struct mtd_info *mtd)
kfree(mtd->eraseregions);
}
-static char im_name[]="cfi_cmdset_0002";
-
-
-static int __init cfi_amdstd_init(void)
-{
- inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
- return 0;
-}
-
-
-static void __exit cfi_amdstd_exit(void)
-{
- inter_module_unregister(im_name);
-}
-
-
-module_init(cfi_amdstd_init);
-module_exit(cfi_amdstd_exit);
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index 0807c1c91e55..fae70a5db540 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -162,6 +162,7 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
return cfi_staa_setup(map);
}
+EXPORT_SYMBOL_GPL(cfi_cmdset_0020);
static struct mtd_info *cfi_staa_setup(struct map_info *map)
{
@@ -237,9 +238,8 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
mtd->unlock = cfi_staa_unlock;
mtd->suspend = cfi_staa_suspend;
mtd->resume = cfi_staa_resume;
- mtd->flags = MTD_CAP_NORFLASH;
- mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */
- mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
+ mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
+ mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
map->fldrv = &cfi_staa_chipdrv;
__module_get(THIS_MODULE);
mtd->name = map->name;
@@ -1410,20 +1410,4 @@ static void cfi_staa_destroy(struct mtd_info *mtd)
kfree(cfi);
}
-static char im_name[]="cfi_cmdset_0020";
-
-static int __init cfi_staa_init(void)
-{
- inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020);
- return 0;
-}
-
-static void __exit cfi_staa_exit(void)
-{
- inter_module_unregister(im_name);
-}
-
-module_init(cfi_staa_init);
-module_exit(cfi_staa_exit);
-
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c
index e636aa86bc24..4bf9f8cac0dd 100644
--- a/drivers/mtd/chips/cfi_probe.c
+++ b/drivers/mtd/chips/cfi_probe.c
@@ -349,12 +349,12 @@ static void print_cfi_ident(struct cfi_ident *cfip)
else
printk("No Vpp line\n");
- printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
- printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
+ printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
+ printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) {
- printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
- printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
+ printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
+ printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
}
else
printk("Full buffer write not supported\n");
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c
index 41bd59d20d85..cdb0f590b40c 100644
--- a/drivers/mtd/chips/gen_probe.c
+++ b/drivers/mtd/chips/gen_probe.c
@@ -37,8 +37,15 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
if (!mtd)
mtd = check_cmd_set(map, 0); /* Then the secondary */
- if (mtd)
+ if (mtd) {
+ if (mtd->size > map->size) {
+ printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n",
+ (unsigned long)mtd->size >> 10,
+ (unsigned long)map->size >> 10);
+ mtd->size = map->size;
+ }
return mtd;
+ }
printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");
@@ -100,7 +107,12 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
* Align bitmap storage size to full byte.
*/
max_chips = map->size >> cfi.chipshift;
- mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
+ if (!max_chips) {
+ printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n");
+ max_chips = 1;
+ }
+
+ mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG;
chip_map = kmalloc(mapsize, GFP_KERNEL);
if (!chip_map) {
printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
@@ -194,25 +206,28 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
{
struct cfi_private *cfi = map->fldrv_priv;
__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
-#if defined(CONFIG_MODULES) && defined(HAVE_INTER_MODULE)
- char probename[32];
+#ifdef CONFIG_MODULES
+ char probename[16+sizeof(MODULE_SYMBOL_PREFIX)];
cfi_cmdset_fn_t *probe_function;
- sprintf(probename, "cfi_cmdset_%4.4X", type);
+ sprintf(probename, MODULE_SYMBOL_PREFIX "cfi_cmdset_%4.4X", type);
- probe_function = inter_module_get_request(probename, probename);
+ probe_function = __symbol_get(probename);
+ if (!probe_function) {
+ request_module(probename + sizeof(MODULE_SYMBOL_PREFIX) - 1);
+ probe_function = __symbol_get(probename);
+ }
if (probe_function) {
struct mtd_info *mtd;
mtd = (*probe_function)(map, primary);
/* If it was happy, it'll have increased its own use count */
- inter_module_put(probename);
+ symbol_put_addr(probe_function);
return mtd;
}
#endif
- printk(KERN_NOTICE "Support for command set %04X not present\n",
- type);
+ printk(KERN_NOTICE "Support for command set %04X not present\n", type);
return NULL;
}
@@ -226,12 +241,8 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
return NULL;
switch(type){
- /* Urgh. Ifdefs. The version with weak symbols was
- * _much_ nicer. Shame it didn't seem to work on
- * anything but x86, really.
- * But we can't rely in inter_module_get() because
- * that'd mean we depend on link order.
- */
+ /* We need these for the !CONFIG_MODULES case,
+ because symbol_get() doesn't work there */
#ifdef CONFIG_MTD_CFI_INTELEXT
case 0x0001:
case 0x0003:
@@ -246,9 +257,9 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
case 0x0020:
return cfi_cmdset_0020(map, primary);
#endif
+ default:
+ return cfi_cmdset_unknown(map, primary);
}
-
- return cfi_cmdset_unknown(map, primary);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index bd2e876a814b..763925747db6 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -70,7 +70,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
mtd->read = mapram_read;
mtd->write = mapram_write;
mtd->sync = mapram_nop;
- mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
+ mtd->flags = MTD_CAP_RAM;
mtd->erasesize = PAGE_SIZE;
while(mtd->size & (mtd->erasesize - 1))
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index 624c12c232c8..bc6ee9ef8a31 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -46,9 +46,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
mtd->write = maprom_write;
mtd->sync = maprom_nop;
mtd->flags = MTD_CAP_ROM;
- mtd->erasesize = 131072;
- while(mtd->size & (mtd->erasesize - 1))
- mtd->erasesize >>= 1;
+ mtd->erasesize = map->size;
__module_get(THIS_MODULE);
return mtd;
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
index 3cc0b23c5865..967abbecdff9 100644
--- a/drivers/mtd/chips/sharp.c
+++ b/drivers/mtd/chips/sharp.c
@@ -140,6 +140,7 @@ static struct mtd_info *sharp_probe(struct map_info *map)
mtd->suspend = sharp_suspend;
mtd->resume = sharp_resume;
mtd->flags = MTD_CAP_NORFLASH;
+ mtd->writesize = 1;
mtd->name = map->name;
memset(sharp, 0, sizeof(*sharp));