]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge tag 'tty-4.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 26 Mar 2017 18:03:42 +0000 (11:03 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 26 Mar 2017 18:03:42 +0000 (11:03 -0700)
Pull tty/serial driver fixes from Greg KH:
 "Here are some tty and serial driver fixes for 4.11-rc4.

  One of these fix a long-standing issue in the ldisc code that was
  found by Dmitry Vyukov with his great fuzzing work. The other fixes
  resolve other reported issues, and there is one revert of a patch in
  4.11-rc1 that wasn't correct.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'tty-4.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: fix data race in tty_ldisc_ref_wait()
  tty: don't panic on OOM in tty_set_ldisc()
  Revert "tty: serial: pl011: add ttyAMA for matching pl011 console"
  tty: acpi/spcr: QDF2400 E44 checks for wrong OEM revision
  serial: 8250_dw: Fix breakage when HAVE_CLK=n
  serial: 8250_dw: Honor clk_round_rate errors in dw8250_set_termios

drivers/acpi/spcr.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/amba-pl011.c
drivers/tty/tty_ldisc.c

index 01c94669a2b0ad91976daf9f3c7ef3338b48e965..3afa8c1fa12702c251d5d3654e2026ba0ebfcd62 100644 (file)
@@ -30,7 +30,7 @@ static bool qdf2400_erratum_44_present(struct acpi_table_header *h)
                return true;
 
        if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) &&
-                       h->oem_revision == 0)
+                       h->oem_revision == 1)
                return true;
 
        return false;
