Merge tag 'tty-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 3 Jul 2023 20:14:58 +0000 (13:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 3 Jul 2023 20:14:58 +0000 (13:14 -0700)
Pull tty/serial driver updates from Greg KH:
 "Here is the big set of tty/serial driver updates for 6.5-rc1.

  Included in here are:

   - tty_audit code cleanups from Jiri

   - more 8250 cleanups from Ilpo

   - samsung_tty driver bugfixes

   - 8250 lock port updates

   - usual fsl_lpuart driver updates and fixes

   - other small serial driver fixes and updates, full details in the
     shortlog

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

* tag 'tty-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (58 commits)
  tty_audit: make data of tty_audit_log() const
  tty_audit: make tty pointers in exposed functions const
  tty_audit: make icanon a bool
  tty_audit: invert the condition in tty_audit_log()
  tty_audit: use kzalloc() in tty_audit_buf_alloc()
  tty_audit: use TASK_COMM_LEN for task comm
  Revert "8250: add support for ASIX devices with a FIFO bug"
  serial: atmel: don't enable IRQs prematurely
  tty: serial: Add Nuvoton ma35d1 serial driver support
  tty: serial: fsl_lpuart: add earlycon for imx8ulp platform
  tty: serial: imx: fix rs485 rx after tx
  selftests: tty: add selftest for tty timestamp updates
  tty: tty_io: update timestamps on all device nodes
  tty: fix hang on tty device with no_room set
  serial: core: fix -EPROBE_DEFER handling in init
  serial: 8250_omap: Use force_suspend and resume for system suspend
  tty: serial: samsung_tty: Use abs() to simplify some code
  tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() when iterating clk
  tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() in case of error
  serial: 8250: Apply FSL workarounds also without SERIAL_8250_CONSOLE
  ...

1  2 
drivers/tty/serial/Kconfig
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/lantiq.c
drivers/tty/tty_io.c
tools/testing/selftests/Makefile

@@@ -450,8 -450,8 +450,8 @@@ config SERIAL_SA110
        help
          If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
          can enable its onboard serial port by enabling this option.
 -        Please read <file:Documentation/arm/sa1100/serial_uart.rst> for further
 -        info.
 +        Please read <file:Documentation/arch/arm/sa1100/serial_uart.rst> for
 +        further info.
  
  config SERIAL_SA1100_CONSOLE
        bool "Console on SA1100 serial port"
@@@ -1555,6 -1555,29 +1555,29 @@@ config SERIAL_SUNPLUS_CONSOL
          you can alter that using a kernel command line option such as
          "console=ttySUPx".
  
+ config SERIAL_NUVOTON_MA35D1
+       tristate "Nuvoton MA35D1 family UART support"
+       depends on ARCH_MA35 || COMPILE_TEST
+       select SERIAL_CORE
+       help
+         This driver supports Nuvoton MA35D1 family UART ports. If you would
+         like to use them, you must answer Y or M to this option. Note that
+         for use as console, it must be included in kernel and not as a
+         module. If you enable this option, Ma35D1 serial ports in the system
+         will be registered as ttyNVTx.
+ config SERIAL_NUVOTON_MA35D1_CONSOLE
+       bool "Console on a Nuvotn MA35D1 family UART port"
+       depends on SERIAL_NUVOTON_MA35D1=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Select this options if you'd like to use the UART port0 of the
+         Nuvoton MA35D1 family as a console.
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default,
+         but you can alter that using a kernel command line option such as
+         "console=ttyNVTx".
  endmenu
  
  config SERIAL_MCTRL_GPIO
  
  /* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
  #define DMA_RX_TIMEOUT                (10)
+ #define DMA_RX_IDLE_CHARS     8
  #define UART_AUTOSUSPEND_TIMEOUT      3000
  
  #define DRIVER_NAME   "fsl-lpuart"
@@@ -282,6 -283,7 +283,7 @@@ struct lpuart_port 
        struct scatterlist      rx_sgl, tx_sgl[2];
        struct circ_buf         rx_ring;
        int                     rx_dma_rng_buf_len;
+       int                     last_residue;
        unsigned int            dma_tx_nents;
        wait_queue_head_t       dma_wait;
        bool                    is_cs7; /* Set to true when character size is 7 */
