diff options
Diffstat (limited to 'drivers/serial/serial_core.c')
-rw-r--r-- | drivers/serial/serial_core.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 851d7c29132b..cd8511298bcb 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -60,7 +60,7 @@ static struct lock_class_key port_lock_key; static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); -static void uart_wait_until_sent(struct tty_struct *tty, int timeout); +static void __uart_wait_until_sent(struct uart_port *port, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); /* @@ -1322,8 +1322,16 @@ static void uart_close(struct tty_struct *tty, struct file *filp) tty->closing = 1; spin_unlock_irqrestore(&port->lock, flags); - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, msecs_to_jiffies(port->closing_wait)); + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + /* + * hack: open-coded tty_wait_until_sent to avoid + * recursive tty_lock + */ + long timeout = msecs_to_jiffies(port->closing_wait); + if (wait_event_interruptible_timeout(tty->write_wait, + !tty_chars_in_buffer(tty), timeout) >= 0) + __uart_wait_until_sent(uport, timeout); + } /* * At this point, we stop accepting input. To do this, we @@ -1339,7 +1347,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * has completely drained; this is especially * important if there is a transmit FIFO! */ - uart_wait_until_sent(tty, uport->timeout); + __uart_wait_until_sent(uport, uport->timeout); } uart_shutdown(tty, state); @@ -1373,17 +1381,13 @@ done: mutex_unlock(&port->mutex); } -static void uart_wait_until_sent(struct tty_struct *tty, int timeout) +static void __uart_wait_until_sent(struct uart_port *port, int timeout) { - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; unsigned long char_time, expire; if (port->type == PORT_UNKNOWN || port->fifosize == 0) return; - tty_lock_nested(); /* already locked when coming from close */ - /* * 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 @@ -1429,6 +1433,15 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) break; } set_current_state(TASK_RUNNING); /* might not be needed */ +} + +static void uart_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + + tty_lock(); + __uart_wait_until_sent(port, timeout); tty_unlock(); } |