-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Kernel level uart fifo control
Background & Motivation
Low-Latency RX Needed for Real-Time Protocols
Many serial UART devices (e.g., 16550A) trigger RX interrupts only when their FIFO reaches a certain threshold (often more than 8 bytes). However, many communication protocols or sensor controls require immediate response to each individual byte received. Delayed interrupts leads to unacceptable latency, breaking protocols that expect immediate responses. The ability to set serial fifo levels is commonly available on modern chipsets. To improve availability of low latency protocols in the linux kernel, it would be beneficial to have a universal API for configuring serial FIFO options/
For example:
The LIN protocol is a low-speed serial communication protocol meant to augment CAN protocol in automotive applications. While initial work to implement the protocol into linux was completed years ago, the slave response mode has never been completely implemented due to the difficulty of achieving latency requirements of the LIN protocol within a linux system.
A discussion on lin-bus implementation in linux highlights the requirements:
"It is necessary to set UART into mode where Rx FIFO is disabled or Rx threshold is set to one. Unfortunately, there is no unified API for this parameter or even its availability which is supported across multiple/all UART drivers implementations."
Current Userspace Implementation for Fifo Size Control via sysfs on 16550 Devices
Yoshihiro Yunomae implemented a user-space interface (ie. /sys/class/tty/ttyS*/rx_trig_bytes) to adjust the RX trigger level in serial devices, enabling select values (eg: 1, 4, 8, or 14 bytes). While this approach successfully implements user-space fifo trigger level control in 16550A-compatible serial devices, implementation in other devices is limited or missing altogether. The current implementation takes advantage of the fact that nearly every 8250-based device after the 16550A uses bits 6 and 7 of the same 'FCR' register to set the RX FIFO trigger level to one of 4 predefined values, in order to offer some degree of control. However, many devices offer further configuration options available with other registers. For example, in addition to the legacy 16550A compatible RX trigger levels, the 16C750 also offers an enhanced 64 byte FIFO mode, which requires setting an additional flag in the FCR[5] as well as the DLAB bit from the LCR[7]. The 16850 offers fully programmable FIFOs(1-127 byte levels) via a completely seperate 'TRG' register.
The diversity of devices represented within the 8250 serial driver core warrants a more flexible approach to FIFO configuration within the tty subsystem. Furthermore, the prevalence of fifo control in serial drivers outside of the 8250 core (such as PL011) warrants extending this interface to the broader tty subsystem. I propose implementing a universal fifo_control callback in the uart_ops to hook into device-specific fifo control functions for each port type which supports . It may be desirable to implement a series of device-specific functions within the tty subsystem to enable setting fifo configuration. Additionally, it may be desirable to disable the FIFO completely (ie. 16450 mode), change the DMA transfer mode to single byte, or set the FIFO timeout where available. Furthermore, many common serial devices which do contain completely programmable FIFOs (eg. the PCI-based WCH384), are currently unsupported in the current sysfs implementation because they are misconfigured. The CH382 is a perfect example, as a 16750-based serial device it SHOULD be supported by the current rx_trig_bytes sysfs interface, but is currently configured as a 16850 which the current rx_trig_bytes does not support.
FIFO Control Scheme Variance
There are considerable implementation differences between how different 16550A-based serial devices implement FIFO control.
| UART Model | FIFO Size (max) | RX Trigger Levels | TX Trigger Levels | Registers Used for FIFO Control | Notes |
|---|---|---|---|---|---|
| 8250 | None | N/A | N/A | N/A | No FIFO support |
| 16450 | None | N/A | N/A | N/A | No FIFO support |
| 16550 | 16 (buggy) | N/A | N/A | FCR exists but doesn't function |
FIFO is broken - not widely used |
| 16550A | 16 | 1, 4, 8, 14 bytes | N/A | FCR[7:6] |
FCR controls FIFO |
| 16650 | 32 | 8, 16, 24, 28 bytes | 16, 8, 24, 30 | FCR |
Tx and Rx programmable FIFOs |
| 16750 | 64 | 1, 4, 8, 14 (legacy) 1, 16, 32, 56 (enhanced) |
N/A | FCR[7:6:5] LCR[7] |
Supports legacy 16 byte FIFO and enhanced 64 byte mode via FCR[5] NOTE: LCR[7] MUST = 1 to enable FCR[5] |
| 16850/16950 | 128 | Fully programmable (1–127 bytes) | Fully programmable (1–127 bytes) | FCRFCTRTRG |
FCTR to select the trigger table TRG to program the FIFO in 'table D' |
Userspace Interface Considerations
Current serial settings such as baudrate, parity, etc, are sent from userspace to the serial subsystem via IOCTL and a termios data struct. However, to avoid implementing a termios3, and to maintain compatability with the current rx_trig_bytes API, we'll implement a series of new sysfs entries, but we'll move everything to the serial_core to keep consistency with other serial sysfs entries.
Reference Documentation
This patch series was designed to work universally, with ANY linux serial device. However, the following datasheets have been specifically used and referenced throughout the design and development of this patch series.
- PC16550D UART Datasheet
- ST16650 UART Datasheet
- TL16C750 UART Datasheet
- XR16C850 UART Datasheet
- PL011 UART Datasheet
- WCH384 UART Datasheet
Sub-issues
Metadata
Metadata
Assignees
Labels
Projects
Status