Skip to content

Commit 2c1fd53

Browse files
miroslav-ondragregkh
authored andcommitted
serial: amba-pl011: Fix RTS handling in RS485 mode
Data loss on serial line was observed during communication through serial ports ttyAMA1 and ttyAMA2 interconnected via RS485 transcievers. Both ports are in one BCM2711 (Compute Module CM40) and they share the same interrupt line. The problem is caused by long waiting for tx queue flush in the function pl011_rs485_tx_stop. Udelay or mdelay are used to wait. The function is called from the interrupt handler. If multiple devices share a single interrupt line, late processing of pending interrupts and data loss may occur. When operation of both devices are synchronous, collisions are quite often. This rework is based on the method used in tty/serial/imx.c Use hrtimer instead of udelay and mdelay calls. Replace simple bool variable rs485_tx_started by 4-state variable rs485_tx_state. Tested-by: Lino Sanfilippo <[email protected]> Signed-off-by: Miroslav Ondra <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b3ee0bc commit 2c1fd53

File tree

1 file changed

+96
-30
lines changed

1 file changed

+96
-30
lines changed

drivers/tty/serial/amba-pl011.c

Lines changed: 96 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,13 @@ struct pl011_dmatx_data {
248248
bool queued;
249249
};
250250

251+
enum pl011_rs485_tx_state {
252+
OFF,
253+
WAIT_AFTER_RTS,
254+
SEND,
255+
WAIT_AFTER_SEND,
256+
};
257+
251258
/*
252259
* We wrap our port structure around the generic uart_port.
253260
*/
@@ -261,8 +268,10 @@ struct uart_amba_port {
261268
unsigned int fifosize; /* vendor-specific */
262269
unsigned int fixed_baud; /* vendor-set fixed baud rate */
263270
char type[12];
264-
bool rs485_tx_started;
265-
unsigned int rs485_tx_drain_interval; /* usecs */
271+
ktime_t rs485_tx_drain_interval; /* nano */
272+
enum pl011_rs485_tx_state rs485_tx_state;
273+
struct hrtimer trigger_start_tx;
274+
struct hrtimer trigger_stop_tx;
266275
#ifdef CONFIG_DMA_ENGINE
267276
/* DMA stuff */
268277
unsigned int dmacr; /* dma control reg */
@@ -1260,30 +1269,31 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
12601269

12611270
static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
12621271
{
1263-
/*
1264-
* To be on the safe side only time out after twice as many iterations
1265-
* as fifo size.
1266-
*/
1267-
const int MAX_TX_DRAIN_ITERS = uap->port.fifosize * 2;
12681272
struct uart_port *port = &uap->port;
1269-
int i = 0;
12701273
u32 cr;
12711274

1272-
/* Wait until hardware tx queue is empty */
1273-
while (!pl011_tx_empty(port)) {
1274-
if (i > MAX_TX_DRAIN_ITERS) {
1275-
dev_warn(port->dev,
1276-
"timeout while draining hardware tx queue\n");
1277-
break;
1278-
}
1275+
if (uap->rs485_tx_state == SEND)
1276+
uap->rs485_tx_state = WAIT_AFTER_SEND;
12791277

1280-
udelay(uap->rs485_tx_drain_interval);
1281-
i++;
1278+
if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
1279+
/* Schedule hrtimer if tx queue not empty */
1280+
if (!pl011_tx_empty(port)) {
1281+
hrtimer_start(&uap->trigger_stop_tx,
1282+
uap->rs485_tx_drain_interval,
1283+
HRTIMER_MODE_REL);
1284+
return;
1285+
}
1286+
if (port->rs485.delay_rts_after_send > 0) {
1287+
hrtimer_start(&uap->trigger_stop_tx,
1288+
ms_to_ktime(port->rs485.delay_rts_after_send),
1289+
HRTIMER_MODE_REL);
1290+
return;
1291+
}
1292+
/* Continue without any delay */
1293+
} else if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
1294+
hrtimer_try_to_cancel(&uap->trigger_start_tx);
12821295
}
12831296

1284-
if (port->rs485.delay_rts_after_send)
1285-
mdelay(port->rs485.delay_rts_after_send);
1286-
12871297
cr = pl011_read(uap, REG_CR);
12881298

12891299
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
@@ -1296,19 +1306,26 @@ static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
12961306
cr |= UART011_CR_RXE;
12971307
pl011_write(cr, uap, REG_CR);
12981308

1299-
uap->rs485_tx_started = false;
1309+
uap->rs485_tx_state = OFF;
13001310
}
13011311

13021312
static void pl011_stop_tx(struct uart_port *port)
13031313
{
13041314
struct uart_amba_port *uap =
13051315
container_of(port, struct uart_amba_port, port);
13061316

1317+
if (port->rs485.flags & SER_RS485_ENABLED &&
1318+
uap->rs485_tx_state == WAIT_AFTER_RTS) {
1319+
pl011_rs485_tx_stop(uap);
1320+
return;
1321+
}
1322+
13071323
uap->im &= ~UART011_TXIM;
13081324
pl011_write(uap->im, uap, REG_IMSC);
13091325
pl011_dma_tx_stop(uap);
13101326

1311-
if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
1327+
if (port->rs485.flags & SER_RS485_ENABLED &&
1328+
uap->rs485_tx_state != OFF)
13121329
pl011_rs485_tx_stop(uap);
13131330
}
13141331

