PERFORCE change 222053 for review

Brooks Davis brooks at FreeBSD.org
Fri Feb 15 12:00:45 UTC 2013


http://p4web.freebsd.org/@@222053?ac=10

Change 222053 by brooks at brooks_zenith on 2013/02/15 12:00:02

	Rework the timeout API to support timeouts when trying to set up
	a buffered write.
	
	Spin when polling for completion and don't call DELAY() between
	polls.  Some operations have documented typical completion times
	on the order of 8 microseconds so any delay would increase
	latency.
	
	Write performance to Intel StrataFlash devices on the DE4 now
	exceeds 140KBps.

Affected files ...

.. //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_core.c#8 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_var.h#6 edit

Differences ...

==== //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_core.c#8 (text+ko) ====

@@ -259,8 +259,9 @@
 cfi_attach(device_t dev) 
 {
 	struct cfi_softc *sc;
+	struct timeval tv;
 	u_int blksz, blocks;
-	u_int r, u;
+	u_int r, u, usec;
 
 	sc = device_get_softc(dev);
 	sc->sc_dev = dev;
@@ -274,17 +275,43 @@
 	sc->sc_tag = rman_get_bustag(sc->sc_res);
 	sc->sc_handle = rman_get_bushandle(sc->sc_res);
 
-	/* Get time-out values for erase and write. */
-	sc->sc_write_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_WRITE);
-	sc->sc_bufwrite_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_BUFWRITE);
-	sc->sc_erase_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_ERASE);
-	sc->sc_write_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_WRITE);
-	sc->sc_bufwrite_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_BUFWRITE);
-	sc->sc_erase_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_ERASE);
+	/* Get time-out values for erase, write, and buffer write. */
+	bintime_clear(&sc->sc_typical_timeouts[CFI_TIMEOUT_ERASE]);
+	usec = 1000 * (1 << cfi_read_qry(sc, CFI_QRY_TTO_ERASE));
+	tv.tv_sec = usec / 1000000;
+	tv.tv_usec = usec % 1000000;
+	timeval2bintime(&tv, &sc->sc_typical_timeouts[CFI_TIMEOUT_ERASE]);
+	sc->sc_max_timeouts[CFI_TIMEOUT_ERASE] =
+	    sc->sc_typical_timeouts[CFI_TIMEOUT_ERASE];
+	bintime_mul(&sc->sc_max_timeouts[CFI_TIMEOUT_ERASE],
+	    1 << cfi_read_qry(sc, CFI_QRY_MTO_ERASE));
+
+	bintime_clear(&sc->sc_typical_timeouts[CFI_TIMEOUT_WRITE]);
+	usec = 1 << cfi_read_qry(sc, CFI_QRY_TTO_WRITE);
+	tv.tv_sec = usec / 1000000;
+	tv.tv_usec = usec % 1000000;
+	timeval2bintime(&tv, &sc->sc_typical_timeouts[CFI_TIMEOUT_WRITE]);
+	sc->sc_max_timeouts[CFI_TIMEOUT_WRITE] =
+	    sc->sc_typical_timeouts[CFI_TIMEOUT_WRITE];
+	bintime_mul(&sc->sc_max_timeouts[CFI_TIMEOUT_WRITE],
+	    1 << cfi_read_qry(sc, CFI_QRY_MTO_WRITE));
+
+	bintime_clear(&sc->sc_typical_timeouts[CFI_TIMEOUT_BUFWRITE]);
+	usec = 1 << cfi_read_qry(sc, CFI_QRY_TTO_BUFWRITE);
+	tv.tv_sec = usec / 1000000;
+	tv.tv_usec = usec % 1000000;
+	timeval2bintime(&tv, &sc->sc_typical_timeouts[CFI_TIMEOUT_BUFWRITE]);
+	sc->sc_max_timeouts[CFI_TIMEOUT_BUFWRITE] =
+	    sc->sc_typical_timeouts[CFI_TIMEOUT_BUFWRITE];
+	bintime_mul(&sc->sc_max_timeouts[CFI_TIMEOUT_BUFWRITE],
+	    1 << cfi_read_qry(sc, CFI_QRY_MTO_BUFWRITE));
 
 	/* Get the maximum size of a multibyte program */
