aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arm/nvidia/tegra_uart.c3
-rw-r--r--sys/dev/uart/uart_dev_ns8250.c14
-rw-r--r--sys/dev/uart/uart_dev_ns8250.h1
-rw-r--r--sys/dev/uart/uart_dev_snps.c1
-rw-r--r--sys/dev/uart/uart_dev_ti8250.c1
-rw-r--r--sys/dev/uart/uart_if.m21
-rw-r--r--sys/dev/uart/uart_tty.c14
-rw-r--r--sys/mips/cavium/uart_dev_oct16550.c17
-rw-r--r--sys/mips/ingenic/jz4780_uart.c3
9 files changed, 67 insertions, 8 deletions
diff --git a/sys/arm/nvidia/tegra_uart.c b/sys/arm/nvidia/tegra_uart.c
index 4332976ea187..fe2701c02cb4 100644
--- a/sys/arm/nvidia/tegra_uart.c
+++ b/sys/arm/nvidia/tegra_uart.c
@@ -136,6 +136,7 @@ static kobj_method_t tegra_methods[] = {
KOBJMETHOD(uart_receive, ns8250_bus_receive),
KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_txbusy, ns8250_bus_txbusy),
KOBJMETHOD(uart_grab, tegra_uart_grab),
KOBJMETHOD(uart_ungrab, tegra_uart_ungrab),
KOBJMETHOD_END
@@ -237,7 +238,7 @@ static device_method_t tegra_uart_bus_methods[] = {
DEVMETHOD(device_probe, tegra_uart_probe),
DEVMETHOD(device_attach, uart_bus_attach),
DEVMETHOD(device_detach, tegra_uart_detach),
- { 0, 0 }
+ DEVMETHOD_END
};
static driver_t tegra_uart_driver = {
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index ec9aea18379a..879fe6e04a70 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -392,9 +392,10 @@ static kobj_method_t ns8250_methods[] = {
KOBJMETHOD(uart_receive, ns8250_bus_receive),
KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_txbusy, ns8250_bus_txbusy),
KOBJMETHOD(uart_grab, ns8250_bus_grab),
KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab),
- { 0, 0 }
+ KOBJMETHOD_END
};
struct uart_class uart_ns8250_class = {
@@ -1048,6 +1049,17 @@ ns8250_bus_transmit(struct uart_softc *sc)
return (0);
}
+bool
+ns8250_bus_txbusy(struct uart_softc *sc)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+
+ if ((uart_getreg(bas, REG_LSR) & (LSR_TEMT | LSR_THRE)) !=
+ (LSR_TEMT | LSR_THRE))
+ return (true);
+ return (false);
+}
+
void
ns8250_bus_grab(struct uart_softc *sc)
{
diff --git a/sys/dev/uart/uart_dev_ns8250.h b/sys/dev/uart/uart_dev_ns8250.h
index 357f4e7f80df..324ff72f6e5d 100644
--- a/sys/dev/uart/uart_dev_ns8250.h
+++ b/sys/dev/uart/uart_dev_ns8250.h
@@ -57,6 +57,7 @@ int ns8250_bus_receive(struct uart_softc *);
int ns8250_bus_setsig(struct uart_softc *, int);
int ns8250_bus_transmit(struct uart_softc *);
void ns8250_bus_grab(struct uart_softc *);
+bool ns8250_bus_txbusy(struct uart_softc *);
void ns8250_bus_ungrab(struct uart_softc *);
#endif /* _DEV_UART_DEV_NS8250_H_ */
diff --git a/sys/dev/uart/uart_dev_snps.c b/sys/dev/uart/uart_dev_snps.c
index 1e3192fe3ab2..7149a13b7004 100644
--- a/sys/dev/uart/uart_dev_snps.c
+++ b/sys/dev/uart/uart_dev_snps.c
@@ -102,6 +102,7 @@ static kobj_method_t snps_methods[] = {
KOBJMETHOD(uart_receive, ns8250_bus_receive),
KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_txbusy, ns8250_bus_txbusy),
KOBJMETHOD(uart_grab, ns8250_bus_grab),
KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab),
KOBJMETHOD_END
diff --git a/sys/dev/uart/uart_dev_ti8250.c b/sys/dev/uart/uart_dev_ti8250.c
index 5a5fc97fd04e..96639f365a9d 100644
--- a/sys/dev/uart/uart_dev_ti8250.c
+++ b/sys/dev/uart/uart_dev_ti8250.c
@@ -106,6 +106,7 @@ static kobj_method_t ti8250_methods[] = {
KOBJMETHOD(uart_receive, ns8250_bus_receive),
KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_txbusy, ns8250_bus_txbusy),
KOBJMETHOD_END
};
diff --git a/sys/dev/uart/uart_if.m b/sys/dev/uart/uart_if.m
index 516e8b0811df..7efe63a10248 100644
--- a/sys/dev/uart/uart_if.m
+++ b/sys/dev/uart/uart_if.m
@@ -38,6 +38,17 @@
INTERFACE uart;
+CODE {
+ static uart_txbusy_t uart_default_txbusy;
+
+ static bool
+ uart_default_txbusy(struct uart_softc *this __unused)
+ {
+
+ return (false);
+ }
+};
+
# attach() - attach hardware.
# This method is called when the device is being attached. All resources
# have been allocated. The transmit and receive buffers exist, but no
@@ -141,6 +152,16 @@ METHOD int transmit {
struct uart_softc *this;
};
+# txbusy() - report if Tx is still busy.
+# This method is called by the tty glue for reporting upward that output is
+# still being drained despite sc_txbusy unset. Non-DEFAULT implementations
+# allow for extra checks, i. e. beyond what can be determined in ipend(),
+# that the Tx path actually is idle. For example, whether the last character
+# has left the transmit shift register in addition to the FIFO being empty.
+METHOD bool txbusy {
+ struct uart_softc *this;
+} DEFAULT uart_default_txbusy;
+
# grab() - Up call from the console to the upper layers of the driver when
# the kernel asks to grab the console. This is valid only for console
# drivers. This method is responsible for transitioning the hardware
diff --git a/sys/dev/uart/uart_tty.c b/sys/dev/uart/uart_tty.c
index 0c69fa25f6cf..736c756322a4 100644
--- a/sys/dev/uart/uart_tty.c
+++ b/sys/dev/uart/uart_tty.c
@@ -389,9 +389,19 @@ uart_tty_busy(struct tty *tp)
sc = tty_softc(tp);
if (sc == NULL || sc->sc_leaving)
- return (FALSE);
+ return (false);
- return (sc->sc_txbusy);
+ /*
+ * The tty locking is sufficient here; we may lose the race against
+ * uart_bus_ihand()/uart_intr() clearing sc_txbusy underneath us, in
+ * which case we will incorrectly but non-fatally report a busy Tx
+ * path upward. However, tty locking ensures that no additional output
+ * is enqueued before UART_TXBUSY() returns, which means that there
+ * are no Tx interrupts to be lost.
+ */
+ if (sc->sc_txbusy)
+ return (true);
+ return (UART_TXBUSY(sc));
}
static struct ttydevsw uart_tty_class = {
diff --git a/sys/mips/cavium/uart_dev_oct16550.c b/sys/mips/cavium/uart_dev_oct16550.c
index 2a932da73dcb..bb9776352819 100644
--- a/sys/mips/cavium/uart_dev_oct16550.c
+++ b/sys/mips/cavium/uart_dev_oct16550.c
@@ -51,8 +51,6 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
*/
#include <sys/cdefs.h>
@@ -397,6 +395,7 @@ static int oct16550_bus_probe(struct uart_softc *);
static int oct16550_bus_receive(struct uart_softc *);
static int oct16550_bus_setsig(struct uart_softc *, int);
static int oct16550_bus_transmit(struct uart_softc *);
+static bool oct16550_bus_txbusy(struct uart_softc *);
static void oct16550_bus_grab(struct uart_softc *);
static void oct16550_bus_ungrab(struct uart_softc *);
@@ -412,9 +411,10 @@ static kobj_method_t oct16550_methods[] = {
KOBJMETHOD(uart_receive, oct16550_bus_receive),
KOBJMETHOD(uart_setsig, oct16550_bus_setsig),
KOBJMETHOD(uart_transmit, oct16550_bus_transmit),
+ KOBJMETHOD(uart_txbusy, oct16550_bus_txbusy),
KOBJMETHOD(uart_grab, oct16550_bus_grab),
KOBJMETHOD(uart_ungrab, oct16550_bus_ungrab),
- { 0, 0 }
+ KOBJMETHOD_END
};
struct uart_class uart_oct16550_class = {
@@ -812,6 +812,17 @@ oct16550_bus_transmit (struct uart_softc *sc)
return (0);
}
+static bool
+oct16550_bus_txbusy(struct uart_softc *sc)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+
+ if ((uart_getreg(bas, REG_LSR) & (LSR_TEMT | LSR_THRE)) !=
+ (LSR_TEMT | LSR_THRE))
+ return (true);
+ return (false);
+}
+
static void
oct16550_bus_grab(struct uart_softc *sc)
{
diff --git a/sys/mips/ingenic/jz4780_uart.c b/sys/mips/ingenic/jz4780_uart.c
index 897ae73ec210..d46d2566c178 100644
--- a/sys/mips/ingenic/jz4780_uart.c
+++ b/sys/mips/ingenic/jz4780_uart.c
@@ -93,6 +93,7 @@ static kobj_method_t jz4780_uart_methods[] = {
KOBJMETHOD(uart_receive, ns8250_bus_receive),
KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_txbusy, ns8250_bus_txbusy),
KOBJMETHOD(uart_grab, ns8250_bus_grab),
KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab),
KOBJMETHOD_END
@@ -205,7 +206,7 @@ static device_method_t jz4780_uart_bus_methods[] = {
DEVMETHOD(device_probe, jz4780_uart_probe),
DEVMETHOD(device_attach, uart_bus_attach),
DEVMETHOD(device_detach, jz4780_uart_detach),
- { 0, 0 }
+ DEVMETHOD_END
};
static driver_t jz4780_uart_driver = {