linux-serial.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4]  Rework hw-assisted flow control
@ 2015-01-25 19:44 Peter Hurley
  2015-01-25 19:44 ` [PATCH 1/4] serial: core: Rework hw-assisted flow control support Peter Hurley
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Peter Hurley @ 2015-01-25 19:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-serial, linux-arm-kernel, linux-omap, Jiri Slaby,
	Peter Hurley

Hi Greg,

This patch series re-implements hw-assisted flow control support,
(aka autoRTS, autoCTS and auto XON/XOFF) in the serial core.
Out-of-tree driver maintainers please note this changes the UART
driver interface for flow control steering.

This series separates mode handling from the capabilities flags.
UPF_HARD_FLOW and UPF_SOFT_FLOW continue to indicate the hardware
is capable of hw-assisted flow control; in addition, UPF_HARD_FLOW
is split into separate capabilities (UPF_AUTO_CTS and UPF_AUTO_RTS)
should the driver require the distinction.

However, the serial core only checks UPF_SOFT_FLOW (to determine
if the UART driver is capable of auto XON/XOFF flow control and
thus needs its set_termios() method called).

Flow control steering in the serial core is now determined by
the uart_port::status field, and the newly introduced
UPSTAT_AUTOCTS, UPSTAT_AUTORTS and UPSTAT_AUTOXOFF for
autoCTS tx flow control, autoRTS rx flow control and auto
IXOFF flow control respectively. [Core support for auto IXON did
not seem necessary, as core intervention does not seem required --
please let me know if that's not the case.]

Typically, the driver should set or reset these flags in their
set_termios() method (in the port lock critical section, if
port lock is used), depending on the hardware capabilities and
requirement.

All drivers which enable hardware autoCTS mode MUST set UPSTAT_AUTOCTS
to prevent the serial core from inadvertently disabling tx. In this
mode, hw_stopped = 0 and uart_handle_cts_change() perform no action
(other than bumping the cts stat for diagnostic purposes).

For hardware which does not automatically disable autoRTS mode
when RTS is lowered or otherwise desires to implement
throttle()/unthrottle() methods, the driver MUST set UPSTAT_AUTORTS.
In this mode, the uart driver throttle()/unthrottle() methods
are called, rather than lowering RTS via set_mctrl().

UPSTAT_AUTORTS _must not_ be set for drivers which do not implement
throttle()/unthrottle() methods; in this case, set_mctrl() is still used
to control the RTS pin.

Even for drivers using UPSTAT_AUTORTS, the driver is still responsible
for properly implementing RTS handling in set_mctrl(), regardless of
current termios settings or hardware mode. That is, if the hardware
is capable of driving the RTS pin, the driver's set_mctrl() method
must lower RTS if !TIOCM_RTS. If that requires disabling autoRTS mode,
then that shall be done. The serial core and userspace must be able to
manually flow control with RTS.

When handling set_mctrl(), the driver may check the uart_port::status
UPSTAT_AUTORTS bit to determine if it set autoRTS mode at set_termios(),
and thus whether to restore its autoRTS mode when RTS is raised. In other
words, the driver does not need to set/check its own private state.

All drivers which enable hardware auto IXOFF flow control mode
MUST set UPSTAT_AUTOXOFF. As with UPSTAT_AUTORTS, throttle()/unthrottle()
methods are required. When this mode is set, the core will _not_ send
START/STOP, and expects the driver/hardware to do so.

This patch series converts in-tree drivers to this 'new' interface.

The last patch rips out a private interface hack being used by a
bluetooth host controller driver to tickle RTS for device wakeup;
this is no longer required now that the offending in-tree driver,
omap-serial, properly drives RTS in autoRTS mode.

Regards,

Peter Hurley (4):
  serial: core: Rework hw-assisted flow control support
  serial: 8250_omap: Use UPSTAT_AUTORTS for RTS handling
  serial: omap: Fix RTS handling
  tty: Remove external interface for tty_set_termios()

 drivers/bluetooth/hci_ath.c         | 15 +-------
 drivers/tty/serial/8250/8250_omap.c | 23 ++++++-----
 drivers/tty/serial/omap-serial.c    | 29 +++++++++-----
 drivers/tty/serial/serial_core.c    | 76 ++++++++++++++-----------------------
 drivers/tty/tty_ioctl.c             |  3 +-
 include/linux/serial_core.h         | 21 ++++++++--
 include/linux/tty.h                 |  1 -
 7 files changed, 83 insertions(+), 85 deletions(-)

-- 
2.2.2


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] serial: core: Rework hw-assisted flow control support
  2015-01-25 19:44 [PATCH 0/4] Rework hw-assisted flow control Peter Hurley
@ 2015-01-25 19:44 ` Peter Hurley
  2015-01-25 19:44 ` [PATCH 2/4] serial: 8250_omap: Use UPSTAT_AUTORTS for RTS handling Peter Hurley
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Peter Hurley @ 2015-01-25 19:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-serial, linux-arm-kernel, linux-omap, Jiri Slaby,
	Peter Hurley

hw-assisted flow control support was added to the serial core
in v3.8 with commits,
dba05832cbe4f ("SERIAL: core: add hardware assisted h/w flow control support")
2cbacafd7af0f ("SERIAL: core: add hardware assisted s/w flow control support")
9aba8d5b01119 ("SERIAL: core: add throttle/unthrottle callbacks for hardware
                assisted flow control")
Since then, additional requirements for serial core support have arisen.
Specifically,
1. Separate tx and rx flow control settings for UARTs which only support
   tx flow control (ie., autoCTS).
2. Disable sw-assisted CTS flow control in autoCTS mode
3. Support for RTS flow control by serial core and userspace in autoRTS mode

Distinguish mode from capability; introduce UPSTAT_AUTORTS, UPSTAT_AUTOCTS
and UPSTAT_AUTOXOFF which, when set by the uart driver, enable serial core
support for hw-assisted rx, hw-assisted tx and hw-assisted in-band/IXOFF
rx flow control, respectively. [Note: hw-assisted in-band/IXON tx flow
control does not require serial core support/intervention and can be
enabled by the uart driver when required.]

These modes must be set/reset in the driver's set_termios() method, based
on termios settings, and thus can be safely queried in any context in which
one of the port lock, port mutex or termios rwsem are held. Set these modes
in the 2 in-tree drivers, omap-serial and 8250_omap, which currently
use UPF_HARD_FLOW/UPF_SOFT_FLOW support.

Retain UPF_HARD_FLOW and UPF_SOFT_FLOW as capabilities; re-define
UPF_HARD_FLOW as both UPF_AUTO_RTS and UPF_AUTO_CTS to allow for distinct
and separate rx and tx flow control capabilities.

Disable sw-assisted CTS flow control when UPSTAT_AUTOCTS is enabled.

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
---
 drivers/tty/serial/8250/8250_omap.c |  7 +++-
 drivers/tty/serial/omap-serial.c    |  7 +++-
 drivers/tty/serial/serial_core.c    | 76 ++++++++++++++-----------------------
 include/linux/serial_core.h         | 21 ++++++++--
 4 files changed, 59 insertions(+), 52 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 316c37b..4473881 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -421,8 +421,11 @@ static void omap_8250_set_termios(struct uart_port *port,
 
 	priv->efr = 0;
 	up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY);
+	up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
+
 	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
 		/* Enable AUTORTS and AUTOCTS */
+		up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
 		priv->efr |= UART_EFR_CTS | UART_EFR_RTS;
 	} else	if (up->port.flags & UPF_SOFT_FLOW) {
 		/*
@@ -438,8 +441,10 @@ static void omap_8250_set_termios(struct uart_port *port,
 		 * Enable XON/XOFF flow control on output.
 		 * Transmit XON1, XOFF1
 		 */
-		if (termios->c_iflag & IXOFF)
+		if (termios->c_iflag & IXOFF) {
+			up->port.status |= UPSTAT_AUTOXOFF;
 			priv->efr |= OMAP_UART_SW_TX;
+		}
 
 		/*
 		 * IXANY Flag:
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 2e1073d..b28cdca 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1053,8 +1053,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 
 	serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
 
+	up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
+
 	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
 		/* Enable AUTORTS and AUTOCTS */
+		up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
 		up->efr |= UART_EFR_CTS | UART_EFR_RTS;
 
 		/* Ensure MCR RTS is asserted */
@@ -1081,8 +1084,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 		 * Enable XON/XOFF flow control on output.
 		 * Transmit XON1, XOFF1
 		 */
-		if (termios->c_iflag & IXOFF)
+		if (termios->c_iflag & IXOFF) {
+			up->port.status |= UPSTAT_AUTOXOFF;
 			up->efr |= OMAP_UART_SW_TX;
+		}
 
 		/*
 		 * IXANY Flag:
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 37dc808..a21b15c 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -179,14 +179,6 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
 			if (tty->termios.c_cflag & CBAUD)
 				uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
 		}
-
-		spin_lock_irq(&uport->lock);
-		if (uart_cts_enabled(uport) &&
-		    !(uport->ops->get_mctrl(uport) & TIOCM_CTS))
-			uport->hw_stopped = 1;
-		else
-			uport->hw_stopped = 0;
-		spin_unlock_irq(&uport->lock);
 	}
 
 	/*
@@ -442,6 +434,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
 {
 	struct uart_port *uport = state->uart_port;
 	struct ktermios *termios;
+	int hw_stopped;
 
 	/*
 	 * If we have no tty, termios, or the port does not exist,
@@ -466,6 +459,18 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
 		uport->status &= ~UPSTAT_DCD_ENABLE;
 	else
 		uport->status |= UPSTAT_DCD_ENABLE;
+
+	/* reset sw-assisted CTS flow control based on (possibly) new mode */
+	hw_stopped = uport->hw_stopped;
+	uport->hw_stopped = uart_softcts_mode(uport) &&
+				!(uport->ops->get_mctrl(uport) & TIOCM_CTS);
+	if (uport->hw_stopped) {
+		if (!hw_stopped)
+			uport->ops->stop_tx(uport);
+	} else {
+		if (hw_stopped)
+			__uart_start(tty);
+	}
 	spin_unlock_irq(&uport->lock);
 }
 
@@ -619,22 +624,22 @@ static void uart_throttle(struct tty_struct *tty)
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_port *port = state->uart_port;
-	upf_t mask = 0;
+	upstat_t mask = 0;
 
 	if (I_IXOFF(tty))
-		mask |= UPF_SOFT_FLOW;
+		mask |= UPSTAT_AUTOXOFF;
 	if (tty->termios.c_cflag & CRTSCTS)
-		mask |= UPF_HARD_FLOW;
+		mask |= UPSTAT_AUTORTS;
 
-	if (port->flags & mask) {
+	if (port->status & mask) {
 		port->ops->throttle(port);
-		mask &= ~port->flags;
+		mask &= ~port->status;
 	}
 
-	if (mask & UPF_SOFT_FLOW)
+	if (mask & UPSTAT_AUTOXOFF)
 		uart_send_xchar(tty, STOP_CHAR(tty));
 
-	if (mask & UPF_HARD_FLOW)
+	if (mask & UPSTAT_AUTORTS)
 		uart_clear_mctrl(port, TIOCM_RTS);
 }
 
@@ -642,22 +647,22 @@ static void uart_unthrottle(struct tty_struct *tty)
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_port *port = state->uart_port;
-	upf_t mask = 0;
+	upstat_t mask = 0;
 
 	if (I_IXOFF(tty))
-		mask |= UPF_SOFT_FLOW;
+		mask |= UPSTAT_AUTOXOFF;
 	if (tty->termios.c_cflag & CRTSCTS)
-		mask |= UPF_HARD_FLOW;
+		mask |= UPSTAT_AUTORTS;
 
-	if (port->flags & mask) {
+	if (port->status & mask) {
 		port->ops->unthrottle(port);
-		mask &= ~port->flags;
+		mask &= ~port->status;
 	}
 
-	if (mask & UPF_SOFT_FLOW)
+	if (mask & UPSTAT_AUTOXOFF)
 		uart_send_xchar(tty, START_CHAR(tty));
 
-	if (mask & UPF_HARD_FLOW)
+	if (mask & UPSTAT_AUTORTS)
 		uart_set_mctrl(port, TIOCM_RTS);
 }
 
@@ -1351,30 +1356,6 @@ static void uart_set_termios(struct tty_struct *tty,
 			mask |= TIOCM_RTS;
 		uart_set_mctrl(uport, mask);
 	}
-
-	/*
-	 * If the port is doing h/w assisted flow control, do nothing.
-	 * We assume that port->hw_stopped has never been set.
-	 */
-	if (uport->flags & UPF_HARD_FLOW)
-		return;
-
-	/* Handle turning off CRTSCTS */
-	if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
-		spin_lock_irq(&uport->lock);
-		uport->hw_stopped = 0;
-		__uart_start(tty);
-		spin_unlock_irq(&uport->lock);
-	}
-	/* Handle turning on CRTSCTS */
-	else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
-		spin_lock_irq(&uport->lock);
-		if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
-			uport->hw_stopped = 1;
-			uport->ops->stop_tx(uport);
-		}
-		spin_unlock_irq(&uport->lock);
-	}
 }
 
 /*
@@ -2853,7 +2834,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
 
 	uport->icount.cts++;
 
-	if (uart_cts_enabled(uport)) {
+	if (uart_softcts_mode(uport)) {
 		if (uport->hw_stopped) {
 			if (status) {
 				uport->hw_stopped = 0;
@@ -2866,6 +2847,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
 				uport->ops->stop_tx(uport);
 			}
 		}
+
 	}
 }
 EXPORT_SYMBOL_GPL(uart_handle_cts_change);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index a0c7033..baf3e1d 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -191,8 +191,10 @@ struct uart_port {
 #define UPF_NO_TXEN_TEST	((__force upf_t) (1 << 15))
 #define UPF_MAGIC_MULTIPLIER	((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
 
-/* Port has hardware-assisted h/w flow control (iow, auto-RTS *not* auto-CTS) */
-#define UPF_HARD_FLOW		((__force upf_t) (1 << 21))
+/* Port has hardware-assisted h/w flow control */
+#define UPF_AUTO_CTS		((__force upf_t) (1 << 20))
+#define UPF_AUTO_RTS		((__force upf_t) (1 << 21))
+#define UPF_HARD_FLOW		((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS))
 /* Port has hardware-assisted s/w flow control */
 #define UPF_SOFT_FLOW		((__force upf_t) (1 << 22))
 #define UPF_CONS_FLOW		((__force upf_t) (1 << 23))
@@ -214,11 +216,17 @@ struct uart_port {
 #error Change mask not equivalent to userspace-visible bit defines
 #endif
 
-	/* status must be updated while holding port lock */
+	/*
+	 * Must hold termios_rwsem, port mutex and port lock to change;
+	 * can hold any one lock to read.
+	 */
 	upstat_t		status;
 
 #define UPSTAT_CTS_ENABLE	((__force upstat_t) (1 << 0))
 #define UPSTAT_DCD_ENABLE	((__force upstat_t) (1 << 1))
+#define UPSTAT_AUTORTS		((__force upstat_t) (1 << 2))
+#define UPSTAT_AUTOCTS		((__force upstat_t) (1 << 3))
+#define UPSTAT_AUTOXOFF		((__force upstat_t) (1 << 4))
 
 	int			hw_stopped;		/* sw-assisted CTS flow state */
 	unsigned int		mctrl;			/* current modem ctrl settings */
@@ -392,6 +400,13 @@ static inline bool uart_cts_enabled(struct uart_port *uport)
 	return !!(uport->status & UPSTAT_CTS_ENABLE);
 }
 
+static inline bool uart_softcts_mode(struct uart_port *uport)
+{
+	upstat_t mask = UPSTAT_CTS_ENABLE | UPSTAT_AUTOCTS;
+
+	return ((uport->status & mask) == UPSTAT_CTS_ENABLE);
+}
+
 /*
  * The following are helper functions for the low level drivers.
  */
-- 
2.2.2


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] serial: 8250_omap: Use UPSTAT_AUTORTS for RTS handling
  2015-01-25 19:44 [PATCH 0/4] Rework hw-assisted flow control Peter Hurley
  2015-01-25 19:44 ` [PATCH 1/4] serial: core: Rework hw-assisted flow control support Peter Hurley
