lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251130104222.63077-6-crescentcy.hsieh@moxa.com>
Date: Sun, 30 Nov 2025 18:41:56 +0800
From: Crescent Hsieh <crescentcy.hsieh@...a.com>
To: gregkh@...uxfoundation.org,
	jirislaby@...nel.org,
	ilpo.jarvinen@...ux.intel.com,
	andy.shevchenko@...il.com
Cc: linux-kernel@...r.kernel.org,
	linux-serial@...r.kernel.org,
	crescentcy.hsieh@...a.com
Subject: [PATCH v1 05/31] serial: 8250_mxupci: enable on-chip software flow control

Extend set_termios() to support on-chip software flow control using the
Enhanced Feature Register (EFR). When IXON/IXOFF is enabled in termios,
EFR[3:0] is configured to enable in-band XON/XOFF flow control.
Corresponding XON1/XOFF1 characters are written via EFR page 0.

This patch also implements throttle() and unthrottle() to handle receive
pause and resume based on software flow control.

Signed-off-by: Crescent Hsieh <crescentcy.hsieh@...a.com>
---
 drivers/tty/serial/8250/8250_mxupci.c | 75 ++++++++++++++++++++++++++-
 1 file changed, 74 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/8250/8250_mxupci.c b/drivers/tty/serial/8250/8250_mxupci.c
index 54e50cd3f472..99bd3e504549 100644
--- a/drivers/tty/serial/8250/8250_mxupci.c
+++ b/drivers/tty/serial/8250/8250_mxupci.c
@@ -45,17 +45,37 @@
 
 /* Enhanced Function Register (EFR) */
 /*
+ * EFR[1:0] - In-Band Receive Flow Control Mode (Compare XON/XOFF):
+ *	00b (0x00) = Disabled
+ *	01b (0x01) = Recognize XON2 & XOFF2 as XOFF character
+ *	10b (0x02) = Recognize XON1 & XOFF1 as XOFF character
+ *	11b (0x03) = Recognize XON1, XON2 & XOFF1, XOFF2 as XOFF character
+ * EFR[3:2] - In-Band Transmit Flow Control Mode (Insert XON/XOFF):
+ *	00b (0x00) = Disabled
+ *	01b (0x04) = Use XON2 & XOFF2 as XOFF character
+ *	10b (0x08) = Use XON1 & XOFF1 as XOFF character
+ *	11b (0x0C) = Use XON1, XON2 & XOFF1, XOFF2 as XOFF character
  * EFR[7:6] - Enhanced Register Page Select:
  *	00b (0x00) = Software flow control characters
  *	01b (0x40) = FIFO trigger level
  *	10b (0x80) = Clock, ID, reset
  *	11b (0xC0) = Alias of Page 2 (same behavior as 10b)
  */
+#define MOXA_UART_EFR_RX_FLOW		0x02	/* Recognize XON1 & XOFF1 as XOFF character */
+#define MOXA_UART_EFR_TX_FLOW		0x08	/* Use XON1 & XOFF1 as XOFF character */
 #define	MOXA_UART_EFR_PAGE_0		0x00	/* Software flow control characters */
 #define	MOXA_UART_EFR_PAGE_1		0x40	/* FIFO trigger level */
 #define	MOXA_UART_EFR_PAGE_2		0x80	/* Clock, ID, reset */
+#define MOXA_UART_EFR_RX_FLOW_MASK	GENMASK(1, 0)
+#define MOXA_UART_EFR_TX_FLOW_MASK	GENMASK(3, 2)
 #define MOXA_UART_EFR_PAGE_MASK		GENMASK(7, 6)
 
+/* Enhanced Registers Page 0 */
+#define MOXA_UART_XON1	0x04
+#define MOXA_UART_XON2	0x05
+#define MOXA_UART_XOFF1	0x06
+#define MOXA_UART_XOFF2	0x07
+
 /* Enhanced Registers Page 1 */
 #define MOXA_UART_RBRTL	0x04	/* Flow Control Low Trigger Level */
 #define MOXA_UART_RBRTH	0x05	/* Flow Control High Trigger Level */
@@ -84,10 +104,11 @@ static void mxupci8250_set_termios(struct uart_port *port, struct ktermios *new,
 	struct uart_8250_port *up = up_to_u8250p(port);
 	struct tty_struct *tty = port->state->port.tty;
 	unsigned int cflag = tty->termios.c_cflag;
+	u8 efr;
 
 	serial8250_do_set_termios(port, new, old);
 
-	up->port.status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
+	up->port.status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS | UPSTAT_AUTOXOFF);
 
 	up->mcr &= ~UART_MCR_AFE;
 
@@ -96,6 +117,31 @@ static void mxupci8250_set_termios(struct uart_port *port, struct ktermios *new,
 		up->port.status |= (UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
 	}
 	serial_out(up, UART_MCR, up->mcr);
+
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+	efr = serial_in(up, UART_EFR);
+	efr &= ~MOXA_UART_EFR_PAGE_MASK;
+	efr |= MOXA_UART_EFR_PAGE_0;
+	serial_out(up, UART_EFR, efr);
+
+	/* Set on-chip software flow control character */
+	serial_out(up, MOXA_UART_XON1, START_CHAR(tty));
+	serial_out(up, MOXA_UART_XON2, START_CHAR(tty));
+	serial_out(up, MOXA_UART_XOFF1, STOP_CHAR(tty));
+	serial_out(up, MOXA_UART_XOFF2, STOP_CHAR(tty));
+
+	efr &= ~(MOXA_UART_EFR_RX_FLOW_MASK | MOXA_UART_EFR_TX_FLOW_MASK);
+
+	if (I_IXON(tty))
+		efr |= MOXA_UART_EFR_RX_FLOW;
+
+	if (I_IXOFF(tty)) {
+		efr |= MOXA_UART_EFR_TX_FLOW;
+		up->port.status |= UPSTAT_AUTOXOFF;
+	}
+	serial_out(up, UART_EFR, efr);
+	serial_out(up, UART_LCR, up->lcr);
 }
 
 static int mxupci8250_startup(struct uart_port *port)
@@ -141,6 +187,31 @@ static void mxupci8250_shutdown(struct uart_port *port)
 	serial8250_do_shutdown(port);
 }
 
+static void mxupci8250_throttle(struct uart_port *port)
+{
+	unsigned long flags;
+
+	uart_port_lock_irqsave(port, &flags);
+
+	port->ops->stop_rx(port);
+
+	uart_port_unlock_irqrestore(port, flags);
+}
+
+static void mxupci8250_unthrottle(struct uart_port *port)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+	unsigned long flags;
+
+	uart_port_lock_irqsave(port, &flags);
+
+	up->ier |= UART_IER_RLSI | UART_IER_RDI;
+	port->read_status_mask |= UART_LSR_DR;
+	serial_out(up, UART_IER, up->ier);
+
+	uart_port_unlock_irqrestore(port, flags);
+}
+
 static int mxupci8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct uart_8250_port up;
@@ -175,6 +246,8 @@ static int mxupci8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
 	up.port.set_termios = mxupci8250_set_termios;
 	up.port.startup = mxupci8250_startup;
 	up.port.shutdown = mxupci8250_shutdown;
+	up.port.throttle = mxupci8250_throttle;
+	up.port.unthrottle = mxupci8250_unthrottle;
 
 	for (i = 0; i < num_ports; i++) {
 		if (serial8250_pci_setup_port(pdev, &up, FL_GET_BASE(FL_BASE2), i * MOXA_UART_OFFSET, 0))
-- 
2.45.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