Merge tag 'tty-5.10-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 1 Nov 2020 17:55:36 +0000 (09:55 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 1 Nov 2020 17:55:36 +0000 (09:55 -0800)
Pull tty/serial fixes from Greg KH:
 "Here are some small TTY and Serial driver fixes for reported issues
  for 5.10-rc2. They include:

   - vt ioctl bugfix for reported problems

   - fsl_lpuart serial driver fix

   - 21285 serial driver bugfix

  All have been in linux-next with no reported issues"

* tag 'tty-5.10-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  vt_ioctl: fix GIO_UNIMAP regression
  vt: keyboard, extend func_buf_lock to readers
  vt: keyboard, simplify vt_kdgkbsent
  tty: serial: fsl_lpuart: LS1021A has a FIFO size of 16 words, like LS1028A
  tty: serial: 21285: fix lockup on open

drivers/tty/serial/21285.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/vt/keyboard.c
drivers/tty/vt/vt_ioctl.c

index 718e010..09baef4 100644 (file)
@@ -50,25 +50,25 @@ static const char serial21285_name[] = "Footbridge UART";
 
 static bool is_enabled(struct uart_port *port, int bit)
 {
-       unsigned long private_data = (unsigned long)port->private_data;
+       unsigned long *private_data = (unsigned long *)&port->private_data;
 
-       if (test_bit(bit, &private_data))
+       if (test_bit(bit, private_data))
                return true;
        return false;
 }
 
 static void enable(struct uart_port *port, int bit)
 {
-       unsigned long private_data = (unsigned long)port->private_data;
+       unsigned long *private_data = (unsigned long *)&port->private_data;
 
-       set_bit(bit, &private_data);
+       set_bit(bit, private_data);
 }
 
 static void disable(struct uart_port *port, int bit)
 {
-       unsigned long private_data = (unsigned long)port->private_data;
+       unsigned long *private_data = (unsigned long *)&port->private_data;
 
-       clear_bit(bit, &private_data);
+       clear_bit(bit, private_data);
 }
 
 #define is_tx_enabled(port)    is_enabled(port, tx_enabled_bit)
index ff4b88c..bd047e1 100644 (file)
@@ -314,9 +314,10 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
 /* Forward declare this for the dma callbacks*/
 static void lpuart_dma_tx_complete(void *arg);
 
-static inline bool is_ls1028a_lpuart(struct lpuart_port *sport)
+static inline bool is_layerscape_lpuart(struct lpuart_port *sport)
 {
-       return sport->devtype == LS1028A_LPUART;
+       return (sport->devtype == LS1021A_LPUART ||
+               sport->devtype == LS1028A_LPUART);
 }
 
 static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
@@ -1701,11 +1702,11 @@ static int lpuart32_startup(struct uart_port *port)
                                            UARTFIFO_FIFOSIZE_MASK);
 
        /*
-        * The LS1028A has a fixed length of 16 words. Although it supports the
-        * RX/TXSIZE fields their encoding is different. Eg the reference manual
-        * states 0b101 is 16 words.
+        * The LS1021A and LS1028A have a fixed FIFO depth of 16 words.
+        * Although they support the RX/TXSIZE fields, their encoding is
+        * different. Eg the reference manual states 0b101 is 16 words.
         */
-       if (is_ls1028a_lpuart(sport)) {
+       if (is_layerscape_lpuart(sport)) {
                sport->rxfifo_size = 16;
                sport->txfifo_size = 16;
                sport->port.fifosize = sport->txfifo_size;
index 0db53b5..78acc27 100644 (file)
@@ -743,8 +743,13 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
                return;
 
        if ((unsigned)value < ARRAY_SIZE(func_table)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&func_buf_lock, flags);
                if (func_table[value])
                        puts_queue(vc, func_table[value]);
+               spin_unlock_irqrestore(&func_buf_lock, flags);
+
        } else
                pr_err("k_fn called with value=%d\n", value);
 }
@@ -1991,13 +1996,11 @@ out:
 #undef s
 #undef v
 
-/* FIXME: This one needs untangling and locking */
+/* FIXME: This one needs untangling */
 int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 {
        struct kbsentry *kbs;
-       char *p;
        u_char *q;
-       u_char __user *up;
        int sz, fnw_sz;
        int delta;
        char *first_free, *fj, *fnw;
@@ -2023,23 +2026,19 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
        i = array_index_nospec(kbs->kb_func, MAX_NR_FUNC);
 
        switch (cmd) {
-       case KDGKBSENT:
-               sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-                                                 a struct member */
-               up = user_kdgkb->kb_string;
-               p = func_table[i];
-               if(p)
-                       for ( ; *p && sz; p++, sz--)
-                               if (put_user(*p, up++)) {
-                                       ret = -EFAULT;
-                                       goto reterr;
-                               }
-               if (put_user('\0', up)) {
-                       ret = -EFAULT;
-                       goto reterr;
-               }
-               kfree(kbs);
-               return ((p && *p) ? -EOVERFLOW : 0);
+       case KDGKBSENT: {
+               /* size should have been a struct member */
+               ssize_t len = sizeof(user_kdgkb->kb_string);
+
+               spin_lock_irqsave(&func_buf_lock, flags);
+               len = strlcpy(kbs->kb_string, func_table[i] ? : "", len);
+               spin_unlock_irqrestore(&func_buf_lock, flags);
+
+               ret = copy_to_user(user_kdgkb->kb_string, kbs->kb_string,
+                               len + 1) ? -EFAULT : 0;
+
+               goto reterr;
+       }
        case KDSKBSENT:
                if (!perm) {
                        ret = -EPERM;
index 0a33b8a..2321775 100644 (file)
@@ -549,7 +549,7 @@ static int vt_io_fontreset(struct console_font_op *op)
 }
 
 static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
-               struct vc_data *vc)
+               bool perm, struct vc_data *vc)
 {
        struct unimapdesc tmp;
 
@@ -557,9 +557,11 @@ static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
                return -EFAULT;
        switch (cmd) {
        case PIO_UNIMAP:
+               if (!perm)
+                       return -EPERM;
                return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
        case GIO_UNIMAP:
-               if (fg_console != vc->vc_num)
+               if (!perm && fg_console != vc->vc_num)
                        return -EPERM;
                return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct),
                                tmp.entries);
@@ -639,10 +641,7 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up,
 
        case PIO_UNIMAP:
        case GIO_UNIMAP:
-               if (!perm)
-                       return -EPERM;
-
-               return do_unimap_ioctl(cmd, up, vc);
+               return do_unimap_ioctl(cmd, up, perm, vc);
 
        default:
                return -ENOIOCTLCMD;