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: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251130104222.63077-25-crescentcy.hsieh@moxa.com>
Date: Sun, 30 Nov 2025 18:42:15 +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 24/31] serial: 8250_mxupci: defer uart_write_wakeup to workqueue

When the TX FIFO drops below WAKEUP_CHARS, mxpcie used to call
uart_write_wakeup() directly from the interrupt path. Move this into a
per-port work item so we avoid doing TTY wakeups in interrupt context and
reduce IRQ-side work.

Changes:
- Add per-port state (event_flags, work, cached uport pointer).
- In tx_chars(), set a TXLOW event and schedule the per-port work instead
  of calling uart_write_wakeup() directly.
- The work handler test-and-clear the TXLOW bit and calls
  uart_write_wakeup().

This keeps IRQ handlers lightweight and avoids potential locking or RT
latency issues while preserving existing behavior.

Note: removal path must cancel pending works before unregistering ports.

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

diff --git a/drivers/tty/serial/8250/8250_mxupci.c b/drivers/tty/serial/8250/8250_mxupci.c
index 15565729b7e4..a19880b99236 100644
--- a/drivers/tty/serial/8250/8250_mxupci.c
+++ b/drivers/tty/serial/8250/8250_mxupci.c
@@ -86,9 +86,14 @@
 #define MOXA_UART_RBRTI	0x06	/* Rx Interrupt Trigger Level */
 #define MOXA_UART_THRTL	0x07	/* Tx Interrupt Trigger Level */
 
+#define MOXA_EVENT_TXLOW BIT(0)
+
 struct mxupci8250_port {
 	int line;
+	unsigned long event_flags;
 	u8 rx_trig_level;
+	struct uart_port *uport;
+	struct work_struct work;
 };
 
 struct mxupci8250 {
@@ -251,6 +256,8 @@ static void mxupci8250_tx_chars(struct uart_8250_port *up)
 {
 	struct uart_port *port = &up->port;
 	struct tty_port *tport = &port->state->port;
+	struct pci_dev *pdev = to_pci_dev(port->dev);
+	struct mxupci8250 *priv = pci_get_drvdata(pdev);
 	unsigned int count, i;
 	unsigned char c;
 
@@ -271,9 +278,10 @@ static void mxupci8250_tx_chars(struct uart_8250_port *up)
 
 		serial_out(up, UART_TX, c);
 	}
-	if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
-		uart_write_wakeup(port);
-
+	if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) {
+		if (!test_and_set_bit(MOXA_EVENT_TXLOW, &priv->port[port->port_id].event_flags))
+			schedule_work(&priv->port[port->port_id].work);
+	}
 	if (kfifo_is_empty(&tport->xmit_fifo) && !(up->capabilities & UART_CAP_RPM))
 		port->ops->stop_tx(port);
 }
@@ -353,9 +361,19 @@ static int mxupci8250_get_rxtrig(struct uart_port *port)
 	return priv->port[port->port_id].rx_trig_level;
 }
 
+static void mxupci8250_work_handler(struct work_struct *work)
+{
+	struct mxupci8250_port *priv_port = container_of(work, struct mxupci8250_port, work);
+
+	if (test_and_clear_bit(MOXA_EVENT_TXLOW, &priv_port->event_flags))
+		uart_write_wakeup(priv_port->uport);
+
+}
+
 static int mxupci8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct uart_8250_port up;
+	struct uart_8250_port *new_port;
 	struct mxupci8250 *priv;
 	unsigned int i, num_ports;
 	int ret;
@@ -409,7 +427,12 @@ static int mxupci8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
 				up.port.iotype, priv->port[i].line);
 			break;
 		}
+		new_port = serial8250_get_port(priv->port[i].line);
+
 		priv->port[i].rx_trig_level = 96;
+		priv->port[i].uport = &new_port->port;
+
+		INIT_WORK(&priv->port[i].work, mxupci8250_work_handler);
 	}
 	pci_set_drvdata(pdev, priv);
 
@@ -421,8 +444,10 @@ static void mxupci8250_remove(struct pci_dev *pdev)
 	struct mxupci8250 *priv = pci_get_drvdata(pdev);
 	unsigned int i;
 
-	for (i = 0; i < priv->num_ports; i++)
+	for (i = 0; i < priv->num_ports; i++) {
+		cancel_work_sync(&priv->port[i].work);
 		serial8250_unregister_port(priv->port[i].line);
+	}
 }
 
 static const struct pci_device_id mxupci8250_pci_ids[] = {
-- 
2.45.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