Skip to contentSkip to conversation

TTY/serial driver fixes for 3.2

PATCH New Greg KH 1 participant 14 messages Nov 22, 2011

Subsystems (6)
lore
Share & tools
lore

Greg KH

author
#0 lore raw

PATCH 1/1 TTY/serial driver fixes for 3.2

Here are some tty/serial driver fixes for your 3.2 tree.

Not many patches here, just an assortment of fixes and a few new devices supported, full details are in the shortlog below.

Please pull from:
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-linus

All of these patches have been in the -mm and -next trees for a while.

Patches will be sent to the linux-serial mailing list, if anyone wants to see them.

thanks,

greg k-h

------------

 Documentation/serial/serial-rs485.txt |   14 +++++++++++---
 MAINTAINERS                           |    2 +-
 drivers/tty/hvc/hvc_dcc.c             |    2 ++
 drivers/tty/serial/Kconfig            |   14 +++++++-------
 drivers/tty/serial/atmel_serial.c     |   16 +++-------------
 drivers/tty/serial/crisv10.c          |   10 ++--------
 drivers/tty/serial/mfd.c              |    4 +---
 drivers/tty/serial/pch_uart.c         |   19 ++++++++++++++-----
 drivers/tty/tty_ldisc.c               |   30 +++++++++++++++++++++++-------
 include/linux/serial.h                |   14 ++++++++------
 10 files changed, 72 insertions(+), 53 deletions(-)

---------------

Alan Cox (1):
serial,mfd: Fix CMSPAR setup

Claudio Scordino (1):
RS485: fix inconsistencies in the meaning of some variables

Doug Anderson (1):
tty/serial: Prevent drop of DCD on suspend for Tegra UARTs

Greg Kroah-Hartman (1):
Revert "tty/serial: Prevent drop of DCD on suspend for Tegra UARTs"

Jiri Slaby (3):
TTY: ldisc, allow waiting for ldisc arbitrarily long
TTY: ldisc, move wait idle to caller
TTY: ldisc, wait for ldisc infinitely in hangup

Lucas Kannebley Tavares (1):
jsm: Change maintainership

Stephen Boyd (1):
tty: hvc_dcc: Fix duplicate character inputs

Tomoya MORINAGA (4):
pch_uart: Fix hw-flow control issue
pch_uart: Support new device LAPIS Semiconductor ML7831 IOH
pch_uart: Change company name OKI SEMICONDUCTOR to LAPIS Semiconductor
pch_uart: Fix DMA resource leak issue

#1 lore raw

PATCH 1/13 jsm: Change maintainership

From: Lucas Kannebley Tavares <[email protected]>

Breno Leitao has passed the maintainership on to me.

---
 MAINTAINERS |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
MAINTAINERS +1 -1
index 4808256..cc6a466 100644
@@ -3710,7 +3710,7 @@ F:	fs/jbd2/
 F:	include/linux/jbd2.h
 
 JSM Neo PCI based serial card
-M:	Breno Leitao <[email protected]>
+M:	Lucas Tavares <[email protected]>
 L:	[email protected]
 S:	Maintained
 F:	drivers/tty/serial/jsm/
Signature · 1 line
1.7.7.3
#2 lore raw

PATCH 2/13 tty: hvc_dcc: Fix duplicate character inputs

From: Stephen Boyd <[email protected]>

Reading from the DCC grabs a character from the buffer and clears the status bit. Since this is a context-changing operation, instructions following the character read that rely on the status bit being accurate need to be synchronized with an ISB.

In this case, the status bit check needs to execute after the character read otherwise we run the risk of reading the character and checking the status bit before the read can clear the status bit in the first place. When this happens, the user will see the same character they typed twice, instead of once.

Add an ISB after the read and the write, so that the status check is synchronized with the read/write operations.

---
 drivers/tty/hvc/hvc_dcc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/tty/hvc/hvc_dcc.c +2 -0
index 435f6fa..44fbeba 100644
@@ -46,6 +46,7 @@ static inline char __dcc_getchar(void)
 
 	asm volatile("mrc p14, 0, %0, c0, c5, 0	@ read comms data reg"
 		: "=r" (__c));
