Module Name:    src
Committed By:   ahoka
Date:           Tue Jun 28 18:14:12 UTC 2011

Modified Files:
        src/sys/dev/flash: files.flash flash.c flash.h
        src/sys/dev/nand: files.nand nand.c nand.h
        src/sys/modules/flash: Makefile
        src/sys/modules/nand: Makefile
Added Files:
        src/sys/dev/flash: flash_io.c flash_io.h
Removed Files:
        src/sys/dev/nand: nand_io.c

Log Message:
Refactor flash and nand driver, so we can reuse the io thread code
in the future nor driver (and any other future driver).

Also simplify some of the code in the process, eg. saner flash attachment.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/flash/files.flash
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/flash/flash.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/flash/flash.h
cvs rdiff -u -r0 -r1.1 src/sys/dev/flash/flash_io.c \
    src/sys/dev/flash/flash_io.h
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/nand/files.nand
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/nand/nand.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/nand/nand.h
cvs rdiff -u -r1.7 -r0 src/sys/dev/nand/nand_io.c
cvs rdiff -u -r1.1 -r1.2 src/sys/modules/flash/Makefile
cvs rdiff -u -r1.2 -r1.3 src/sys/modules/nand/Makefile

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/flash/files.flash
diff -u src/sys/dev/flash/files.flash:1.1 src/sys/dev/flash/files.flash:1.2
--- src/sys/dev/flash/files.flash:1.1	Sat Feb 26 18:07:30 2011
+++ src/sys/dev/flash/files.flash	Tue Jun 28 18:14:11 2011
@@ -1,9 +1,10 @@
-# $NetBSD: files.flash,v 1.1 2011/02/26 18:07:30 ahoka Exp $
+# $NetBSD: files.flash,v 1.2 2011/06/28 18:14:11 ahoka Exp $
 
 define	flashbus	{ [offset = 0], [size = 0], [readonly = 0] }
 
 device	flash
 attach	flash at flashbus
 file	dev/flash/flash.c		flash
+file	dev/flash/flash_io.c		flash
 
 defflag opt_flash.h			FLASH_STATIC_PARTITIONS

Index: src/sys/dev/flash/flash.c
diff -u src/sys/dev/flash/flash.c:1.6 src/sys/dev/flash/flash.c:1.7
--- src/sys/dev/flash/flash.c:1.6	Tue Jun 28 07:00:17 2011
+++ src/sys/dev/flash/flash.c	Tue Jun 28 18:14:11 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: flash.c,v 1.6 2011/06/28 07:00:17 ahoka Exp $	*/
+/*	$NetBSD: flash.c,v 1.7 2011/06/28 18:14:11 ahoka Exp $	*/
 
 /*-
  * Copyright (c) 2011 Department of Software Engineering,
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: flash.c,v 1.6 2011/06/28 07:00:17 ahoka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: flash.c,v 1.7 2011/06/28 18:14:11 ahoka Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -61,14 +61,8 @@
 #include <sys/flashio.h>
 #include "flash.h"
 
-#define FLASH_DEBUG 1
 #ifdef FLASH_DEBUG
-#define DPRINTF(x)	if (flashdebug) printf x
-#define DPRINTFN(n,x)	if (flashdebug>(n)) printf x
-int	flashdebug = FLASH_DEBUG;
-#else
-#define DPRINTF(x)
-#define DPRINTFN(n,x)
+int flashdebug = FLASH_DEBUG;
 #endif
 
 extern struct cfdriver flash_cd;
@@ -146,9 +140,10 @@
 	sc->sc_dev = self;
 	sc->sc_parent_dev = parent;
 	sc->flash_if = faa->flash_if;
+	sc->sc_partinfo = faa->partinfo;
 	sc->hw_softc = device_private(parent);
 
-	format_bytes(pbuf[0], sizeof(pbuf[0]), sc->flash_if->size);
+	format_bytes(pbuf[0], sizeof(pbuf[0]), sc->sc_partinfo.part_size);
 	format_bytes(pbuf[1], sizeof(pbuf[1]), sc->flash_if->erasesize);
 
 	aprint_naive("\n");
@@ -168,10 +163,10 @@
 
 	aprint_normal_dev(sc->sc_dev,
 	    "size: %#jx, offset: %#jx",
-	    (uintmax_t )sc->flash_if->partition.part_size,
-	    (uintmax_t )sc->flash_if->partition.part_offset);
+	    (uintmax_t )sc->sc_partinfo.part_size,
+	    (uintmax_t )sc->sc_partinfo.part_offset);
 
-	if (sc->flash_if->partition.part_flags & FLASH_PART_READONLY) {
+	if (sc->sc_partinfo.part_flags & FLASH_PART_READONLY) {
 		sc->sc_readonly = true;
 		aprint_normal(", read only");
 	} else {
@@ -180,7 +175,7 @@
 
 	aprint_normal("\n");
 
-	if (sc->flash_if->partition.part_size == 0) {
+	if (sc->sc_partinfo.part_size == 0) {
 		aprint_error_dev(self,
 		    "partition size must be larger than 0\n");
 		return;
@@ -271,7 +266,7 @@
 	int unit = minor(dev);
 	struct flash_softc *sc;
 
-	DPRINTFN(1, ("flash: opening device unit %d\n", unit));
+	FLDPRINTFN(1, ("flash: opening device unit %d\n", unit));
 
 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
 		return ENXIO;
@@ -295,7 +290,7 @@
 	struct flash_softc *sc;
 	int err;
 
-	DPRINTFN(1, ("flash: closing flash device unit %d\n", unit));
+	FLDPRINTFN(1, ("flash: closing flash device unit %d\n", unit));
 
 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
 		return ENXIO;
@@ -348,7 +343,7 @@
 	}
 
 	flash_if = sc->flash_if;
-	part = &flash_if->partition;
+	part = &sc->sc_partinfo;
 
 	/* divider */
 	KASSERT(flash_if->writesize != 0);
