serial: core: Document and assert lock requirements for irq helpers
[firefly-linux-kernel-4.4.55.git] / drivers / tty / serial / serial_core.c
index 0742f77ac4104e98b29e8d9ab9a50cda9054bf97..f764de32b658a6615131ff581d994cc0bf3d8772 100644 (file)
@@ -600,12 +600,11 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
        if (port->ops->send_xchar)
                port->ops->send_xchar(port, ch);
        else {
+               spin_lock_irqsave(&port->lock, flags);
                port->x_char = ch;
-               if (ch) {
-                       spin_lock_irqsave(&port->lock, flags);
+               if (ch)
                        port->ops->start_tx(port);
-                       spin_unlock_irqrestore(&port->lock, flags);
-               }
+               spin_unlock_irqrestore(&port->lock, flags);
        }
 }
 
@@ -648,12 +647,8 @@ static void uart_unthrottle(struct tty_struct *tty)
                mask &= ~port->flags;
        }
 
-       if (mask & UPF_SOFT_FLOW) {
-               if (port->x_char)
-                       port->x_char = 0;
-               else
-                       uart_send_xchar(tty, START_CHAR(tty));
-       }
+       if (mask & UPF_SOFT_FLOW)
+               uart_send_xchar(tty, START_CHAR(tty));
 
        if (mask & UPF_HARD_FLOW)
                uart_set_mctrl(port, TIOCM_RTS);
@@ -2748,17 +2743,24 @@ EXPORT_SYMBOL(uart_match_port);
  *     uart_handle_dcd_change - handle a change of carrier detect state
  *     @uport: uart_port structure for the open port
  *     @status: new carrier detect status, nonzero if active
+ *
+ *     Caller must hold uport->lock
  */
 void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
 {
        struct tty_port *port = &uport->state->port;
        struct tty_struct *tty = port->tty;
-       struct tty_ldisc *ld = tty ? tty_ldisc_ref(tty) : NULL;
+       struct tty_ldisc *ld;
 
-       if (ld) {
-               if (ld->ops->dcd_change)
-                       ld->ops->dcd_change(tty, status);
-               tty_ldisc_deref(ld);
+       lockdep_assert_held_once(&uport->lock);
+
+       if (tty) {
+               ld = tty_ldisc_ref(tty);
+               if (ld) {
+                       if (ld->ops->dcd_change)
+                               ld->ops->dcd_change(tty, status);
+                       tty_ldisc_deref(ld);
+               }
        }
 
        uport->icount.dcd++;
@@ -2776,12 +2778,16 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
  *     uart_handle_cts_change - handle a change of clear-to-send state
  *     @uport: uart_port structure for the open port
  *     @status: new clear to send status, nonzero if active
+ *
+ *     Caller must hold uport->lock
  */
 void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
 {
        struct tty_port *port = &uport->state->port;
        struct tty_struct *tty = port->tty;
 
+       lockdep_assert_held_once(&uport->lock);
+
        uport->icount.cts++;
 
        if (tty_port_cts_enabled(port)) {