mtd/drivers/mtd/chips cfi_cmdset_0001.c,1.104,1.105
Joakim Tjernlund
jocke at infradead.org
Mon Oct 21 09:40:09 EDT 2002
Update of /home/cvs/mtd/drivers/mtd/chips
In directory phoenix.infradead.org:/tmp/cvs-serv13263/chips
Modified Files:
cfi_cmdset_0001.c
Log Message:
Better point()/unpoint support impl. in cfi_cmdset_0001.c.
The other chip drivers should be able to copy the point()/unpoint()
support in cfi_cmdset_0001.c. Updated mtdpart.c pmc551.c slram.c mtdram.c
due to match the unpoint() prototype change.
Index: cfi_cmdset_0001.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0001.c,v
retrieving revision 1.104
retrieving revision 1.105
diff -u -r1.104 -r1.105
--- cfi_cmdset_0001.c 16 Oct 2002 08:27:25 -0000 1.104
+++ cfi_cmdset_0001.c 21 Oct 2002 13:40:06 -0000 1.105
@@ -54,7 +54,8 @@
static int do_point (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf);
-static void do_unpoint (struct mtd_info *mtd, u_char *addr);
+static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
+ size_t len);
static struct mtd_chip_driver cfi_intelext_chipdrv = {
probe: NULL, /* Not usable directly */
@@ -177,6 +178,7 @@
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].ref_point_counter = 0;
}
map->fldrv = &cfi_intelext_chipdrv;
@@ -282,23 +284,164 @@
return mtd;
}
+static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
+{
+ cfi_word status, status_OK;
+ unsigned long timeo;
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long cmd_addr;
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ adr += chip->start;
+
+ /* Ensure cmd read/writes are aligned. */
+ cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
+
+ /* Let's determine this according to the interleave only once */
+ status_OK = CMD(0x80);
+
+ timeo = jiffies + HZ;
+ retry:
+ spin_lock_bh(chip->mutex);
+
+ /* Check that the chip's ready to talk to us.
+ * If it's in FL_ERASING state, suspend it and make it talk now.
+ */
+ switch (chip->state) {
+
+ case FL_READY:
+ case FL_POINT:
+ break;
+
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ cfi_write(map, CMD(0x70), cmd_addr);
+ chip->state = FL_STATUS;
+
+ case FL_STATUS:
+ status = cfi_read(map, cmd_addr);
+ if ((status & status_OK) == status_OK) {
+ cfi_write(map, CMD(0xff), cmd_addr);
+ chip->state = FL_READY;
+ break;
+ }
+
+ /* Urgh. Chip not yet ready to talk to us. */
+ if (time_after(jiffies, timeo)) {
+ spin_unlock_bh(chip->mutex);
+ printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ spin_unlock_bh(chip->mutex);
+ cfi_udelay(1);
+ goto retry;
+
+ default:
+ /* Stick ourselves on a wait queue to be woken when
+ someone changes the status */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock_bh(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ timeo = jiffies + HZ;
+ goto retry;
+ }
+
+ chip->state = FL_POINT;
+ chip->ref_point_counter++;
+ spin_unlock_bh(chip->mutex);
+ return 0;
+}
static int do_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
{
struct map_info *map = mtd->priv;
-
+ struct cfi_private *cfi = map->fldrv_priv;
+ unsigned long ofs;
+ int chipnum;
+ int ret = 0;
+
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = map->point(map, from, len);
+ *mtdbuf = map->point(map, from, len);
+ if(*mtdbuf == NULL)
+ return -EINVAL; /* can not point this region */
+
+ /* Now lock the chip(s) to POINT state */
+
+ /* ofs: offset within the first chip that the first read should start */
+ chipnum = (from >> cfi->chipshift);
+ ofs = from - (chipnum << cfi->chipshift);
+
+ while (len) {
+ unsigned long thislen;
+
+ if (chipnum >= cfi->numchips)
+ break;
+
+ if ((len + ofs -1) >> cfi->chipshift)
+ thislen = (1<<cfi->chipshift) - ofs;
+ else
+ thislen = len;
+
+ ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen);
+ if (ret)
+ break;
+
+ *retlen += thislen;
+ len -= thislen;
+
+ ofs = 0;
+ chipnum++;
+ }
*retlen = len;
return 0;
}
-static void do_unpoint (struct mtd_info *mtd, u_char *addr)
+static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
{
struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ unsigned long ofs;
+ int chipnum;
+
+ map->unpoint(map, addr, from, len);
+ /* Now unlock the chip(s) POINT state */
- map->unpoint(map, addr);
+ /* ofs: offset within the first chip that the first read should start */
+ chipnum = (from >> cfi->chipshift);
+ ofs = from - (chipnum << cfi->chipshift);
+
+ while (len) {
+ unsigned long thislen;
+ struct flchip *chip;
+
+ chip = &cfi->chips[chipnum];
+ if (chipnum >= cfi->numchips)
+ break;
+
+ if ((len + ofs -1) >> cfi->chipshift)
+ thislen = (1<<cfi->chipshift) - ofs;
+ else
+ thislen = len;
+
+ spin_lock_bh(chip->mutex);
+ if(chip->state == FL_POINT){
+ chip->ref_point_counter--;
+ if(chip->ref_point_counter == 0)
+ chip->state = FL_READY;
+ } else
+ printk("Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
+ wake_up(&chip->wq);
+ spin_unlock_bh(chip->mutex);
+
+ len -= thislen;
+ ofs = 0;
+ chipnum++;
+ }
}
static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
@@ -373,6 +516,7 @@
#endif
case FL_READY:
+ case FL_POINT:
break;
case FL_CFI_QUERY:
More information about the linux-mtd-cvs
mailing list