Date: Sun, 29 Dec 2002 23:11:25 -0800 (PST) From: Marcel Moolenaar <marcel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 22913 for review Message-ID: <200212300711.gBU7BP4o056703@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=22913 Change 22913 by marcel@marcel_nfs on 2002/12/29 23:11:16 Extract the logic to flush both the transmitter and receiver from sioinitfifo() and put it in sioflush(). We call sioflush() from sioopen() as well. This replaces the compiled-out fiddling with the FIFOs. Although it's probably more efficient to reset the FIFOs as a way to clear them, I don't think it's generally a good idea. Flushing the transmitter and receiver also applies to non-FIFO UARTs. Slightly change the logic to flush the receiver. UARTs that are integrated in baseboard management controllers (BMCs) can be pretty chattyi when first probed (8KB of data has been observed). We take our time to flush the receiver to make sure we can reliably determine the FIFO size. The previous logic failed too often... Affected files ... .. //depot/projects/ia64/sys/dev/sio/sio.c#32 edit Differences ... ==== //depot/projects/ia64/sys/dev/sio/sio.c#32 (text+ko) ==== @@ -35,6 +35,7 @@ * from: i386/isa sio.c,v 1.234 */ +#include "opt_comconsole.h" #include "opt_ddb.h" #include "opt_sio.h" @@ -264,6 +265,52 @@ /* TUNABLE_INT("machdep.conspeed", &comdefaultrate); */ /* + * Flush the UART. Flush the transmitter FIFO and shift register first, then + * flush the receiver FIFO. In this order flushing works correctly even when + * the UART is in loopback mode. Bad timing may cause at most one character + * to remain in the receiver FIFO/buffer after we're done flushing. This + * would be the character that is (partly) in the receiver shift register. + */ +static int +sioflush(struct com_s *com) +{ + int delay, limit; + + /* 1/10th the time to transmit 1 character (estimate). */ + delay = 16000000 * com->reg_dl / com->rclk; + + /* Flush the transmitter. */ + limit = (com->fifosize) ? com->fifosize : 1; + limit = (limit + 2) * 10; + while ((sio_getreg(com, com_lsr) & LSR_TEMT) == 0 && --limit) + DELAY(delay); + if (limit == 0) { + printf("transmitter appears stuck... "); + return (EIO); + } + + DELAY(10*delay); + + /* + * Flush the receiver. Pick an arbitrary high limit to avoid + * getting stuck in an infinite loop when the hardware is + * broken. + */ + limit=32768; + while ((sio_getreg(com, com_lsr) & LSR_RXRDY) && --limit) { + (void)sio_getreg(com, com_data); + /* XXX barrier */ + DELAY(5*delay); + } + if (limit == 0) { + printf("receiver appears broken... "); + return (EIO); + } + + return (0); +} + +/* * Initialize the FIFOs and determine the size of the receiver FIFO. We * assume that the transmitter FIFO has the same size. First we set DMA * mode (mode 1) with the highest trigger level. In combination with @@ -326,36 +373,10 @@ return (0); } - /* - * We have FIFOs. Flush the transmitter FIFO and shift register. - * This could fill up the receiver FIFO, so we flush that too. - * Bad timing may cause at most one character to remain in the - * receiver FIFO after we're done flushing. This cannot do any - * harm, so we don't worry about it. - */ - limit = 30; - while ((sio_getreg(com, com_lsr) & LSR_TEMT) == 0 && --limit) { - if (delay) - DELAY(delay); - } - if (limit == 0) { - sio_setreg(com, com_mcr, com->reg_mcr); - /* XXX barrier */ - printf("transmitter appears stuck... "); - goto fallback; - } - - limit = 10300; - while ((sio_getreg(com, com_lsr) & LSR_RXRDY) && --limit) { - (void)sio_getreg(com, com_data); - /* XXX barrier */ - if (delay) - DELAY(delay); - } - if (limit == 0) { + /* We have FIFOs. Flush the transmitter and receiver. */ + if (sioflush(com)) { sio_setreg(com, com_mcr, com->reg_mcr); /* XXX barrier */ - printf("receiver appears broken... "); goto fallback; } @@ -635,6 +656,8 @@ if (com->rclk == 0) com->rclk = DEFAULT_RCLK; + sio_setreg(com, com_fcr, 0); + /* XXX barrier */ sio_setreg(com, com_lcr, LCR_8BITS | LCR_DLAB); /* XXX barrier */ com->reg_dl = siodivisor(com->rclk, comdefaultrate); @@ -897,51 +920,10 @@ --com->wopeners; if (error != 0) goto out; -#if 0 - /* - * XXX we should goto open_top if comparam() slept. - */ - if (com->hasfifo) { - int i; - /* - * (Re)enable and drain fifos. - * - * Certain SMC chips cause problems if the fifos - * are enabled while input is ready. Turn off the - * fifo if necessary to clear the input. We test - * the input ready bit after enabling the fifos - * since we've already enabled them in comparam() - * and to handle races between enabling and fresh - * input. - */ - for (i = 0; i < 500; i++) { - sio_setreg(com, com_fcr, - FCR_RCV_RST | FCR_XMT_RST - | com->reg_fcr); - /* - * XXX the delays are for superstitious - * historical reasons. It must be less than - * the character time at the maximum - * supported speed (87 usec at 115200 bps - * 8N1). Otherwise we might loop endlessly - * if data is streaming in. We used to use - * delays of 100. That usually worked - * because DELAY(100) used to usually delay - * for about 85 usec instead of 100. - */ - DELAY(50); - if (!(sio_getreg(com, com_lsr) & LSR_RXRDY)) - break; - sio_setreg(com, com_fcr, 0); - DELAY(50); - (void) sio_getreg(com, com_data); - } - if (i == 500) { - error = EIO; - goto out; - } - } -#endif + + error = sioflush(com); + if (error) + goto out; mtx_lock_spin(&sio_lock); (void) sio_getreg(com, com_lsr); To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe p4-projects" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200212300711.gBU7BP4o056703>