Skip to content

Commit 7c62218

Browse files
l1kgregkh
authored andcommitted
serial: core: Initialize rs485 RTS polarity already on probe
commit 2dd8a74 upstream. RTS polarity of rs485-enabled ports is currently initialized on uart open via: tty_port_open() tty_port_block_til_ready() tty_port_raise_dtr_rts() # if (C_BAUD(tty)) uart_dtr_rts() uart_port_dtr_rts() There's at least three problems here: First, if no baud rate is set, RTS polarity is not initialized. That's the right thing to do for rs232, but not for rs485, which requires that RTS is deasserted unconditionally. Second, if the DeviceTree property "linux,rs485-enabled-at-boot-time" is present, RTS should be deasserted as early as possible, i.e. on probe. Otherwise it may remain asserted until first open. Third, even though RTS is deasserted on open and close, it may subsequently be asserted by uart_throttle(), uart_unthrottle() or uart_set_termios() because those functions aren't rs485-aware. (Only uart_tiocmset() is.) To address these issues, move RTS initialization from uart_port_dtr_rts() to uart_configure_port(). Prevent subsequent modification of RTS polarity by moving the existing rs485 check from uart_tiocmget() to uart_update_mctrl(). That way, RTS is initialized on probe and then remains unmodified unless the uart transmits data. If rs485 is enabled at runtime (instead of at boot) through a TIOCSRS485 ioctl(), RTS is initialized by the uart driver's ->rs485_config() callback and then likewise remains unmodified. The PL011 driver initializes RTS on uart open and prevents subsequent modification in its ->set_mctrl() callback. That code is obsoleted by the present commit, so drop it. Cc: Jan Kiszka <[email protected]> Cc: Su Bao Cheng <[email protected]> Signed-off-by: Lukas Wunner <[email protected]> Link: https://lore.kernel.org/r/2d2acaf3a69e89b7bf687c912022b11fd29dfa1e.1642909284.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8e57da5 commit 7c62218

File tree

2 files changed

+13
-36
lines changed

2 files changed

+13
-36
lines changed

drivers/tty/serial/amba-pl011.c

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,13 +1620,6 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
16201620
container_of(port, struct uart_amba_port, port);
16211621
unsigned int cr;
16221622

1623-
if (port->rs485.flags & SER_RS485_ENABLED) {
1624-
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
1625-
mctrl &= ~TIOCM_RTS;
1626-
else
1627-
mctrl |= TIOCM_RTS;
1628-
}
1629-
16301623
cr = pl011_read(uap, REG_CR);
16311624

16321625
#define TIOCMBIT(tiocmbit, uartbit) \
@@ -1850,14 +1843,8 @@ static int pl011_startup(struct uart_port *port)
18501843
cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
18511844
cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
18521845

1853-
if (port->rs485.flags & SER_RS485_ENABLED) {
1854-
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
1855-
cr &= ~UART011_CR_RTS;
1856-
else
1857-
cr |= UART011_CR_RTS;
1858-
} else {
1846+
if (!(port->rs485.flags & SER_RS485_ENABLED))
18591847
cr |= UART011_CR_TXE;
1860-
}
18611848

18621849
pl011_write(cr, uap, REG_CR);
18631850

drivers/tty/serial/serial_core.c

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
144144
unsigned long flags;
145145
unsigned int old;
146146

147+
if (port->rs485.flags & SER_RS485_ENABLED) {
148+
set &= ~TIOCM_RTS;
149+
clear &= ~TIOCM_RTS;
150+
}
151+
147152
spin_lock_irqsave(&port->lock, flags);
148153
old = port->mctrl;
149154
port->mctrl = (old & ~clear) | set;
@@ -157,23 +162,10 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
157162

158163
static void uart_port_dtr_rts(struct uart_port *uport, int raise)
159164
{
160-
int rs485_on = uport->rs485_config &&
161-
(uport->rs485.flags & SER_RS485_ENABLED);
162-
int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND);
163-
164-
if (raise) {
165-
if (rs485_on && RTS_after_send) {
166-
uart_set_mctrl(uport, TIOCM_DTR);
167-
uart_clear_mctrl(uport, TIOCM_RTS);
168-
} else {
169-
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
170-
}
171-
} else {
172-
unsigned int clear = TIOCM_DTR;
173-
174-
clear |= (!rs485_on || RTS_after_send) ? TIOCM_RTS : 0;
175-
uart_clear_mctrl(uport, clear);
176-
}
165+
if (raise)
166+
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
167+
else
168+
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
177169
}
178170

179171
/*
@@ -1089,11 +1081,6 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
10891081
goto out;
10901082

10911083
if (!tty_io_error(tty)) {
1092-
if (uport->rs485.flags & SER_RS485_ENABLED) {
1093-
set &= ~TIOCM_RTS;
1094-
clear &= ~TIOCM_RTS;
1095-
}
1096-
10971084
uart_update_mctrl(uport, set, clear);
10981085
ret = 0;
10991086
}
@@ -2408,6 +2395,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
24082395
*/
24092396
spin_lock_irqsave(&port->lock, flags);
24102397
port->mctrl &= TIOCM_DTR;
2398+
if (port->rs485.flags & SER_RS485_ENABLED &&
2399+
!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
2400+
port->mctrl |= TIOCM_RTS;
24112401
port->ops->set_mctrl(port, port->mctrl);
24122402
spin_unlock_irqrestore(&port->lock, flags);
24132403

0 commit comments

Comments
 (0)