diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index 57fc7915adac..43c55cb991a5 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -15,7 +15,6 @@ static void __dma_tx_complete(void *param)
{
struct uart_8250_port *p = param;
struct uart_8250_dma *dma = p->dma;
- struct tty_port *tport = &p->port.state->port;
unsigned long flags;
int ret;
@@ -30,8 +29,7 @@ static void __dma_tx_complete(void *param)
uart_xmit_advance(&p->port, dma->tx_size);
- if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
- uart_write_wakeup(&p->port);
+ uart_write_wakeup_if_needed(&p->port);
ret = serial8250_tx_dma(p);
if (ret || !dma->tx_running)
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 51013dd2d851..477d645be9b0 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1106,8 +1106,7 @@ static void omap_8250_tx_dma_complete(struct uart_8250_port *p)
omap8250_restore_regs(p);
}
- if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
- uart_write_wakeup(&p->port);
+ uart_write_wakeup_if_needed(&p->port);
if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(&p->port)) {
int ret;diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index c0deec0e6af4..0f6613814ce3 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -100,6 +100,11 @@ static inline struct uart_port *uart_port_check(struct uart_state *state)
return state->uart_port;
}
+static bool uart_xmit_writable(const struct uart_state *state)
+{
+ return state->xmit_ready && !state->xmit_blocked;
+}
+
/**
* uart_write_wakeup - schedule write processing
* @port: port to be processed@@ -114,15 +119,77 @@ static inline struct uart_port *uart_port_check(struct uart_state *state)
void uart_write_wakeup(struct uart_port *port)
{
struct uart_state *state = port->state;
+
+ lockdep_assert_held_once(&port->lock);
+
/*
* This means you called this function _after_ the port was
* closed. No cookie for you.
*/
BUG_ON(!state);
+ if (!uart_xmit_writable(state))
+ return;
tty_port_tty_wakeup(&state->port);
}
EXPORT_SYMBOL(uart_write_wakeup);
+/* Publish readiness without releasing any transfer's storage reservation. */
+static void uart_xmit_enable(struct uart_port *port)
+{
+ struct uart_state *state = port->state;
+
+ lockdep_assert_held_once(&port->lock);
+ if (state->xmit_ready)
+ return;
+ state->xmit_ready = true;
+ uart_write_wakeup_if_needed(port);
+}
+
+/**
+ * uart_xmit_block - reserve flushed transmit storage
+ * @port: port whose transmit storage is still in use
+ *
+ * A driver may call this from ->flush_buffer() if DMA still owns the old
+ * transmit data. The logical FIFO has already been emptied, but writers
+ * must not overwrite its storage until uart_xmit_unblock() is called.
+ * write_room() reports zero and write()/put_char() accept no data meanwhile.
+ * Line-discipline write wakeups are deferred until the reservation is released.
+ *
+ * The driver must unblock after retiring the transfer, including on shutdown.
+ * Serial core separately gates writes and wakeups until startup or resume
+ * has made the port ready.
+ * Repeated calls are idempotent, not nested reservations.
+ *
+ * Context: @port->lock held.
+ */
+void uart_xmit_block(struct uart_port *port)
+{
+ lockdep_assert_held_once(&port->lock);
+ port->state->xmit_blocked = true;
+}
+EXPORT_SYMBOL_GPL(uart_xmit_block);
+
+/**
+ * uart_xmit_unblock - release reserved transmit storage and wake writers
+ * @port: port whose storage is available again
+ *
+ * The old transfer must no longer access the FIFO storage, and any required
+ * DMA synchronization must have completed before this call.
+ * Retirement is recorded even while the port is inactive. Writes and wakeups
+ * remain deferred until startup or resume has made the port ready.
+ *
+ * Context: @port->lock held.
+ */
+void uart_xmit_unblock(struct uart_port *port)
+{
+ lockdep_assert_held_once(&port->lock);
+ if (!port->state->xmit_blocked)
+ return;
+ port->state->xmit_blocked = false;
+ uart_write_wakeup(port);
+}
+EXPORT_SYMBOL_GPL(uart_xmit_unblock);
+
static void uart_stop(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;@@ -141,7 +208,10 @@ static void __uart_start(struct uart_state *state)
struct serial_port_device *port_dev;
int err;
- if (!port || port->flags & UPF_DEAD || uart_tx_stopped(port))
+ if (!port || port->flags & UPF_DEAD || uart_tx_stopped(port) || !state->xmit_ready)
+ return;
+ /* High-priority flow-control characters have their own storage. */
+ if (state->xmit_blocked && !port->x_char)
return;
port_dev = port->port_dev;
@@ -375,6 +445,11 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state,
return -EIO;
serial_base_port_startup(uport);
+ scoped_guard(uart_port_lock_irq, uport) {
+ uart_xmit_enable(uport);
+ if (!kfifo_is_empty(&port->xmit_fifo) || uport->x_char)
+ __uart_start(state);
+ }
return 0;
}@@ -397,8 +472,11 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
- if (uport)
+ if (uport) {
+ scoped_guard(uart_port_lock_irq, uport)
+ state->xmit_ready = false;
serial_base_port_shutdown(uport);
+ }
if (tty_port_initialized(port)) {
tty_port_set_initialized(port, false);@@ -593,7 +671,7 @@ static int uart_put_char(struct tty_struct *tty, u8 c)
return 0;
}
- if (port)
+ if (port && uart_xmit_writable(state))
ret = kfifo_put(&state->port.xmit_fifo, c);
uart_port_unlock_deref(port, flags);
return ret;
@@ -624,7 +702,7 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
return 0;
}
- if (port)
+ if (port && uart_xmit_writable(state))
ret = kfifo_in(&state->port.xmit_fifo, buf, count);
__uart_start(state);
@@ -640,7 +718,7 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned int ret;
port = uart_port_ref_lock(state, &flags);
- if (!state->port.xmit_buf)
+ if (!state->port.xmit_buf || !uart_xmit_writable(state))
ret = 0;
else
ret = kfifo_avail(&state->port.xmit_fifo);
@@ -682,8 +760,12 @@ static void uart_flush_buffer(struct tty_struct *tty)
kfifo_reset(&state->port.xmit_fifo);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
+ /* Serialize the wakeup with reservation changes, including another flush. */
+ uart_write_wakeup(port);
uart_port_unlock_deref(port, flags);
- tty_port_tty_wakeup(&state->port);
+
+ /* Drain waiters observe FIFO emptiness, not write readiness. */
+ wake_up_interruptible(&tty->write_wait);
}
/*
@@ -1748,8 +1830,10 @@ static void uart_tty_port_shutdown(struct tty_port *port)
if (WARN(!uport, "detached port still initialized!\n"))
return;
- scoped_guard(uart_port_lock_irq, uport)
+ scoped_guard(uart_port_lock_irq, uport) {
+ state->xmit_ready = false;
uport->ops->stop_rx(uport);
+ }
serial_base_port_shutdown(uport);
uart_port_shutdown(port);@@ -2391,9 +2475,10 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
unsigned int mctrl;
tty_port_set_suspended(port, true);
- tty_port_set_initialized(port, false);
scoped_guard(uart_port_lock_irq, uport) {
+ state->xmit_ready = false;
+ tty_port_set_initialized(port, false);
ops->stop_tx(uport);
if (!(uport->rs485.flags & SER_RS485_ENABLED))
ops->set_mctrl(uport, 0);@@ -2498,8 +2583,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
if (!(uport->rs485.flags & SER_RS485_ENABLED))
ops->set_mctrl(uport, uport->mctrl);
ops->start_tx(uport);
+ tty_port_set_initialized(port, true);
+ uart_xmit_enable(uport);
}
- tty_port_set_initialized(port, true);
} else {
/*
* Failed to resume - maybe hardware went away?diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 4eeb8253752a..2297b870cb86 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -208,8 +208,17 @@ struct gpio_desc;
* Flush any write buffers, reset any DMA state and stop any ongoing DMA
* transfers.
*
- * This will be called whenever the @port->state->xmit circular buffer is
- * cleared.
+ * This is called after the transmit FIFO has been cleared, with @port->lock
+ * still held. A driver whose asynchronous transfer can still access the
+ * flushed storage must call uart_xmit_block() before returning. This keeps
+ * write_room() at zero and prevents write() and put_char() from reusing the
+ * storage until the driver calls uart_xmit_unblock().
+ *
+ * Release the reservation only after the transfer and its callbacks have
+ * retired and any required DMA synchronization has completed. Shutdown must
+ * also retire the transfer and release the reservation before returning,
+ * since serial core then frees the transmit buffer. Serial core separately
+ * gates writes and wakeups until startup or resume has made the port ready.
*
* Locking: @port->lock taken.
* Interrupts: locally disabled.
@@ -834,6 +843,9 @@ enum uart_pm_state {
*/
struct uart_state {
struct tty_port port;
+ /* TX readiness and storage ownership; protected by the UART port lock. */
+ bool xmit_ready;
+ bool xmit_blocked;
enum uart_pm_state pm_state;
@@ -909,6 +921,24 @@ struct uart_driver {
};
void uart_write_wakeup(struct uart_port *port);
+void uart_xmit_block(struct uart_port *port);
+void uart_xmit_unblock(struct uart_port *port);
+
+/**
+ * uart_write_wakeup_if_needed - notify writers when queued output is low
+ * @port: port to be processed
+ *
+ * Keep one-shot write-wakeup notifications pending until fewer than
+ * %WAKEUP_CHARS remain in the transmit FIFO. This also applies to output
+ * retained across suspend and resume.
+ *
+ * Context: @port->lock held.
+ */
+static inline void uart_write_wakeup_if_needed(struct uart_port *port)
+{
+ if (kfifo_len(&port->state->port.xmit_fifo) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
/**
* enum UART_TX_FLAGS -- flags for uart_port_tx_flags()
--
2.53.0