Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: 8250: Provide flag for IER toggling for RS485

For RS485 mode, if SER_RS485_RX_DURING_TX is not available, the
console ->write() callback needs to enable/disable Tx. It does
this by calling the ->rs485_start_tx() and ->rs485_stop_tx()
callbacks. However, some of these callbacks also disable/enable
interrupts and makes power management calls. This causes 2
problems for console writing:

1. A console write can occur in contexts that are illegal for
pm_runtime_*(). It is not even necessary for console writing
to use pm_runtime_*() because a console already does this in
serial8250_console_setup() and serial8250_console_exit().

2. The console ->write() callback already handles
disabling/enabling the interrupts by properly restoring the
previous IER value.

Add an argument @toggle_ier to the ->rs485_start_tx() and
->rs485_stop_tx() callbacks to specify if they may disable/enable
receive interrupts while using pm_runtime_*(). Console writing
will not allow the toggling.

For all call sites other than console writing there is no
functional change.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20250107212702.169493-5-john.ogness@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

John Ogness and committed by
Greg Kroah-Hartman
910ef438 95a1b409

+22 -18
+2 -2
drivers/tty/serial/8250/8250.h
··· 231 231 232 232 int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, 233 233 struct serial_rs485 *rs485); 234 - void serial8250_em485_start_tx(struct uart_8250_port *p); 235 - void serial8250_em485_stop_tx(struct uart_8250_port *p); 234 + void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier); 235 + void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier); 236 236 void serial8250_em485_destroy(struct uart_8250_port *p); 237 237 extern struct serial_rs485 serial8250_em485_supported; 238 238
+2 -2
drivers/tty/serial/8250/8250_bcm2835aux.c
··· 46 46 u32 cntl; 47 47 }; 48 48 49 - static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) 49 + static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up, bool toggle_ier) 50 50 { 51 51 if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { 52 52 struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev); ··· 65 65 serial8250_out_MCR(up, UART_MCR_RTS); 66 66 } 67 67 68 - static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up) 68 + static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up, bool toggle_ier) 69 69 { 70 70 if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) 71 71 serial8250_out_MCR(up, 0);
+1 -1
drivers/tty/serial/8250/8250_omap.c
··· 365 365 366 366 if (up->port.rs485.flags & SER_RS485_ENABLED && 367 367 up->port.rs485_config == serial8250_em485_config) 368 - serial8250_em485_stop_tx(up); 368 + serial8250_em485_stop_tx(up, true); 369 369 } 370 370 371 371 /*
+15 -11
drivers/tty/serial/8250/8250_port.c
··· 578 578 579 579 deassert_rts: 580 580 if (p->em485->tx_stopped) 581 - p->rs485_stop_tx(p); 581 + p->rs485_stop_tx(p, true); 582 582 583 583 return 0; 584 584 } ··· 1398 1398 /** 1399 1399 * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback 1400 1400 * @p: uart 8250 port 1401 + * @toggle_ier: true to allow enabling receive interrupts 1401 1402 * 1402 1403 * Generic callback usable by 8250 uart drivers to stop rs485 transmission. 1403 1404 */ 1404 - void serial8250_em485_stop_tx(struct uart_8250_port *p) 1405 + void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier) 1405 1406 { 1406 1407 unsigned char mcr = serial8250_in_MCR(p); 1407 1408 ··· 1423 1422 if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { 1424 1423 serial8250_clear_and_reinit_fifos(p); 1425 1424 1426 - p->ier |= UART_IER_RLSI | UART_IER_RDI; 1427 - serial_port_out(&p->port, UART_IER, p->ier); 1425 + if (toggle_ier) { 1426 + p->ier |= UART_IER_RLSI | UART_IER_RDI; 1427 + serial_port_out(&p->port, UART_IER, p->ier); 1428 + } 1428 1429 } 1429 1430 } 1430 1431 EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); ··· 1441 1438 serial8250_rpm_get(p); 1442 1439 uart_port_lock_irqsave(&p->port, &flags); 1443 1440 if (em485->active_timer == &em485->stop_tx_timer) { 1444 - p->rs485_stop_tx(p); 1441 + p->rs485_stop_tx(p, true); 1445 1442 em485->active_timer = NULL; 1446 1443 em485->tx_stopped = true; 1447 1444 } ··· 1473 1470 em485->active_timer = &em485->stop_tx_timer; 1474 1471 hrtimer_start(&em485->stop_tx_timer, ns_to_ktime(stop_delay), HRTIMER_MODE_REL); 1475 1472 } else { 1476 - p->rs485_stop_tx(p); 1473 + p->rs485_stop_tx(p, true); 1477 1474 em485->active_timer = NULL; 1478 1475 em485->tx_stopped = true; 1479 1476 } ··· 1562 1559 /** 1563 1560 * serial8250_em485_start_tx() - generic ->rs485_start_tx() callback 1564 1561 * @up: uart 8250 port 1562 + * @toggle_ier: true to allow disabling receive interrupts 1565 1563 * 1566 1564 * Generic callback usable by 8250 uart drivers to start rs485 transmission. 1567 1565 * Assumes that setting the RTS bit in the MCR register means RTS is high. ··· 1570 1566 * stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the 1571 1567 * UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.) 1572 1568 */ 1573 - void serial8250_em485_start_tx(struct uart_8250_port *up) 1569 + void serial8250_em485_start_tx(struct uart_8250_port *up, bool toggle_ier) 1574 1570 { 1575 1571 unsigned char mcr = serial8250_in_MCR(up); 1576 1572 1577 - if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) 1573 + if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && toggle_ier) 1578 1574 serial8250_stop_rx(&up->port); 1579 1575 1580 1576 if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) ··· 1608 1604 if (em485->tx_stopped) { 1609 1605 em485->tx_stopped = false; 1610 1606 1611 - up->rs485_start_tx(up); 1607 + up->rs485_start_tx(up, true); 1612 1608 1613 1609 if (up->port.rs485.delay_rts_before_send > 0) { 1614 1610 em485->active_timer = &em485->start_tx_timer; ··· 3428 3424 3429 3425 if (em485) { 3430 3426 if (em485->tx_stopped) 3431 - up->rs485_start_tx(up); 3427 + up->rs485_start_tx(up, false); 3432 3428 mdelay(port->rs485.delay_rts_before_send); 3433 3429 } 3434 3430 ··· 3466 3462 if (em485) { 3467 3463 mdelay(port->rs485.delay_rts_after_send); 3468 3464 if (em485->tx_stopped) 3469 - up->rs485_stop_tx(up); 3465 + up->rs485_stop_tx(up, false); 3470 3466 } 3471 3467 3472 3468 serial_port_out(port, UART_IER, ier);
+2 -2
include/linux/serial_8250.h
··· 161 161 void (*dl_write)(struct uart_8250_port *up, u32 value); 162 162 163 163 struct uart_8250_em485 *em485; 164 - void (*rs485_start_tx)(struct uart_8250_port *); 165 - void (*rs485_stop_tx)(struct uart_8250_port *); 164 + void (*rs485_start_tx)(struct uart_8250_port *up, bool toggle_ier); 165 + void (*rs485_stop_tx)(struct uart_8250_port *up, bool toggle_ier); 166 166 167 167 /* Serial port overrun backoff */ 168 168 struct delayed_work overrun_backoff;