+	isb();
 
 	return __c;
 }
@@ -55,6 +56,7 @@ static inline void __dcc_putchar(char c)
 	asm volatile("mcr p14, 0, %0, c0, c5, 0	@ write a char"
 		: /* no output register */
 		: "r" (c));
+	isb();
 }
 
 static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
Signature · 1 line
1.7.7.3
#3 lore raw

PATCH 3/13 pch_uart: Fix hw-flow control issue

In reply to Greg Kroah-Hartman

From: Tomoya MORINAGA <[email protected]>

Using hardware flow control,
currently, register of the control-bit(AFE) is not set. This patch fixes the issue.

---
 drivers/tty/serial/pch_uart.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/tty/serial/pch_uart.c +1 -0
index 21febef..2f07a67 100644
@@ -1280,6 +1280,7 @@ static void pch_uart_set_termios(struct uart_port *port,
 	if (rtn)
 		goto out;
 
+	pch_uart_set_mctrl(&priv->port, priv->port.mctrl);
 	/* Don't rewrite B0 */
 	if (tty_termios_baud_rate(termios))
 		tty_termios_encode_baud_rate(termios, baud, baud);
Signature · 1 line
1.7.7.3
#4 lore raw

PATCH 4/13 pch_uart: Support new device LAPIS Semiconductor ML7831 IOH

In reply to Greg Kroah-Hartman

From: Tomoya MORINAGA <[email protected]>

ML7831 is companion chip for Intel Atom E6xx series.

---
 drivers/tty/serial/Kconfig    |   14 +++++++-------
 drivers/tty/serial/pch_uart.c |    8 ++++++++
 2 files changed, 15 insertions(+), 7 deletions(-)
drivers/tty/serial/Kconfig +7 -7
index 5f479da..925a1e5 100644
@@ -1560,7 +1560,7 @@ config SERIAL_IFX6X60
 	  Support for the IFX6x60 modem devices on Intel MID platforms.
 
 config SERIAL_PCH_UART
-	tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) UART"
+	tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
 	depends on PCI
 	select SERIAL_CORE
 	help
@@ -1568,12 +1568,12 @@ config SERIAL_PCH_UART
 	  which is an IOH(Input/Output Hub) for x86 embedded processor.
 	  Enabling PCH_DMA, this PCH UART works as DMA mode.
 
-	  This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
-	  Output Hub), ML7213 and ML7223.
-	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
-	  for MP(Media Phone) use.
-	  ML7213/ML7223 is companion chip for Intel Atom E6xx series.
-	  ML7213/ML7223 is completely compatible for Intel EG20T PCH.
+	  This driver also can be used for LAPIS Semiconductor IOH(Input/
+	  Output Hub), ML7213, ML7223 and ML7831.
+	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+	  for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+	  ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+	  ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
 
 config SERIAL_MSM_SMD
 	bool "Enable tty device interface for some SMD ports"
drivers/tty/serial/pch_uart.c +8 -0
index 2f07a67..2ef0e7d 100644
@@ -258,6 +258,8 @@ enum pch_uart_num_t {
 	pch_ml7213_uart2,
 	pch_ml7223_uart0,
 	pch_ml7223_uart1,
+	pch_ml7831_uart0,
+	pch_ml7831_uart1,
 };
 
 static struct pch_uart_driver_data drv_dat[] = {
@@ -270,6 +272,8 @@ static struct pch_uart_driver_data drv_dat[] = {
 	[pch_ml7213_uart2] = {PCH_UART_2LINE, 2},
 	[pch_ml7223_uart0] = {PCH_UART_8LINE, 0},
 	[pch_ml7223_uart1] = {PCH_UART_2LINE, 1},
+	[pch_ml7831_uart0] = {PCH_UART_8LINE, 0},
+	[pch_ml7831_uart1] = {PCH_UART_2LINE, 1},
 };
 
 static unsigned int default_baud = 9600;
@@ -1553,6 +1557,10 @@ static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
 	 .driver_data = pch_ml7223_uart0},
 	{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800D),
 	 .driver_data = pch_ml7223_uart1},
+	{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8811),
+	 .driver_data = pch_ml7831_uart0},
+	{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8812),
+	 .driver_data = pch_ml7831_uart1},
 	{0,},
 };
 
