diff mbox series

[8/8] serial: 8250: Support console on software emulated rs485 ports

Message ID 65edffce4670a19e598015c03cbe46f1ffd93e43.1582895077.git.lukas@wunner.de
State New
Headers show
Series rs485 support for Raspberry Pi aux uart | expand

Commit Message

Lukas Wunner Feb. 28, 2020, 1:31 p.m. UTC
Commit e490c9144cfa ("tty: Add software emulated RS485 support for 8250")
introduced support to use RTS as an rs485 Transmit Enable signal if data
is transmitted through the tty layer.

Console messages bypass the tty layer and instead are emitted via
serial8250_console_write().  Amend that function to drive RTS as well,
allowing for a console on rs485 ports.

Note that serial8250_console_write() may be called concurrently to the
tty layer accessing the port.  The two protect their accesses with the
port lock, but serial8250_console_write() may find RTS still being
asserted by the tty layer, in which case it shouldn't be deasserted
after the console message has been printed.  Recognize such situations
by checking the em485->tx_stopped flag.

If a delay_rts_before_send or delay_rts_after_send has been specified,
serial8250_console_write() busy-waits for its duration.  Optimizations
for those wait times are conceivable:  E.g. if RTS is already asserted,
we could check whether em485->start_tx_timer is active and wait only
for the remaining expire time.  But this would require calling into
the hrtimer infrastructure, which involves acquiring locks and
potentially reprogramming timer hardware.  Such operations seem too
risky in the context of console printout, which needs to work even when
the kernel has crashed and emits a BUG splat.  So I've gone with a
simplistic solution which just always waits for the full delay.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matwey V. Kornilov <matwey@sai.msu.ru>
---
 drivers/tty/serial/8250/8250_port.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
diff mbox series

Patch

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 8e8cca690bf9..0879bb8855cf 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -3204,6 +3204,7 @@  static void serial8250_console_restore(struct uart_8250_port *up)
 void serial8250_console_write(struct uart_8250_port *up, const char *s,
 			      unsigned int count)
 {
+	struct uart_8250_em485 *em485 = up->em485;
 	struct uart_port *port = &up->port;
 	unsigned long flags;
 	unsigned int ier;
@@ -3234,6 +3235,12 @@  void serial8250_console_write(struct uart_8250_port *up, const char *s,
 		up->canary = 0;
 	}
 
+	if (em485) {
+		if (em485->tx_stopped)
+			up->rs485_start_tx(up);
+		mdelay(port->rs485.delay_rts_before_send);
+	}
+
 	uart_console_write(port, s, count, serial8250_console_putchar);
 
 	/*
@@ -3243,6 +3250,12 @@  void serial8250_console_write(struct uart_8250_port *up, const char *s,
 	wait_for_xmitr(up, BOTH_EMPTY);
 	serial_port_out(port, UART_IER, ier);
 
+	if (em485) {
+		mdelay(port->rs485.delay_rts_before_send);
+		if (em485->tx_stopped)
+			up->rs485_stop_tx(up);
+	}
+
 	/*
 	 *	The receive handling will happen properly because the
 	 *	receive ready bit will still be set; it is not cleared