summaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/8250/8250_port.c
diff options
context:
space:
mode:
authorLukas Wunner <lukas@wunner.de>2020-02-28 14:31:08 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-03-07 09:52:02 +0100
commit7f9803072ff636fc22ad941ff059e020e9d77ed4 (patch)
tree4259aa777c4cc5c8645e95bc888184fa1280e7aa /drivers/tty/serial/8250/8250_port.c
parentf93bf75891147602d55b90937628157cc13dbdb8 (diff)
downloadlinux-stable-7f9803072ff636fc22ad941ff059e020e9d77ed4.tar.gz
linux-stable-7f9803072ff636fc22ad941ff059e020e9d77ed4.tar.bz2
linux-stable-7f9803072ff636fc22ad941ff059e020e9d77ed4.zip
serial: 8250: Support console on software emulated rs485 ports
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> Link: https://lore.kernel.org/r/65edffce4670a19e598015c03cbe46f1ffd93e43.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/8250/8250_port.c')
-rw-r--r--drivers/tty/serial/8250/8250_port.c13
1 files changed, 13 insertions, 0 deletions
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