serial: Drop timeout from uart_port

Since commit 31f6bd7fad ("serial: Store character timing information
to uart_port"), per frame timing information is available on uart_port.
Uart port's timeout can be derived from frame_time by multiplying with
fifosize.

Most callers of uart_poll_timeout are not made under port's lock. To be
on the safe side, make sure frame_time is only accessed once. As
fifo_size is effectively a constant, it shouldn't cause any issues.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20220613113905.22962-1-ilpo.jarvinen@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Ilpo Järvinen 2022-06-13 14:39:05 +03:00 committed by Greg Kroah-Hartman
parent ab24a01b27
commit f9008285bb
4 changed files with 27 additions and 25 deletions

View file

@ -422,8 +422,9 @@ Other functions
---------------
uart_update_timeout(port,cflag,baud)
Update the FIFO drain timeout, port->timeout, according to the
number of bits, parity, stop bits and baud rate.
Update the frame timing information according to the number of bits,
parity, stop bits and baud rate. The FIFO drain timeout is derived
from the frame timing information.
Locking: caller is expected to take port->lock

View file

@ -481,12 +481,6 @@ static int __init mux_probe(struct parisc_device *dev)
port->line = port_cnt;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MUX_CONSOLE);
/* The port->timeout needs to match what is present in
* uart_wait_until_sent in serial_core.c. Otherwise
* the time spent in msleep_interruptable will be very
* long, causing the appearance of a console hang.
*/
port->timeout = HZ / 50;
spin_lock_init(&port->lock);
status = uart_add_one_port(&mux_driver, port);

View file

@ -327,13 +327,14 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
}
/**
* uart_update_timeout - update per-port FIFO timeout.
* uart_update_timeout - update per-port frame timing information.
* @port: uart_port structure describing the port
* @cflag: termios cflag value
* @baud: speed of the port
*
* Set the port FIFO timeout value. The @cflag value should
* reflect the actual hardware settings.
* Set the port frame timing information from which the FIFO timeout
* value is derived. The @cflag value should reflect the actual hardware
* settings.
*/
void
uart_update_timeout(struct uart_port *port, unsigned int cflag,
@ -343,13 +344,6 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag,
u64 frame_time;
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);
@ -1698,7 +1692,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
unsigned long char_time, expire;
unsigned long char_time, expire, fifo_timeout;
port = uart_port_ref(state);
if (!port)
@ -1728,12 +1722,13 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
* 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
* takes longer than FIFO timeout, this is probably due to a
* UART bug of some kind. So, we clamp the timeout parameter at
* 2*port->timeout.
* 2 * FIFO timeout.
*/
if (timeout == 0 || timeout > 2 * port->timeout)
timeout = 2 * port->timeout;
fifo_timeout = uart_fifo_timeout(port);
if (timeout == 0 || timeout > 2 * fifo_timeout)
timeout = 2 * fifo_timeout;
}
expire = jiffies + timeout;

View file

@ -232,7 +232,6 @@ struct uart_port {
int hw_stopped; /* sw-assisted CTS flow state */
unsigned int mctrl; /* current modem ctrl settings */
unsigned int timeout; /* character-based timeout */
unsigned int frame_time; /* frame timing in ns */
unsigned int type; /* port type */
const struct uart_ops *ops;
@ -335,10 +334,23 @@ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios
unsigned int max);
unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud);
/*
* Calculates FIFO drain time.
*/
static inline unsigned long uart_fifo_timeout(struct uart_port *port)
{
u64 fifo_timeout = (u64)READ_ONCE(port->frame_time) * port->fifosize;
/* Add .02 seconds of slop */
fifo_timeout += 20 * NSEC_PER_MSEC;
return max(nsecs_to_jiffies(fifo_timeout), 1UL);
}
/* Base timer interval for polling */
static inline int uart_poll_timeout(struct uart_port *port)
{
int timeout = port->timeout;
int timeout = uart_fifo_timeout(port);
return timeout > 6 ? (timeout / 2 - 2) : 1;
}