Signature · 1 line
1.7.7.3
#5 lore raw

PATCH 5/13 pch_uart: Change company name OKI SEMICONDUCTOR to LAPIS Semiconductor

In reply to Greg Kroah-Hartman

From: Tomoya MORINAGA <[email protected]>

On October 1 in 2011,
OKI SEMICONDUCTOR Co., Ltd. changed the company name in to LAPIS Semiconductor Co., Ltd.

---
 drivers/tty/serial/pch_uart.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/tty/serial/pch_uart.c +3 -3
index 2ef0e7d..ac852b5 100644
@@ -1,5 +1,5 @@
 /*
- *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
  *
  *This program is free software; you can redistribute it and/or modify
  *it under the terms of the GNU General Public License as published by
@@ -46,8 +46,8 @@ enum {
 
 /* Set the max number of UART port
  * Intel EG20T PCH: 4 port
- * OKI SEMICONDUCTOR ML7213 IOH: 3 port
- * OKI SEMICONDUCTOR ML7223 IOH: 2 port
+ * LAPIS Semiconductor ML7213 IOH: 3 port
+ * LAPIS Semiconductor ML7223 IOH: 2 port
 */
 #define PCH_UART_NR	4
 
Signature · 1 line
1.7.7.3
#6 lore raw

PATCH 6/13 tty/serial: Prevent drop of DCD on suspend for Tegra UARTs

In reply to Greg Kroah-Hartman

From: Doug Anderson <[email protected]>

On Tegra UARTs (except UART1), the DTR / DCD / DSR lines are not externally accessible. Instead, the DTR line internally appears to be looped back to be the input to the DCD and DSR lines. The net effect of this is that when we drop DTR (like when we suspend), we'll see DCD drop too. ...and when we see DCD drop, we treat that as a hangup.

In order to prevent this hangup from occurring at every sleep, we need to force DTR to remain high on Tegra UARTs.

This patch uses the mcr_mask / mcr_force fields, which were originally added for the kludge ALPHA_KLUDGE_MCR. Using these fields does not prevent us from removing ALPHA_KLUDGE_MCR--we can just remove the "if" tests I have added and always init mcr_mask / mcr_force from the serial8250_config.

NOTE: If we have people that are using UARTA on a Tegra and need to control DTR, we'll need to either add a separate port type for UARTA or we'll need to add some tegra-specific code to detect whether the DTR needs to be left high.

---
 drivers/tty/serial/8250.c |   14 ++++++++++++++
 drivers/tty/serial/8250.h |    2 ++
 2 files changed, 16 insertions(+), 0 deletions(-)
drivers/tty/serial/8250.c +14 -0
index eeadf1b..2b0a4b6 100644
@@ -308,6 +308,8 @@ static const struct serial8250_config uart_config[] = {
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
 				  UART_FCR_T_TRIG_01,
 		.flags		= UART_CAP_FIFO | UART_CAP_RTOIE,
+		.mcr_mask	= ~UART_MCR_DTR,
+		.mcr_force	= UART_MCR_DTR,
 	},
 	[PORT_XR17D15X] = {
 		.name		= "XR17D15X",
@@ -1229,6 +1231,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
 	up->port.fifosize = uart_config[up->port.type].fifo_size;
 	up->capabilities = uart_config[up->port.type].flags;
 	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
+	if (!ALPHA_KLUDGE_MCR) {
+		up->mcr_mask = uart_config[up->port.type].mcr_mask;
+		up->mcr_force = uart_config[up->port.type].mcr_force;
+	}
 
 	if (up->port.type == PORT_UNKNOWN)
 		goto out;
@@ -1987,6 +1993,10 @@ static int serial8250_startup(struct uart_port *port)
 	up->port.fifosize = uart_config[up->port.type].fifo_size;
 	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
 	up->capabilities = uart_config[up->port.type].flags;
+	if (!ALPHA_KLUDGE_MCR) {
+		up->mcr_mask = uart_config[up->port.type].mcr_mask;
+		up->mcr_force = uart_config[up->port.type].mcr_force;
+	}
 	up->mcr = 0;
 
 	if (up->port.iotype != up->cur_iotype)
@@ -2793,6 +2803,10 @@ serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
 	up->port.fifosize = uart_config[type].fifo_size;
 	up->capabilities = uart_config[type].flags;
 	up->tx_loadsz = uart_config[type].tx_loadsz;
+	if (!ALPHA_KLUDGE_MCR) {
+		up->mcr_mask = uart_config[type].mcr_mask;
+		up->mcr_force = uart_config[type].mcr_force;
+	}
 }
 
 static void __init