index 6ee55a2d47bb429f73cf9d2b2711b109f6746a3d..e65808c482f1847d09d819a24defb0e5cf6508b5 100644 (file)
@@ -257,7 +257,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
 {
        unsigned int baud = tty_termios_baud_rate(termios);
        struct dw8250_data *d = p->private_data;
-       unsigned int rate;
+       long rate;
        int ret;
 
        if (IS_ERR(d->clk) || !old)
@@ -265,7 +265,12 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
 
        clk_disable_unprepare(d->clk);
        rate = clk_round_rate(d->clk, baud * 16);
-       ret = clk_set_rate(d->clk, rate);
+       if (rate < 0)
+               ret = rate;
+       else if (rate == 0)
+               ret = -ENOENT;
+       else
+               ret = clk_set_rate(d->clk, rate);
        clk_prepare_enable(d->clk);
 
        if (!ret)
index 8789ea423ccfd1054d9d5433538d0a8e466525dd..56f92d7348bf45b898b8b01a4aec813069958ec9 100644 (file)
@@ -2373,7 +2373,7 @@ static int __init pl011_console_match(struct console *co, char *name, int idx,
        if (strcmp(name, "qdf2400_e44") == 0) {
                pr_info_once("UART: Working around QDF2400 SoC erratum 44");
                qdf2400_e44_present = true;
-       } else if (strcmp(name, "pl011") != 0 || strcmp(name, "ttyAMA") != 0) {
+       } else if (strcmp(name, "pl011") != 0) {
                return -ENODEV;
        }
 
index 68947f6de5ad6339adea804182597229c3eb1d38..b0500a0a87b86161b8cf8befcee9753ff6cda74d 100644 (file)
@@ -271,10 +271,13 @@ const struct file_operations tty_ldiscs_proc_fops = {
 
 struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
 {
+       struct tty_ldisc *ld;
+
        ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
-       if (!tty->ldisc)
+       ld = tty->ldisc;
+       if (!ld)
                ldsem_up_read(&tty->ldisc_sem);
-       return tty->ldisc;
+       return ld;
 }
 EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
 
@@ -488,41 +491,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
        tty_ldisc_debug(tty, "%p: closed\n", ld);
 }
 
-/**
- *     tty_ldisc_restore       -       helper for tty ldisc change
- *     @tty: tty to recover
- *     @old: previous ldisc
- *
- *     Restore the previous line discipline or N_TTY when a line discipline
- *     change fails due to an open error
- */
-
-static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
-{
-       struct tty_ldisc *new_ldisc;
-       int r;
-
-       /* There is an outstanding reference here so this is safe */
-       old = tty_ldisc_get(tty, old->ops->num);
-       WARN_ON(IS_ERR(old));
-       tty->ldisc = old;
-       tty_set_termios_ldisc(tty, old->ops->num);
-       if (tty_ldisc_open(tty, old) < 0) {
-               tty_ldisc_put(old);
-               /* This driver is always present */
-               new_ldisc = tty_ldisc_get(tty, N_TTY);
-               if (IS_ERR(new_ldisc))
-                       panic("n_tty: get");
-               tty->ldisc = new_ldisc;
-               tty_set_termios_ldisc(tty, N_TTY);
-               r = tty_ldisc_open(tty, new_ldisc);
-               if (r < 0)
-                       panic("Couldn't open N_TTY ldisc for "
-                             "%s --- error %d.",
-                             tty_name(tty), r);
-       }
-}
-
 /**
  *     tty_set_ldisc           -       set line discipline
  *     @tty: the terminal to set
@@ -536,12 +504,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
 
 int tty_set_ldisc(struct tty_struct *tty, int disc)
 {
-       int retval;
-       struct tty_ldisc *old_ldisc, *new_ldisc;
-
-       new_ldisc = tty_ldisc_get(tty, disc);
-       if (IS_ERR(new_ldisc))
-               return PTR_ERR(new_ldisc);
+       int retval, old_disc;
 
        tty_lock(tty);
        retval = tty_ldisc_lock(tty, 5 * HZ);
@@ -554,7 +517,8 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
        }
 
        /* Check the no-op case */
-       if (tty->ldisc->ops->num == disc)
+       old_disc = tty->ldisc->ops->num;
+       if (old_disc == disc)
                goto out;
 
        if (test_bit(TTY_HUPPED, &tty->flags)) {
@@ -563,34 +527,25 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
                goto out;
        }
 
-       old_ldisc = tty->ldisc;
-
-       /* Shutdown the old discipline. */
-       tty_ldisc_close(tty, old_ldisc);
-
-       /* Now set up the new line discipline. */
-       tty->ldisc = new_ldisc;
-       tty_set_termios_ldisc(tty, disc);
-
-       retval = tty_ldisc_open(tty, new_ldisc);
+       retval = tty_ldisc_reinit(tty, disc);
        if (retval < 0) {
                /* Back to the old one or N_TTY if we can't */
-               tty_ldisc_put(new_ldisc);
-               tty_ldisc_restore(tty, old_ldisc);
+               if (tty_ldisc_reinit(tty, old_disc) < 0) {
+                       pr_err("tty: TIOCSETD failed, reinitializing N_TTY\n");
+                       if (tty_ldisc_reinit(tty, N_TTY) < 0) {
+                               /* At this point we have tty->ldisc == NULL. */
+                               pr_err("tty: reinitializing N_TTY failed\n");
+                       }
+               }
        }
 
-       if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) {
+       if (tty->ldisc && tty->ldisc->ops->num != old_disc &&
+           tty->ops->set_ldisc) {
                down_read(&tty->termios_rwsem);
                tty->ops->set_ldisc(tty);
                up_read(&tty->termios_rwsem);
        }
 
-       /* At this point we hold a reference to the new ldisc and a
-          reference to the old ldisc, or we hold two references to
-          the old ldisc (if it was restored as part of error cleanup
-          above). In either case, releasing a single reference from
-          the old ldisc is correct. */
-       new_ldisc = old_ldisc;
 out:
        tty_ldisc_unlock(tty);
 
@@ -598,7 +553,6 @@ out:
           already running */
        tty_buffer_restart_work(tty->port);
 err:
-       tty_ldisc_put(new_ldisc);       /* drop the extra reference */
        tty_unlock(tty);
        return retval;
 }
@@ -659,10 +613,8 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
        int retval;
 
        ld = tty_ldisc_get(tty, disc);
-       if (IS_ERR(ld)) {
-               BUG_ON(disc == N_TTY);
+       if (IS_ERR(ld))
                return PTR_ERR(ld);
-       }
 
        if (tty->ldisc) {
                tty_ldisc_close(tty, tty->ldisc);
@@ -674,10 +626,8 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
        tty_set_termios_ldisc(tty, disc);
        retval = tty_ldisc_open(tty, tty->ldisc);
        if (retval) {
-               if (!WARN_ON(disc == N_TTY)) {
-                       tty_ldisc_put(tty->ldisc);
-                       tty->ldisc = NULL;
-               }
+               tty_ldisc_put(tty->ldisc);
+               tty->ldisc = NULL;
        }
        return retval;
 }