Date: Wed, 20 Aug 2003 21:32:20 -0700 (PDT) From: Marcel Moolenaar <marcel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 36548 for review Message-ID: <200308210432.h7L4WKip031216@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=36548 Change 36548 by marcel@marcel_nfs on 2003/08/20 21:31:41 o Fix a hang on sparc64 caused by the ns8250 driver enabling Tx interrupts. Something special must be going on on sparc64 that goes beyond using the device for keyboard or mouse. We now don't enable Tx interrupts until we actually need to transmit data. o Move the logic that clears pending interrupts to a seperate function so that we can reuse it in *bus_attach() prior to enabling interrupts. o In *bus_attach(), don't call ns8250_flush() for it can only be called when the UART has FIFOs. Instead call ns8250_bus_flush(), which drains non-FIFO UARTS. As a side-effect ns8250_bus_flush() preserves the FIFO setting, so we can program the FIFO prior to flushing it. o In *bus_detach(), disable interrupts and clear any pending interrupts. o In *bus_transmit(), only wait for the transmitter holding register to be empty once, not prior to writing each character to it. We're now close to 99% efficient on a 115200 bps line (and faster than sio(4)). NOTE: pluto1 (and pluto2 for that matter) suffers from the loss of Tx interrupts. This change may on the offchance fix it, because we reenable Tx interrupts everytime we fill the Tx FIFO, but I doubt it. I expect we need to tweak some more when we extend testing to a wide variety of hardware. Affected files ... .. //depot/projects/uart/dev/uart/uart_dev_ns8250.c#18 edit Differences ... ==== //depot/projects/uart/dev/uart/uart_dev_ns8250.c#18 (text+ko) ==== @@ -42,6 +42,29 @@ #define DEFAULT_RCLK 1843200 +/* + * Clear pending interrupts. THRE is cleared by reading IIR. Data + * that may have been received gets lost here. + */ +static void +ns8250_clrint(struct uart_bas *bas) +{ + uint8_t iir; + + iir = uart_getreg(bas, REG_IIR); + while ((iir & IIR_NOPEND) == 0) { + iir &= IIR_IMASK; + if (iir == IIR_RLS) + (void)uart_getreg(bas, REG_LSR); + else if (iir == IIR_RXRDY || iir == IIR_RXTOUT) + (void)uart_getreg(bas, REG_DATA); + else if (iir == IIR_MLSC) + (void)uart_getreg(bas, REG_MSR); + uart_barrier(bas); + iir = uart_getreg(bas, REG_IIR); + } +} + static int ns8250_delay(struct uart_bas *bas) { @@ -240,7 +263,6 @@ ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { - uint8_t iir; if (bas->rclk == 0) bas->rclk = DEFAULT_RCLK; @@ -258,23 +280,7 @@ uart_setreg(bas, REG_MCR, MCR_IENABLE | MCR_RTS | MCR_DTR); uart_barrier(bas); - /* - * Clear pending interrupts. THRE is cleared by reading IIR. Data - * that may have been received gets lost here. - */ - iir = uart_getreg(bas, REG_IIR); - while ((iir & IIR_NOPEND) == 0) { - iir &= IIR_IMASK; - if (iir == IIR_RLS) - (void)uart_getreg(bas, REG_LSR); - else if (iir == IIR_RXRDY || iir == IIR_RXTOUT) - (void)uart_getreg(bas, REG_DATA); - else if (iir == IIR_MLSC) - (void)uart_getreg(bas, REG_MSR); - uart_barrier(bas); - iir = uart_getreg(bas, REG_IIR); - } - uart_barrier(bas); + ns8250_clrint(bas); } static void @@ -331,6 +337,7 @@ struct ns8250_softc { struct uart_softc base; uint8_t fcr; + uint8_t ier; uint8_t mcr; int signals; }; @@ -385,26 +392,32 @@ ns8250->mcr = uart_getreg(bas, REG_MCR); ns8250->fcr = FCR_ENABLE | FCR_RX_MEDH; - ns8250_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); uart_setreg(bas, REG_FCR, ns8250->fcr); uart_barrier(bas); + ns8250_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); + if (ns8250->mcr & MCR_DTR) ns8250->signals |= UART_SIG_DTR; if (ns8250->mcr & MCR_RTS) ns8250->signals |= UART_SIG_RTS; ns8250_bus_getsig(sc); - uart_setreg(bas, REG_IER, - IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); + ns8250_clrint(bas); + ns8250->ier = IER_EMSC | IER_ERLS | IER_ERXRDY; + uart_setreg(bas, REG_IER, ns8250->ier); uart_barrier(bas); - return (0); } static int ns8250_bus_detach(struct uart_softc *sc) { + struct uart_bas *bas; + bas = &sc->sc_bas; + uart_setreg(bas, REG_IER, 0); + uart_barrier(bas); + ns8250_clrint(bas); return (0); } @@ -667,14 +680,16 @@ static int ns8250_bus_transmit(struct uart_softc *sc) { + struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas; int i; bas = &sc->sc_bas; - + while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) + ; + uart_setreg(bas, REG_IER, ns8250->ier | IER_ETXRDY); + uart_barrier(bas); for (i = 0; i < sc->sc_txdatasz; i++) { - while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) - ; uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]); uart_barrier(bas); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200308210432.h7L4WKip031216>