Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Jun 2012 21:29:58 GMT
From:      Brooks Davis <brooks@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 212124 for review
Message-ID:  <201206012129.q51LTwYx093568@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@212124?ac=10

Change 212124 by brooks@brooks_ecr_current on 2012/06/01 21:29:32

	Checkpoint a working write implementation in word mode, an ifdef'd
	non-working buffer mode write implementation, and an untested
	erase ioctl based on Simon's suggestion to alwasy erase 128K blocks.

Affected files ...

.. //depot/projects/ctsrd/beribsd/src/sys/dev/isf/isf.c#4 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/isf/isf.h#4 edit

Differences ...

==== //depot/projects/ctsrd/beribsd/src/sys/dev/isf/isf.c#4 (text+ko) ====

@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2012 Robert N. M. Watson
- # Copyright (c) 2012 SRI International
+ * Copyright (c) 2012 SRI International
  * All rights reserved.
  *
  * This software was developed by SRI International and the University of
@@ -64,16 +64,17 @@
 
 /* Write Mode */
 #define	ISF_CMD_WPS	0x40	/* Word Program Setup */
+#define ISF_CMD_BPS	0xE8	/* Buffered Program Setup */
 #define	ISF_CMD_BPC	0xD0	/* Buffered Program Confirm */
 
 /* Erase Mode */
 #define	ISF_CMD_BES	0x20	/* Block Erase Setup */
-#define IFS_CMD_BEC	0xD0	/* Block Erase Confirm */
+#define ISF_CMD_BEC	0xD0	/* Block Erase Confirm */
 
 /* Block Locking/Unlocking */
 #define	ISF_CMD_LBS	0x60	/* Lock Block Setup */
-#define	IFS_CMD_LB	0x01	/* Lock Block */
-#define	IFS_CMD_UB	0xD0	/* Unlock Block */
+#define	ISF_CMD_LB	0x01	/* Lock Block */
+#define	ISF_CMD_UB	0xD0	/* Unlock Block */
 
 /*
  * Read Device Identifier registers.
@@ -109,6 +110,16 @@
 #define ISF_REG_PP15	0xFA	/* 128-bit Protection Register 15 */
 #define ISF_REG_PP16	0x102	/* 128-bit Protection Register 16 */
 