@@@ -310,7 -312,7 +312,7 @@@ static const struct lpuart_soc_data ls1
  static const struct lpuart_soc_data ls1028a_data = {
        .devtype = LS1028A_LPUART,
        .iotype = UPIO_MEM32,
 -      .rx_watermark = 1,
 +      .rx_watermark = 0,
  };
  
  static struct lpuart_soc_data imx7ulp_data = {
@@@ -331,7 -333,7 +333,7 @@@ static struct lpuart_soc_data imx8qxp_d
        .devtype = IMX8QXP_LPUART,
        .iotype = UPIO_MEM32,
        .reg_off = IMX_REG_OFF,
-       .rx_watermark = 31,
+       .rx_watermark = 7, /* A lower watermark is ideal for low baud rates. */
  };
  static struct lpuart_soc_data imxrt1050_data = {
        .devtype = IMXRT1050_LPUART,
@@@ -1255,6 -1257,8 +1257,8 @@@ static void lpuart_copy_rx_to_tty(struc
                sport->port.icount.rx += copied;
        }
  
+       sport->last_residue = state.residue;
  exit:
        dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1,
                               DMA_FROM_DEVICE);
@@@ -1272,11 -1276,43 +1276,43 @@@ static void lpuart_dma_rx_complete(voi
        lpuart_copy_rx_to_tty(sport);
  }
  
+ /*
+  * Timer function to simulate the hardware EOP (End Of Package) event.
+  * The timer callback is to check for new RX data and copy to TTY buffer.
+  * If no new data are received since last interval, the EOP condition is
+  * met, complete the DMA transfer by copying the data. Otherwise, just
+  * restart timer.
+  */
  static void lpuart_timer_func(struct timer_list *t)
  {
        struct lpuart_port *sport = from_timer(sport, t, lpuart_timer);
+       enum dma_status dmastat;
+       struct dma_chan *chan = sport->dma_rx_chan;
+       struct circ_buf *ring = &sport->rx_ring;
+       struct dma_tx_state state;
+       unsigned long flags;
+       int count;
  
-       lpuart_copy_rx_to_tty(sport);
+       dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state);
+       if (dmastat == DMA_ERROR) {
+               dev_err(sport->port.dev, "Rx DMA transfer failed!\n");
+               return;
+       }
+       ring->head = sport->rx_sgl.length - state.residue;
+       count = CIRC_CNT(ring->head, ring->tail, sport->rx_sgl.length);
+       /* Check if new data received before copying */
+       if ((count != 0) && (sport->last_residue == state.residue))
+               lpuart_copy_rx_to_tty(sport);
+       else
+               mod_timer(&sport->lpuart_timer,
+                         jiffies + sport->dma_rx_timeout);
+       if (spin_trylock_irqsave(&sport->port.lock, flags)) {
+               sport->last_residue = state.residue;
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+       }
  }
  
  static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
         */
        sport->rx_dma_rng_buf_len = (DMA_RX_TIMEOUT * baud /  bits / 1000) * 2;
        sport->rx_dma_rng_buf_len = (1 << fls(sport->rx_dma_rng_buf_len));
+       sport->rx_dma_rng_buf_len = max_t(int,
+                                         sport->rxfifo_size * 2,
+                                         sport->rx_dma_rng_buf_len);
+       /*
+        * Keep this condition check in case rxfifo_size is unavailable
+        * for some SoCs.
+        */
        if (sport->rx_dma_rng_buf_len < 16)
                sport->rx_dma_rng_buf_len = 16;
  
