From owner-p4-projects@FreeBSD.ORG Fri Feb 15 12:00:45 2013 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 6DBAA74F; Fri, 15 Feb 2013 12:00:45 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 31D3974D for ; Fri, 15 Feb 2013 12:00:45 +0000 (UTC) (envelope-from brooks@freebsd.org) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:1900:2254:2068::682:0]) by mx1.freebsd.org (Postfix) with ESMTP id 1620E6F5 for ; Fri, 15 Feb 2013 12:00:45 +0000 (UTC) Received: from skunkworks.freebsd.org ([127.0.1.74]) by skunkworks.freebsd.org (8.14.6/8.14.6) with ESMTP id r1FC0ir8016119 for ; Fri, 15 Feb 2013 12:00:44 GMT (envelope-from brooks@freebsd.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.6/8.14.6/Submit) id r1FC0i3s016116 for perforce@freebsd.org; Fri, 15 Feb 2013 12:00:44 GMT (envelope-from brooks@freebsd.org) Date: Fri, 15 Feb 2013 12:00:44 GMT Message-Id: <201302151200.r1FC0i3s016116@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to brooks@freebsd.org using -f From: Brooks Davis Subject: PERFORCE change 222053 for review To: Perforce Change Reviews Precedence: bulk X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.14 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 Feb 2013 12:00:45 -0000 http://p4web.freebsd.org/@@222053?ac=10 Change 222053 by brooks@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;