@@ -371,7 +366,7 @@
 		goto done;
 	}
 
-	device_blks = sc->flash_if->size / DEV_BSIZE;
+	device_blks = sc->sc_partinfo.part_size / DEV_BSIZE;
 	KASSERT(part->part_offset % DEV_BSIZE == 0);
 	bp->b_rawblkno = bp->b_blkno + (part->part_offset / DEV_BSIZE);
 
@@ -455,7 +450,7 @@
 	case FLASH_DUMP:
 		dp = data;
 		offset = dp->dp_block * sc->flash_if->erasesize;
-		DPRINTF(("Reading from block: %jd len: %jd\n",
+		FLDPRINTF(("Reading from block: %jd len: %jd\n",
 			(intmax_t )dp->dp_block, (intmax_t )dp->dp_len));
 		err = flash_read(sc->sc_parent_dev, offset, dp->dp_len,
 		    &retlen, dp->dp_buf);
@@ -473,7 +468,7 @@
 		ip->ip_page_size = sc->flash_if->page_size;
 		ip->ip_erase_size = sc->flash_if->erasesize;
 		ip->ip_flash_type = sc->flash_if->type;
-		ip->ip_flash_size = sc->flash_if->size;
+		ip->ip_flash_size = sc->sc_partinfo.part_size;
 		break;
 	default:
 		err = ENODEV;
@@ -537,9 +532,9 @@
 }
 
 static inline flash_off_t
-flash_get_part_offset(struct flash_softc *fl, size_t poffset)
+flash_get_part_offset(struct flash_softc *sc, size_t poffset)
 {
-	return fl->flash_if->partition.part_offset + poffset;
+	return sc->sc_partinfo.part_offset + poffset;
 }
 
 int
@@ -553,11 +548,11 @@
 		return EACCES;
 
 	/* adjust for flash partition */
-	e.ei_addr += sc->flash_if->partition.part_offset;
+	e.ei_addr += sc->sc_partinfo.part_offset;
 
 	/* bounds check for flash partition */
-	if (e.ei_addr + e.ei_len > sc->flash_if->partition.part_size +
-	    sc->flash_if->partition.part_offset)
+	if (e.ei_addr + e.ei_len > sc->sc_partinfo.part_size +
+	    sc->sc_partinfo.part_offset)
 		return EINVAL;
 
 	return sc->flash_if->erase(device_parent(self), &e);
@@ -569,10 +564,10 @@
 {
 	struct flash_softc *sc = device_private(self);
 
-	offset += sc->flash_if->partition.part_offset;
+	offset += sc->sc_partinfo.part_offset;
 
-	if (offset + len > sc->flash_if->partition.part_size +
-	    sc->flash_if->partition.part_offset)
+	if (offset + len > sc->sc_partinfo.part_size +
+	    sc->sc_partinfo.part_offset)
 		return EINVAL;
 
 	return sc->flash_if->read(device_parent(self),
@@ -588,10 +583,10 @@
 	if (sc->sc_readonly)
 		return EACCES;
 
-	offset += sc->flash_if->partition.part_offset;
+	offset += sc->sc_partinfo.part_offset;
 
-	if (offset + len > sc->flash_if->partition.part_size +
-	    sc->flash_if->partition.part_offset)
+	if (offset + len > sc->sc_partinfo.part_size +
+	    sc->sc_partinfo.part_offset)
 		return EINVAL;
 
 	return sc->flash_if->write(device_parent(self),
@@ -606,11 +601,11 @@
 	if (sc->sc_readonly)
 		return EACCES;
 
-	offset += sc->flash_if->partition.part_offset;
+	offset += sc->sc_partinfo.part_offset;
 
 	if (offset + sc->flash_if->erasesize >=
-	    sc->flash_if->partition.part_size +
-	    sc->flash_if->partition.part_offset)
+	    sc->sc_partinfo.part_size +
+	    sc->sc_partinfo.part_offset)
 		return EINVAL;
 
 	return sc->flash_if->block_markbad(device_parent(self), offset);
@@ -621,11 +616,11 @@
 {
 	struct flash_softc *sc = device_private(self);
 
-	offset += sc->flash_if->partition.part_offset;
+	offset += sc->sc_partinfo.part_offset;
 
 	if (offset + sc->flash_if->erasesize >
-	    sc->flash_if->partition.part_size +
-	    sc->flash_if->partition.part_offset)
+	    sc->sc_partinfo.part_size +
+	    sc->sc_partinfo.part_offset)
 		return EINVAL;
 
 	return sc->flash_if->block_isbad(device_parent(self), offset, bad);

Index: src/sys/dev/flash/flash.h
diff -u src/sys/dev/flash/flash.h:1.3 src/sys/dev/flash/flash.h:1.4
--- src/sys/dev/flash/flash.h:1.3	Mon Apr  4 14:25:09 2011
+++ src/sys/dev/flash/flash.h	Tue Jun 28 18:14:11 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: flash.h,v 1.3 2011/04/04 14:25:09 ahoka Exp $	*/
+/*	$NetBSD: flash.h,v 1.4 2011/06/28 18:14:11 ahoka Exp $	*/
 
 /*-
  * Copyright (c) 2011 Department of Software Engineering,
@@ -41,6 +41,21 @@
 #include <sys/buf.h>
 #include <sys/flashio.h>
 
+#define FLASH_DEBUG 1
+#ifdef FLASH_DEBUG
+#define FLDPRINTF(x)	if (flashdebug) printf x
+#define FLDPRINTFN(n,x)	if (flashdebug>(n)) printf x
+#else
+#define FLDPRINTF(x)
+#define FLDPRINTFN(n,x)
+#endif
+
+struct flash_partition {
+	flash_off_t part_offset;
+	flash_size_t part_size;
+	int part_flags;
+};
+
 /**
  *  flash_softc - private structure for flash layer driver
  */
@@ -50,12 +65,14 @@
 	device_t sc_parent_dev;		/* Hardware (parent) device */
 	void *hw_softc;			/* Hardware device private softc */
 	struct flash_interface *flash_if;	/* Hardware interface */
+	struct flash_partition sc_partinfo;	/* partition information */
 
 	bool sc_readonly;		/* read only flash device */
 };
 
 struct flash_attach_args {
 	struct flash_interface *flash_if;	/* Hardware interface */
+	struct flash_partition partinfo;
 };
 
 device_t flash_attach_mi(struct flash_interface *, device_t);
@@ -65,12 +82,6 @@
 
 /**
  * struct erase_instruction - instructions to erase a flash eraseblock
- * @fd: flash descriptor
- * @addr: start address of the erase operation
- * @len: the erase length
- * @callback: callback operation, called when erase finished
- * @priv: private data
- * @state: the erase operation's result
  */
 struct flash_erase_instruction {
 	flash_off_t ei_addr;
@@ -85,25 +96,8 @@
 	FLASH_PART_FILESYSTEM	= (1<<2)
 };
 
-struct flash_partition {
-	flash_off_t part_offset;
-	flash_off_t part_size;
-	int part_flags;
-};
-
 /**
  * struct flash_interface - interface for flash operations
- * @type: type of flash device
- * @size: size of flash
- * @page_size: page size of flash
- * @erasesize: erase size of flash
- * @writesize: minimum write size of flash
- * @minor: minor number of the character device attached to this driver
- * @erase: erase operation of the flash
- * @read: read operation of the flash
- * @write: write operation of the flash
- * @block_markbad: marks a block as bad on the flash
- * @block_isbad: checks if a block is bad on flash
  */
 struct flash_interface {
 	int (*erase)(device_t, struct flash_erase_instruction *);
@@ -115,11 +109,6 @@
 
 	int (*submit)(device_t, struct buf *);
 
-	/* storage for partition info */
-	struct flash_partition partition;
-
-	/* total size of mtd */
-	flash_size_t size;	 
 	uint32_t page_size;
 	uint32_t erasesize;
 	uint32_t writesize;
@@ -146,10 +135,6 @@
 
 /*
  * check_pattern - checks the buffer only contains the byte pattern
- * @buf: the buffer to check
- * @patt: the pattern to match
- * @offset: the starting byte number, the matching starts from here
- * @size: the buffer size
  *
  * This functions checks if the buffer only contains a specified byte pattern.
  * Returns %0 if found something else, %1 otherwise.

Index: src/sys/dev/nand/files.nand
diff -u src/sys/dev/nand/files.nand:1.3 src/sys/dev/nand/files.nand:1.4
--- src/sys/dev/nand/files.nand:1.3	Sun Mar 27 13:33:04 2011
+++ src/sys/dev/nand/files.nand	Tue Jun 28 18:14:11 2011
@@ -1,11 +1,10 @@
-# $NetBSD: files.nand,v 1.3 2011/03/27 13:33:04 ahoka Exp $
+# $NetBSD: files.nand,v 1.4 2011/06/28 18:14:11 ahoka Exp $
 
 define	nandbus	{ }
 
 device	nand: flashbus
 attach	nand at nandbus
 file	dev/nand/nand.c		nand
-file	dev/nand/nand_io.c	nand
 file	dev/nand/hamming.c	nand
 file	dev/nand/nand_bbt.c	nand
 file	dev/nand/nand_crc.c	nand

Index: src/sys/dev/nand/nand.c
diff -u src/sys/dev/nand/nand.c:1.12 src/sys/dev/nand/nand.c:1.13
--- src/sys/dev/nand/nand.c:1.12	Tue Jun 28 07:16:11 2011
+++ src/sys/dev/nand/nand.c	Tue Jun 28 18:14:11 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: nand.c,v 1.12 2011/06/28 07:16:11 ahoka Exp $	*/
+/*	$NetBSD: nand.c,v 1.13 2011/06/28 18:14:11 ahoka Exp $	*/
 
 /*-
  * Copyright (c) 2010 Department of Software Engineering,
@@ -34,7 +34,7 @@
 /* Common driver for NAND chips implementing the ONFI 2.2 specification */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nand.c,v 1.12 2011/06/28 07:16:11 ahoka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nand.c,v 1.13 2011/06/28 18:14:11 ahoka Exp $");
 
 #include "locators.h"
 
@@ -42,10 +42,10 @@
 #include <sys/types.h>
 #include <sys/device.h>
 #include <sys/kmem.h>
-#include <sys/sysctl.h>
 #include <sys/atomic.h>
 
 #include <dev/flash/flash.h>
+#include <dev/flash/flash_io.h>
 #include <dev/nand/nand.h>
 #include <dev/nand/onfi.h>
 #include <dev/nand/hamming.h>
@@ -75,8 +75,17 @@
 int	nanddebug = NAND_DEBUG;
 #endif
 
-int nand_cachesync_timeout = 1;
-int nand_cachesync_nodenum;
+struct flash_interface nand_flash_if = {
+	.type = FLASH_TYPE_NAND,
+
+	.read = nand_flash_read,
+	.write = nand_flash_write,
+	.erase = nand_flash_erase,
+	.block_isbad = nand_flash_isbad,
+	.block_markbad = nand_flash_markbad,
+
+	.submit = nand_io_submit
+};
 
 #ifdef NAND_VERBOSE
 const struct nand_manufacturer nand_mfrs[] = {
@@ -138,13 +147,17 @@
 		return;
 	}
 
+	nand_flash_if.erasesize = chip->nc_block_size;
+	nand_flash_if.page_size = chip->nc_page_size;
+	nand_flash_if.writesize = chip->nc_page_size;
+
 	/* allocate cache */
 	chip->nc_oob_cache = kmem_alloc(chip->nc_spare_size, KM_SLEEP);
 	chip->nc_page_cache = kmem_alloc(chip->nc_page_size, KM_SLEEP);
 
 	mutex_init(&sc->sc_device_lock, MUTEX_DEFAULT, IPL_NONE);
 
-	if (nand_sync_thread_start(self)) {
+	if (flash_sync_thread_init(&sc->sc_flash_io, &nand_flash_if)) {
 		goto error;
 	}
 
@@ -174,42 +187,23 @@
 {
 	struct nand_softc *sc = device_private(parent);
 	struct nand_chip *chip = &sc->sc_chip;
-	struct flash_interface *flash_if;
 	struct flash_attach_args faa;
 
-	flash_if = kmem_alloc(sizeof(*flash_if), KM_SLEEP);
-
-	flash_if->type = FLASH_TYPE_NAND;
-
-	flash_if->read = nand_flash_read;
-	flash_if->write = nand_flash_write;
-	flash_if->erase = nand_flash_erase;
-	flash_if->block_isbad = nand_flash_isbad;
-	flash_if->block_markbad = nand_flash_markbad;
+	faa.flash_if = &nand_flash_if;
 
-	flash_if->submit = nand_io_submit;
-
-	flash_if->erasesize = chip->nc_block_size;
-	flash_if->page_size = chip->nc_page_size;
-	flash_if->writesize = chip->nc_page_size;
-
-	flash_if->partition.part_offset = cf->cf_loc[FLASHBUSCF_OFFSET];
+	faa.partinfo.part_offset = cf->cf_loc[FLASHBUSCF_OFFSET];
 
 	if (cf->cf_loc[FLASHBUSCF_SIZE] == 0) {
-		flash_if->size = chip->nc_size -
-		    flash_if->partition.part_offset;
-		flash_if->partition.part_size = flash_if->size;
+		faa.partinfo.part_size = chip->nc_size -
+		    faa.partinfo.part_offset;
 	} else {
-		flash_if->size = cf->cf_loc[FLASHBUSCF_SIZE];
-		flash_if->partition.part_size = cf->cf_loc[FLASHBUSCF_SIZE];
+		faa.partinfo.part_size = cf->cf_loc[FLASHBUSCF_SIZE];
 	}
 
 	if (cf->cf_loc[FLASHBUSCF_READONLY])
-		flash_if->partition.part_flags = FLASH_PART_READONLY;
+		faa.partinfo.part_flags = FLASH_PART_READONLY;
 	else
-		flash_if->partition.part_flags = 0;
-
-	faa.flash_if = flash_if;
+		faa.partinfo.part_flags = 0;
 
 	if (config_match(parent, cf, &faa)) {
 		if (config_attach(parent, cf, &faa, nand_print) != NULL) {
@@ -217,8 +211,6 @@
 		} else {
 			return 1;
 		}
-	} else {
-		kmem_free(flash_if, sizeof(*flash_if));
 	}
 
 	return 1;
@@ -1494,69 +1486,6 @@
 	return error;
 }
 
-static int
-sysctl_nand_verify(SYSCTLFN_ARGS)
-{
-	int error, t;
-	struct sysctlnode node;
-
-	node = *rnode;
-	t = *(int *)rnode->sysctl_data;
-	node.sysctl_data = &t;
-	error = sysctl_lookup(SYSCTLFN_CALL(&node));
-	if (error || newp == NULL)
-		return error;
-
-	if (node.sysctl_num == nand_cachesync_nodenum) {
-		if (t <= 0 || t > 60)
-			return EINVAL;
-	} else {
-		return EINVAL;
-	}
-
-	*(int *)rnode->sysctl_data = t;
-
-	return 0;
-}
-
-SYSCTL_SETUP(sysctl_nand, "sysctl nand subtree setup")
-{
-	int rc, nand_root_num;
-	const struct sysctlnode *node;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, NULL,
-	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
-	    NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) {
-		goto error;
-	}
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "nand",
-	    SYSCTL_DESCR("NAND driver controls"),
-	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
-		goto error;
-	}
-
-	nand_root_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
-	    CTLTYPE_INT, "cache_sync_timeout",
-	    SYSCTL_DESCR("NAND write cache sync timeout in seconds"),
-	    sysctl_nand_verify, 0, &nand_cachesync_timeout,
-	    0, CTL_HW, nand_root_num, CTL_CREATE,
-	    CTL_EOL)) != 0) {
-		goto error;
-	}
-
-	nand_cachesync_nodenum = node->sysctl_num;
-
-	return;
-
-error:
-	aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
-}
-
 MODULE(MODULE_CLASS_DRIVER, nand, "flash");
 
 #ifdef _MODULE

