* [PATCH 1/5] tty: serial: samsung: fix TX kfifo underflow on flush
2026-10-31 12:39 ` [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers Samarth Narang
@ 2026-10-31 12:39 ` Samarth Narang
2026-10-31 12:39 ` [PATCH 2/5] serial: tegra: don't advance the TX kfifo for a flushed transfer Samarth Narang
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Samarth Narang @ 2026-10-31 12:39 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Samarth Narang, Krzysztof Kozlowski, Peter Griffin, Alim Akhtar,
Marek Szyprowski, Laxman Dewangan, Thierry Reding,
Jonathan Hunter, Orson Zhai, Baolin Wang, Chunyan Zhang,
linux-serial, linux-samsung-soc, linux-arm-msm, linux-tegra,
linux-arm-kernel, linux-kernel
uart_flush_buffer() resets the transmit kfifo under the port lock before
calling the driver's flush_buffer() hook. Since samsung_tty does not
implement this hook, an outstanding TX DMA transfer may complete after
the flush and call uart_xmit_advance() using the old transfer's byte
count. This can advance the kfifo tail past its head, causing
kfifo_len() to wrap and the driver to transmit stale buffer contents.
The same issue was addressed in 8250 by commit 9e512eaaf8f4 ("serial:
8250: Fix fifo underflow on flush").
Add a flush_buffer() hook that terminates the outstanding TX DMA
transfer and clears tx_in_progress. Since the TX buffer remains mapped
while the port is open, DMA synchronization is not required before
returning from the hook.
A completion that is already running when the flush occurs may have
calculated its byte count before taking the port lock, so it must skip
the kfifo update if the transfer has since been retired by either
flush_buffer() or stop_tx(), which already advances the kfifo itself.
Fixes: 29bef7990845 ("serial: samsung: add DMA support for TX")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Samarth Narang <samarth.colleges@gmail.com>
---
drivers/tty/serial/samsung_tty.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 640f85e2d636..2bea7ef078d2 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -317,6 +317,20 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
ourport->tx_mode = 0;
}
+static void s3c24xx_serial_flush_buffer(struct uart_port *port)
+{
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+
+ if (!dma || !dma->tx_chan || ourport->tx_in_progress != S3C24XX_TX_DMA)
+ return;
+
+ /* The kfifo has been reset: the completion must not advance it */
+ dmaengine_terminate_async(dma->tx_chan);
+ async_tx_ack(dma->tx_desc);
+ ourport->tx_in_progress = 0;
+}
+
static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
static void s3c24xx_serial_tx_dma_complete(void *args)
@@ -339,6 +353,12 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
uart_port_lock_irqsave(port, &flags);
+ /* Already retired by stop_tx or flush_buffer */
+ if (ourport->tx_in_progress != S3C24XX_TX_DMA) {
+ uart_port_unlock_irqrestore(port, flags);
+ return;
+ }
+
uart_xmit_advance(port, count);
ourport->tx_in_progress = 0;
@@ -1682,6 +1702,7 @@ static const struct uart_ops s3c64xx_serial_ops = {
.get_mctrl = s3c24xx_serial_get_mctrl,
.set_mctrl = s3c24xx_serial_set_mctrl,
.stop_tx = s3c24xx_serial_stop_tx,
+ .flush_buffer = s3c24xx_serial_flush_buffer,
.start_tx = s3c24xx_serial_start_tx,
.stop_rx = s3c24xx_serial_stop_rx,
.break_ctl = s3c24xx_serial_break_ctl,
@@ -1703,6 +1724,7 @@ static const struct uart_ops apple_s5l_serial_ops = {
.get_mctrl = s3c24xx_serial_get_mctrl,
.set_mctrl = s3c24xx_serial_set_mctrl,
.stop_tx = s3c24xx_serial_stop_tx,
+ .flush_buffer = s3c24xx_serial_flush_buffer,
.start_tx = s3c24xx_serial_start_tx,
.stop_rx = s3c24xx_serial_stop_rx,
.break_ctl = s3c24xx_serial_break_ctl,
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 2/5] serial: tegra: don't advance the TX kfifo for a flushed transfer
2026-10-31 12:39 ` [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers Samarth Narang
2026-10-31 12:39 ` [PATCH 1/5] tty: serial: samsung: fix TX kfifo underflow on flush Samarth Narang
@ 2026-10-31 12:39 ` Samarth Narang
2026-10-31 12:39 ` [PATCH 3/5] serial: sprd: fix TX kfifo underflow on flush Samarth Narang
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Samarth Narang @ 2026-10-31 12:39 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Samarth Narang, Krzysztof Kozlowski, Peter Griffin, Alim Akhtar,
Marek Szyprowski, Laxman Dewangan, Thierry Reding,
Jonathan Hunter, Orson Zhai, Baolin Wang, Chunyan Zhang,
linux-serial, linux-samsung-soc, linux-arm-msm, linux-tegra,
linux-arm-kernel, linux-kernel
tegra_uart_flush_buffer() terminates the TX DMA transfer after the
serial core has reset the transmit kfifo, but leaves tx_in_progress set.
A completion callback that was already running may have calculated its
byte count from tx_bytes_requested before acquiring the port lock,
allowing it to call uart_xmit_advance() on the reset kfifo after the
flush. This can advance the kfifo tail past its head, causing
kfifo_len() to wrap and the driver to transmit stale buffer contents.
The same race was fixed in qcom-geni by commit 452d6fa37ae9 ("serial:
qcom_geni: fix kfifo underflow when flush precedes DMA completion IRQ").
Clear tx_in_progress in the flush hook and have the completion callback
skip the kfifo update if the transfer has already been retired by either
the flush or tegra_uart_stop_tx(), which also advances the kfifo itself.
Fixes: e9ea096dd225 ("serial: tegra: add serial driver")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Samarth Narang <samarth.colleges@gmail.com>
---
drivers/tty/serial/serial-tegra.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index b0fc4ae3686f..8b712a9bc293 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -537,6 +537,11 @@ static void tegra_uart_tx_dma_complete(void *args)
count = tup->tx_bytes_requested - state.residue;
async_tx_ack(tup->tx_dma_desc);
uart_port_lock_irqsave(&tup->uport, &flags);
+ /* Already retired by stop_tx or flush_buffer */
+ if (tup->tx_in_progress != TEGRA_UART_TX_DMA) {
+ uart_port_unlock_irqrestore(&tup->uport, flags);
+ return;
+ }
uart_xmit_advance(&tup->uport, count);
tup->tx_in_progress = 0;
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
@@ -1276,6 +1281,9 @@ static void tegra_uart_flush_buffer(struct uart_port *u)
tup->tx_bytes = 0;
if (tup->tx_dma_chan)
dmaengine_terminate_all(tup->tx_dma_chan);
+ /* The kfifo has been reset: the completion must not advance it */
+ if (tup->tx_in_progress == TEGRA_UART_TX_DMA)
+ tup->tx_in_progress = 0;
}
static void tegra_uart_shutdown(struct uart_port *u)
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 3/5] serial: sprd: fix TX kfifo underflow on flush
2026-10-31 12:39 ` [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers Samarth Narang
2026-10-31 12:39 ` [PATCH 1/5] tty: serial: samsung: fix TX kfifo underflow on flush Samarth Narang
2026-10-31 12:39 ` [PATCH 2/5] serial: tegra: don't advance the TX kfifo for a flushed transfer Samarth Narang
@ 2026-10-31 12:39 ` Samarth Narang
2026-10-31 12:39 ` [PATCH 4/5] tty: serial: msm: " Samarth Narang
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Samarth Narang @ 2026-10-31 12:39 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Samarth Narang, Krzysztof Kozlowski, Peter Griffin, Alim Akhtar,
Marek Szyprowski, Laxman Dewangan, Thierry Reding,
Jonathan Hunter, Orson Zhai, Baolin Wang, Chunyan Zhang,
linux-serial, linux-samsung-soc, linux-arm-msm, linux-tegra,
linux-arm-kernel, linux-kernel
uart_flush_buffer() resets the transmit kfifo under the port lock before
calling the driver's flush_buffer() hook. Since sprd_serial does not
implement this hook, an outstanding TX DMA transfer may complete after
the flush and call uart_xmit_advance() using the flushed transfer's
tx_dma.trans_len. This can advance the kfifo tail past its head, causing
kfifo_len() to wrap and the driver to transmit stale buffer contents.
The same issue was fixed in 8250 by commit 9e512eaaf8f4 ("serial: 8250:
Fix fifo underflow on flush").
Since the TX buffer is mapped separately for each transfer and the flush
hook runs under the port lock, DMA cannot be terminated and its mapping
safely released synchronously from the hook. Instead, leave the
outstanding transfer running and mark it as flushed, allowing the
completion callback to unmap the buffer without advancing the kfifo.
Apply the same check in sprd_stop_tx_dma() if the transfer is stopped
before completion. With this approach, the data already queued for DMA
before the flush may still be transmitted.
Fixes: f4487db58eb7 ("serial: sprd: Add DMA mode support")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Samarth Narang <samarth.colleges@gmail.com>
---
drivers/tty/serial/sprd_serial.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 3fdf5939a62c..718732b683f1 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -133,6 +133,7 @@ struct sprd_uart_port {
struct clk *clk;
struct sprd_uart_dma tx_dma;
struct sprd_uart_dma rx_dma;
+ bool tx_flushed;
dma_addr_t pos;
unsigned char *rx_buf_tail;
const struct sprd_uart_data *pdata;
@@ -236,13 +237,15 @@ static void sprd_stop_tx_dma(struct uart_port *port)
dmaengine_tx_status(sp->tx_dma.chn, sp->tx_dma.cookie, &state);
if (state.residue) {
trans_len = state.residue - sp->tx_dma.phys_addr;
- uart_xmit_advance(port, trans_len);
+ if (!sp->tx_flushed)
+ uart_xmit_advance(port, trans_len);
dma_unmap_single(port->dev, sp->tx_dma.phys_addr,
sp->tx_dma.trans_len, DMA_TO_DEVICE);
}
dmaengine_terminate_all(sp->tx_dma.chn);
sp->tx_dma.trans_len = 0;
+ sp->tx_flushed = false;
}
static int sprd_tx_buf_remap(struct uart_port *port)
@@ -273,7 +276,9 @@ static void sprd_complete_tx_dma(void *data)
dma_unmap_single(port->dev, sp->tx_dma.phys_addr,
sp->tx_dma.trans_len, DMA_TO_DEVICE);
- uart_xmit_advance(port, sp->tx_dma.trans_len);
+ if (!sp->tx_flushed)
+ uart_xmit_advance(port, sp->tx_dma.trans_len);
+ sp->tx_flushed = false;
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
@@ -555,6 +560,20 @@ static void sprd_stop_tx(struct uart_port *port)
serial_out(port, SPRD_ICLR, iclr);
}
+static void sprd_flush_buffer(struct uart_port *port)
+{
+ struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port,
+ port);
+
+ /*
+ * The kfifo has been reset. Let the running transfer finish, so that
+ * its buffer is unmapped only once it has stopped, but do not advance
+ * the kfifo for it.
+ */
+ if (sp->tx_dma.trans_len)
+ sp->tx_flushed = true;
+}
+
static void sprd_start_tx(struct uart_port *port)
{
struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port,
@@ -946,6 +965,7 @@ static const struct uart_ops serial_sprd_ops = {
.get_mctrl = sprd_get_mctrl,
.set_mctrl = sprd_set_mctrl,
.stop_tx = sprd_stop_tx,
+ .flush_buffer = sprd_flush_buffer,
.start_tx = sprd_start_tx,
.stop_rx = sprd_stop_rx,
.break_ctl = sprd_break_ctl,
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 4/5] tty: serial: msm: fix TX kfifo underflow on flush
2026-10-31 12:39 ` [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers Samarth Narang
` (2 preceding siblings ...)
2026-10-31 12:39 ` [PATCH 3/5] serial: sprd: fix TX kfifo underflow on flush Samarth Narang
@ 2026-10-31 12:39 ` Samarth Narang
2026-10-31 12:39 ` [PATCH 5/5] serial: pch_uart: " Samarth Narang
2026-10-31 12:59 ` [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers Greg Kroah-Hartman
5 siblings, 0 replies; 9+ messages in thread
From: Samarth Narang @ 2026-10-31 12:39 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Samarth Narang, Krzysztof Kozlowski, Peter Griffin, Alim Akhtar,
Marek Szyprowski, Laxman Dewangan, Thierry Reding,
Jonathan Hunter, Orson Zhai, Baolin Wang, Chunyan Zhang,
linux-serial, linux-samsung-soc, linux-arm-msm, linux-tegra,
linux-arm-kernel, linux-kernel
uart_flush_buffer() resets the transmit kfifo under the port lock before
calling the driver's flush_buffer() hook. Since msm_serial does not
implement this hook, an outstanding TX DMA transfer may complete after
the flush and call uart_xmit_advance() using the flushed transfer's byte
count. The existing check for a stopped transfer relies on tx_sg, which
the flush does not clear, so it does not catch this case. The kfifo tail
then advances past its head, causing kfifo_len() to wrap and the driver
to transmit stale buffer contents. The same issue was fixed in 8250 by
commit 9e512eaaf8f4 ("serial: 8250: Fix fifo underflow on flush").
Since the TX buffer is mapped separately for each transfer and the flush
hook runs under the port lock, the driver cannot synchronously terminate
DMA and safely unmap the buffer from that context. Instead, leave the
outstanding transfer running and mark it as flushed, allowing the
completion callback to unmap the buffer without advancing the kfifo.
Clear the flag when preparing the next transfer. This avoids the kfifo
underflow, although the data already queued for DMA before the flush may
still be transmitted.
Fixes: 3a878c430fd6 ("tty: serial: msm: Add TX DMA support")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Samarth Narang <samarth.colleges@gmail.com>
---
drivers/tty/serial/msm_serial.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index bfa44b01c3e9..a9eca971e9ff 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -185,6 +185,7 @@ struct msm_port {
bool break_detected;
struct msm_dma tx_dma;
struct msm_dma rx_dma;
+ bool tx_dma_flushed;
};
static inline struct msm_port *to_msm_port(struct uart_port *up)
@@ -428,6 +429,19 @@ static void msm_stop_tx(struct uart_port *port)
msm_write(port, msm_port->imr, MSM_UART_IMR);
}
+static void msm_flush_buffer(struct uart_port *port)
+{
+ struct msm_port *msm_port = to_msm_port(port);
+
+ /*
+ * The kfifo has been reset. Let the running transfer finish, so that
+ * its buffer is unmapped only once it has stopped, but do not advance
+ * the kfifo for it.
+ */
+ if (sg_dma_len(&msm_port->tx_dma.tx_sg))
+ msm_port->tx_dma_flushed = true;
+}
+
static void msm_start_tx(struct uart_port *port)
{
struct msm_port *msm_port = to_msm_port(port);
@@ -479,7 +493,8 @@ static void msm_complete_tx_dma(void *args)
}
count = sg_dma_len(&dma->tx_sg) - state.residue;
- uart_xmit_advance(port, count);
+ if (!msm_port->tx_dma_flushed)
+ uart_xmit_advance(port, count);
sg_init_table(&dma->tx_sg, 1);
/* Restore "Tx FIFO below watermark" interrupt */
@@ -503,6 +518,7 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
int ret;
u32 val;
+ msm_port->tx_dma_flushed = false;
sg_init_table(&dma->tx_sg, 1);
kfifo_dma_out_prepare(&tport->xmit_fifo, &dma->tx_sg, 1, count);
@@ -1549,6 +1565,7 @@ static const struct uart_ops msm_uart_pops = {
.set_mctrl = msm_set_mctrl,
.get_mctrl = msm_get_mctrl,
.stop_tx = msm_stop_tx,
+ .flush_buffer = msm_flush_buffer,
.start_tx = msm_start_tx,
.stop_rx = msm_stop_rx,
.enable_ms = msm_enable_ms,
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 5/5] serial: pch_uart: fix TX kfifo underflow on flush
2026-10-31 12:39 ` [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers Samarth Narang
` (3 preceding siblings ...)
2026-10-31 12:39 ` [PATCH 4/5] tty: serial: msm: " Samarth Narang
@ 2026-10-31 12:39 ` Samarth Narang
2026-10-31 12:59 ` [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers Greg Kroah-Hartman
5 siblings, 0 replies; 9+ messages in thread
From: Samarth Narang @ 2026-10-31 12:39 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Samarth Narang, Krzysztof Kozlowski, Peter Griffin, Alim Akhtar,
Marek Szyprowski, Laxman Dewangan, Thierry Reding,
Jonathan Hunter, Orson Zhai, Baolin Wang, Chunyan Zhang,
linux-serial, linux-samsung-soc, linux-arm-msm, linux-tegra,
linux-arm-kernel, linux-kernel
uart_flush_buffer() resets the transmit kfifo under the port lock before
calling the driver's flush_buffer() hook. Since pch_uart does not
implement this hook, an outstanding TX DMA transfer may complete after
the flush and call uart_xmit_advance() for each entry of the flushed
transfer's scatterlist. This can advance the kfifo tail past its head,
causing kfifo_len() to wrap and the driver to transmit stale buffer
contents. The completion callback also updates the kfifo without holding
the port lock, allowing it to race with the flush itself. The same issue
was fixed in 8250 by commit 9e512eaaf8f4 ("serial: 8250: Fix fifo
underflow on flush").
Since the TX buffer is mapped separately for each transfer and the flush
hook runs under the port lock, the driver cannot synchronously terminate
DMA and safely unmap the buffer from that context. Instead, leave the
outstanding transfer running and mark it as flushed, allowing the
completion callback to unmap the buffer without advancing the kfifo.
Take the port lock in the completion callback to synchronize access to
the flush flag and kfifo state. This prevents the underflow, although
the data already queued for DMA before the flush may still be
transmitted.
Fixes: 3c6a483275f4 ("Serial: EG20T: add PCH_UART driver")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Samarth Narang <samarth.colleges@gmail.com>
---
drivers/tty/serial/pch_uart.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 9505d255f09c..122025c4a0a6 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -230,6 +230,7 @@ struct eg20t_port {
struct scatterlist *sg_tx_p;
int nent;
int orig_nent;
+ bool tx_dma_flushed;
struct scatterlist sg_rx;
int tx_dma_use;
void *rx_buf_virt;
@@ -750,18 +751,23 @@ static void pch_dma_tx_complete(void *arg)
struct eg20t_port *priv = arg;
struct uart_port *port = &priv->port;
struct scatterlist *sg = priv->sg_tx_p;
+ unsigned long flags;
int i;
- for (i = 0; i < priv->nent; i++, sg++)
- uart_xmit_advance(port, sg_dma_len(sg));
+ uart_port_lock_irqsave(port, &flags);
+ if (!priv->tx_dma_flushed)
+ for (i = 0; i < priv->nent; i++, sg++)
+ uart_xmit_advance(port, sg_dma_len(sg));
async_tx_ack(priv->desc_tx);
dma_unmap_sg(port->dev, priv->sg_tx_p, priv->orig_nent, DMA_TO_DEVICE);
priv->tx_dma_use = 0;
+ priv->tx_dma_flushed = false;
priv->nent = 0;
priv->orig_nent = 0;
kfree(priv->sg_tx_p);
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
+ uart_port_unlock_irqrestore(port, flags);
}
static int handle_rx_to(struct eg20t_port *priv)
@@ -947,6 +953,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
}
priv->orig_nent = num;
priv->nent = nent;
+ priv->tx_dma_flushed = false;
for (i = 0; i < nent; i++, sg++) {
sg->offset = tail + fifo_size * i;
@@ -1150,6 +1157,21 @@ static void pch_uart_stop_tx(struct uart_port *port)
priv->tx_dma_use = 0;
}
+static void pch_uart_flush_buffer(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+
+ priv = container_of(port, struct eg20t_port, port);
+
+ /*
+ * The kfifo has been reset. Let the running transfer finish, so that
+ * its buffer is unmapped only once it has stopped, but do not advance
+ * the kfifo for it.
+ */
+ if (priv->nent)
+ priv->tx_dma_flushed = true;
+}
+
static void pch_uart_start_tx(struct uart_port *port)
{
struct eg20t_port *priv;
@@ -1520,6 +1542,7 @@ static const struct uart_ops pch_uart_ops = {
.set_mctrl = pch_uart_set_mctrl,
.get_mctrl = pch_uart_get_mctrl,
.stop_tx = pch_uart_stop_tx,
+ .flush_buffer = pch_uart_flush_buffer,
.start_tx = pch_uart_start_tx,
.stop_rx = pch_uart_stop_rx,
.enable_ms = pch_uart_enable_ms,
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers
2026-10-31 12:39 ` [PATCH 0/5] serial: fix TX kfifo underflow on flush in five drivers Samarth Narang
` (4 preceding siblings ...)
2026-10-31 12:39 ` [PATCH 5/5] serial: pch_uart: " Samarth Narang
@ 2026-10-31 12:59 ` Greg Kroah-Hartman
5 siblings, 0 replies; 9+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-31 12:59 UTC (permalink / raw)
To: Samarth Narang
Cc: Jiri Slaby, Krzysztof Kozlowski, Peter Griffin, Alim Akhtar,
Marek Szyprowski, Laxman Dewangan, Thierry Reding,
Jonathan Hunter, Orson Zhai, Baolin Wang, Chunyan Zhang,
linux-serial, linux-samsung-soc, linux-arm-msm, linux-tegra,
linux-arm-kernel, linux-kernel
On Sat, Oct 31, 2026 at 12:39:06PM +0000, Samarth Narang wrote:
> This series addresses the TX kfifo underflow reported in the parent
> thread, where uart_flush_buffer() resets the transmit kfifo but a
> completion callback from an earlier DMA transfer may still call
> uart_xmit_advance() using the byte count from before the flush.
>
> The fixes take two approaches depending on how each driver manages its
> TX DMA mappings. In samsung and tegra, which map the TX buffer once,
> samsung's new flush_buffer() terminates the outstanding transfer, as
> tegra's already does, following the approach introduced in 8250 by
> 9e512eaaf8f4. A completion already in progress skips the kfifo update if
> the transfer has since been retired by flush_buffer() or stop_tx().
>
> In sprd, msm, and pch_uart, which map each transfer separately,
> terminating DMA there would leave the flush hook to unmap a buffer the
> controller may still be reading. These drivers therefore leave the
> transfer running and mark it as flushed, allowing the completion
> callback to unmap the buffer without advancing the kfifo. This means
> that the data already queued for DMA before the flush may still be
> transmitted.
>
> All five patches have only been compile-tested with arm64 defconfig and
> the relevant drivers enabled, including pch_uart through COMPILE_TEST,
> using W=1 with no new warnings. I do not have access to the affected
> hardware, so testing by someone with suitable devices would be
> appreciated.
If you don't have the hardware, and can't test that the race is even
there, are you sure this is needed? :)
What about using qemu?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 9+ messages in thread