+#define	ISF_SR_BWS	(1 << 0)	/* BEFP Status */
+#define	ISF_SR_BLS	(1 << 1)	/* Block-Locked Status */
+#define ISF_SR_PSS	(1 << 2)	/* Program Suspend Status */
+#define	ISF_SR_VPPS	(1 << 3)	/* Vpp Status */
+#define	ISF_SR_PS	(1 << 4)	/* Program Status */
+#define ISF_SR_ES	(1 << 5)	/* Erase Status */
+#define ISF_SR_ESS	(1 << 6)	/* Erase Suspend Status */
+#define ISF_SR_DWS	(1 << 7)	/* Device Write Status */
+#define ISF_SR_FSC_MASK	(ISF_SR_VPPS | ISF_SR_PS | ISF_SR_BLS)
+
 static void	isf_task(void *arg);
 
 /* 
@@ -152,7 +163,62 @@
 	bus_write_2(sc->isf_res, off, htole16(cmd));
 }
 
+static uint16_t
+isf_read_status(struct isf_softc *sc, off_t off)
+{
+	
+	isf_write_cmd(sc, off, ISF_CMD_RSR);
+	return isf_read_reg(sc, off);
+}
+
 static void
+isf_clear_status(struct isf_softc *sc)
+{
+	
+	isf_write_cmd(sc, 0, ISF_CMD_CSR);
+}
+
+static int
+isf_full_status_check(struct isf_softc *sc)
+{
+	int		error = 0;
+	uint16_t	status;
+	
+	status = isf_read_status(sc, 0);
+	if (status & ISF_SR_VPPS) {
+		device_printf(sc->isf_dev, "Vpp Range Error\n");
+		error = EIO;
+	} else if (status & ISF_SR_PS) {
+		device_printf(sc->isf_dev, "Program Error\n");
+		error = EIO;
+	} else if (status & ISF_SR_BLS) {
+		device_printf(sc->isf_dev, "Device Protect Error\n");
+		error = EIO;
+	}
+	isf_clear_status(sc);
+
+	return(error);
+}
+
+static void
+isf_unlock_block(struct isf_softc *sc, off_t off)
+{
+
+	isf_write_cmd(sc, off, ISF_CMD_LBS);
+	isf_write_cmd(sc, off, ISF_CMD_UB);
+	isf_write_cmd(sc, off, ISF_CMD_RA);
+}
+
+static void
+isf_lock_block(struct isf_softc *sc, off_t off)
+{
+
+	isf_write_cmd(sc, off, ISF_CMD_LBS);
+	isf_write_cmd(sc, off, ISF_CMD_LB);
+	isf_write_cmd(sc, off, ISF_CMD_RA);
+}
+
+static void
 isf_read(struct isf_softc *sc, off_t off, void *data, size_t len)
 {
 
@@ -166,10 +232,13 @@
 	bus_read_region_2(sc->isf_res, off, (uint16_t *)data, len / 2);
 }
 
-#ifdef NOTYET
-static void
+static int
 isf_write(struct isf_softc *sc, off_t off, void *data, size_t len)
 {
+	int		 error = 0;
+	uint16_t	*dp;
+	uint16_t	 status;
+	off_t		 coff;
 
 	KASSERT((uintptr_t)data % 2 == 0,
 	    ("%s: unaligned data %p", __func__, data));
@@ -178,9 +247,81 @@
 	KASSERT(off % ISF_SECTORSIZE == 0,
 	    ("%s: invalid offset %ju\n", __func__, off));
 
-	bus_write_region_2(sc->isf_res, off, (uint16_t *)data, len / 2);
+	isf_unlock_block(sc, off);
+
+#ifdef ISF_BUFFER_PROGRAM
+	for (dp = data, coff = off; dp - (uint16_t *)data < len / 2;
+	    dp += 32, coff += 64) {
+		isf_clear_status(sc);
+		isf_write_cmd(sc, coff, ISF_CMD_BPS);
+		while ( !(isf_read_reg(sc, coff) & ISF_SR_DWS) )
+			/* XXX: should have a timeout */
+			isf_write_cmd(sc, coff, ISF_CMD_BPS);
+
+		isf_write_cmd(sc, coff, 32);
+		//bus_write_region_2(sc->isf_res, coff, dp, 32);
+		for (int i = 0; i < 32; i++)
+			isf_write_cmd(sc, coff + i * 2, *(dp + 1));
+
+		isf_write_cmd(sc, coff, ISF_CMD_BPC);
+
+		status = isf_read_reg(sc, coff);
+		while ( !(status & ISF_SR_DWS) ) {
+			if (status & ISF_SR_PSS)
+				panic("%s: suspend not supported", __func__);
+			status = isf_read_reg(sc, coff);
+		}
+		isf_full_status_check(sc);
+
+		isf_write_cmd(sc, coff, ISF_CMD_RA);
+	}
+#else
+	for (dp = data, coff = off; dp - (uint16_t *)data < len / 2;
+	    dp++, coff += 2) {
+		isf_write_cmd(sc, coff, ISF_CMD_WPS);
+		bus_write_2(sc->isf_res, coff, *dp);
+		status = isf_read_reg(sc, coff);
+		while ( !(status & ISF_SR_DWS) ) {
+			if (status & ISF_SR_PSS)
+				panic("%s: suspend not supported", __func__);
+			status = isf_read_reg(sc, coff);
+		}
+	}
+	isf_full_status_check(sc);
+	isf_write_cmd(sc, coff, ISF_CMD_RA);
+#endif
+
+	isf_lock_block(sc, off);
+
+	return error;
+}
+
+static void
+isf_erase_range(struct isf_softc *sc, off_t blk_off, size_t size)
+{
+	uint16_t	w, status;
+	off_t		off;
+
+	for (off = blk_off; off < blk_off + size; off += 2) {
+		w = bus_read_2(sc->isf_res, off);
+		if (w == 0xFFFF)
+			continue;
+		
+		isf_clear_status(sc);
+		isf_unlock_block(sc, off);
+		isf_write_cmd(sc, off, ISF_CMD_BES);
+		isf_write_cmd(sc, off, ISF_CMD_BEC);
+
+		status = isf_read_status(sc, off);
+		while ( !(status & ISF_SR_DWS) ) {
+			if (status & ISF_SR_PSS)
+				panic("%s: suspend not supported", __func__);
+			status = isf_read_status(sc, off);
+		}
+
+		isf_write_cmd(sc, off, ISF_CMD_RA);
+	}
 }
