Commit f9008285 authored by Ilpo Järvinen's avatar Ilpo Järvinen Committed by Greg Kroah-Hartman
Browse files

serial: Drop timeout from uart_port



Since commit 31f6bd7f ("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: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20220613113905.22962-1-ilpo.jarvinen@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ab24a01b
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -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

+0 −6
Original line number Diff line number Diff line
@@ -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);
+10 −15
Original line number Diff line number Diff line
@@ -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;
+14 −2
Original line number Diff line number Diff line
@@ -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;
}