PERFORCE change 212124 for review
Brooks Davis
brooks at FreeBSD.org
Fri Jun 1 21:29:59 UTC 2012
http://p4web.freebsd.org/@@212124?ac=10
Change 212124 by brooks at 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_ */
More information about the p4-projects
mailing list