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>