Index: sys/dev/uart/uart_dev_ns8250.h =================================================================== --- sys/dev/uart/uart_dev_ns8250.h +++ sys/dev/uart/uart_dev_ns8250.h @@ -41,6 +41,14 @@ uint8_t ier_mask; uint8_t ier_rxbits; uint8_t busy_detect; + + /* + * Error bits from LSR register are cleared on read. They must + * be saved whenever the register is read but not immediately used. + * LSR_SAVE_FLAGS is a bit mask used to store only the needed bits from LSR. + */ +#define LSR_SAVE_FLAGS 0x1E + uint8_t lsr_saved_flags; }; extern struct uart_ops uart_ns8250_ops; Index: sys/dev/uart/uart_dev_ns8250.c =================================================================== --- sys/dev/uart/uart_dev_ns8250.c +++ sys/dev/uart/uart_dev_ns8250.c @@ -64,6 +64,24 @@ TUNABLE_INT("hw.broken_txfifo", &broken_txfifo); /* + * Clear the saved LSR value. + */ +static void +ns8250_clear_saved_lsr(struct ns8250_softc *ns8250) +{ + ns8250->lsr_saved_flags = 0; +} + +/* + * Update the LSR saved value, using bit OR between new and existing value + */ +static void +ns8250_update_saved_lsr(struct ns8250_softc *ns8250, uint8_t lsr) +{ + ns8250->lsr_saved_flags |= (lsr & LSR_SAVE_FLAGS); +} + +/* * Clear pending interrupts. THRE is cleared by reading IIR. Data * that may have been received gets lost here. */ @@ -77,11 +95,14 @@ iir &= IIR_IMASK; if (iir == IIR_RLS) { lsr = uart_getreg(bas, REG_LSR); - if (lsr & (LSR_BI|LSR_FE|LSR_PE)) + if (lsr & (LSR_BI|LSR_FE|LSR_PE)) { (void)uart_getreg(bas, REG_DATA); - } else if (iir == IIR_RXRDY || iir == IIR_RXTOUT) + ns8250_clear_saved_lsr((struct ns8250_softc *)bas); + } + } else if (iir == IIR_RXRDY || iir == IIR_RXTOUT) { (void)uart_getreg(bas, REG_DATA); - else if (iir == IIR_MLSC) + ns8250_clear_saved_lsr((struct ns8250_softc *)bas); + } else if (iir == IIR_MLSC) (void)uart_getreg(bas, REG_MSR); uart_barrier(bas); iir = uart_getreg(bas, REG_IIR); @@ -163,6 +184,7 @@ * management board that tend to get a lot of data send * to it when the UART is first activated. */ + ns8250_clear_saved_lsr((struct ns8250_softc *)bas); limit=10*4096; while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) && --limit) { (void)uart_getreg(bas, REG_DATA); @@ -190,8 +212,10 @@ fcr = FCR_ENABLE; if (what & UART_FLUSH_TRANSMITTER) fcr |= FCR_XMT_RST; - if (what & UART_FLUSH_RECEIVER) + if (what & UART_FLUSH_RECEIVER) { fcr |= FCR_RCV_RST; + ns8250_clear_saved_lsr((struct ns8250_softc *)bas); + } uart_setreg(bas, REG_FCR, fcr); uart_barrier(bas); } @@ -203,6 +227,7 @@ int divisor; uint8_t lcr; + ns8250_clear_saved_lsr((struct ns8250_softc *)bas); lcr = 0; if (databits >= 8) lcr |= LCR_8BITS; @@ -333,8 +358,11 @@ static int ns8250_rxready(struct uart_bas *bas) { + uint8_t lsr; - return ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) != 0 ? 1 : 0); + lsr = uart_getreg(bas, REG_LSR); + ns8250_update_saved_lsr((struct ns8250_softc *)bas, lsr); + return ((lsr & LSR_RXRDY) != 0 ? 1 : 0); } static int @@ -351,6 +379,7 @@ } c = uart_getreg(bas, REG_DATA); + ns8250_clear_saved_lsr((struct ns8250_softc*)bas); uart_unlock(hwmtx); @@ -683,12 +712,19 @@ ipend = 0; if (iir & IIR_RXRDY) { lsr = uart_getreg(bas, REG_LSR); - if (lsr & LSR_OE) + if (lsr & LSR_OE) { ipend |= SER_INT_OVERRUN; - if (lsr & LSR_BI) + lsr &= ~LSR_OE; + } + if (lsr & LSR_BI) { ipend |= SER_INT_BREAK; - if (lsr & LSR_RXRDY) + lsr &= ~LSR_BI; + } + if (lsr & LSR_RXRDY) { ipend |= SER_INT_RXREADY; + lsr &= ~LSR_RXRDY; + } + ns8250_update_saved_lsr(ns8250, lsr); } else { if (iir & IIR_TXRDY) { ipend |= SER_INT_TXIDLE; @@ -894,12 +930,16 @@ ns8250_bus_receive(struct uart_softc *sc) { struct uart_bas *bas; + struct ns8250_softc* ns8250; int xc; uint8_t lsr; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); - lsr = uart_getreg(bas, REG_LSR); + ns8250 = (struct ns8250_softc*)sc; + lsr = uart_getreg(bas, REG_LSR) | ns8250->lsr_saved_flags; + ns8250->lsr_saved_flags = 0; + while (lsr & LSR_RXRDY) { if (uart_rx_full(sc)) { sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;