]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/serial/serial_core.c
serial-core: skip call set_termios/console_start when no_console_suspend
[mirror_ubuntu-artful-kernel.git] / drivers / serial / serial_core.c
index a55751a12c380248e3c2a40b9d51d33e61ea3de4..ff21200f94f4a1632721a7f069fbb4996a15087c 100644 (file)
@@ -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);
 
 /*
@@ -1274,7 +1274,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        struct uart_port *uport;
        unsigned long flags;
 
-       BUG_ON(!kernel_locked());
+       BUG_ON(!tty_locked());
 
        if (!state)
                return;
@@ -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;
 
-       lock_kernel();
-
        /*
         * 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,7 +1433,16 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
                        break;
        }
        set_current_state(TASK_RUNNING); /* might not be needed */
-       unlock_kernel();
+}
+
+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();
 }
 
 /*
@@ -1444,7 +1457,7 @@ static void uart_hangup(struct tty_struct *tty)
        struct tty_port *port = &state->port;
        unsigned long flags;
 
-       BUG_ON(!kernel_locked());
+       BUG_ON(!tty_locked());
        pr_debug("uart_hangup(%d)\n", state->uart_port->line);
 
        mutex_lock(&port->mutex);
@@ -1520,8 +1533,16 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
        struct uart_state *state = container_of(port, struct uart_state, port);
        struct uart_port *uport = state->uart_port;
 
-       if (onoff)
+       if (onoff) {
                uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+
+               /*
+                * If this is the first open to succeed,
+                * adjust things to suit.
+                */
+               if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags))
+                       uart_update_termios(port->tty, state);
+       }
        else
                uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 }
@@ -1570,7 +1591,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        struct tty_port *port;
        int retval, line = tty->index;
 
-       BUG_ON(!kernel_locked());
+       BUG_ON(!tty_locked());
        pr_debug("uart_open(%d) called\n", line);
 
        /*
@@ -1636,15 +1657,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        if (retval == 0)
                retval = tty_port_block_til_ready(port, tty, filp);
 
-       /*
-        * If this is the first open to succeed, adjust things to suit.
-        */
-       if (retval == 0 && !(port->flags & ASYNC_NORMAL_ACTIVE)) {
-               set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
-
-               uart_update_termios(tty, state);
-       }
-
 fail:
        return retval;
 }
@@ -2053,7 +2065,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
        /*
         * Re-enable the console device after suspending.
         */
-       if (uart_console(uport)) {
+       if (console_suspend_enabled && uart_console(uport)) {
                uart_change_pm(state, 0);
                uport->ops->set_termios(uport, &termios, NULL);
                console_start(uport->cons);