Module Name: src Committed By: jmcneill Date: Tue Sep 11 10:05:31 UTC 2018
Modified Files: src/sys/arch/arm/samsung: exynos_uart.c Log Message: Make this driver MPSAFE To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/samsung/exynos_uart.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/samsung/exynos_uart.c diff -u src/sys/arch/arm/samsung/exynos_uart.c:1.1 src/sys/arch/arm/samsung/exynos_uart.c:1.2 --- src/sys/arch/arm/samsung/exynos_uart.c:1.1 Thu Jul 5 13:11:58 2018 +++ src/sys/arch/arm/samsung/exynos_uart.c Tue Sep 11 10:05:31 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_uart.c,v 1.1 2018/07/05 13:11:58 jmcneill Exp $ */ +/* $NetBSD: exynos_uart.c,v 1.2 2018/09/11 10:05:31 jmcneill Exp $ */ /*- * Copyright (c) 2013-2018 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: exynos_uart.c,v 1.1 2018/07/05 13:11:58 jmcneill Exp $"); +__KERNEL_RCSID(1, "$NetBSD: exynos_uart.c,v 1.2 2018/09/11 10:05:31 jmcneill Exp $"); #define cn_trap() \ do { \ @@ -77,6 +77,7 @@ struct exynos_uart_softc { device_t sc_dev; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; + kmutex_t sc_lock; u_int sc_freq; void *sc_ih; @@ -186,6 +187,7 @@ exynos_uart_attach(device_t parent, devi sc->sc_dev = self; sc->sc_bst = faa->faa_bst; + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH); sc->sc_console = is_console; if (is_console) { sc->sc_bsh = exynos_uart_cnsc.sc_bsh; @@ -259,13 +261,13 @@ static int exynos_uart_cngetc(dev_t dev) { struct exynos_uart_softc * const sc = &exynos_uart_cnsc; - uint32_t status; + uint32_t ufstat; int s, c; s = splserial(); - status = RD4(sc, SSCOM_UTRSTAT); - if ((status & UTRSTAT_RXREADY) == 0) { + ufstat = RD4(sc, SSCOM_UFSTAT); + if (__SHIFTOUT(ufstat, UFSTAT_RXCOUNT) == 0) { splx(s); return -1; } @@ -334,6 +336,8 @@ exynos_uart_open(dev_t dev, int flag, in return EBUSY; } + mutex_enter(&sc->sc_lock); + if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { tp->t_dev = dev; ttychars(tp); @@ -354,6 +358,8 @@ exynos_uart_open(dev_t dev, int flag, in /* Enable RX and error interrupts */ WR4(sc, SSCOM_UINTM, ~0u & ~(UINT_RXD|UINT_ERROR)); + mutex_exit(&sc->sc_lock); + return tp->t_linesw->l_open(dev, tp); } @@ -364,12 +370,16 @@ exynos_uart_close(dev_t dev, int flag, i device_lookup_private(&exuart_cd, minor(dev)); struct tty *tp = sc->sc_tty; + mutex_enter(&sc->sc_lock); + tp->t_linesw->l_close(tp, flag); ttyclose(tp); /* Disable interrupts */ WR4(sc, SSCOM_UINTM, ~0u); + mutex_exit(&sc->sc_lock); + return 0; } @@ -447,8 +457,6 @@ exynos_uart_start(struct tty *tp) } tp->t_state |= TS_BUSY; - splx(s); - for (brem = q_to_b(&tp->t_outq, sc->sc_buf, sizeof(sc->sc_buf)); brem > 0; brem--, p++) { @@ -459,7 +467,6 @@ exynos_uart_start(struct tty *tp) SSCOM_UTXH, *p); } - s = spltty(); tp->t_state &= ~TS_BUSY; if (ttypull(tp)) { tp->t_state |= TS_TIMEOUT; @@ -473,47 +480,51 @@ exynos_uart_param(struct tty *tp, struct { struct exynos_uart_softc *sc = tp->t_sc; - if (tp->t_ospeed == t->c_ospeed && - tp->t_cflag == t->c_cflag) - return 0; - - uint32_t ulcon = 0, ubrdiv; - switch (ISSET(t->c_cflag, CSIZE)) { - case CS5: - ulcon |= ULCON_LENGTH_5; - break; - case CS6: - ulcon |= ULCON_LENGTH_6; - break; - case CS7: - ulcon |= ULCON_LENGTH_7; - break; - case CS8: - ulcon |= ULCON_LENGTH_8; - break; - } - switch (ISSET(t->c_cflag, PARENB|PARODD)) { - case PARENB|PARODD: - ulcon |= ULCON_PARITY_ODD; - break; - case PARENB: - ulcon |= ULCON_PARITY_EVEN; - break; - default: - ulcon |= ULCON_PARITY_NONE; - break; - } - if (ISSET(t->c_cflag, CSTOPB)) - ulcon |= ULCON_STOP; - WR4(sc, SSCOM_ULCON, ulcon); + mutex_enter(&sc->sc_lock); + + if (tp->t_cflag != t->c_cflag) { + uint32_t ulcon = 0; + switch (ISSET(t->c_cflag, CSIZE)) { + case CS5: + ulcon |= ULCON_LENGTH_5; + break; + case CS6: + ulcon |= ULCON_LENGTH_6; + break; + case CS7: + ulcon |= ULCON_LENGTH_7; + break; + case CS8: + ulcon |= ULCON_LENGTH_8; + break; + } + switch (ISSET(t->c_cflag, PARENB|PARODD)) { + case PARENB|PARODD: + ulcon |= ULCON_PARITY_ODD; + break; + case PARENB: + ulcon |= ULCON_PARITY_EVEN; + break; + default: + ulcon |= ULCON_PARITY_NONE; + break; + } + if (ISSET(t->c_cflag, CSTOPB)) + ulcon |= ULCON_STOP; + WR4(sc, SSCOM_ULCON, ulcon); + } - ubrdiv = (sc->sc_freq / 16) / t->c_ospeed - 1; - WR4(sc, SSCOM_UBRDIV, ubrdiv); + if (tp->t_ospeed != t->c_ospeed) { + const uint32_t ubrdiv = (sc->sc_freq / 16) / t->c_ospeed - 1; + WR4(sc, SSCOM_UBRDIV, ubrdiv); + } tp->t_ispeed = t->c_ispeed; tp->t_ospeed = t->c_ospeed; tp->t_cflag = t->c_cflag; + mutex_exit(&sc->sc_lock); + return 0; } @@ -524,6 +535,8 @@ exynos_uart_intr(void *priv) struct tty *tp = sc->sc_tty; uint32_t uintp, uerstat, ufstat, c; + mutex_enter(&sc->sc_lock); + uintp = RD4(sc, SSCOM_UINTP); for (;;) { @@ -551,6 +564,8 @@ exynos_uart_intr(void *priv) WR4(sc, SSCOM_UINTP, uintp); + mutex_exit(&sc->sc_lock); + return 1; }