drivers/tty/serial/8250.h +2 -0
index 6edf4a6..1f75100 100644
@@ -35,6 +35,8 @@ struct serial8250_config {
 	unsigned short	tx_loadsz;
 	unsigned char	fcr;
 	unsigned int	flags;
+	unsigned char	mcr_mask;
+	unsigned char	mcr_force;
 };
 
 #define UART_CAP_FIFO	(1 << 8)	/* UART has FIFO */
Signature · 1 line
1.7.7.3
#7 lore raw

PATCH 7/13 serial,mfd: Fix CMSPAR setup

In reply to Greg Kroah-Hartman

From: Alan Cox <[email protected]>

This is referenced the wrong way. Mika Westerberg added some checks to the tty to support multiple console, but the real problem is simply referencing the termios object via the wrong path.

---
 drivers/tty/serial/mfd.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)
drivers/tty/serial/mfd.c +1 -3
index 286c386..e272d39 100644
@@ -884,7 +884,6 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
 {
 	struct uart_hsu_port *up =
 			container_of(port, struct uart_hsu_port, port);
-	struct tty_struct *tty = port->state->port.tty;
 	unsigned char cval, fcr = 0;
 	unsigned long flags;
 	unsigned int baud, quot;
@@ -907,8 +906,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
 	}
 
 	/* CMSPAR isn't supported by this driver */
-	if (tty)
-		tty->termios->c_cflag &= ~CMSPAR;
+	termios->c_cflag &= ~CMSPAR;
 
 	if (termios->c_cflag & CSTOPB)
 		cval |= UART_LCR_STOP;
Signature · 1 line
1.7.7.3
#8 lore raw

PATCH 8/13 pch_uart: Fix DMA resource leak issue

In reply to Greg Kroah-Hartman

From: Tomoya MORINAGA <[email protected]>

Changing UART mode PIO->DMA->PIO->DMA like below, pch_uart driver can't get DMA channel resource.

setserial /dev/ttyPCH0 ^low_latency
setserial /dev/ttyPCH0 low_latency

CAUSE:
Changing mode using setserial command, ".startup" function which gets DMA channel is called before ".verify_port" function which sets dma-flag(use_dma/use_dma_flag) as 1.

PIO->DMA
.startup: Since dma-flag is 0, DMA channel is not requested. .verify_port: dma-flag is set as 1.
.shutdown: N/A

DMA->PIO
.startup: Since dma-flag is 1, DMA channel is requested. .verify_port: dma-flag is set as 0.
.shutdown: Since dma-flag is 0, DMA channel is not released.

This means DMA channel resource leak occurs.
Next time, this driver can't get DMA channel resource forever.

MODIFICATION:
Currently, when release DMA channel resource, this driver checks dma-flag. However, this specification occurs the above issue.
This driver must check whether dma_request_channel is executed or not. The values are saved in private data variable "chan_tx/chan_tx". These variables mean if the value is NULL, DMA channel is not requested, if not NULL, DMA channel is requested.

This patch fixes the issue.

---
 drivers/tty/serial/pch_uart.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/tty/serial/pch_uart.c +2 -2
index ac852b5..d6aba8c 100644
@@ -632,6 +632,7 @@ static void pch_request_dma(struct uart_port *port)
 		dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n",
 			__func__);
 		dma_release_channel(priv->chan_tx);
+		priv->chan_tx = NULL;
 		return;
 	}
 
@@ -1219,8 +1220,7 @@ static void pch_uart_shutdown(struct uart_port *port)
 		dev_err(priv->port.dev,
 			"pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
 
-	if (priv->use_dma_flag)
-		pch_free_dma(port);
+	pch_free_dma(port);
 
 	free_irq(priv->port.irq, priv);
 }
