diff options
author | marcel <marcel@FreeBSD.org> | 2003-09-17 01:41:21 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2003-09-17 01:41:21 +0000 |
commit | 96dbeb7199a05e6fb1bc00cdfcd8727467423d09 (patch) | |
tree | 976d5fcb92d42c5763ac054fcd83a3a3ba593d98 /sys/dev/uart/uart_dev_ns8250.c | |
parent | 25d51778fc93c3659f92b88183b9b4f4814bc3f4 (diff) | |
download | FreeBSD-src-96dbeb7199a05e6fb1bc00cdfcd8727467423d09.zip FreeBSD-src-96dbeb7199a05e6fb1bc00cdfcd8727467423d09.tar.gz |
Add locking to the hardware drivers. I intended to figure out more
precisely where locking would be needed before adding it, but it
seems uart(4) draws slightly too much attention to have it without
locking for too long.
The lock added is a spinlock that protects access to the underlying
hardware. As a first and obvious stab at this, each method of the
hardware interface grabs the lock. Roughly speaking this serializes
the methods. Exceptions are the probe, attach and detach methods.
Diffstat (limited to 'sys/dev/uart/uart_dev_ns8250.c')
-rw-r--r-- | sys/dev/uart/uart_dev_ns8250.c | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index ada5710..7c4d264 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -427,15 +427,19 @@ ns8250_bus_flush(struct uart_softc *sc, int what) { struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas; + int error; bas = &sc->sc_bas; + mtx_lock_spin(&sc->sc_hwmtx); if (sc->sc_hasfifo) { ns8250_flush(bas, what); uart_setreg(bas, REG_FCR, ns8250->fcr); uart_barrier(bas); - return (0); - } - return (ns8250_drain(bas, what)); + error = 0; + } else + error = ns8250_drain(bas, what); + mtx_unlock_spin(&sc->sc_hwmtx); + return (error); } static int @@ -447,7 +451,9 @@ ns8250_bus_getsig(struct uart_softc *sc) do { old = sc->sc_hwsig; sig = old; + mtx_lock_spin(&sc->sc_hwmtx); msr = uart_getreg(&sc->sc_bas, REG_MSR); + mtx_unlock_spin(&sc->sc_hwmtx); SIGCHG(msr & MSR_DSR, sig, UART_SIG_DSR, UART_SIG_DDSR); SIGCHG(msr & MSR_CTS, sig, UART_SIG_CTS, UART_SIG_DCTS); SIGCHG(msr & MSR_DCD, sig, UART_SIG_DCD, UART_SIG_DDCD); @@ -461,9 +467,12 @@ static int ns8250_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) { struct uart_bas *bas; + int error; uint8_t efr, lcr; bas = &sc->sc_bas; + error = 0; + mtx_lock_spin(&sc->sc_hwmtx); switch (request) { case UART_IOCTL_BREAK: lcr = uart_getreg(bas, REG_LCR); @@ -505,9 +514,11 @@ ns8250_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) uart_barrier(bas); break; default: - return (EINVAL); + error = EINVAL; + break; } - return (0); + mtx_unlock_spin(&sc->sc_hwmtx); + return (error); } static int @@ -518,13 +529,16 @@ ns8250_bus_ipend(struct uart_softc *sc) uint8_t iir, lsr; bas = &sc->sc_bas; + mtx_lock_spin(&sc->sc_hwmtx); iir = uart_getreg(bas, REG_IIR); - if (iir & IIR_NOPEND) + if (iir & IIR_NOPEND) { + mtx_unlock_spin(&sc->sc_hwmtx); return (0); - + } ipend = 0; if (iir & IIR_RXRDY) { lsr = uart_getreg(bas, REG_LSR); + mtx_unlock_spin(&sc->sc_hwmtx); if (lsr & LSR_OE) ipend |= UART_IPEND_OVERRUN; if (lsr & LSR_BI) @@ -532,12 +546,12 @@ ns8250_bus_ipend(struct uart_softc *sc) if (lsr & LSR_RXRDY) ipend |= UART_IPEND_RXREADY; } else { + mtx_unlock_spin(&sc->sc_hwmtx); if (iir & IIR_TXRDY) ipend |= UART_IPEND_TXIDLE; else ipend |= UART_IPEND_SIGCHG; } - return ((sc->sc_leaving) ? 0 : ipend); } @@ -546,9 +560,13 @@ ns8250_bus_param(struct uart_softc *sc, int baudrate, int databits, int stopbits, int parity) { struct uart_bas *bas; + int error; bas = &sc->sc_bas; - return (ns8250_param(bas, baudrate, databits, stopbits, parity)); + mtx_lock_spin(&sc->sc_hwmtx); + error = ns8250_param(bas, baudrate, databits, stopbits, parity); + mtx_unlock_spin(&sc->sc_hwmtx); + return (error); } static int @@ -697,6 +715,7 @@ ns8250_bus_receive(struct uart_softc *sc) uint8_t lsr; bas = &sc->sc_bas; + mtx_lock_spin(&sc->sc_hwmtx); while (!uart_rx_full(sc)) { lsr = uart_getreg(bas, REG_LSR); if ((lsr & LSR_RXRDY) == 0) @@ -708,6 +727,7 @@ ns8250_bus_receive(struct uart_softc *sc) xc |= UART_STAT_PARERR; uart_rx_put(sc, xc); } + mtx_unlock_spin(&sc->sc_hwmtx); return (0); } @@ -731,6 +751,7 @@ ns8250_bus_setsig(struct uart_softc *sc, int sig) UART_SIG_DRTS); } } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); + mtx_lock_spin(&sc->sc_hwmtx); ns8250->mcr &= ~(MCR_DTR|MCR_RTS); if (new & UART_SIG_DTR) ns8250->mcr |= MCR_DTR; @@ -738,6 +759,7 @@ ns8250_bus_setsig(struct uart_softc *sc, int sig) ns8250->mcr |= MCR_RTS; uart_setreg(bas, REG_MCR, ns8250->mcr); uart_barrier(bas); + mtx_unlock_spin(&sc->sc_hwmtx); return (0); } @@ -749,6 +771,7 @@ ns8250_bus_transmit(struct uart_softc *sc) int i; bas = &sc->sc_bas; + mtx_lock_spin(&sc->sc_hwmtx); while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) ; uart_setreg(bas, REG_IER, ns8250->ier | IER_ETXRDY); @@ -758,5 +781,6 @@ ns8250_bus_transmit(struct uart_softc *sc) uart_barrier(bas); } sc->sc_txbusy = 1; + mtx_unlock_spin(&sc->sc_hwmtx); return (0); } |