@@ -1328,10 +1345,19 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
13281345
struct uart_port *port = &uap->port;
13291346
u32 cr;
13301347

1348+
if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
1349+
uap->rs485_tx_state = SEND;
1350+
return;
1351+
}
1352+
if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
1353+
hrtimer_try_to_cancel(&uap->trigger_stop_tx);
1354+
uap->rs485_tx_state = SEND;
1355+
return;
1356+
}
1357+
/* uap->rs485_tx_state == OFF */
13311358
/* Enable transmitter */
13321359
cr = pl011_read(uap, REG_CR);
13331360
cr |= UART011_CR_TXE;
1334-
13351361
/* Disable receiver if half-duplex */
13361362
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
13371363
cr &= ~UART011_CR_RXE;
@@ -1343,10 +1369,14 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
13431369

13441370
pl011_write(cr, uap, REG_CR);
13451371

1346-
if (port->rs485.delay_rts_before_send)
1347-
mdelay(port->rs485.delay_rts_before_send);
1348-
1349-
uap->rs485_tx_started = true;
1372+
if (port->rs485.delay_rts_before_send > 0) {
1373+
uap->rs485_tx_state = WAIT_AFTER_RTS;
1374+
hrtimer_start(&uap->trigger_start_tx,
1375+
ms_to_ktime(port->rs485.delay_rts_before_send),
1376+
HRTIMER_MODE_REL);
1377+
} else {
1378+
uap->rs485_tx_state = SEND;
1379+
}
13501380
}
13511381

13521382
static void pl011_start_tx(struct uart_port *port)
@@ -1355,13 +1385,44 @@ static void pl011_start_tx(struct uart_port *port)
13551385
container_of(port, struct uart_amba_port, port);
13561386

13571387
if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
1358-
!uap->rs485_tx_started)
1388+
uap->rs485_tx_state != SEND) {
13591389
pl011_rs485_tx_start(uap);
1390+
if (uap->rs485_tx_state == WAIT_AFTER_RTS)
1391+
return;
1392+
}
13601393

13611394
if (!pl011_dma_tx_start(uap))
13621395
pl011_start_tx_pio(uap);
13631396
}
13641397

1398+
static enum hrtimer_restart pl011_trigger_start_tx(struct hrtimer *t)
1399+
{
1400+
struct uart_amba_port *uap =
1401+
container_of(t, struct uart_amba_port, trigger_start_tx);
1402+
unsigned long flags;
1403+
1404+
uart_port_lock_irqsave(&uap->port, &flags);
1405+
if (uap->rs485_tx_state == WAIT_AFTER_RTS)
1406+
pl011_start_tx(&uap->port);
1407+
uart_port_unlock_irqrestore(&uap->port, flags);
1408+
1409+
return HRTIMER_NORESTART;
1410+
}
1411+
1412+
static enum hrtimer_restart pl011_trigger_stop_tx(struct hrtimer *t)
1413+
{
1414+
struct uart_amba_port *uap =
1415+
container_of(t, struct uart_amba_port, trigger_stop_tx);
1416+
unsigned long flags;
1417+
1418+
uart_port_lock_irqsave(&uap->port, &flags);
1419+
if (uap->rs485_tx_state == WAIT_AFTER_SEND)
1420+
pl011_rs485_tx_stop(uap);
1421+
uart_port_unlock_irqrestore(&uap->port, flags);
1422+
1423+
return HRTIMER_NORESTART;
1424+
}
1425+
13651426
static void pl011_stop_rx(struct uart_port *port)
13661427
{
13671428
struct uart_amba_port *uap =
@@ -1953,7 +2014,7 @@ static void pl011_shutdown(struct uart_port *port)
19532014

19542015
pl011_dma_shutdown(uap);
19552016

1956-
if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
2017+
if ((port->rs485.flags & SER_RS485_ENABLED && uap->rs485_tx_state != OFF))
19572018
pl011_rs485_tx_stop(uap);
19582019

19592020
free_irq(uap->port.irq, uap);
@@ -2098,7 +2159,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
20982159
* with the given baud rate. We use this as the poll interval when we
20992160
* wait for the tx queue to empty.
21002161
*/
2101-
uap->rs485_tx_drain_interval = DIV_ROUND_UP(bits * 1000 * 1000, baud);
2162+
uap->rs485_tx_drain_interval = ns_to_ktime(DIV_ROUND_UP(bits * NSEC_PER_SEC, baud));
21022163

21032164
pl011_setup_status_masks(port, termios);
21042165

@@ -2807,6 +2868,11 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
28072868
}
28082869
}
28092870

2871+
hrtimer_init(&uap->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
2872+
hrtimer_init(&uap->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
2873+
uap->trigger_start_tx.function = pl011_trigger_start_tx;
2874+
uap->trigger_stop_tx.function = pl011_trigger_stop_tx;
2875+
28102876
ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
28112877
if (ret)
28122878
return ret;

0 commit comments

Comments
 (0)