瀏覽代碼

Merge tag 'tty-4.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg KH:
 "Here are some tty and serial driver fixes for reported issues for
  4.17-rc3.

  Nothing major, but a number of small things:

   - device tree fixes/updates for serial ports

   - earlycon fixes

   - n_gsm fixes

   - tty core change reverted to help resolve syszkaller reports

   - other serial driver small fixes

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

* tag 'tty-4.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: Use __GFP_NOFAIL for tty_ldisc_get()
  tty: serial: xuartps: Setup early console when uartclk is also passed
  tty: Don't call panic() at tty_ldisc_init()
  tty: Avoid possible error pointer dereference at tty_ldisc_restore().
  dt-bindings: mvebu-uart: DT fix s/interrupts-names/interrupt-names/
  tty: serial: qcom_geni_serial: Use signed variable to get IRQ
  earlycon: Use a pointer table to fix __earlycon_table stride
  serial: sh-sci: Document r8a77470 bindings
  dt-bindings: meson-uart: DT fix s/clocks-names/clock-names/
  serial: imx: fix cached UCR2 read on software reset
  serial: imx: warn user when using unsupported configuration
  serial: mvebu-uart: Fix local flags handling on termios update
  tty: n_gsm: Fix DLCI handling for ADM mode if debug & 2 is not set
  tty: n_gsm: Fix long delays with control frame timeouts in ADM mode
Linus Torvalds 7 年之前
父節點
當前提交
b52c85a7b7

+ 1 - 1
Documentation/devicetree/bindings/serial/amlogic,meson-uart.txt

@@ -21,7 +21,7 @@ Required properties:
 - interrupts : identifier to the device interrupt
 - interrupts : identifier to the device interrupt
 - clocks : a list of phandle + clock-specifier pairs, one for each
 - clocks : a list of phandle + clock-specifier pairs, one for each
 	   entry in clock names.
 	   entry in clock names.
-- clocks-names :
+- clock-names :
    * "xtal" for external xtal clock identifier
    * "xtal" for external xtal clock identifier
    * "pclk" for the bus core clock, either the clk81 clock or the gate clock
    * "pclk" for the bus core clock, either the clk81 clock or the gate clock
    * "baud" for the source of the baudrate generator, can be either the xtal
    * "baud" for the source of the baudrate generator, can be either the xtal

+ 1 - 1
Documentation/devicetree/bindings/serial/mvebu-uart.txt

@@ -24,7 +24,7 @@ Required properties:
     - Must contain two elements for the extended variant of the IP
     - Must contain two elements for the extended variant of the IP
       (marvell,armada-3700-uart-ext): "uart-tx" and "uart-rx",
       (marvell,armada-3700-uart-ext): "uart-tx" and "uart-rx",
       respectively the UART TX interrupt and the UART RX interrupt. A
       respectively the UART TX interrupt and the UART RX interrupt. A
-      corresponding interrupts-names property must be defined.
+      corresponding interrupt-names property must be defined.
     - For backward compatibility reasons, a single element interrupts
     - For backward compatibility reasons, a single element interrupts
       property is also supported for the standard variant of the IP,
       property is also supported for the standard variant of the IP,
       containing only the UART sum interrupt. This form is deprecated
       containing only the UART sum interrupt. This form is deprecated

+ 2 - 0
Documentation/devicetree/bindings/serial/renesas,sci-serial.txt

@@ -17,6 +17,8 @@ Required properties:
     - "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART.
     - "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART.
     - "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART.
     - "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART.
     - "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART.
     - "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART.
+    - "renesas,scif-r8a77470" for R8A77470 (RZ/G1C) SCIF compatible UART.
+    - "renesas,hscif-r8a77470" for R8A77470 (RZ/G1C) HSCIF compatible UART.
     - "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART.
     - "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART.
     - "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART.
     - "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART.
     - "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART.
     - "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART.

+ 5 - 2
drivers/of/fdt.c

@@ -942,7 +942,7 @@ int __init early_init_dt_scan_chosen_stdout(void)
 	int offset;
 	int offset;
 	const char *p, *q, *options = NULL;
 	const char *p, *q, *options = NULL;
 	int l;
 	int l;
-	const struct earlycon_id *match;
+	const struct earlycon_id **p_match;
 	const void *fdt = initial_boot_params;
 	const void *fdt = initial_boot_params;
 
 
 	offset = fdt_path_offset(fdt, "/chosen");
 	offset = fdt_path_offset(fdt, "/chosen");
