Add mxpcie8250_rx_chars() to retrieve data from the Rx FIFO via
memory-mapped FIFO access, using the UART-specific FIFO byte counter
and FIFO memory region.
This avoids per-byte I/O reads through serial_in(), improving receive
throughput on Moxa PCIe UART devices. For break and error conditions,
the handler falls back to serial8250_rx_chars() to retain standard
error handling logic.
Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
drivers/tty/serial/8250/8250_mxpcie.c | 37 +++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index fe2906d16d80..cf519960d5d1 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/tty_flip.h>
#include <linux/8250_pci.h>
#include "8250.h"
@@ -35,6 +36,7 @@
/* UART */
#define MOXA_PUART_BASE_BAUD 921600
#define MOXA_PUART_OFFSET 0x200
+#define MOXA_PUART_FIFO_SIZE 128
/* Special Function Register (SFR) */
#define MOXA_PUART_SFR 0x07
@@ -70,6 +72,9 @@
#define MOXA_PUART_RTL 0x11 /* Rx Interrupt Trigger Level */
#define MOXA_PUART_FCL 0x12 /* Flow Control Low Trigger Level */
#define MOXA_PUART_FCH 0x13 /* Flow Control High Trigger Level */
+#define MOXA_PUART_RX_FIFO_CNT 0x15 /* Rx FIFO Data Counter */
+
+#define MOXA_PUART_RX_FIFO_MEM 0x100 /* Memory Space to Rx FIFO Data Register */
#define MOXA_GPIO_DIRECTION 0x09
#define MOXA_GPIO_OUTPUT 0x0A
@@ -253,6 +258,30 @@ static void mxpcie8250_unthrottle(struct uart_port *port)
uart_port_unlock_irqrestore(port, flags);
}
+static void mxpcie8250_rx_chars(struct uart_8250_port *up)
+{
+ struct uart_port *port = &up->port;
+ struct tty_port *tport = &port->state->port;
+ int recv_room, gdl, i;
+ u8 buf[MOXA_PUART_FIFO_SIZE];
+
+ recv_room = tty_buffer_request_room(tport, port->fifosize);
+
+ if (recv_room) {
+ gdl = serial_in(up, MOXA_PUART_RX_FIFO_CNT);
+
+ if (gdl > recv_room)
+ gdl = recv_room;
+
+ for (i = 0; i < gdl; ++i)
+ buf[i] = *(port->membase + MOXA_PUART_RX_FIFO_MEM + i);
+
+ port->icount.rx += gdl;
+ tty_insert_flip_string(tport, buf, gdl);
+ tty_flip_buffer_push(tport);
+ }
+}
+
static int mxpcie8250_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -275,8 +304,12 @@ static int mxpcie8250_handle_irq(struct uart_port *port)
!(port->read_status_mask & UART_LSR_DR))
skip_rx = true;
- if (lsr & (UART_LSR_DR | UART_LSR_BI) && !skip_rx)
- lsr = serial8250_rx_chars(up, lsr);
+ if (lsr & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
+ if (lsr & UART_LSR_BRK_ERROR_BITS)
+ lsr = serial8250_rx_chars(up, lsr);
+ else
+ mxpcie8250_rx_chars(up);
+ }
serial8250_modem_status(up);
--
2.45.2