+       sport->last_residue = 0;
+       sport->dma_rx_timeout = max(nsecs_to_jiffies(
+               sport->port.frame_time * DMA_RX_IDLE_CHARS), 1UL);
        ring->buf = kzalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC);
        if (!ring->buf)
                return -ENOMEM;
@@@ -1689,12 -1736,13 +1736,13 @@@ static void lpuart_rx_dma_startup(struc
        if (!sport->dma_rx_chan)
                goto err;
  
+       /* set default Rx DMA timeout */
+       sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT);
        ret = lpuart_start_rx_dma(sport);
        if (ret)
                goto err;
  
-       /* set Rx DMA timeout */
-       sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT);
        if (!sport->dma_rx_timeout)
                sport->dma_rx_timeout = 1;
  
@@@ -2676,6 -2724,7 +2724,7 @@@ OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-
  OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
  OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1028a-lpuart", ls1028a_early_console_setup);
  OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
+ OF_EARLYCON_DECLARE(lpuart32, "fsl,imx8ulp-lpuart", lpuart32_imx_early_console_setup);
  OF_EARLYCON_DECLARE(lpuart32, "fsl,imx8qxp-lpuart", lpuart32_imx_early_console_setup);
  OF_EARLYCON_DECLARE(lpuart32, "fsl,imxrt1050-lpuart", lpuart32_imx_early_console_setup);
  EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
