]> git.baikalelectronics.ru Git - kernel.git/commitdiff
serial: Drop timeout from uart_port
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Mon, 13 Jun 2022 11:39:05 +0000 (14:39 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Jun 2022 12:34:45 +0000 (14:34 +0200)
Since commit cf5023c57065 ("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>
Documentation/driver-api/serial/driver.rst
drivers/tty/serial/mux.c
drivers/tty/serial/serial_core.c
include/linux/serial_core.h

index 7ef83fd3917b26a38091b1cb29b46ff18d124fdc..1e7ab4142d4910b540054d49410e6e803d4706ab 100644 (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
 
index 643dfbcc43f992fb064833f5f9451bde2fd47443..0ba0f4d9459d5d5f2eb6810159fb8ad6b5b31c45 100644 (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);
index 1368b0ef7d7fa2cc9196b41bc370485f68b4d1b1..75ece750bedcb7f4c1ca116836adc462db027073 100644 (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;
index 8032ffa741edf130d08857f5cd476c4df79d870f..faaf2372c60dbc2e1b8d32bc6a701d10beedce53 100644 (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;
 }