Index: src/sys/dev/nand/nand.h
diff -u src/sys/dev/nand/nand.h:1.10 src/sys/dev/nand/nand.h:1.11
--- src/sys/dev/nand/nand.h:1.10	Tue Jun 28 07:16:11 2011
+++ src/sys/dev/nand/nand.h	Tue Jun 28 18:14:11 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: nand.h,v 1.10 2011/06/28 07:16:11 ahoka Exp $	*/
+/*	$NetBSD: nand.h,v 1.11 2011/06/28 18:14:11 ahoka Exp $	*/
 
 /*-
  * Copyright (c) 2010 Department of Software Engineering,
@@ -43,6 +43,7 @@
 
 #include <dev/nand/onfi.h>
 #include <dev/flash/flash.h>
+#include <dev/flash/flash_io.h>
 
 #ifdef NAND_DEBUG
 #define DPRINTF(x)	printf x
@@ -50,8 +51,6 @@
 #define DPRINTF(x)
 #endif
 
-//#define NAND_VERBOSE
-
 /* same as in linux for compatibility */
 enum {
 	NAND_BAD_MARKER_OFFSET		= 0,
@@ -157,7 +156,7 @@
 	size_t sc_part_offset;
 	size_t sc_part_size;
 	kmutex_t sc_device_lock; /* serialize access to chip */
-	struct nand_write_cache sc_cache;
+	struct flash_io sc_flash_io;
 };
 
 /* structure holding the nand api */