@@@ -250,7 -250,6 +250,7 @@@ lqasc_err_int(int irq, void *_port
        struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
  
        spin_lock_irqsave(&ltq_port->lock, flags);
 +      __raw_writel(ASC_IRNCR_EIR, port->membase + LTQ_ASC_IRNCR);
        /* clear any pending interrupts */
        asc_update_bits(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
                ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
@@@ -890,7 -889,9 +890,9 @@@ static int lqasc_remove(struct platform
  {
        struct uart_port *port = platform_get_drvdata(pdev);
  
-       return uart_remove_one_port(&lqasc_reg, port);
+       uart_remove_one_port(&lqasc_reg, port);
+       return 0;
  }
  
  static const struct ltq_soc_data soc_data_lantiq = {
diff --combined drivers/tty/tty_io.c
  #include <linux/compat.h>
  #include <linux/uaccess.h>
  #include <linux/termios_internal.h>
+ #include <linux/fs.h>
  
  #include <linux/kbd_kern.h>
  #include <linux/vt_kern.h>
@@@ -466,7 -467,7 +467,7 @@@ static const struct file_operations tty
        .llseek         = no_llseek,
        .read_iter      = tty_read,
        .write_iter     = tty_write,
 -      .splice_read    = generic_file_splice_read,
 +      .splice_read    = copy_splice_read,
        .splice_write   = iter_file_splice_write,
        .poll           = tty_poll,
        .unlocked_ioctl = tty_ioctl,
@@@ -481,7 -482,7 +482,7 @@@ static const struct file_operations con
        .llseek         = no_llseek,
        .read_iter      = tty_read,
        .write_iter     = redirected_tty_write,
 -      .splice_read    = generic_file_splice_read,
 +      .splice_read    = copy_splice_read,
        .splice_write   = iter_file_splice_write,
        .poll           = tty_poll,
        .unlocked_ioctl = tty_ioctl,
@@@ -811,18 -812,26 +812,26 @@@ void start_tty(struct tty_struct *tty
  }
  EXPORT_SYMBOL(start_tty);
  
- static void tty_update_time(struct timespec64 *time)
+ static void tty_update_time(struct tty_struct *tty, bool mtime)
  {
        time64_t sec = ktime_get_real_seconds();
+       struct tty_file_private *priv;
  
-       /*
-        * We only care if the two values differ in anything other than the
-        * lower three bits (i.e every 8 seconds).  If so, then we can update
-        * the time of the tty device, otherwise it could be construded as a
-        * security leak to let userspace know the exact timing of the tty.
-        */
-       if ((sec ^ time->tv_sec) & ~7)
-               time->tv_sec = sec;
+       spin_lock(&tty->files_lock);
+       list_for_each_entry(priv, &tty->tty_files, list) {
+               struct inode *inode = file_inode(priv->file);
+               struct timespec64 *time = mtime ? &inode->i_mtime : &inode->i_atime;
+               /*
+                * We only care if the two values differ in anything other than the
+                * lower three bits (i.e every 8 seconds).  If so, then we can update
+                * the time of the tty device, otherwise it could be construded as a
+                * security leak to let userspace know the exact timing of the tty.
+                */
+               if ((sec ^ time->tv_sec) & ~7)
+                       time->tv_sec = sec;
+       }
+       spin_unlock(&tty->files_lock);
  }
  
  /*
@@@ -928,7 -937,7 +937,7 @@@ static ssize_t tty_read(struct kiocb *i
        tty_ldisc_deref(ld);
  
        if (i > 0)
-               tty_update_time(&inode->i_atime);
+               tty_update_time(tty, false);
  
        return i;
  }
@@@ -1036,7 -1045,7 +1045,7 @@@ static inline ssize_t do_tty_write
                cond_resched();
        }
        if (written) {
-               tty_update_time(&file_inode(file)->i_mtime);
+               tty_update_time(tty, true);
                ret = written;
        }
  out:
@@@ -4,7 -4,6 +4,7 @@@ TARGETS += amd-pstat
  TARGETS += arm64
  TARGETS += bpf
  TARGETS += breakpoints
 +TARGETS += cachestat
  TARGETS += capabilities
  TARGETS += cgroup
  TARGETS += clone3
@@@ -87,6 -86,7 +87,7 @@@ TARGETS += timer
  endif
  TARGETS += tmpfs
  TARGETS += tpm2
+ TARGETS += tty
  TARGETS += user
  TARGETS += vDSO
  TARGETS += mm
@@@ -145,12 -145,10 +146,12 @@@ ifneq ($(KBUILD_OUTPUT),
    abs_objtree := $(realpath $(abs_objtree))
    BUILD := $(abs_objtree)/kselftest
    KHDR_INCLUDES := -isystem ${abs_objtree}/usr/include
 +  KHDR_DIR := ${abs_objtree}/usr/include
  else
    BUILD := $(CURDIR)
    abs_srctree := $(shell cd $(top_srcdir) && pwd)
    KHDR_INCLUDES := -isystem ${abs_srctree}/usr/include
 +  KHDR_DIR := ${abs_srctree}/usr/include
    DEFAULT_INSTALL_HDR_PATH := 1
  endif
  
@@@ -164,7 -162,7 +165,7 @@@ export KHDR_INCLUDE
  # all isn't the first target in the file.
  .DEFAULT_GOAL := all
  
 -all:
 +all: kernel_header_files
        @ret=1;                                                 \
        for TARGET in $(TARGETS); do                            \
                BUILD_TARGET=$$BUILD/$$TARGET;                  \
                                $(if $(FORCE_TARGETS),|| exit); \
                ret=$$((ret * $$?));                            \
        done; exit $$ret;
 +
 +kernel_header_files:
 +      @ls $(KHDR_DIR)/linux/*.h >/dev/null 2>/dev/null;                          \
 +      if [ $$? -ne 0 ]; then                                                     \
 +            RED='\033[1;31m';                                                  \
 +            NOCOLOR='\033[0m';                                                 \
 +            echo;                                                              \
 +            echo -e "$${RED}error$${NOCOLOR}: missing kernel header files.";   \
 +            echo "Please run this and try again:";                             \
 +            echo;                                                              \
 +            echo "    cd $(top_srcdir)";                                       \
 +            echo "    make headers";                                           \
 +            echo;                                                              \
 +          exit 1;                                                                \
 +      fi
 +
 +.PHONY: kernel_header_files
  
  run_tests: all
        @for TARGET in $(TARGETS); do \