In the Linux kernel, the tty driver interface for UART devices is abstracted by the serial core API. The serial core supplies the tty driver implementation and, in turn, defines a set of control methods to be implemented by the UART driver. The control methods, along with other details of the serial core API, are defined in include/linux/serial_core.h and briefly documented in Documentation/serial/driver .
The UART driver methods used by the serial core to manage output flow control are:
void start_tx(struct uart_port *) void stop_tx(struct uart_port *)
If only that were true. While
stop_tx() is straightforward to implement, the serial core leaves much to the UART driver to determine what action(s) should be taken when the
start_tx() method is called. The table below summarizes the appropriate action(s).
||Transmit the 1-byte value in x_char, regardless of any other state. Only required if the UART driver does not define a
||Flow is stopped. Do not transmit data in the tx ring buffer. Turn off the transmitter or, at least, disable further tx interrupts.|
||No data to transmit; disable further tx interrupts.|
The serial core does not maintain or track the ‘transmitter enabled’ state. In practice, this means the
start_tx()/stop_tx() interface is asymmetric; that is, the serial core calls
start_tx() if the transmitter may need to be on and only calls
stop_tx() if the transmitter should be off.
The serial core also expects the UART driver to automatically turn off the transmitter (or disable further tx ints) if conditions dictate, such as if the tx ring buffer is empty. For example, the 8250 UART driver evaluates the conditions and auto-stops transmission from its interrupt handler:
serial8250_default_handle_irq serial8250_handle_irq ... if (transmitter holding register empty) serial8520_tx_chars if (port->x_char != 0) transmit x_char return if (uart_tx_stopped(port)) stop transmitter return if (uart_circ_empty(xmit)) disable further THRE ints return transmit data if (uart_circ_empty(xmit)) disable further THRE ints
As of Linux kernel v3.15, the serial core calls
start_tx() even if there is no data in the tx ring buffer. This is a bug fix to accommodate hardware which does actually stop the transmitter in its
stop_tx() method (rather than just disabling the THRE interrupt), and thus may have an empty ring buffer while data may still be in the transmitter. Seth Bollinger points out,
Any window, however small, could leave bytes stuck in the transmitter
forever — particularly if there will be no further transmission until
receiving a response.
Out-of-tree UART drivers should be reviewed to verify that transmit is not attempted if the tx ring buffer is empty (other than for sending x_char).
If the UART driver does not define a
send_xchar() method, the UART driver’s
start_tx() method must cause the byte value in
port->x_char to be transmitted, if non-zero. After the x_char is sent,
port->x_char must be reset to 0. The UART driver should strive to send the x_char as soon as possible, preferably before any data already in the tx ring buffer. If possible, DMA drivers should stop in-progress DMA, transmit the x_char, and restart DMA. The reference UART driver, amba-pl011.c , uses this scheme when operating in DMA mode.
x_char must be sent regardless of the flow control state. Conversely, sending x_char must not cause data in the tx ring buffer to be sent if flow is off; ie., if
uart_tx_stopped(port). Sending x_char should also not cause a write wakeup.
A standalone unit test for a UART driver’s x_char handling is available for download below. Instructions for compiling, using, and diagnosing are included in the file.