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