@ 2015-01-25 19:44 ` Peter Hurley
  2015-01-25 19:44 ` [PATCH 3/4] serial: omap: Fix " Peter Hurley
       [not found] ` <1422215094-3216-1-git-send-email-peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>
  3 siblings, 0 replies; 6+ messages in thread
From: Peter Hurley @ 2015-01-25 19:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-serial, linux-arm-kernel, linux-omap, Jiri Slaby,
	Peter Hurley

Commit 88838d3112702 ("serial: omap_8250: Fix RTS handling") fixed
RTS pin control when in autoRTS mode.

New support added in "serial: core: Rework hw-assisted flow control support"
enables a much simpler approach; rather than masking out autoRTS
whenever writing the EFR register, use the UPSTAT_* mode to determine if
autoRTS should be enabled when raising RTS (in omap8250_set_mctrl()).

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
---
 drivers/tty/serial/8250/8250_omap.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 4473881..59d6e90 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -120,10 +120,11 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
 	 */
 	lcr = serial_in(up, UART_LCR);
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-	if (mctrl & TIOCM_RTS)
-		serial_out(up, UART_EFR, priv->efr);
+	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+		priv->efr |= UART_EFR_RTS;
 	else
-		serial_out(up, UART_EFR, priv->efr & ~UART_EFR_RTS);
+		priv->efr &= ~UART_EFR_RTS;
+	serial_out(up, UART_EFR, priv->efr);
 	serial_out(up, UART_LCR, lcr);
 }
 
@@ -272,10 +273,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 	serial_dl_write(up, priv->quot);
 
-	if (up->port.mctrl & TIOCM_RTS)
-		serial_out(up, UART_EFR, priv->efr);
-	else
-		serial_out(up, UART_EFR, priv->efr & ~UART_EFR_RTS);
+	serial_out(up, UART_EFR, priv->efr);
 
 	/* Configure flow control */
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -424,9 +422,9 @@ static void omap_8250_set_termios(struct uart_port *port,
 	up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
 
 	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
-		/* Enable AUTORTS and AUTOCTS */
+		/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
 		up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
-		priv->efr |= UART_EFR_CTS | UART_EFR_RTS;
+		priv->efr |= UART_EFR_CTS;
 	} else	if (up->port.flags & UPF_SOFT_FLOW) {
 		/*
 		 * IXON Flag:
-- 
2.2.2


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] serial: omap: Fix RTS handling
  2015-01-25 19:44 [PATCH 0/4] Rework hw-assisted flow control Peter Hurley
  2015-01-25 19:44 ` [PATCH 1/4] serial: core: Rework hw-assisted flow control support Peter Hurley
  2015-01-25 19:44 ` [PATCH 2/4] serial: 8250_omap: Use UPSTAT_AUTORTS for RTS handling Peter Hurley
@ 2015-01-25 19:44 ` Peter Hurley
       [not found] ` <1422215094-3216-1-git-send-email-peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>
  3 siblings, 0 replies; 6+ messages in thread
From: Peter Hurley @ 2015-01-25 19:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-serial, linux-arm-kernel, linux-omap, Jiri Slaby,
	Peter Hurley

The OMAP UART ignores MCR[1] (ie., RTS) when in autoRTS mode. This
makes it impossible for either the serial core or userspace to
manually flow control the sender.

Disable autoRTS mode when RTS is lowered and restore the previous
mode when RTS is raised.

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
---
 drivers/tty/serial/omap-serial.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index b28cdca..e01b65e 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -681,7 +681,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
 static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 	struct uart_omap_port *up = to_uart_omap_port(port);
-	unsigned char mcr = 0, old_mcr;
+	unsigned char mcr = 0, old_mcr, lcr;
 
 	dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
 	if (mctrl & TIOCM_RTS)
@@ -701,6 +701,17 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
 		     UART_MCR_DTR | UART_MCR_RTS);
 	up->mcr = old_mcr | mcr;
 	serial_out(up, UART_MCR, up->mcr);
+
+	/* Turn off autoRTS if RTS is lowered; restore autoRTS if RTS raised */
+	lcr = serial_in(up, UART_LCR);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+		up->efr |= UART_EFR_RTS;
+	else
+		up->efr &= UART_EFR_RTS;
+	serial_out(up, UART_EFR, up->efr);
+	serial_out(up, UART_LCR, lcr);
+
 	pm_runtime_mark_last_busy(up->dev);
 	pm_runtime_put_autosuspend(up->dev);
 }
@@ -756,8 +767,6 @@ static int serial_omap_startup(struct uart_port *port)
 	 * (they will be reenabled in set_termios())
 	 */
 	serial_omap_clear_fifos(up);
-	/* For Hardware flow control */
-	serial_out(up, UART_MCR, UART_MCR_RTS);
 
 	/*
 	 * Clear the interrupt registers.
@@ -1056,12 +1065,9 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
 
 	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
-		/* Enable AUTORTS and AUTOCTS */
+		/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
 		up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
-		up->efr |= UART_EFR_CTS | UART_EFR_RTS;
-
-		/* Ensure MCR RTS is asserted */
-		up->mcr |= UART_MCR_RTS;
+		up->efr |= UART_EFR_CTS;
 	} else {
 		/* Disable AUTORTS and AUTOCTS */
 		up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
-- 
2.2.2


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] tty: Remove external interface for tty_set_termios()
       [not found] ` <1422215094-3216-1-git-send-email-peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>
