Skip to content

Commit

Permalink
serial: core: Use usec resolution for timeout
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas Wunner <lukas@wunner.de>
[p.rosenberger: port to 5.10]
Signed-off-by: Philipp Rosenberger <p.rosenberger@kunbus.com>
  • Loading branch information
l1k authored and Philipp Rosenberger committed May 6, 2021
1 parent 60ace52 commit 7d26df5
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 15 deletions.
2 changes: 1 addition & 1 deletion drivers/tty/serial/mux.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ static int __init mux_probe(struct parisc_device *dev)
* the time spent in msleep_interruptable will be very
* long, causing the appearance of a console hang.
*/
port->timeout = HZ / 50;
port->timeout = 20 * MSEC_PER_SEC;
spin_lock_init(&port->lock);

status = uart_add_one_port(&mux_driver, port);
Expand Down
27 changes: 15 additions & 12 deletions drivers/tty/serial/serial_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/security.h>
#include <linux/math64.h>

#include <linux/irq.h>
#include <linux/uaccess.h>
Expand Down Expand Up @@ -366,7 +367,7 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag,
* Figure the timeout to send the above number of bits.
* Add .02 seconds of slop
*/
port->timeout = (HZ * bits) / baud + HZ/50;
port->timeout = div_u64(USEC_PER_SEC * bits, baud) + 20 * MSEC_PER_SEC;
}

EXPORT_SYMBOL(uart_update_timeout);
Expand Down Expand Up @@ -1596,7 +1597,8 @@ 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;
ktime_t expire;

port = uart_port_ref(state);
if (!port)
Expand All @@ -1607,18 +1609,19 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
return;
}

/* tty layer only uses jiffies resolution, but serial core uses usec */
timeout = jiffies_to_usecs(timeout);

/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
* interval should also be less than the timeout.
* send a single character. The check interval should also be
* less than the 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 = (port->timeout - 20 * MSEC_PER_SEC) / port->fifosize;
char_time = char_time / 5;
if (char_time == 0)
char_time = 1;
if (timeout && timeout < char_time)
char_time = timeout;

Expand All @@ -1634,21 +1637,21 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout == 0 || timeout > 2 * port->timeout)
timeout = 2 * port->timeout;

expire = jiffies + timeout;
expire = ktime_add_us(ktime_get(), timeout);

pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
port->line, jiffies, expire);
pr_debug("uart_wait_until_sent(%d), now=%llu, expire=%llu...\n",
port->line, ktime_to_us(ktime_get()), ktime_to_us(expire));

/*
* Check whether the transmitter is empty every 'char_time'.
* 'timeout' / 'expire' give us the maximum amount of time
* we wait.
*/
while (!port->ops->tx_empty(port)) {
msleep_interruptible(jiffies_to_msecs(char_time));
usleep_range(char_time, char_time + 50);
if (signal_pending(current))
break;
if (time_after(jiffies, expire))
if (ktime_after(ktime_get(), expire))
break;
}
uart_port_deref(port);
Expand Down
4 changes: 2 additions & 2 deletions include/linux/serial_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ 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 timeout; /* timespan to transmit full FIFO (usec) */
unsigned int type; /* port type */
const struct uart_ops *ops;
unsigned int custom_divisor;
Expand Down Expand Up @@ -335,7 +335,7 @@ unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud);
/* Base timer interval for polling */
static inline int uart_poll_timeout(struct uart_port *port)
{
int timeout = port->timeout;
int timeout = usecs_to_jiffies(port->timeout);

return timeout > 6 ? (timeout / 2 - 2) : 1;
}
Expand Down

0 comments on commit 7d26df5

Please sign in to comment.