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