@ 2015-01-25 19:44   ` Peter Hurley
  2015-01-25 20:36     ` Marcel Holtmann
  0 siblings, 1 reply; 6+ messages in thread
From: Peter Hurley @ 2015-01-25 19:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Jiri Slaby, Peter Hurley,
	Marcel Holtmann, Johan Hedberg,
	linux-bluetooth-u79uwXL29TY76Z2rM5mHXA

tty_set_termios() is an internal helper intended for file scope use.

UART drivers which are capable of driving the RTS pin must
properly handle the tiocmset() method, regardless of termios settings.
A failure to do so is a UART driver bug and should be fixed there.
Do not use this interface to workaround UART driver bugs.

Cc: Marcel Holtmann <marcel-kz+m5ild9QBg9hUCZPvPmw@public.gmane.org>
Cc: Johan Hedberg <johan.hedberg-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: <linux-bluetooth-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Signed-off-by: Peter Hurley <peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>
---
 drivers/bluetooth/hci_ath.c | 15 ++-------------
 drivers/tty/tty_ioctl.c     |  3 +--
 include/linux/tty.h         |  1 -
 3 files changed, 3 insertions(+), 16 deletions(-)

diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 2ff6dfd..9c4dcf4 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -51,33 +51,22 @@ struct ath_struct {
 
 static int ath_wakeup_ar3k(struct tty_struct *tty)
 {
-	struct ktermios ktermios;
 	int status = tty->driver->ops->tiocmget(tty);
 
 	if (status & TIOCM_CTS)
 		return status;
 
-	/* Disable Automatic RTSCTS */
-	ktermios = tty->termios;
-	ktermios.c_cflag &= ~CRTSCTS;
-	tty_set_termios(tty, &ktermios);
-
 	/* Clear RTS first */
-	status = tty->driver->ops->tiocmget(tty);
+	tty->driver->ops->tiocmget(tty);
 	tty->driver->ops->tiocmset(tty, 0x00, TIOCM_RTS);
 	mdelay(20);
 
 	/* Set RTS, wake up board */
-	status = tty->driver->ops->tiocmget(tty);
+	tty->driver->ops->tiocmget(tty);
 	tty->driver->ops->tiocmset(tty, TIOCM_RTS, 0x00);
 	mdelay(20);
 
 	status = tty->driver->ops->tiocmget(tty);
-
-	/* Enable Automatic RTSCTS */
-	ktermios.c_cflag |= CRTSCTS;
-	status = tty_set_termios(tty, &ktermios);
-
 	return status;
 }
 
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index d73f695..69fc0b8 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -533,7 +533,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
  *	Locking: termios_rwsem
  */
 
-int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
+static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
 {
 	struct ktermios old_termios;
 	struct tty_ldisc *ld;
@@ -566,7 +566,6 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
 	up_write(&tty->termios_rwsem);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(tty_set_termios);
 
 /**
  *	set_termios		-	set termios values for a tty
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 0992238..8c316b6 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -491,7 +491,6 @@ static inline speed_t tty_get_baud_rate(struct tty_struct *tty)
 
 extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
 extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
-extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
 
 extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
 extern void tty_ldisc_deref(struct tty_ldisc *);
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 4/4] tty: Remove external interface for tty_set_termios()
  2015-01-25 19:44   ` [PATCH 4/4] tty: Remove external interface for tty_set_termios() Peter Hurley
@ 2015-01-25 20:36     ` Marcel Holtmann
  0 siblings, 0 replies; 6+ messages in thread
From: Marcel Holtmann @ 2015-01-25 20:36 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Greg Kroah-Hartman, linux-serial, linux-arm-kernel, linux-omap,
	Jiri Slaby, Johan Hedberg, linux-bluetooth

Hi Peter,

> tty_set_termios() is an internal helper intended for file scope use.
> 
> UART drivers which are capable of driving the RTS pin must
> properly handle the tiocmset() method, regardless of termios settings.
> A failure to do so is a UART driver bug and should be fixed there.
> Do not use this interface to workaround UART driver bugs.
> 
> Cc: Marcel Holtmann <marcel@holtmann.org>
> Cc: Johan Hedberg <johan.hedberg@gmail.com>
> Cc: <linux-bluetooth@vger.kernel.org>
> Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
> ---
> drivers/bluetooth/hci_ath.c | 15 ++-------------
> drivers/tty/tty_ioctl.c     |  3 +--
> include/linux/tty.h         |  1 -
> 3 files changed, 3 insertions(+), 16 deletions(-)

I think the less complication is if this goes through the TTY tree.

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-01-25 20:36 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-25 19:44 [PATCH 0/4] Rework hw-assisted flow control Peter Hurley
2015-01-25 19:44 ` [PATCH 1/4] serial: core: Rework hw-assisted flow control support Peter Hurley
2015-01-25 19:44 ` [PATCH 2/4] serial: 8250_omap: Use UPSTAT_AUTORTS for RTS handling Peter Hurley
2015-01-25 19:44 ` [PATCH 3/4] serial: omap: Fix " Peter Hurley
     [not found] ` <1422215094-3216-1-git-send-email-peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>
2015-01-25 19:44   ` [PATCH 4/4] tty: Remove external interface for tty_set_termios() Peter Hurley
2015-01-25 20:36     ` Marcel Holtmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).