-	sc->sc_maxbuf = 1 << (cfi_read_qry(sc, CFI_QRY_MAXBUF) |
-	    cfi_read_qry(sc, CFI_QRY_MAXBUF) << 8);
+	if (bintime_isset(&sc->sc_typical_timeouts[CFI_TIMEOUT_BUFWRITE]))
+		sc->sc_maxbuf = 1 << (cfi_read_qry(sc, CFI_QRY_MAXBUF) |
+		    cfi_read_qry(sc, CFI_QRY_MAXBUF) << 8);
+	else
+		sc->sc_maxbuf = 0;
 
 	/* Get erase regions. */
 	sc->sc_regions = cfi_read_qry(sc, CFI_QRY_NREGIONS);
@@ -338,18 +365,21 @@
 }
 
 static int
-cfi_wait_ready(struct cfi_softc *sc, u_int ofs, u_int timeout)
+cfi_wait_ready(struct cfi_softc *sc, u_int ofs, struct bintime *start,
+    enum cfi_wait_cmd cmd)
 {
-	int done, error;
+	int done, error, tto_exceeded;
 	uint32_t st0 = 0, st = 0;
+	struct bintime mend, now, tend;
 
+	tend = mend = *start;
+	bintime_add(&tend, &sc->sc_typical_timeouts[cmd]);
+	bintime_add(&mend, &sc->sc_max_timeouts[cmd]);
+
 	done = 0;
 	error = 0;
-	timeout *= 10;
-	while (!done && !error && timeout) {
-		DELAY(100);
-		timeout--;
-
+	tto_exceeded = 0;
+	while (!done && !error) {
 		switch (sc->sc_cmdset) {
 		case CFI_VEND_INTEL_ECS:
 		case CFI_VEND_INTEL_SCS:
@@ -377,7 +407,25 @@
 			done = ((st & 0x40) == (st0 & 0x40)) ? 1 : 0;
 			break;
 		}
+
+		binuptime(&now);
+		if (tto_exceeded || bintime_cmp(&now, &tend, >)) {
+			if (!tto_exceeded)
+				tto_exceeded = 1;
+			if (bintime_cmp(&now, &mend, >)) {
+#ifdef CFI_DEBUG_TIMEOUT
+				device_printf(sc->sc_dev,
+				    "max timeout exceeded (cmd %d)", cmd);
+#endif
+				break;
+			}
+		}
 	}
+#ifdef CFI_DEBUG_TIMEOUT
+	if (tto_exceeded)
+		device_printf(sc->sc_dev,
+		    "typical timeout exceeded (cmd %d)", cmd);
+#endif
 	if (!done && !error)
 		error = ETIMEDOUT;
 	if (error)
@@ -396,6 +444,7 @@
 	int error, i, neederase = 0;
 	uint32_t st;
 	u_int wlen;
+	struct bintime start;
 
 	switch (sc->sc_cmdset) {
 	case CFI_VEND_INTEL_ECS:
@@ -414,6 +463,7 @@
 		}
 
 	if (neederase) {
+		binuptime(&start);
 		/* Erase the block. */
 		switch (sc->sc_cmdset) {
 		case CFI_VEND_INTEL_ECS:
@@ -431,7 +481,8 @@
 			/* Better safe than sorry... */
 			return (ENODEV);
 		}
-		error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_erase_timeout);
+		error = cfi_wait_ready(sc, sc->sc_wrofs, &start, 
+		    CFI_TIMEOUT_ERASE);
 		if (error)
 			goto out;
 	} else
@@ -440,13 +491,14 @@
 	/* Write the block using a multibyte write if supported. */
 	ptr.x8 = sc->sc_wrbuf;
 	cpyprt.x8 = sc->sc_wrbufcpy;
-	if (sc->sc_bufwrite_timeout > 0 && sc->sc_maxbuf > sc->sc_width) {
+	if (sc->sc_maxbuf > sc->sc_width) {
 		switch (sc->sc_cmdset) {
 		case CFI_VEND_INTEL_ECS:
 		case CFI_VEND_INTEL_SCS:
 			for (i = 0; i < sc->sc_wrbufsz; i += wlen) {
 				wlen = MIN(sc->sc_maxbuf, sc->sc_wrbufsz - i);
 
+				binuptime(&start);
 				do {
 					cfi_write(sc, sc->sc_wrofs + i,
 					    CFI_BCS_BUF_PROG_SETUP);
@@ -476,8 +528,8 @@
 
 				cfi_write(sc, sc->sc_wrofs, CFI_BCS_CONFIRM);
 
-				error = cfi_wait_ready(sc, sc->sc_wrofs + i,
-				    sc->sc_write_timeout);
+				error = cfi_wait_ready(sc, sc->sc_wrofs + 1,
+				    &start, CFI_TIMEOUT_BUFWRITE);
 
 				goto out;
 			}
@@ -509,6 +561,7 @@
 			}
 		}
 
+		binuptime(&start);
 		switch (sc->sc_cmdset) {
 		case CFI_VEND_INTEL_ECS:
 		case CFI_VEND_INTEL_SCS:
@@ -534,7 +587,8 @@
 			break;
 		}
 
-		error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_write_timeout);
+		error = cfi_wait_ready(sc, sc->sc_wrofs, &start,
+		   CFI_TIMEOUT_WRITE);
 		if (error)
 			goto out;
 	}
@@ -630,6 +684,7 @@
 #ifdef CFI_ARMEDANDDANGEROUS
 	register_t intr;
 	int i, error;
+	struct bintime start;
 #endif
 
 	if (sc->sc_cmdset != CFI_VEND_INTEL_ECS)
@@ -639,11 +694,12 @@
 #ifdef CFI_ARMEDANDDANGEROUS
 	for (i = 7; i >= 4; i--, id >>= 16) {
 		intr = intr_disable();
+		binuptime(&start);
 		cfi_write(sc, 0, CFI_INTEL_PP_SETUP);
 		cfi_put16(sc, CFI_INTEL_PR(i), id&0xffff);
 		intr_restore(intr);
-		error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS,
-		    sc->sc_write_timeout);
+		error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS, &start,
+		    CFI_TIMEOUT_WRITE);
 		if (error)
 			break;
 	}
