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

serial: max310x: rework RX interrupt handling

Currently, the RX interrupt logic uses the RXEMPTY interrupt, with the
RXEMPTYINV bit set, which means we get an RX interrupt as soon as the
RX FIFO is non-empty.

However, with the MAX310X having a FIFO of 128 bytes, this makes very
poor use of the FIFO: we trigger an interrupt as soon as the RX FIFO
has one byte, which means a lot of interrupts, each only collecting a
few bytes from the FIFO, causing a significant CPU load.

Instead this commit relies on two other RX interrupt events:

- MAX310X_IRQ_RXFIFO_BIT, which triggers when the RX FIFO has reached
a certain threshold, which we define to be half of the FIFO
size. This ensure we get an interrupt before the RX FIFO fills up.

- MAX310X_LSR_RXTO_BIT, which triggers when the RX FIFO has received
some bytes, and then no more bytes are received for a certain
time. Arbitrarily, this time is defined to the time is takes to
receive 4 characters.

On a Microchip SAMA5D3 platform that is receiving 20 bytes every 16ms
over one MAX310X UART, this patch has allowed to reduce the CPU
consumption of the interrupt handler thread from ~25% to 6-7%.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Link: https://lore.kernel.org/r/20201001074415.349739-1-thomas.petazzoni@bootlin.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Thomas Petazzoni and committed by
Greg Kroah-Hartman
fce3c5c1 85985a3d

+24 -5
+24 -5
drivers/tty/serial/max310x.c
··· 1056 1056 max310x_port_update(port, MAX310X_MODE1_REG, 1057 1057 MAX310X_MODE1_TRNSCVCTRL_BIT, 0); 1058 1058 1059 - /* Configure MODE2 register & Reset FIFOs*/ 1060 - val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT; 1061 - max310x_port_write(port, MAX310X_MODE2_REG, val); 1059 + /* Reset FIFOs */ 1060 + max310x_port_write(port, MAX310X_MODE2_REG, 1061 + MAX310X_MODE2_FIFORST_BIT); 1062 1062 max310x_port_update(port, MAX310X_MODE2_REG, 1063 1063 MAX310X_MODE2_FIFORST_BIT, 0); 1064 1064 ··· 1086 1086 /* Clear IRQ status register */ 1087 1087 max310x_port_read(port, MAX310X_IRQSTS_REG); 1088 1088 1089 - /* Enable RX, TX, CTS change interrupts */ 1090 - val = MAX310X_IRQ_RXEMPTY_BIT | MAX310X_IRQ_TXEMPTY_BIT; 1089 + /* 1090 + * Let's ask for an interrupt after a timeout equivalent to 1091 + * the receiving time of 4 characters after the last character 1092 + * has been received. 1093 + */ 1094 + max310x_port_write(port, MAX310X_RXTO_REG, 4); 1095 + 1096 + /* 1097 + * Make sure we also get RX interrupts when the RX FIFO is 1098 + * filling up quickly, so get an interrupt when half of the RX 1099 + * FIFO has been filled in. 1100 + */ 1101 + max310x_port_write(port, MAX310X_FIFOTRIGLVL_REG, 1102 + MAX310X_FIFOTRIGLVL_RX(MAX310X_FIFO_SIZE / 2)); 1103 + 1104 + /* Enable RX timeout interrupt in LSR */ 1105 + max310x_port_write(port, MAX310X_LSR_IRQEN_REG, 1106 + MAX310X_LSR_RXTO_BIT); 1107 + 1108 + /* Enable LSR, RX FIFO trigger, CTS change interrupts */ 1109 + val = MAX310X_IRQ_LSR_BIT | MAX310X_IRQ_RXFIFO_BIT | MAX310X_IRQ_TXEMPTY_BIT; 1091 1110 max310x_port_write(port, MAX310X_IRQEN_REG, val | MAX310X_IRQ_CTS_BIT); 1092 1111 1093 1112 return 0;