@@ -969,7 +969,10 @@ int __init early_init_dt_scan_chosen_stdout(void)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	for (match = __earlycon_table; match < __earlycon_table_end; match++) {
+	for (p_match = __earlycon_table; p_match < __earlycon_table_end;
+	     p_match++) {
+		const struct earlycon_id *match = *p_match;
+
 		if (!match->compatible[0])
 		if (!match->compatible[0])
 			continue;
 			continue;
 
 

+ 22 - 1
drivers/tty/n_gsm.c

@@ -121,6 +121,9 @@ struct gsm_dlci {
 	struct mutex mutex;
 	struct mutex mutex;
 
 
 	/* Link layer */
 	/* Link layer */
+	int mode;
+#define DLCI_MODE_ABM		0	/* Normal Asynchronous Balanced Mode */
+#define DLCI_MODE_ADM		1	/* Asynchronous Disconnected Mode */
 	spinlock_t lock;	/* Protects the internal state */
 	spinlock_t lock;	/* Protects the internal state */
 	struct timer_list t1;	/* Retransmit timer for SABM and UA */
 	struct timer_list t1;	/* Retransmit timer for SABM and UA */
 	int retries;
 	int retries;
@@ -1364,7 +1367,13 @@ retry:
 	ctrl->data = data;
 	ctrl->data = data;
 	ctrl->len = clen;
 	ctrl->len = clen;
 	gsm->pending_cmd = ctrl;
 	gsm->pending_cmd = ctrl;
-	gsm->cretries = gsm->n2;
+
+	/* If DLCI0 is in ADM mode skip retries, it won't respond */
+	if (gsm->dlci[0]->mode == DLCI_MODE_ADM)
+		gsm->cretries = 1;
+	else
+		gsm->cretries = gsm->n2;
+
 	mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
 	mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
 	gsm_control_transmit(gsm, ctrl);
 	gsm_control_transmit(gsm, ctrl);
 	spin_unlock_irqrestore(&gsm->control_lock, flags);
 	spin_unlock_irqrestore(&gsm->control_lock, flags);
@@ -1472,6 +1481,7 @@ static void gsm_dlci_t1(struct timer_list *t)
 			if (debug & 8)
 			if (debug & 8)
 				pr_info("DLCI %d opening in ADM mode.\n",
 				pr_info("DLCI %d opening in ADM mode.\n",
 					dlci->addr);
 					dlci->addr);
+			dlci->mode = DLCI_MODE_ADM;
 			gsm_dlci_open(dlci);
 			gsm_dlci_open(dlci);
 		} else {
 		} else {
 			gsm_dlci_close(dlci);
 			gsm_dlci_close(dlci);
@@ -2861,11 +2871,22 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
 static int gsm_carrier_raised(struct tty_port *port)
 static int gsm_carrier_raised(struct tty_port *port)
 {
 {
 	struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
 	struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+	struct gsm_mux *gsm = dlci->gsm;
+
 	/* Not yet open so no carrier info */
 	/* Not yet open so no carrier info */
 	if (dlci->state != DLCI_OPEN)
 	if (dlci->state != DLCI_OPEN)
 		return 0;
 		return 0;
 	if (debug & 2)
 	if (debug & 2)
 		return 1;
 		return 1;
+
+	/*
+	 * Basic mode with control channel in ADM mode may not respond
+	 * to CMD_MSC at all and modem_rx is empty.
+	 */
+	if (gsm->encoding == 0 && gsm->dlci[0]->mode == DLCI_MODE_ADM &&
+	    !dlci->modem_rx)
+		return 1;
+
 	return dlci->modem_rx & TIOCM_CD;
 	return dlci->modem_rx & TIOCM_CD;
 }
 }
 
 

+ 4 - 2
drivers/tty/serial/earlycon.c

@@ -169,7 +169,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
  */
  */
 int __init setup_earlycon(char *buf)
 int __init setup_earlycon(char *buf)
 {
 {
-	const struct earlycon_id *match;
+	const struct earlycon_id **p_match;
 
 
 	if (!buf || !buf[0])
 	if (!buf || !buf[0])
 		return -EINVAL;
 		return -EINVAL;
@@ -177,7 +177,9 @@ int __init setup_earlycon(char *buf)
 	if (early_con.flags & CON_ENABLED)
 	if (early_con.flags & CON_ENABLED)
 		return -EALREADY;
 		return -EALREADY;
 
 
-	for (match = __earlycon_table; match < __earlycon_table_end; match++) {
+	for (p_match = __earlycon_table; p_match < __earlycon_table_end;
+	     p_match++) {
+		const struct earlycon_id *match = *p_match;
 		size_t len = strlen(match->name);
 		size_t len = strlen(match->name);
 
 
 		if (strncmp(buf, match->name, len))
 		if (strncmp(buf, match->name, len))

+ 18 - 1
drivers/tty/serial/imx.c

@@ -316,7 +316,7 @@ static u32 imx_uart_readl(struct imx_port *sport, u32 offset)
 		 * differ from the value that was last written. As it only
 		 * differ from the value that was last written. As it only
 		 * clears after being set, reread conditionally.
 		 * clears after being set, reread conditionally.
 		 */
 		 */
-		if (sport->ucr2 & UCR2_SRST)
+		if (!(sport->ucr2 & UCR2_SRST))
 			sport->ucr2 = readl(sport->port.membase + offset);
 			sport->ucr2 = readl(sport->port.membase + offset);
 		return sport->ucr2;
 		return sport->ucr2;
 		break;
 		break;
@@ -1833,6 +1833,11 @@ static int imx_uart_rs485_config(struct uart_port *port,
 		rs485conf->flags &= ~SER_RS485_ENABLED;
 		rs485conf->flags &= ~SER_RS485_ENABLED;
 
 
 	if (rs485conf->flags & SER_RS485_ENABLED) {
 	if (rs485conf->flags & SER_RS485_ENABLED) {
+		/* Enable receiver if low-active RTS signal is requested */
+		if (sport->have_rtscts &&  !sport->have_rtsgpio &&
+		    !(rs485conf->flags & SER_RS485_RTS_ON_SEND))
+			rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
 		/* disable transmitter */
 		/* disable transmitter */
 		ucr2 = imx_uart_readl(sport, UCR2);
 		ucr2 = imx_uart_readl(sport, UCR2);
 		if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
 		if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
@@ -2265,6 +2270,18 @@ static int imx_uart_probe(struct platform_device *pdev)
 	    (!sport->have_rtscts && !sport->have_rtsgpio))
 	    (!sport->have_rtscts && !sport->have_rtsgpio))
 		dev_err(&pdev->dev, "no RTS control, disabling rs485\n");
 		dev_err(&pdev->dev, "no RTS control, disabling rs485\n");
 
 
+	/*
+	 * If using the i.MX UART RTS/CTS control then the RTS (CTS_B)
+	 * signal cannot be set low during transmission in case the
+	 * receiver is off (limitation of the i.MX UART IP).
+	 */
+	if (sport->port.rs485.flags & SER_RS485_ENABLED &&
+	    sport->have_rtscts && !sport->have_rtsgpio &&
+	    (!(sport->port.rs485.flags & SER_RS485_RTS_ON_SEND) &&
+	     !(sport->port.rs485.flags & SER_RS485_RX_DURING_TX)))
+		dev_err(&pdev->dev,
+			"low-active RTS not possible when receiver is off, enabling receiver\n");
+
 	imx_uart_rs485_config(&sport->port, &sport->port.rs485);
 	imx_uart_rs485_config(&sport->port, &sport->port.rs485);
 
 
 	/* Disable interrupts before requesting them */
 	/* Disable interrupts before requesting them */

+ 0 - 1
drivers/tty/serial/mvebu-uart.c

@@ -495,7 +495,6 @@ static void mvebu_uart_set_termios(struct uart_port *port,
 		termios->c_iflag |= old->c_iflag & ~(INPCK | IGNPAR);
 		termios->c_iflag |= old->c_iflag & ~(INPCK | IGNPAR);
 		termios->c_cflag &= CREAD | CBAUD;
 		termios->c_cflag &= CREAD | CBAUD;
 		termios->c_cflag |= old->c_cflag & ~(CREAD | CBAUD);
 		termios->c_cflag |= old->c_cflag & ~(CREAD | CBAUD);
-		termios->c_lflag = old->c_lflag;
 	}
 	}
 
 
 	spin_unlock_irqrestore(&port->lock, flags);
 	spin_unlock_irqrestore(&port->lock, flags);

+ 6 - 4
drivers/tty/serial/qcom_geni_serial.c

@@ -1022,6 +1022,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
 	struct qcom_geni_serial_port *port;
 	struct qcom_geni_serial_port *port;
 	struct uart_port *uport;
 	struct uart_port *uport;
 	struct resource *res;
 	struct resource *res;
+	int irq;
 
 
 	if (pdev->dev.of_node)
 	if (pdev->dev.of_node)
 		line = of_alias_get_id(pdev->dev.of_node, "serial");
 		line = of_alias_get_id(pdev->dev.of_node, "serial");
@@ -1061,11 +1062,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
 	port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
 	port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
 	port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
 	port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
 
 
-	uport->irq = platform_get_irq(pdev, 0);
-	if (uport->irq < 0) {
-		dev_err(&pdev->dev, "Failed to get IRQ %d\n", uport->irq);
-		return uport->irq;
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "Failed to get IRQ %d\n", irq);
+		return irq;
 	}
 	}
+	uport->irq = irq;
 
 
 	uport->private_data = &qcom_geni_console_driver;
 	uport->private_data = &qcom_geni_console_driver;
 	platform_set_drvdata(pdev, port);
 	platform_set_drvdata(pdev, port);

+ 1 - 1
drivers/tty/serial/xilinx_uartps.c

@@ -1181,7 +1181,7 @@ static int __init cdns_early_console_setup(struct earlycon_device *device,
 	/* only set baud if specified on command line - otherwise
 	/* only set baud if specified on command line - otherwise
 	 * assume it has been initialized by a boot loader.
 	 * assume it has been initialized by a boot loader.
 	 */
 	 */
-	if (device->baud) {
+	if (port->uartclk && device->baud) {
 		u32 cd = 0, bdiv = 0;
 		u32 cd = 0, bdiv = 0;
 		u32 mr;
 		u32 mr;
 		int div8;
 		int div8;

+ 4 - 1
drivers/tty/tty_io.c

@@ -2816,7 +2816,10 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
 
 
 	kref_init(&tty->kref);
 	kref_init(&tty->kref);
 	tty->magic = TTY_MAGIC;
 	tty->magic = TTY_MAGIC;
-	tty_ldisc_init(tty);
+	if (tty_ldisc_init(tty)) {
+		kfree(tty);
+		return NULL;
+	}
 	tty->session = NULL;
 	tty->session = NULL;
 	tty->pgrp = NULL;
 	tty->pgrp = NULL;
 	mutex_init(&tty->legacy_mutex);
 	mutex_init(&tty->legacy_mutex);

+ 13 - 16
drivers/tty/tty_ldisc.c

@@ -176,12 +176,11 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
 			return ERR_CAST(ldops);
 			return ERR_CAST(ldops);
 	}
 	}
 
 
-	ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
-	if (ld == NULL) {
-		put_ldops(ldops);
-		return ERR_PTR(-ENOMEM);
-	}
-
+	/*
+	 * There is no way to handle allocation failure of only 16 bytes.
+	 * Let's simplify error handling and save more memory.
+	 */
+	ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL | __GFP_NOFAIL);
 	ld->ops = ldops;
 	ld->ops = ldops;
 	ld->tty = tty;
 	ld->tty = tty;
 
 
@@ -527,19 +526,16 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld)
 static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
 static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
 {
 {
 	/* There is an outstanding reference here so this is safe */
 	/* 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);
+	if (tty_ldisc_failto(tty, old->ops->num) < 0) {
+		const char *name = tty_name(tty);
+
+		pr_warn("Falling back ldisc for %s.\n", name);
 		/* The traditional behaviour is to fall back to N_TTY, we
 		/* The traditional behaviour is to fall back to N_TTY, we
 		   want to avoid falling back to N_NULL unless we have no
 		   want to avoid falling back to N_NULL unless we have no
 		   choice to avoid the risk of breaking anything */
 		   choice to avoid the risk of breaking anything */
 		if (tty_ldisc_failto(tty, N_TTY) < 0 &&
 		if (tty_ldisc_failto(tty, N_TTY) < 0 &&
 		    tty_ldisc_failto(tty, N_NULL) < 0)
 		    tty_ldisc_failto(tty, N_NULL) < 0)
-			panic("Couldn't open N_NULL ldisc for %s.",
-			      tty_name(tty));
+			panic("Couldn't open N_NULL ldisc for %s.", name);
 	}
 	}
 }
 }
 
 
@@ -824,12 +820,13 @@ EXPORT_SYMBOL_GPL(tty_ldisc_release);
  *	the tty structure is not completely set up when this call is made.
  *	the tty structure is not completely set up when this call is made.
  */
  */
 
 
-void tty_ldisc_init(struct tty_struct *tty)
+int tty_ldisc_init(struct tty_struct *tty)
 {
 {
 	struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
 	struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
 	if (IS_ERR(ld))
 	if (IS_ERR(ld))
-		panic("n_tty: init_tty");
+		return PTR_ERR(ld);
 	tty->ldisc = ld;
 	tty->ldisc = ld;
+	return 0;
 }
 }
 
 
 /**
 /**

+ 1 - 1
include/asm-generic/vmlinux.lds.h

@@ -188,7 +188,7 @@
 #endif
 #endif
 
 
 #ifdef CONFIG_SERIAL_EARLYCON
 #ifdef CONFIG_SERIAL_EARLYCON
-#define EARLYCON_TABLE() STRUCT_ALIGN();			\
+#define EARLYCON_TABLE() . = ALIGN(8);				\
 			 VMLINUX_SYMBOL(__earlycon_table) = .;	\
 			 VMLINUX_SYMBOL(__earlycon_table) = .;	\
 			 KEEP(*(__earlycon_table))		\
 			 KEEP(*(__earlycon_table))		\
 			 VMLINUX_SYMBOL(__earlycon_table_end) = .;
 			 VMLINUX_SYMBOL(__earlycon_table_end) = .;

+ 14 - 7
include/linux/serial_core.h

@@ -351,10 +351,10 @@ struct earlycon_id {
 	char	name[16];
 	char	name[16];
 	char	compatible[128];
 	char	compatible[128];
 	int	(*setup)(struct earlycon_device *, const char *options);
 	int	(*setup)(struct earlycon_device *, const char *options);
-} __aligned(32);
+};
 
 
-extern const struct earlycon_id __earlycon_table[];
-extern const struct earlycon_id __earlycon_table_end[];
+extern const struct earlycon_id *__earlycon_table[];
+extern const struct earlycon_id *__earlycon_table_end[];
 
 
 #if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
 #if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
 #define EARLYCON_USED_OR_UNUSED	__used
 #define EARLYCON_USED_OR_UNUSED	__used
@@ -362,12 +362,19 @@ extern const struct earlycon_id __earlycon_table_end[];
 #define EARLYCON_USED_OR_UNUSED	__maybe_unused
 #define EARLYCON_USED_OR_UNUSED	__maybe_unused
 #endif
 #endif
 
 
-#define OF_EARLYCON_DECLARE(_name, compat, fn)				\
-	static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name)	\
-	     EARLYCON_USED_OR_UNUSED __section(__earlycon_table)	\
+#define _OF_EARLYCON_DECLARE(_name, compat, fn, unique_id)		\
+	static const struct earlycon_id unique_id			\
+	     EARLYCON_USED_OR_UNUSED __initconst			\
 		= { .name = __stringify(_name),				\
 		= { .name = __stringify(_name),				\
 		    .compatible = compat,				\
 		    .compatible = compat,				\
-		    .setup = fn  }
+		    .setup = fn  };					\
+	static const struct earlycon_id EARLYCON_USED_OR_UNUSED		\
+		__section(__earlycon_table)				\
+		* const __PASTE(__p, unique_id) = &unique_id
+
+#define OF_EARLYCON_DECLARE(_name, compat, fn)				\
+	_OF_EARLYCON_DECLARE(_name, compat, fn,				\
+			     __UNIQUE_ID(__earlycon_##_name))
 
 
 #define EARLYCON_DECLARE(_name, fn)	OF_EARLYCON_DECLARE(_name, "", fn)
 #define EARLYCON_DECLARE(_name, fn)	OF_EARLYCON_DECLARE(_name, "", fn)
 
 

+ 1 - 1
include/linux/tty.h

@@ -701,7 +701,7 @@ extern int tty_unregister_ldisc(int disc);
 extern int tty_set_ldisc(struct tty_struct *tty, int disc);
 extern int tty_set_ldisc(struct tty_struct *tty, int disc);
 extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty);
 extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty);
 extern void tty_ldisc_release(struct tty_struct *tty);
 extern void tty_ldisc_release(struct tty_struct *tty);
-extern void tty_ldisc_init(struct tty_struct *tty);
+extern int __must_check tty_ldisc_init(struct tty_struct *tty);
 extern void tty_ldisc_deinit(struct tty_struct *tty);
 extern void tty_ldisc_deinit(struct tty_struct *tty);
 extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
 extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
 				 char *f, int count);
 				 char *f, int count);