@@ -683,6 +739,7 @@
 #ifdef CFI_ARMEDANDDANGEROUS
 	register_t intr;
 	int error;
+	struct bintime start;
 #endif
 	if (sc->sc_cmdset != CFI_VEND_INTEL_ECS)
 		return EOPNOTSUPP;
@@ -692,10 +749,12 @@
 	/* worthy of console msg */
 	device_printf(sc->sc_dev, "set PLR\n");
 	intr = intr_disable();
+	binuptime(&start);
 	cfi_write(sc, 0, CFI_INTEL_PP_SETUP);
 	cfi_put16(sc, CFI_INTEL_PLR, 0xFFFD);
 	intr_restore(intr);
-	error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS, sc->sc_write_timeout);
+	error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS, &start,
+	    CFI_TIMEOUT_WRITE);
 	cfi_write(sc, 0, CFI_BCS_READ_ARRAY);
 	return error;
 #else

==== //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_var.h#6 (text+ko) ====

@@ -32,6 +32,12 @@
 #ifndef _DEV_CFI_VAR_H_
 #define	_DEV_CFI_VAR_H_
 
+enum cfi_wait_cmd {
+	CFI_TIMEOUT_ERASE,
+	CFI_TIMEOUT_WRITE,
+	CFI_TIMEOUT_BUFWRITE
+};
+
 struct cfi_region {
 	u_int		r_blocks;
 	u_int		r_blksz;
@@ -51,9 +57,8 @@
 	struct cfi_region *sc_region;	/* Array of region info. */
 
 	u_int		sc_cmdset;
-	u_int		sc_erase_timeout;
-	u_int		sc_bufwrite_timeout;
-	u_int		sc_write_timeout;
+	struct bintime	sc_typical_timeouts[3];
+	struct bintime	sc_max_timeouts[3];
 
 	u_int		sc_maxbuf;
 


More information about the p4-projects mailing list