Index: src/sys/modules/flash/Makefile
diff -u src/sys/modules/flash/Makefile:1.1 src/sys/modules/flash/Makefile:1.2
--- src/sys/modules/flash/Makefile:1.1	Sat Feb 26 18:07:31 2011
+++ src/sys/modules/flash/Makefile	Tue Jun 28 18:14:12 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.1 2011/02/26 18:07:31 ahoka Exp $
+#	$NetBSD: Makefile,v 1.2 2011/06/28 18:14:12 ahoka Exp $
 
 .include "../Makefile.inc"
 
@@ -6,6 +6,6 @@
 
 KMOD=	flash
 IOCONF=	flash.ioconf
-SRCS=	flash.c
+SRCS=	flash.c flash_io.c
 
 .include <bsd.kmodule.mk>

Index: src/sys/modules/nand/Makefile
diff -u src/sys/modules/nand/Makefile:1.2 src/sys/modules/nand/Makefile:1.3
--- src/sys/modules/nand/Makefile:1.2	Wed Mar  9 10:05:28 2011
+++ src/sys/modules/nand/Makefile	Tue Jun 28 18:14:12 2011
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.2 2011/03/09 10:05:28 ahoka Exp $
+# $NetBSD: Makefile,v 1.3 2011/06/28 18:14:12 ahoka Exp $
 
 .include "../Makefile.inc"
 
