diff options
author | Rafael Gago <rafael.gago@gmail.com> | 2017-07-31 10:46:43 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-08-28 20:51:20 +0200 |
commit | 6e0a5de2136b26bd0b3501f2f362abfffeb47d1e (patch) | |
tree | 7ee3baed1bbcf78c70c378a3cb909c1583a6041a /drivers/tty | |
parent | a6845e1e1b781933ed7f54919f5ea4a108d1b9f2 (diff) | |
download | linux-6e0a5de2136b26bd0b3501f2f362abfffeb47d1e.tar.bz2 |
serial: 8250: Use hrtimers for rs485 delays
Previously the timers where based on the classic timers, giving a too
coarse resolution on systems with configs of less than 1000 HZ.
This patch changes the rs485 timers to hrtimers.
Signed-off-by: Rafael Gago Castano <rgc@hms.se>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/8250/8250_port.c | 63 |
1 files changed, 40 insertions, 23 deletions
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 25aae660cb9e..6b745e440b81 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -37,7 +37,7 @@ #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/pm_runtime.h> -#include <linux/timer.h> +#include <linux/ktime.h> #include <asm/io.h> #include <asm/irq.h> @@ -553,8 +553,8 @@ static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p) serial8250_out_MCR(p, mcr); } -static void serial8250_em485_handle_start_tx(unsigned long arg); -static void serial8250_em485_handle_stop_tx(unsigned long arg); +static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t); +static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t); void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) { @@ -609,12 +609,14 @@ int serial8250_em485_init(struct uart_8250_port *p) if (!p->em485) return -ENOMEM; - setup_timer(&p->em485->stop_tx_timer, - serial8250_em485_handle_stop_tx, (unsigned long)p); - setup_timer(&p->em485->start_tx_timer, - serial8250_em485_handle_start_tx, (unsigned long)p); + hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx; + p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx; + p->em485->port = p; p->em485->active_timer = NULL; - serial8250_em485_rts_after_send(p); return 0; @@ -639,8 +641,8 @@ void serial8250_em485_destroy(struct uart_8250_port *p) if (!p->em485) return; - del_timer(&p->em485->start_tx_timer); - del_timer(&p->em485->stop_tx_timer); + hrtimer_cancel(&p->em485->start_tx_timer); + hrtimer_cancel(&p->em485->stop_tx_timer); kfree(p->em485); p->em485 = NULL; @@ -1435,12 +1437,13 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p) serial_port_out(&p->port, UART_IER, p->ier); } } - -static void serial8250_em485_handle_stop_tx(unsigned long arg) +static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) { - struct uart_8250_port *p = (struct uart_8250_port *)arg; - struct uart_8250_em485 *em485 = p->em485; + struct uart_8250_em485 *em485; + struct uart_8250_port *p; unsigned long flags; + em485 = container_of(t, struct uart_8250_em485, stop_tx_timer); + p = em485->port; serial8250_rpm_get(p); spin_lock_irqsave(&p->port.lock, flags); @@ -1451,6 +1454,16 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg) } spin_unlock_irqrestore(&p->port.lock, flags); serial8250_rpm_put(p); + return HRTIMER_NORESTART; +} + +static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) +{ + long sec = msec / 1000; + long nsec = (msec % 1000) * 1000000; + ktime_t t = ktime_set(sec, nsec); + + hrtimer_start(hrt, t, HRTIMER_MODE_REL); } static void __stop_tx_rs485(struct uart_8250_port *p) @@ -1463,8 +1476,8 @@ static void __stop_tx_rs485(struct uart_8250_port *p) */ if (p->port.rs485.delay_rts_after_send > 0) { em485->active_timer = &em485->stop_tx_timer; - mod_timer(&em485->stop_tx_timer, jiffies + - p->port.rs485.delay_rts_after_send * HZ / 1000); + start_hrtimer_ms(&em485->stop_tx_timer, + p->port.rs485.delay_rts_after_send); } else { __do_stop_tx_rs485(p); } @@ -1494,8 +1507,8 @@ static inline void __stop_tx(struct uart_8250_port *p) if ((lsr & BOTH_EMPTY) != BOTH_EMPTY) return; - del_timer(&em485->start_tx_timer); em485->active_timer = NULL; + hrtimer_cancel(&em485->start_tx_timer); __stop_tx_rs485(p); } @@ -1558,8 +1571,9 @@ static inline void start_tx_rs485(struct uart_port *port) if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) serial8250_stop_rx(&up->port); - del_timer(&em485->stop_tx_timer); em485->active_timer = NULL; + if (hrtimer_is_queued(&em485->stop_tx_timer)) + hrtimer_cancel(&em485->stop_tx_timer); mcr = serial8250_in_MCR(up); if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) != @@ -1572,8 +1586,8 @@ static inline void start_tx_rs485(struct uart_port *port) if (up->port.rs485.delay_rts_before_send > 0) { em485->active_timer = &em485->start_tx_timer; - mod_timer(&em485->start_tx_timer, jiffies + - up->port.rs485.delay_rts_before_send * HZ / 1000); + start_hrtimer_ms(&em485->start_tx_timer, + up->port.rs485.delay_rts_before_send); return; } } @@ -1581,11 +1595,13 @@ static inline void start_tx_rs485(struct uart_port *port) __start_tx(port); } -static void serial8250_em485_handle_start_tx(unsigned long arg) +static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) { - struct uart_8250_port *p = (struct uart_8250_port *)arg; - struct uart_8250_em485 *em485 = p->em485; + struct uart_8250_em485 *em485; + struct uart_8250_port *p; unsigned long flags; + em485 = container_of(t, struct uart_8250_em485, start_tx_timer); + p = em485->port; spin_lock_irqsave(&p->port.lock, flags); if (em485 && @@ -1594,6 +1610,7 @@ static void serial8250_em485_handle_start_tx(unsigned long arg) em485->active_timer = NULL; } spin_unlock_irqrestore(&p->port.lock, flags); + return HRTIMER_NORESTART; } static void serial8250_start_tx(struct uart_port *port) |