Signature · 1 line
1.7.7.3
#9 lore raw

PATCH 9/13 RS485: fix inconsistencies in the meaning of some variables

In reply to Greg Kroah-Hartman

From: Claudio Scordino <[email protected]>

The crisv10.c and the atmel_serial.c serial drivers intepret the fields of the serial_rs485 structure in a different way.

In particular, crisv10.c uses SER_RS485_RTS_AFTER_SEND and SER_RS485_RTS_ON_SEND for the voltage of the RTS pin; atmel_serial.c, instead, uses these values to know if a delay must be set before and after sending. This patch makes the usage of these variables consistent across all drivers and fixes the Documentation as well.

Quoted 1 line

From now on, SER_RS485_RTS_AFTER_SEND and SER_RS485_RTS_ON_SEND will be

used to set the voltage of the RTS pin (as in the crisv10.c driver); the delay will be understood by looking only at the value of delay_rts_before_send and delay_rts_after_send.

---
 Documentation/serial/serial-rs485.txt |   14 +++++++++++---
 drivers/tty/serial/atmel_serial.c     |   16 +++-------------
 drivers/tty/serial/crisv10.c          |   10 ++--------
 include/linux/serial.h                |   14 ++++++++------
 4 files changed, 24 insertions(+), 30 deletions(-)
Documentation/serial/serial-rs485.txt +11 -3
index 079cb3d..41c8378 100644
@@ -97,15 +97,23 @@
 
 	struct serial_rs485 rs485conf;
 
-	/* Set RS485 mode: */
+	/* Enable RS485 mode: */
 	rs485conf.flags |= SER_RS485_ENABLED;
 
+	/* Set logical level for RTS pin equal to 1 when sending: */
+	rs485conf.flags |= SER_RS485_RTS_ON_SEND;
+	/* or, set logical level for RTS pin equal to 0 when sending: */
+	rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
+
+	/* Set logical level for RTS pin equal to 1 after sending: */
+	rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
+	/* or, set logical level for RTS pin equal to 0 after sending: */
+	rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
+
 	/* Set rts delay before send, if needed: */
-	rs485conf.flags |= SER_RS485_RTS_BEFORE_SEND;
 	rs485conf.delay_rts_before_send = ...;
 
 	/* Set rts delay after send, if needed: */
-	rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
 	rs485conf.delay_rts_after_send = ...;
 
 	/* Set this flag if you want to receive data even whilst sending data */
drivers/tty/serial/atmel_serial.c +3 -13
index 4a0f86f..4c823f3 100644
@@ -228,7 +228,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
 	if (rs485conf->flags & SER_RS485_ENABLED) {
 		dev_dbg(port->dev, "Setting UART to RS485\n");
 		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
-		if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
+		if ((rs485conf->delay_rts_after_send) > 0)
 			UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
 		mode |= ATMEL_US_USMODE_RS485;
 	} else {
@@ -304,7 +304,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
 
 	if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
 		dev_dbg(port->dev, "Setting UART to RS485\n");
-		if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+		if ((atmel_port->rs485.delay_rts_after_send) > 0)
 			UART_PUT_TTGR(port,
 					atmel_port->rs485.delay_rts_after_send);
 		mode |= ATMEL_US_USMODE_RS485;
@@ -1228,7 +1228,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
 
 	if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
 		dev_dbg(port->dev, "Setting UART to RS485\n");
-		if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+		if ((atmel_port->rs485.delay_rts_after_send) > 0)
 			UART_PUT_TTGR(port,
 					atmel_port->rs485.delay_rts_after_send);
 		mode |= ATMEL_US_USMODE_RS485;
@@ -1447,16 +1447,6 @@ static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
 		rs485conf->delay_rts_after_send = rs485_delay[1];
 		rs485conf->flags = 0;
 
-		if (rs485conf->delay_rts_before_send == 0 &&
-		    rs485conf->delay_rts_after_send == 0) {
-			rs485conf->flags |= SER_RS485_RTS_ON_SEND;
-		} else {
-			if (rs485conf->delay_rts_before_send)
-				rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND;
-			if (rs485conf->delay_rts_after_send)
-				rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
-		}
-
 		if (of_get_property(np, "rs485-rx-during-tx", NULL))
 			rs485conf->flags |= SER_RS485_RX_DURING_TX;
 
drivers/tty/serial/crisv10.c +2 -8
index b743504..1dfba7b 100644
@@ -3234,9 +3234,8 @@ rs_write(struct tty_struct *tty,
 		e100_disable_rx(info);
 		e100_enable_rx_irq(info);
 #endif
-		if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) &&
-			(info->rs485.delay_rts_before_send > 0))
-				msleep(info->rs485.delay_rts_before_send);
+		if (info->rs485.delay_rts_before_send > 0)
+			msleep(info->rs485.delay_rts_before_send);
 	}
 #endif /* CONFIG_ETRAX_RS485 */
 