@@ -7,7 +7,6 @@
 KMOD=   nand
 IOCONF=	nand.ioconf
 SRCS=	nand.c
-SRCS+=	nand_io.c
 SRCS+=	nand_bbt.c
 SRCS+=	nand_crc.c
 SRCS+=	hamming.c

Added files:

Index: src/sys/dev/flash/flash_io.c
diff -u /dev/null src/sys/dev/flash/flash_io.c:1.1
--- /dev/null	Tue Jun 28 18:14:12 2011
+++ src/sys/dev/flash/flash_io.c	Tue Jun 28 18:14:11 2011
@@ -0,0 +1,419 @@
+/*	$NetBSD: flash_io.c,v 1.1 2011/06/28 18:14:11 ahoka Exp $	*/
+
+/*-
+ * Copyright (c) 2011 Department of Software Engineering,
+ *		      University of Szeged, Hungary
+ * Copyright (c) 2011 Adam Hoka <ah...@netbsd.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: flash_io.c,v 1.1 2011/06/28 18:14:11 ahoka Exp $");
+
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/bufq.h>
+#include <sys/kernel.h>
+#include <sys/kmem.h>
+#include <sys/kthread.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+
+#include <dev/flash/flash.h>
+#include <dev/flash/flash_io.h>
+
+#ifdef FLASH_DEBUG
+extern int flashdebug;
+#endif
+
+int flash_cachesync_timeout = 1;
+int flash_cachesync_nodenum;
+
+void flash_io_read(struct flash_io *, struct buf *);
+void flash_io_write(struct flash_io *, struct buf *);
+void flash_io_done(struct flash_io *, struct buf *, int);
+int flash_io_cache_write(struct flash_io *, flash_addr_t, struct buf *);
+void flash_io_cache_sync(struct flash_io *);
+
+static int
+flash_timestamp_diff(struct bintime *bt, struct bintime *b2)
+{
+	struct bintime b1 = *bt;
+	struct timeval tv;
+
+	bintime_sub(&b1, b2);
+	bintime2timeval(&b1, &tv);
+
+	return tvtohz(&tv);
+}
+
+static flash_addr_t
+flash_io_getblock(struct flash_io *fio, struct buf *bp)
+{
+	flash_off_t block, last;
+
+	/* get block number of first byte */
+	block = bp->b_rawblkno * DEV_BSIZE / fio->fio_if->erasesize;
+
+	/* block of the last bite */
+	last = (bp->b_rawblkno * DEV_BSIZE + bp->b_resid - 1)
+	    / fio->fio_if->erasesize;
+
+	/* spans trough multiple blocks, needs special handling */
+	if (last != block) {
+		printf("0x%jx -> 0x%jx\n",
+		    bp->b_rawblkno * DEV_BSIZE,
+		    bp->b_rawblkno * DEV_BSIZE + bp->b_resid - 1);
+		panic("TODO: multiple block write. last: %jd, current: %jd",
+		    (intmax_t )last, (intmax_t )block);
+	}
+
+	return block;
+}
+
+int
+flash_sync_thread_init(struct flash_io *fio, struct flash_interface *flash_if)
+{
+	int error;
+
+	FLDPRINTF(("starting flash io thread\n"));
+
+	fio->fio_if = flash_if;
+
+	fio->fio_data = kmem_alloc(fio->fio_if->erasesize, KM_SLEEP);
+
+	mutex_init(&fio->fio_lock, MUTEX_DEFAULT, IPL_NONE);
+	cv_init(&fio->fio_cv, "flashcv");
+
+	error = bufq_alloc(&fio->fio_bufq, "fcfs", BUFQ_SORT_RAWBLOCK);
+	if (error)
+		goto err_bufq;
+
+	fio->fio_exiting = false;
+	fio->fio_write_pending = false;
+
+	/* arrange to allocate the kthread */
+	error = kthread_create(PRI_NONE, KTHREAD_JOINABLE | KTHREAD_MPSAFE,
+	    NULL, flash_sync_thread, fio, &fio->fio_thread, "flashio");
+
+	if (!error)
+		return 0;
+
+	bufq_free(fio->fio_bufq);
+err_bufq:
+	cv_destroy(&fio->fio_cv);
+	mutex_destroy(&fio->fio_lock);
+	kmem_free(fio->fio_data, fio->fio_if->erasesize);
+
+	return error;
+}
+
+void
+flash_sync_thread_destroy(struct flash_io *fio)
+{
+	FLDPRINTF(("stopping flash io thread\n"));
+
+	mutex_enter(&fio->fio_lock);
+
+	fio->fio_exiting = true;
+	cv_broadcast(&fio->fio_cv);
+
+	mutex_exit(&fio->fio_lock);
+
+	kthread_join(fio->fio_thread);
+
+	kmem_free(fio->fio_data, fio->fio_if->erasesize);
+	bufq_free(fio->fio_bufq);
+	mutex_destroy(&fio->fio_lock);
+	cv_destroy(&fio->fio_cv);
+}
+
+int
+flash_io_submit(struct flash_io *fio, struct buf *bp)
+{
+	FLDPRINTF(("submitting job to flash io thread: %p\n", bp));
+
+	if (__predict_false(fio->fio_exiting)) {
+		flash_io_done(fio, bp, ENODEV);
+		return ENODEV;
+	}
+
+	if (BUF_ISREAD(bp)) {
+		FLDPRINTF(("we have a read job\n"));
+
+		mutex_enter(&fio->fio_lock);
+		if (fio->fio_write_pending)
+			flash_io_cache_sync(fio);
+		mutex_exit(&fio->fio_lock);
+
+		flash_io_read(fio, bp);
+	} else {
+		FLDPRINTF(("we have a write job\n"));
+
+		flash_io_write(fio, bp);
+	}
+	return 0;
+}
+
+int
+flash_io_cache_write(struct flash_io *fio, flash_addr_t block, struct buf *bp)
+{
+	size_t retlen;
+	flash_addr_t base, offset;
+	int error;
+
+	KASSERT(mutex_owned(&fio->fio_lock));
+	KASSERT(fio->fio_if->erasesize != 0);
+
+	base = block * fio->fio_if->erasesize;
+	offset = bp->b_rawblkno * DEV_BSIZE - base;
+
+	FLDPRINTF(("io cache write, offset: %jd\n", (intmax_t )offset));
+
+	if (!fio->fio_write_pending) {
+		fio->fio_block = block;
+		/*
+		 * fill the cache with data from flash,
+		 * so we dont have to bother with gaps later
+		 */
+		FLDPRINTF(("filling buffer from offset %ju\n", (uintmax_t)base));
+		error = fio->fio_if->read(fio->fio_dev,
+		    base, fio->fio_if->erasesize,
+		    &retlen, fio->fio_data);
+		FLDPRINTF(("cache filled\n"));
+
+		if (error)
+			return error;
+
+		fio->fio_write_pending = true;
+		/* save creation time for aging */
+		binuptime(&fio->fio_creation);
+	}
+	/* copy data to cache */
+	memcpy(fio->fio_data + offset, bp->b_data, bp->b_resid);
+	bufq_put(fio->fio_bufq, bp);
+
+	/* update timestamp */
+	binuptime(&fio->fio_last_write);
+
+	return 0;
+}
+
+void
+flash_io_cache_sync(struct flash_io *fio)
+{
+	struct flash_erase_instruction ei;
+	struct buf *bp;
+	size_t retlen;
+	flash_addr_t base;
+	int error;
+
+	KASSERT(mutex_owned(&fio->fio_lock));
+
+	if (!fio->fio_write_pending) {
+		FLDPRINTF(("trying to sync with an invalid buffer\n"));
+		return;
+	}
+
+	base = fio->fio_block * fio->fio_if->erasesize;
+
+	FLDPRINTF(("eraseing block at 0x%jx\n", (uintmax_t )base));
+	ei.ei_addr = base;
+	ei.ei_len = fio->fio_if->erasesize;
+	ei.ei_callback = NULL;
+	error = fio->fio_if->erase(fio->fio_dev, &ei);
+
+	if (error) {
+		aprint_error_dev(fio->fio_dev, "cannot erase flash flash!\n");
+		goto out;
+	}
+
+	FLDPRINTF(("writing %zu bytes to 0x%jx\n",
+		fio->fio_if->erasesize, (uintmax_t )base));
+
+	error = fio->fio_if->write(fio->fio_dev,
+	    base, fio->fio_if->erasesize, &retlen, fio->fio_data);
+
+	if (error || retlen != fio->fio_if->erasesize) {
+		aprint_error_dev(fio->fio_dev, "can't sync write cache: %d\n", error);
+		goto out;
+	}
+
+out:
+	while ((bp = bufq_get(fio->fio_bufq)) != NULL)
+		flash_io_done(fio, bp, error);
+
+	fio->fio_block = -1;
+	fio->fio_write_pending = false;
+}
+
+void
+flash_sync_thread(void * arg)
+{
+	struct flash_io *fio = arg;
+	struct bintime now;
+
+	mutex_enter(&fio->fio_lock);
+
+	while (!fio->fio_exiting) {
+		cv_timedwait_sig(&fio->fio_cv, &fio->fio_lock, hz / 4);
+		if (!fio->fio_write_pending) {
+			continue;
+		}
+		/* see if the cache is older than 3 seconds (safety limit),
+		 * or if we havent touched the cache since more than 1 ms
+		 */
+		binuptime(&now);
+		if (flash_timestamp_diff(&now, &fio->fio_last_write) > hz / 5) {
+			FLDPRINTF(("syncing write cache after timeout\n"));
+			flash_io_cache_sync(fio);
+		} else if (flash_timestamp_diff(&now, &fio->fio_creation)
+		    > 3 * hz) {
+			aprint_error_dev(fio->fio_dev,
+			    "syncing write cache after 3 sec timeout!\n");
+			flash_io_cache_sync(fio);
+		}
+	}
+
+	mutex_exit(&fio->fio_lock);
+
+	kthread_exit(0);
+}
+
+void
+flash_io_read(struct flash_io *fio, struct buf *bp)
+{
+	size_t retlen;
+	flash_addr_t offset;
+	int error;
+
+	FLDPRINTF(("flash io read\n"));
+
+	offset = bp->b_rawblkno * DEV_BSIZE;
+
+	error = fio->fio_if->read(fio->fio_dev, offset, bp->b_resid,
+	    &retlen, bp->b_data);
+
+	flash_io_done(fio, bp, error);
+}
+
+void
+flash_io_write(struct flash_io *fio, struct buf *bp)
+{
+	flash_addr_t block;
+
+	FLDPRINTF(("flash io write\n"));
+
+	block = flash_io_getblock(fio, bp);
+	FLDPRINTF(("write to block %jd\n", (intmax_t )block));
+
+	mutex_enter(&fio->fio_lock);
+
+	if (fio->fio_write_pending && fio->fio_block != block) {
+		FLDPRINTF(("writing to new block, syncing caches\n"));
+		flash_io_cache_sync(fio);
+	}
+
+	flash_io_cache_write(fio, block, bp);
+
+	mutex_exit(&fio->fio_lock);
+}
+
+void
+flash_io_done(struct flash_io *fio, struct buf *bp, int error)
+{
+	FLDPRINTF(("io done: %p\n", bp));
+
+	if (error == 0)
+		bp->b_resid = 0;
+
+	bp->b_error = error;
+	biodone(bp);
+}
+
+static int
+sysctl_flash_verify(SYSCTLFN_ARGS)
+{
+	int error, t;
+	struct sysctlnode node;
+
+	node = *rnode;
+	t = *(int *)rnode->sysctl_data;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (node.sysctl_num == flash_cachesync_nodenum) {
+		if (t <= 0 || t > 60)
+			return EINVAL;
+	} else {
+		return EINVAL;
+	}
+
+	*(int *)rnode->sysctl_data = t;
+
+	return 0;
+}
+
+SYSCTL_SETUP(sysctl_flash, "sysctl flash subtree setup")
+{
+	int rc, flash_root_num;
+	const struct sysctlnode *node;
+
+	if ((rc = sysctl_createv(clog, 0, NULL, NULL,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
+	    NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) {
+		goto error;
+	}
+
+	if ((rc = sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "flash",
+	    SYSCTL_DESCR("FLASH driver controls"),
+	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
+		goto error;
+	}
+
+	flash_root_num = node->sysctl_num;
+
+	if ((rc = sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+	    CTLTYPE_INT, "cache_sync_timeout",
+	    SYSCTL_DESCR("FLASH write cache sync timeout in seconds"),
+	    sysctl_flash_verify, 0, &flash_cachesync_timeout,
+	    0, CTL_HW, flash_root_num, CTL_CREATE,
+	    CTL_EOL)) != 0) {
+		goto error;
+	}
+
+	flash_cachesync_nodenum = node->sysctl_num;
+
+	return;
+
+error:
+	aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
+}
Index: src/sys/dev/flash/flash_io.h
diff -u /dev/null src/sys/dev/flash/flash_io.h:1.1
--- /dev/null	Tue Jun 28 18:14:12 2011
+++ src/sys/dev/flash/flash_io.h	Tue Jun 28 18:14:11 2011
@@ -0,0 +1,24 @@
+#ifndef _FLASH_IO_H_
+#define _FLASH_IO_H_
+
+struct flash_io {
+	device_t fio_dev;
+	struct bintime fio_creation;
+	struct bintime fio_last_write;
+	struct bufq_state *fio_bufq;
+	uint8_t *fio_data;
+	daddr_t fio_block;
+	kmutex_t fio_lock;
+	bool fio_write_pending;
+	struct lwp *fio_thread;
+	kcondvar_t fio_cv;
+	bool fio_exiting;
+	struct flash_interface *fio_if;
+};
+
+int flash_io_submit(struct flash_io *, struct buf *);
+void flash_sync_thread(void *);
+int flash_sync_thread_init(struct flash_io *, struct flash_interface *);
+void flash_sync_thread_destroy(struct flash_io *);
+
+#endif

Reply via email to