diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-06-03 21:08:40 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-06-03 21:08:40 +0300 |
commit | 932c2989b59008e530ffcc7c7e6ef507a28b28ca (patch) | |
tree | 5d51787f2ace2b9a2fd2393662818fd14aa219be /drivers/tty/serial/serial_core.c | |
parent | 4ad680f083ec360e0991c453e18a38ed9ae500d7 (diff) | |
parent | 25e02ba60f0fbe65ba07553b5b2b8867726273c4 (diff) | |
download | linux-932c2989b59008e530ffcc7c7e6ef507a28b28ca.tar.xz |
Merge tag 'tty-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty and serial driver updates from Greg KH:
"Here is the big set of tty and serial driver updates for 5.19-rc1.
Lots of tiny cleanups in here, the major stuff is:
- termbit cleanups and unification by Ilpo. A much needed change that
goes a long way to making things simpler for all of the different
arches
- tty documentation cleanups and movements to their own place in the
documentation tree
- old tty driver cleanups and fixes from Jiri to bring some existing
drivers into the modern world
- RS485 cleanups and unifications to make it easier for individual
drivers to support this mode instead of having to duplicate logic
in each driver
- Lots of 8250 driver updates and additions
- new device id additions
- n_gsm continued fixes and cleanups
- other minor serial driver updates and cleanups
All of these have been in linux-next for weeks with no reported issues"
* tag 'tty-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (166 commits)
tty: Rework receive flow control char logic
pcmcia: synclink_cs: Don't allow CS5-6
serial: stm32-usart: Correct CSIZE, bits, and parity
serial: st-asc: Sanitize CSIZE and correct PARENB for CS7
serial: sifive: Sanitize CSIZE and c_iflag
serial: sh-sci: Don't allow CS5-6
serial: txx9: Don't allow CS5-6
serial: rda-uart: Don't allow CS5-6
serial: digicolor-usart: Don't allow CS5-6
serial: uartlite: Fix BRKINT clearing
serial: cpm_uart: Fix build error without CONFIG_SERIAL_CPM_CONSOLE
serial: core: Do stop_rx in suspend path for console if console_suspend is disabled
tty: serial: qcom-geni-serial: Remove uart frequency table. Instead, find suitable frequency with call to clk_round_rate.
dt-bindings: serial: renesas,em-uart: Add RZ/V2M clock to access the registers
serial: 8250_fintek: Check SER_RS485_RTS_* only with RS485
Revert "serial: 8250_mtk: Make sure to select the right FEATURE_SEL"
serial: msm_serial: disable interrupts in __msm_console_write()
serial: meson: acquire port->lock in startup()
serial: 8250_dw: Use dev_err_probe()
serial: 8250_dw: Use devm_add_action_or_reset()
...
Diffstat (limited to 'drivers/tty/serial/serial_core.c')
-rw-r--r-- | drivers/tty/serial/serial_core.c | 89 |
1 files changed, 69 insertions, 20 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 6a8963caf954..9a85b41caa0a 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -24,6 +24,7 @@ #include <linux/sysrq.h> #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/math64.h> #include <linux/security.h> #include <linux/irq.h> @@ -42,6 +43,11 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) +/* + * Max time with active RTS before/after data is sent. + */ +#define RS485_MAX_RTS_DELAY 100 /* msecs */ + static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); @@ -333,15 +339,18 @@ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud) { - unsigned int size; + unsigned int size = tty_get_frame_size(cflag); + u64 frame_time; - size = tty_get_frame_size(cflag) * port->fifosize; + frame_time = (u64)size * NSEC_PER_SEC; + size *= port->fifosize; /* * Figure the timeout to send the above number of bits. * Add .02 seconds of slop */ port->timeout = (HZ * size) / baud + HZ/50; + port->frame_time = DIV64_U64_ROUND_UP(frame_time, baud); } EXPORT_SYMBOL(uart_update_timeout); @@ -1296,8 +1305,36 @@ static int uart_set_rs485_config(struct uart_port *port, if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) return -EFAULT; + /* pick sane settings if the user hasn't */ + if (!(rs485.flags & SER_RS485_RTS_ON_SEND) == + !(rs485.flags & SER_RS485_RTS_AFTER_SEND)) { + dev_warn_ratelimited(port->dev, + "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", + port->name, port->line); + rs485.flags |= SER_RS485_RTS_ON_SEND; + rs485.flags &= ~SER_RS485_RTS_AFTER_SEND; + } + + if (rs485.delay_rts_before_send > RS485_MAX_RTS_DELAY) { + rs485.delay_rts_before_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay before sending clamped to %u ms\n", + port->name, port->line, rs485.delay_rts_before_send); + } + + if (rs485.delay_rts_after_send > RS485_MAX_RTS_DELAY) { + rs485.delay_rts_after_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay after sending clamped to %u ms\n", + port->name, port->line, rs485.delay_rts_after_send); + } + /* Return clean padding area to userspace */ + memset(rs485.padding, 0, sizeof(rs485.padding)); + spin_lock_irqsave(&port->lock, flags); ret = port->rs485_config(port, &rs485); + if (!ret) + port->rs485 = rs485; spin_unlock_irqrestore(&port->lock, flags); if (ret) return ret; @@ -1610,24 +1647,24 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ - char_time = (port->timeout - HZ/50) / port->fifosize; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; + char_time = max(nsecs_to_jiffies(port->frame_time / 5), 1UL); + if (timeout && timeout < char_time) char_time = timeout; - /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than port->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*port->timeout. - */ - if (timeout == 0 || timeout > 2 * port->timeout) - timeout = 2 * port->timeout; + if (!uart_cts_enabled(port)) { + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than port->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*port->timeout. + */ + if (timeout == 0 || timeout > 2 * port->timeout) + timeout = 2 * port->timeout; + } expire = jiffies + timeout; @@ -1643,7 +1680,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; - if (time_after(jiffies, expire)) + if (timeout && time_after(jiffies, expire)) break; } uart_port_deref(port); @@ -2174,15 +2211,23 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) } put_device(tty_dev); - /* Nothing to do if the console is not suspending */ - if (!console_suspend_enabled && uart_console(uport)) + /* + * Nothing to do if the console is not suspending + * except stop_rx to prevent any asynchronous data + * over RX line. Re-start_rx, when required, is + * done by set_termios in resume sequence + */ + if (!console_suspend_enabled && uart_console(uport)) { + uport->ops->stop_rx(uport); goto unlock; + } uport->suspended = 1; if (tty_port_initialized(port)) { const struct uart_ops *ops = uport->ops; int tries; + unsigned int mctrl; tty_port_set_suspended(port, 1); tty_port_set_initialized(port, 0); @@ -2190,6 +2235,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) spin_lock_irq(&uport->lock); ops->stop_tx(uport); ops->set_mctrl(uport, 0); + /* save mctrl so it can be restored on resume */ + mctrl = uport->mctrl; + uport->mctrl = 0; ops->stop_rx(uport); spin_unlock_irq(&uport->lock); @@ -2203,6 +2251,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) uport->name); ops->shutdown(uport); + uport->mctrl = mctrl; } /* |