@@ -3693,10 +3692,6 @@ rs_ioctl(struct tty_struct *tty,
 
 		rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send;
 		rs485data.flags = 0;
-		if (rs485data.delay_rts_before_send != 0)
-			rs485data.flags |= SER_RS485_RTS_BEFORE_SEND;
-		else
-			rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
 
 		if (rs485ctrl.enabled)
 			rs485data.flags |= SER_RS485_ENABLED;
@@ -4531,7 +4526,6 @@ static int __init rs_init(void)
 		/* Set sane defaults */
 		info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND);
 		info->rs485.flags |= SER_RS485_RTS_AFTER_SEND;
-		info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
 		info->rs485.delay_rts_before_send = 0;
 		info->rs485.flags &= ~(SER_RS485_ENABLED);
 #endif
include/linux/serial.h +8 -6
index 97ff8e2..3d86517 100644
@@ -207,13 +207,15 @@ struct serial_icounter_struct {
 
 struct serial_rs485 {
 	__u32	flags;			/* RS485 feature flags */
-#define SER_RS485_ENABLED		(1 << 0)
-#define SER_RS485_RTS_ON_SEND		(1 << 1)
-#define SER_RS485_RTS_AFTER_SEND	(1 << 2)
-#define SER_RS485_RTS_BEFORE_SEND	(1 << 3)
+#define SER_RS485_ENABLED		(1 << 0)	/* If enabled */
+#define SER_RS485_RTS_ON_SEND		(1 << 1)	/* Logical level for
+							   RTS pin when
+							   sending */
+#define SER_RS485_RTS_AFTER_SEND	(1 << 2)	/* Logical level for
+							   RTS pin after sent*/
 #define SER_RS485_RX_DURING_TX		(1 << 4)
-	__u32	delay_rts_before_send;	/* Milliseconds */
-	__u32	delay_rts_after_send;	/* Milliseconds */
+	__u32	delay_rts_before_send;	/* Delay before send (milliseconds) */
+	__u32	delay_rts_after_send;	/* Delay after send (milliseconds) */
 	__u32	padding[5];		/* Memory is cheap, new structs
 					   are a royal PITA .. */
 };
Signature · 1 line
1.7.7.3
#10 lore raw

PATCH 10/13 Revert "tty/serial: Prevent drop of DCD on suspend for Tegra UARTs"

In reply to Greg Kroah-Hartman

This reverts commit 9636b755da7b498094bdf15b4ce9f6fd16995e4e.

It wasn't supposed to be applied, thanks to Doug for letting me know.

---
 drivers/tty/serial/8250.c |   14 --------------
 drivers/tty/serial/8250.h |    2 --
 2 files changed, 0 insertions(+), 16 deletions(-)
drivers/tty/serial/8250.c +0 -14
index 2b0a4b6..eeadf1b 100644
@@ -308,8 +308,6 @@ static const struct serial8250_config uart_config[] = {
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
 				  UART_FCR_T_TRIG_01,
 		.flags		= UART_CAP_FIFO | UART_CAP_RTOIE,
-		.mcr_mask	= ~UART_MCR_DTR,
-		.mcr_force	= UART_MCR_DTR,
 	},
 	[PORT_XR17D15X] = {
 		.name		= "XR17D15X",
@@ -1231,10 +1229,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
 	up->port.fifosize = uart_config[up->port.type].fifo_size;
 	up->capabilities = uart_config[up->port.type].flags;
 	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
-	if (!ALPHA_KLUDGE_MCR) {
-		up->mcr_mask = uart_config[up->port.type].mcr_mask;
-		up->mcr_force = uart_config[up->port.type].mcr_force;
-	}
 
 	if (up->port.type == PORT_UNKNOWN)
 		goto out;
@@ -1993,10 +1987,6 @@ static int serial8250_startup(struct uart_port *port)
 	up->port.fifosize = uart_config[up->port.type].fifo_size;
 	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
 	up->capabilities = uart_config[up->port.type].flags;
-	if (!ALPHA_KLUDGE_MCR) {
-		up->mcr_mask = uart_config[up->port.type].mcr_mask;
-		up->mcr_force = uart_config[up->port.type].mcr_force;
-	}
 	up->mcr = 0;
 
 	if (up->port.iotype != up->cur_iotype)
@@ -2803,10 +2793,6 @@ serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
 	up->port.fifosize = uart_config[type].fifo_size;
 	up->capabilities = uart_config[type].flags;
 	up->tx_loadsz = uart_config[type].tx_loadsz;
-	if (!ALPHA_KLUDGE_MCR) {
-		up->mcr_mask = uart_config[type].mcr_mask;
-		up->mcr_force = uart_config[type].mcr_force;
-	}
 }
 
 static void __init
drivers/tty/serial/8250.h +0 -2
index 1f75100..6edf4a6 100644
@@ -35,8 +35,6 @@ struct serial8250_config {
 	unsigned short	tx_loadsz;
 	unsigned char	fcr;
 	unsigned int	flags;
-	unsigned char	mcr_mask;
-	unsigned char	mcr_force;
 };
 
 #define UART_CAP_FIFO	(1 << 8)	/* UART has FIFO */
Signature · 1 line
1.7.7.3
#11 lore raw

PATCH 11/13 TTY: ldisc, allow waiting for ldisc arbitrarily long

In reply to Greg Kroah-Hartman

From: Jiri Slaby <[email protected]>

To fix a nasty bug in ldisc hup vs. reinit we need to wait infinitely long for ldisc to be gone. So here we add a parameter to tty_ldisc_wait_idle to allow that.

This is only a preparation for the real fix which is done in the following patches.

Cc Dave Young <[email protected]>
Cc Dave Jones <[email protected]>
Cc Ben Hutchings <[email protected]>
Cc Dmitriy Matrosov <[email protected]>
Cc Alan Cox <[email protected]>
Cc stable <[email protected]>
---
 drivers/tty/tty_ldisc.c |   11 ++++++-----
 1 files changed, 6 insertions(+), 5 deletions(-)
drivers/tty/tty_ldisc.c +6 -5
index 512c49f..534d176 100644
@@ -547,15 +547,16 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
 /**
  *	tty_ldisc_wait_idle	-	wait for the ldisc to become idle
  *	@tty: tty to wait for
+ *	@timeout: for how long to wait at most
  *
  *	Wait for the line discipline to become idle. The discipline must
  *	have been halted for this to guarantee it remains idle.
  */
-static int tty_ldisc_wait_idle(struct tty_struct *tty)
+static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
 {
-	int ret;
+	long ret;
 	ret = wait_event_timeout(tty_ldisc_idle,
-			atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
+			atomic_read(&tty->ldisc->users) == 1, timeout);
 	if (ret < 0)
 		return ret;
 	return ret > 0 ? 0 : -EBUSY;
@@ -665,7 +666,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
 	tty_ldisc_flush_works(tty);
 
-	retval = tty_ldisc_wait_idle(tty);
+	retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 
 	tty_lock();
 	mutex_lock(&tty->ldisc_mutex);
@@ -762,7 +763,7 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
 	if (IS_ERR(ld))
 		return -1;
 
-	WARN_ON_ONCE(tty_ldisc_wait_idle(tty));
+	WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ));
 
 	tty_ldisc_close(tty, tty->ldisc);
 	tty_ldisc_put(tty->ldisc);