-#endif
 
 /*
  * disk(9) methods.
@@ -189,9 +330,28 @@
 isf_disk_ioctl(struct disk *disk, u_long cmd, void *data, int fflag,
     struct thread *td)
 {
+	int			error = 0;
+	struct isf_softc	*sc = disk->d_drv1;
+	struct isf_range	*ir;
 
-	/* XXXRW: more here? */
-	return (EINVAL);
+	switch (cmd) {
+	case ISF_ERASE:
+		ir = data;
+		if (ir->ir_off % ISF_ERASE_BLOCK != 0 ||
+		    ir->ir_off >= disk->d_mediasize ||
+		    ir->ir_size == 0 ||
+		    ir->ir_size % ISF_ERASE_BLOCK != 0 ||
+		    ir->ir_off + ir->ir_size > disk->d_mediasize) {
+			error = EINVAL;
+			break;
+		}
+		isf_erase_range(sc, ir->ir_off, ir->ir_size);
+		break;
+	default:
+		error = EINVAL;
+	}
+
+	return (error);
 }
 
 static void
@@ -218,6 +378,7 @@
 	struct isf_softc	*sc = arg;
 	struct bio		*bp;
 	int			ss = sc->isf_disk->d_sectorsize;
+	int			error;
 
 	for (;;) {
 		ISF_LOCK(sc);
@@ -236,15 +397,30 @@
 			break;
 
 		case BIO_WRITE:
+			error = 0;
 #ifdef NOTYET
 			/*
-			 * XXXRW: copied and pasted from altera_sdcard --
-			 *  obviously won't work.
+			 * Read in the block we want to write and check that
+			 * we're only setting bits to 0.
 			 */
-			isf_write(sc, bp->bio_pbklno * ss, bp->bio_data,
+			isf_read(sc, bp->bio_pblkno * ss, sc->isf_rbuf,
 			    bp->bio_bcount);
+			for (i = 0; i < bp->bio_bcount / 2; i++)
+				if (sc->isf_rbuf[i] &
+				    (unit16_t *)bp->bio_data[i] !=
+				    (unit16_t *)bp->bio_data[i]) {
+					error = EIO;
+					break;
+				}
 #endif
-			biofinish(bp, NULL, ENXIO);
+				
+			if (error == 0)
+				error = isf_write(sc, bp->bio_pblkno * ss,
+				    bp->bio_data, bp->bio_bcount);
+			if (error == 0)
+				biodone(bp);
+			else
+				biofinish(bp, NULL, error);
 			break;
 
 		default:
@@ -355,6 +531,15 @@
 		    "Unsupported flash size %lu\n", size);
 		return (ENXIO);
 	}
+
+	isf_write_cmd(sc, 0, ISF_CMD_RDI);
+	if (isf_read_reg(sc, ISF_REG_ID) != 0x8961) {
+		device_printf(sc->isf_dev,
+		    "Unsupported device ID 0x%04x\n",
+		    isf_read_reg(sc, ISF_REG_ID));
+		return (ENXIO);
+	}
+
 	bioq_init(&sc->isf_bioq);
 	ISF_LOCK_INIT(sc);
 	sc->isf_disk = NULL;

==== //depot/projects/ctsrd/beribsd/src/sys/dev/isf/isf.h#4 (text+ko) ====

@@ -32,6 +32,13 @@
 #ifndef _DEV_ISF_H_
 #define	_DEV_ISF_H_
 
+struct isf_range {
+	off_t	ir_off;		/* Offset of range to delete (set to 0xFF) */
+	size_t	ir_size;	/* Size of range */
+};
+
+#define	ISF_ERASE	_IOW('I', 1, struct isf_range)
+
 /*
  * XXXRW: For now, support only 256Mb parts, but we may want to support others
  * in the future.
@@ -42,7 +49,9 @@
  */
 #define	ISF_SECTORSIZE	(512)
 #define	ISF_MEDIASIZE	(256 * 1024 * 1024 / 8)
+#define ISF_ERASE_BLOCK	(128 * 1024)
 
+#ifdef _KERNEL
 struct isf_softc {
 	device_t		 isf_dev;
 	int			 isf_unit;
@@ -56,6 +65,7 @@
 	 * Fields relating to in-progress and pending I/O, if any.
 	 */
 	struct bio_queue_head	 isf_bioq;
+	uint16_t		 isf_rbuf[ISF_SECTORSIZE / 2];
 };
 
 #define	ISF_LOCK(sc)		mtx_lock(&(sc)->isf_lock)
@@ -70,5 +80,6 @@
 
 int	isf_attach(struct isf_softc *sc);
 void	isf_detach(struct isf_softc *sc);
+#endif /* _KERNEL */
 
 #endif	/* _DEV_ISF_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206012129.q51LTwYx093568>