Signature · 1 line
1.7.7.3
#12 lore raw

PATCH 12/13 TTY: ldisc, move wait idle to caller

In reply to Greg Kroah-Hartman

From: Jiri Slaby <[email protected]>

It is the only place where reinit is called from. And we really need to wait for the old ldisc to go once. Actually this is the place where the waiting originally was (before removed and re-added later).

This will make the fix in the following patch easier to implement.

Cc Dave Young <[email protected]>
Cc Dave Jones <[email protected]>
Cc Ben Hutchings <[email protected]>
Cc Dmitriy Matrosov <[email protected]>
Cc Alan Cox <[email protected]>
Cc stable <[email protected]>
---
 drivers/tty/tty_ldisc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/tty/tty_ldisc.c +2 -2
index 534d176..a69a755 100644
@@ -763,8 +763,6 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
 	if (IS_ERR(ld))
 		return -1;
 
-	WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ));
-
 	tty_ldisc_close(tty, tty->ldisc);
 	tty_ldisc_put(tty->ldisc);
 	tty->ldisc = NULL;
@@ -848,6 +846,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 	   it means auditing a lot of other paths so this is
 	   a FIXME */
 	if (tty->ldisc) {	/* Not yet closed */
+		WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ));
+
 		if (reset == 0) {
 
 			if (!tty_ldisc_reinit(tty, tty->termios->c_line))
Signature · 1 line
1.7.7.3
#13 lore raw

PATCH 13/13 TTY: ldisc, wait for ldisc infinitely in hangup

In reply to Greg Kroah-Hartman

From: Jiri Slaby <[email protected]>

For /dev/console case, we do not kill all ldisc users. It's due to redirected_tty_write test in __tty_hangup. In that case there still might be a process waiting e.g. in n_tty_read for input.

We wait for such processes to disappear. The problem is that we use a timeout. After this timeout, we continue closing the ldisc and start freeing tty resources. It obviously leads to crashes when the other process is woken.

So to fix this, we wait infinitely before reiniting the ldisc. (The tiocsetd remains untouched -- times out after 5s.)

This is nicely reproducible with this run from shell:
exec 0<>/dev/console 1<>/dev/console 2<>/dev/console
and stopping a getty like:
systemctl stop [email protected]

The crash proper may be produced only under load or with constified timing the same as for 92f6fa09b.

Cc Dave Young <[email protected]>
Cc Dave Jones <[email protected]>
Cc Ben Hutchings <[email protected]>
Cc Dmitriy Matrosov <[email protected]>
Cc Alan Cox <[email protected]>
Cc stable <[email protected]>
---
 drivers/tty/tty_ldisc.c |   19 +++++++++++++++++--
 1 files changed, 17 insertions(+), 2 deletions(-)
drivers/tty/tty_ldisc.c +17 -2
index a69a755..8e0924f 100644
@@ -36,6 +36,7 @@
 
 #include <linux/kmod.h>
 #include <linux/nsproxy.h>
+#include <linux/ratelimit.h>
 
 /*
  *	This guards the refcounted line discipline lists. The lock
@@ -837,7 +838,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 	tty_unlock();
 	cancel_work_sync(&tty->buf.work);
 	mutex_unlock(&tty->ldisc_mutex);
-
+retry:
 	tty_lock();
 	mutex_lock(&tty->ldisc_mutex);
 
@@ -846,7 +847,21 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 	   it means auditing a lot of other paths so this is
 	   a FIXME */
 	if (tty->ldisc) {	/* Not yet closed */
-		WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ));
+		if (atomic_read(&tty->ldisc->users) != 1) {
+			char cur_n[TASK_COMM_LEN], tty_n[64];
+			long timeout = 3 * HZ;
+			tty_unlock();
+
+			while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
+				timeout = MAX_SCHEDULE_TIMEOUT;
+				printk_ratelimited(KERN_WARNING
+					"%s: waiting (%s) for %s took too long, but we keep waiting...\n",
+					__func__, get_task_comm(cur_n, current),
+					tty_name(tty, tty_n));
+			}
+			mutex_unlock(&tty->ldisc_mutex);
+			goto retry;
+		}
 
 		if (reset == 0) {
 
Signature · 1 line
1.7.7.3