[PATCH 12/13] serial: linflexuart: Add DMA support

Larisa Grigore posted 13 patches 1 month, 2 weeks ago
[PATCH 12/13] serial: linflexuart: Add DMA support
Posted by Larisa Grigore 1 month, 2 weeks ago
Add support for using DMA to avoid generating one interrupt per
character and losing characters while copy-paste.
In UART mode, the DMA capability can be used only if the UART Tx/Rx
buffers are configured as FIFOs.
If the DMA related properties are missing from the device tree, the
driver will fall back to interrupt + Buffer mode.
On the RX side, a timer is used to periodically poll for received data.

Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
Co-developed-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Co-developed-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Co-developed-by: Phu Luu An <phu.luuan@nxp.com>
Signed-off-by: Phu Luu An <phu.luuan@nxp.com>
Co-developed-by: Js Ha <js.ha@nxp.com>
Signed-off-by: Js Ha <js.ha@nxp.com>
Co-developed-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
Signed-off-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
---
 drivers/tty/serial/fsl_linflexuart.c | 642 +++++++++++++++++++++++++--
 1 file changed, 597 insertions(+), 45 deletions(-)

diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index a5a34fd81bcf..dff37c68cff0 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -3,19 +3,24 @@
  * Freescale LINFlexD UART serial port driver
  *
  * Copyright 2012-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2019, 2021-2022 NXP
+ * Copyright 2017-2019, 2021-2022, 2025 NXP
  */
 
 #include <linux/clk.h>
 #include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_dma.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/slab.h>
 #include <linux/tty_flip.h>
+#include <linux/jiffies.h>
 #include <linux/delay.h>
 
 /* All registers are 32-bit width */
@@ -42,6 +47,12 @@
 #define GCR	0x004C	/* Global control register			*/
 #define UARTPTO	0x0050	/* UART preset timeout register			*/
 #define UARTCTO	0x0054	/* UART current timeout register		*/
+/* The offsets for DMARXE/DMATXE in master mode only			*/
+#define DMATXE	0x0058	/* DMA Tx enable register			*/
+#define DMARXE	0x005C	/* DMA Rx enable register			*/
+
+#define DMATXE_DRE0	BIT(0)
+#define DMARXE_DRE0	BIT(0)
 
 /*
  * Register field definitions
@@ -140,6 +151,9 @@
 
 #define PREINIT_DELAY			2000 /* us */
 
+#define FSL_UART_RX_DMA_BUFFER_SIZE	(PAGE_SIZE)
+#define LINFLEXD_UARTCR_FIFO_SIZE	(4)
+
 enum linflex_clk {
 	LINFLEX_CLK_LIN,
 	LINFLEX_CLK_IPG,
@@ -154,6 +168,24 @@ static const char * const linflex_clks_id[] = {
 struct linflex_port {
 	struct uart_port	port;
 	struct clk_bulk_data	clks[LINFLEX_CLK_NUM];
+	unsigned int		txfifo_size;
+	unsigned int		rxfifo_size;
+	bool			dma_tx_use;
+	bool			dma_rx_use;
+	struct dma_chan		*dma_tx_chan;
+	struct dma_chan		*dma_rx_chan;
+	struct dma_async_tx_descriptor  *dma_tx_desc;
+	struct dma_async_tx_descriptor  *dma_rx_desc;
+	dma_addr_t		dma_tx_buf_bus;
+	dma_addr_t		dma_rx_buf_bus;
+	dma_cookie_t		dma_tx_cookie;
+	dma_cookie_t		dma_rx_cookie;
+	unsigned char		*dma_rx_buf_virt;
+	unsigned int		dma_tx_bytes;
+	int			dma_tx_in_progress;
+	int			dma_rx_in_progress;
+	unsigned long		dma_rx_timeout;
+	struct timer_list	timer;
 };
 
 static const struct of_device_id linflex_dt_ids[] = {
@@ -168,6 +200,76 @@ MODULE_DEVICE_TABLE(of, linflex_dt_ids);
 static struct uart_port *earlycon_port;
 #endif
 
+static void linflex_dma_tx_complete(void *arg);
+static void linflex_dma_rx_complete(void *arg);
+static void linflex_console_putchar(struct uart_port *port, unsigned char ch);
+
+static inline struct linflex_port *
+to_linflex_port(struct uart_port *uart)
+{
+	return container_of(uart, struct linflex_port, port);
+}
+
+static void linflex_copy_rx_to_tty(struct linflex_port *lfport,
+				   struct tty_port *tty, int count)
+{
+	size_t copied;
+
+	lfport->port.icount.rx += count;
+
+	if (!tty) {
+		dev_err(lfport->port.dev, "No tty port\n");
+		return;
+	}
+
+	dma_sync_single_for_cpu(lfport->port.dev, lfport->dma_rx_buf_bus,
+				FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+	copied = tty_insert_flip_string(tty,
+					((unsigned char *)(lfport->dma_rx_buf_virt)),
+					count);
+
+	if (copied != count) {
+		WARN_ON(1);
+		dev_err(lfport->port.dev, "RxData copy to tty layer failed\n");
+	}
+}
+
+static void linflex_enable_dma_rx(struct uart_port *port)
+{
+	unsigned long dmarxe = readl(port->membase + DMARXE);
+
+	writel(dmarxe | DMARXE_DRE0, port->membase + DMARXE);
+	while (!(readl(port->membase + DMARXE) & DMARXE_DRE0))
+		;
+}
+
+static void linflex_enable_dma_tx(struct uart_port *port)
+{
+	unsigned long dmatxe = readl(port->membase + DMATXE);
+
+	writel(dmatxe | DMATXE_DRE0, port->membase + DMATXE);
+	while (!(readl(port->membase + DMATXE) & DMATXE_DRE0))
+		;
+}
+
+static void linflex_disable_dma_rx(struct uart_port *port)
+{
+	unsigned long dmarxe = readl(port->membase + DMARXE);
+
+	writel(dmarxe & 0xFFFF0000, port->membase + DMARXE);
+	while (readl(port->membase + DMARXE) & DMARXE_DRE0)
+		;
+}
+
+static void linflex_disable_dma_tx(struct uart_port *port)
+{
+	unsigned long dmatxe = readl(port->membase + DMATXE);
+
+	writel(dmatxe & 0xFFFF0000, port->membase + DMATXE);
+	while (readl(port->membase + DMATXE) & DMATXE_DRE0)
+		;
+}
+
 static inline void linflex_wait_tx_fifo_empty(struct uart_port *port)
 {
 	unsigned long cr = readl(port->membase + UARTCR);
@@ -179,36 +281,113 @@ static inline void linflex_wait_tx_fifo_empty(struct uart_port *port)
 		;
 }
 
+static void _linflex_stop_tx(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
+	unsigned long ier;
+
+	if (!lfport->dma_tx_use) {
+		ier = readl(port->membase + LINIER);
+		ier &= ~(LINFLEXD_LINIER_DTIE);
+		writel(ier, port->membase + LINIER);
+		return;
+	}
+
+	linflex_disable_dma_tx(port);
+}
+
 static void linflex_stop_tx(struct uart_port *port)
 {
+	struct linflex_port *lfport = to_linflex_port(port);
+	struct dma_tx_state state;
+	unsigned int count;
+
+	_linflex_stop_tx(port);
+
+	if (!lfport->dma_tx_in_progress)
+		return;
+
+	dmaengine_pause(lfport->dma_tx_chan);
+	dmaengine_tx_status(lfport->dma_tx_chan,
+			    lfport->dma_tx_cookie, &state);
+	dmaengine_terminate_all(lfport->dma_tx_chan);
+	count = lfport->dma_tx_bytes - state.residue;
+	uart_xmit_advance(port, count);
+
+	lfport->dma_tx_in_progress = 0;
+}
+
+static void _linflex_start_rx(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
 	unsigned long ier;
 
-	ier = readl(port->membase + LINIER);
-	ier &= ~(LINFLEXD_LINIER_DTIE);
-	writel(ier, port->membase + LINIER);
+	if (!lfport->dma_rx_use) {
+		ier = readl(port->membase + LINIER);
+		writel(ier | LINFLEXD_LINIER_DRIE, port->membase + LINIER);
+		return;
+	}
+
+	linflex_enable_dma_rx(port);
 }
 
-static void linflex_stop_rx(struct uart_port *port)
+static void _linflex_stop_rx(struct uart_port *port)
 {
+	struct linflex_port *lfport = to_linflex_port(port);
 	unsigned long ier;
 
-	ier = readl(port->membase + LINIER);
-	writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER);
+	if (!lfport->dma_rx_use) {
+		ier = readl(port->membase + LINIER);
+		writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER);
+		return;
+	}
+
+	linflex_disable_dma_rx(port);
+}
+
+static void linflex_stop_rx(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
+	struct dma_tx_state state;
+	unsigned int count;
+
+	_linflex_stop_rx(port);
+
+	if (!lfport->dma_rx_in_progress)
+		return;
+
+	dmaengine_pause(lfport->dma_rx_chan);
+	dmaengine_tx_status(lfport->dma_rx_chan,
+			    lfport->dma_rx_cookie, &state);
+	dmaengine_terminate_all(lfport->dma_rx_chan);
+	count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
+
+	lfport->dma_rx_in_progress = 0;
+	linflex_copy_rx_to_tty(lfport, &port->state->port, count);
+	tty_flip_buffer_push(&port->state->port);
 }
 
 static void linflex_put_char(struct uart_port *sport, unsigned char c)
 {
+	struct linflex_port *lfport = to_linflex_port(sport);
 	unsigned long status;
 
 	writeb(c, sport->membase + BDRL);
 
 	/* Waiting for data transmission completed. */
-	while (((status = readl(sport->membase + UARTSR)) &
-				LINFLEXD_UARTSR_DTFTFF) !=
-				LINFLEXD_UARTSR_DTFTFF)
-		;
+	if (!lfport->dma_tx_use) {
+		while (((status = readl(sport->membase + UARTSR)) &
+					LINFLEXD_UARTSR_DTFTFF) !=
+					LINFLEXD_UARTSR_DTFTFF)
+			;
+	} else {
+		while (((status = readl(sport->membase + UARTSR)) &
+					LINFLEXD_UARTSR_DTFTFF))
+			;
+	}
 
-	writel(LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR);
+	if (!lfport->dma_tx_use)
+		writel(LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR);
 }
 
 static inline void linflex_transmit_buffer(struct uart_port *sport)
@@ -228,18 +407,198 @@ static inline void linflex_transmit_buffer(struct uart_port *sport)
 		linflex_stop_tx(sport);
 }
 
+static int linflex_dma_tx(struct linflex_port *lfport, unsigned int count,
+			  unsigned int tail)
+{
+	struct uart_port *sport = &lfport->port;
+	dma_addr_t tx_bus_addr;
+
+	while ((readl(sport->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF))
+		;
+
+	dma_sync_single_for_device(sport->dev, lfport->dma_tx_buf_bus,
+				   UART_XMIT_SIZE, DMA_TO_DEVICE);
+	lfport->dma_tx_bytes = count;
+	tx_bus_addr = lfport->dma_tx_buf_bus + tail;
+	lfport->dma_tx_desc =
+		dmaengine_prep_slave_single(lfport->dma_tx_chan, tx_bus_addr,
+					    lfport->dma_tx_bytes, DMA_MEM_TO_DEV,
+					    DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+	if (!lfport->dma_tx_desc) {
+		dev_err(sport->dev, "Not able to get desc for tx\n");
+		return -EIO;
+	}
+
+	lfport->dma_tx_desc->callback = linflex_dma_tx_complete;
+	lfport->dma_tx_desc->callback_param = sport;
+	lfport->dma_tx_in_progress = 1;
+	lfport->dma_tx_cookie = dmaengine_submit(lfport->dma_tx_desc);
+	dma_async_issue_pending(lfport->dma_tx_chan);
+
+	linflex_enable_dma_tx(&lfport->port);
+	return 0;
+}
+
+static void linflex_prepare_tx(struct linflex_port *lfport)
+{
+	struct tty_port *tport = &lfport->port.state->port;
+	unsigned int count, tail;
+
+	count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE);
+
+	if (!count || lfport->dma_tx_in_progress)
+		return;
+
+	linflex_dma_tx(lfport, count, tail);
+}
+
+static void linflex_restart_dma_tx(struct linflex_port *lfport)
+{
+	struct uart_port *sport = &lfport->port;
+	struct tty_port *tport = &sport->state->port;
+
+	if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
+		uart_write_wakeup(sport);
+
+	linflex_prepare_tx(lfport);
+}
+
+static void linflex_dma_tx_complete(void *arg)
+{
+	struct linflex_port *lfport = arg;
+	struct uart_port *sport = &lfport->port;
+	unsigned long flags;
+
+	uart_port_lock_irqsave(sport, &flags);
+
+	/* stopped before? */
+	if (!lfport->dma_tx_in_progress)
+		goto out_tx_callback;
+
+	uart_xmit_advance(sport, lfport->dma_tx_bytes);
+	lfport->dma_tx_in_progress = 0;
+
+	linflex_restart_dma_tx(lfport);
+
+out_tx_callback:
+	uart_port_unlock_irqrestore(sport, flags);
+}
+
+static void linflex_flush_buffer(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
+
+	if (lfport->dma_tx_use) {
+		linflex_disable_dma_tx(port);
+		dmaengine_terminate_async(lfport->dma_tx_chan);
+		lfport->dma_tx_in_progress = 0;
+	}
+}
+
+static int linflex_dma_rx(struct linflex_port *lfport)
+{
+	dma_sync_single_for_device(lfport->port.dev, lfport->dma_rx_buf_bus,
+				   FSL_UART_RX_DMA_BUFFER_SIZE,
+				   DMA_FROM_DEVICE);
+	lfport->dma_rx_desc = dmaengine_prep_slave_single(lfport->dma_rx_chan,
+							  lfport->dma_rx_buf_bus,
+							  FSL_UART_RX_DMA_BUFFER_SIZE,
+							  DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
+							  DMA_CTRL_ACK);
+
+	if (!lfport->dma_rx_desc) {
+		dev_err(lfport->port.dev, "Not able to get desc for rx\n");
+		return -EIO;
+	}
+
+	lfport->dma_rx_desc->callback = linflex_dma_rx_complete;
+	lfport->dma_rx_desc->callback_param = lfport;
+	lfport->dma_rx_in_progress = 1;
+	lfport->dma_rx_cookie = dmaengine_submit(lfport->dma_rx_desc);
+	dma_async_issue_pending(lfport->dma_rx_chan);
+
+	linflex_enable_dma_rx(&lfport->port);
+	return 0;
+}
+
+static void linflex_dma_rx_complete(void *arg)
+{
+	struct linflex_port *lfport = arg;
+	struct tty_port *port = &lfport->port.state->port;
+	unsigned long flags;
+
+	timer_delete_sync(&lfport->timer);
+
+	uart_port_lock_irqsave(&lfport->port, &flags);
+
+	/* stopped before? */
+	if (!lfport->dma_rx_in_progress) {
+		uart_port_unlock_irqrestore(&lfport->port, flags);
+		return;
+	}
+
+	lfport->dma_rx_in_progress = 0;
+	linflex_copy_rx_to_tty(lfport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
+	tty_flip_buffer_push(port);
+	linflex_dma_rx(lfport);
+
+	uart_port_unlock_irqrestore(&lfport->port, flags);
+
+	mod_timer(&lfport->timer, jiffies + lfport->dma_rx_timeout);
+}
+
+static void linflex_timer_func(struct timer_list *t)
+{
+	struct linflex_port *lfport = timer_container_of(lfport, t, timer);
+	unsigned long flags;
+
+	uart_port_lock_irqsave(&lfport->port, &flags);
+
+	/* stopped before? */
+	if (!lfport->dma_rx_in_progress) {
+		uart_port_unlock_irqrestore(&lfport->port, flags);
+		return;
+	}
+
+	linflex_stop_rx(&lfport->port);
+	linflex_dma_rx(lfport);
+
+	uart_port_unlock_irqrestore(&lfport->port, flags);
+	mod_timer(&lfport->timer, jiffies + lfport->dma_rx_timeout);
+}
+
+static void _linflex_start_tx(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
+	unsigned long ier;
+
+	if (lfport->dma_tx_use) {
+		linflex_enable_dma_tx(&lfport->port);
+	} else {
+		ier = readl(port->membase + LINIER);
+		writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER);
+	}
+}
+
 static void linflex_start_tx(struct uart_port *port)
 {
+	struct linflex_port *lfport = to_linflex_port(port);
 	unsigned long ier;
 
-	linflex_transmit_buffer(port);
-	ier = readl(port->membase + LINIER);
-	writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER);
+	if (lfport->dma_tx_use) {
+		linflex_prepare_tx(lfport);
+	} else {
+		linflex_transmit_buffer(port);
+		ier = readl(port->membase + LINIER);
+		writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER);
+	}
 }
 
 static irqreturn_t linflex_txint(int irq, void *dev_id)
 {
-	struct uart_port *sport = dev_id;
+	struct linflex_port *lfport = dev_id;
+	struct uart_port *sport = &lfport->port;
 	struct tty_port *tport = &sport->state->port;
 	unsigned long flags;
 
@@ -263,7 +622,8 @@ static irqreturn_t linflex_txint(int irq, void *dev_id)
 
 static irqreturn_t linflex_rxint(int irq, void *dev_id)
 {
-	struct uart_port *sport = dev_id;
+	struct linflex_port *lfport = dev_id;
+	struct uart_port *sport = &lfport->port;
 	unsigned int flg;
 	struct tty_port *port = &sport->state->port;
 	unsigned long flags, status;
@@ -316,14 +676,14 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id)
 
 static irqreturn_t linflex_int(int irq, void *dev_id)
 {
-	struct uart_port *sport = dev_id;
+	struct linflex_port *lfport = dev_id;
 	unsigned long status;
 
-	status = readl(sport->membase + UARTSR);
+	status = readl(lfport->port.membase + UARTSR);
 
-	if (status & LINFLEXD_UARTSR_DRFRFE)
+	if (status & LINFLEXD_UARTSR_DRFRFE && !lfport->dma_rx_use)
 		linflex_rxint(irq, dev_id);
-	if (status & LINFLEXD_UARTSR_DTFTFF)
+	if (status & LINFLEXD_UARTSR_DTFTFF && !lfport->dma_rx_use)
 		linflex_txint(irq, dev_id);
 
 	return IRQ_HANDLED;
@@ -332,11 +692,15 @@ static irqreturn_t linflex_int(int irq, void *dev_id)
 /* return TIOCSER_TEMT when transmitter is not busy */
 static unsigned int linflex_tx_empty(struct uart_port *port)
 {
+	struct linflex_port *lfport = to_linflex_port(port);
 	unsigned long status;
 
 	status = readl(port->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF;
 
-	return status ? TIOCSER_TEMT : 0;
+	if (!lfport->dma_tx_use)
+		return status ? TIOCSER_TEMT : 0;
+	else
+		return status ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int linflex_get_mctrl(struct uart_port *port)
@@ -354,6 +718,7 @@ static void linflex_break_ctl(struct uart_port *port, int break_state)
 
 static void linflex_setup_watermark(struct uart_port *sport)
 {
+	struct linflex_port *lfport = to_linflex_port(sport);
 	unsigned long cr, ier, cr1;
 
 	/* Disable transmission/reception */
@@ -396,6 +761,14 @@ static void linflex_setup_watermark(struct uart_port *sport)
 
 	cr = (LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART);
 
+	/* FIFO mode enabled for DMA Rx mode. */
+	if (lfport->dma_rx_use)
+		cr |= LINFLEXD_UARTCR_RFBM;
+
+	/* FIFO mode enabled for DMA Tx mode. */
+	if (lfport->dma_tx_use)
+		cr |= LINFLEXD_UARTCR_TFBM;
+
 	writel(cr, sport->membase + UARTCR);
 
 	cr1 &= ~(LINFLEXD_LINCR1_INIT);
@@ -406,44 +779,169 @@ static void linflex_setup_watermark(struct uart_port *sport)
 	writel(cr, sport->membase + UARTCR);
 
 	ier = readl(sport->membase + LINIER);
-	ier |= LINFLEXD_LINIER_DRIE;
-	ier |= LINFLEXD_LINIER_DTIE;
+	if (!lfport->dma_rx_use)
+		ier |= LINFLEXD_LINIER_DRIE;
+
+	if (!lfport->dma_tx_use)
+		ier |= LINFLEXD_LINIER_DTIE;
 
 	writel(ier, sport->membase + LINIER);
 }
 
+static int linflex_dma_tx_request(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
+	struct tty_port *tport = &port->state->port;
+	struct dma_slave_config dma_tx_sconfig;
+	dma_addr_t dma_bus;
+	int ret;
+
+	dma_bus = dma_map_single(port->dev, tport->xmit_buf,
+				 UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+	if (dma_mapping_error(port->dev, dma_bus)) {
+		dev_err(port->dev, "dma_map_single tx failed\n");
+		return -ENOMEM;
+	}
+
+	memset(&dma_tx_sconfig, 0, sizeof(dma_tx_sconfig));
+	dma_tx_sconfig.dst_addr = port->mapbase + BDRL;
+	dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_tx_sconfig.dst_maxburst = 1;
+	dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
+	ret = dmaengine_slave_config(lfport->dma_tx_chan, &dma_tx_sconfig);
+
+	if (ret < 0) {
+		dev_err(port->dev, "Dma slave config failed, err = %d\n",
+			ret);
+		return ret;
+	}
+
+	lfport->dma_tx_buf_bus = dma_bus;
+	lfport->dma_tx_in_progress = 0;
+
+	return 0;
+}
+
+static int linflex_dma_rx_request(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
+	struct dma_slave_config dma_rx_sconfig;
+	unsigned char *dma_buf;
+	dma_addr_t dma_bus;
+	int ret;
+
+	dma_buf = devm_kmalloc(port->dev, FSL_UART_RX_DMA_BUFFER_SIZE,
+			       GFP_KERNEL);
+
+	if (!dma_buf) {
+		dev_err(port->dev, "Dma rx alloc failed\n");
+		return -ENOMEM;
+	}
+
+	dma_bus = dma_map_single(port->dev, dma_buf,
+				 FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+	if (dma_mapping_error(port->dev, dma_bus)) {
+		dev_err(port->dev, "dma_map_single rx failed\n");
+		return -ENOMEM;
+	}
+
+	memset(&dma_rx_sconfig, 0, sizeof(dma_rx_sconfig));
+	dma_rx_sconfig.src_addr = port->mapbase + BDRM;
+	dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_rx_sconfig.src_maxburst = 1;
+	dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
+	ret = dmaengine_slave_config(lfport->dma_rx_chan, &dma_rx_sconfig);
+
+	if (ret < 0) {
+		dev_err(port->dev, "Dma slave config failed, err = %d\n",
+			ret);
+		return ret;
+	}
+
+	lfport->dma_rx_buf_virt = dma_buf;
+	lfport->dma_rx_buf_bus = dma_bus;
+	lfport->dma_rx_in_progress = 0;
+
+	return 0;
+}
+
+static void linflex_dma_tx_free(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
+
+	dma_unmap_single(lfport->port.dev, lfport->dma_tx_buf_bus, UART_XMIT_SIZE,
+			 DMA_TO_DEVICE);
+
+	lfport->dma_tx_buf_bus = 0;
+}
+
+static void linflex_dma_rx_free(struct uart_port *port)
+{
+	struct linflex_port *lfport = to_linflex_port(port);
+
+	dma_unmap_single(lfport->port.dev, lfport->dma_rx_buf_bus,
+			 FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+	devm_kfree(lfport->port.dev, lfport->dma_rx_buf_virt);
+
+	lfport->dma_rx_buf_bus = 0;
+	lfport->dma_rx_buf_virt = NULL;
+}
+
 static int linflex_startup(struct uart_port *port)
 {
+	struct linflex_port *lfport = to_linflex_port(port);
 	int ret = 0;
 	unsigned long flags;
+	bool dma_rx_use, dma_tx_use;
+
+	dma_rx_use = lfport->dma_rx_chan && !linflex_dma_rx_request(port);
+	dma_tx_use = lfport->dma_tx_chan && !linflex_dma_tx_request(port);
 
 	uart_port_lock_irqsave(port, &flags);
 
+	lfport->dma_rx_use = dma_rx_use;
+	lfport->dma_tx_use = dma_tx_use;
+	lfport->port.fifosize = LINFLEXD_UARTCR_FIFO_SIZE;
+
 	linflex_setup_watermark(port);
 
+	if (lfport->dma_rx_use && !linflex_dma_rx(lfport)) {
+		timer_setup(&lfport->timer, linflex_timer_func, 0);
+		mod_timer(&lfport->timer, jiffies + lfport->dma_rx_timeout);
+	}
 	uart_port_unlock_irqrestore(port, flags);
 
-	ret = devm_request_irq(port->dev, port->irq, linflex_int, 0,
-			       DRIVER_NAME, port);
-
+	if (!lfport->dma_rx_use || !lfport->dma_tx_use) {
+		ret = devm_request_irq(port->dev, port->irq, linflex_int, 0,
+				       DRIVER_NAME, lfport);
+	}
 	return ret;
 }
 
 static void linflex_shutdown(struct uart_port *port)
 {
-	unsigned long ier;
+	struct linflex_port *lfport = to_linflex_port(port);
 	unsigned long flags;
 
+	timer_delete_sync(&lfport->timer);
+
 	uart_port_lock_irqsave(port, &flags);
 
-	/* disable interrupts */
-	ier = readl(port->membase + LINIER);
-	ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE);
-	writel(ier, port->membase + LINIER);
+	linflex_stop_tx(port);
+	linflex_stop_rx(port);
 
 	uart_port_unlock_irqrestore(port, flags);
 
-	devm_free_irq(port->dev, port->irq, port);
+	if (!lfport->dma_rx_use || !lfport->dma_tx_use)
+		devm_free_irq(port->dev, port->irq, lfport);
+
+	if (lfport->dma_rx_use)
+		linflex_dma_rx_free(port);
+
+	if (lfport->dma_tx_use)
+		linflex_dma_tx_free(port);
 }
 
 static unsigned char
@@ -463,6 +961,7 @@ static void
 linflex_set_termios(struct uart_port *port, struct ktermios *termios,
 		    const struct ktermios *old)
 {
+	struct linflex_port *lfport = to_linflex_port(port);
 	unsigned long flags;
 	unsigned long cr, old_cr, cr1, gcr;
 	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
@@ -472,6 +971,9 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
 
 	uart_port_lock_irqsave(port, &flags);
 
+	_linflex_stop_rx(port);
+	_linflex_stop_tx(port);
+
 	old_cr = readl(port->membase + UARTCR) &
 		~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
 	cr = old_cr;
@@ -608,6 +1110,8 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
 		writel(fbr, port->membase + LINFBRR);
 	}
 
+	lfport->dma_rx_timeout = msecs_to_jiffies(DIV_ROUND_UP(10000000, baud));
+
 	writel(cr, port->membase + UARTCR);
 
 	cr1 &= ~(LINFLEXD_LINCR1_INIT);
@@ -617,6 +1121,9 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
 	cr |= (LINFLEXD_UARTCR_TXEN) | (LINFLEXD_UARTCR_RXEN);
 	writel(cr, port->membase + UARTCR);
 
+	_linflex_start_rx(port);
+	_linflex_start_tx(port);
+
 	uart_port_unlock_irqrestore(port, flags);
 }
 
@@ -657,6 +1164,7 @@ static const struct uart_ops linflex_pops = {
 	.request_port	= linflex_request_port,
 	.release_port	= linflex_release_port,
 	.config_port	= linflex_config_port,
+	.flush_buffer	= linflex_flush_buffer,
 };
 
 static struct uart_port *linflex_ports[UART_NR];
@@ -690,18 +1198,16 @@ static void linflex_console_putchar(struct uart_port *port, unsigned char ch)
 static void linflex_string_write(struct uart_port *sport, const char *s,
 				 unsigned int count)
 {
-	unsigned long cr, ier = 0;
-
-	ier = readl(sport->membase + LINIER);
-	linflex_stop_tx(sport);
+	unsigned long cr;
 
+	_linflex_stop_tx(sport);
 	cr = readl(sport->membase + UARTCR);
 	cr |= (LINFLEXD_UARTCR_TXEN);
 	writel(cr, sport->membase + UARTCR);
 
 	uart_console_write(sport, s, count, linflex_console_putchar);
 
-	writel(ier, sport->membase + LINIER);
+	_linflex_start_tx(sport);
 }
 
 static void
@@ -881,30 +1387,59 @@ static int linflex_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	sport = &lfport->port;
+	sport->dev = &pdev->dev;
+
+	lfport->dma_tx_chan = dma_request_chan(sport->dev, "tx");
+	if (IS_ERR(lfport->dma_tx_chan)) {
+		ret = PTR_ERR(lfport->dma_tx_chan);
+		if (ret == -EPROBE_DEFER)
+			return ret;
+
+		dev_info(sport->dev,
+			 "DMA tx channel request failed, operating without tx DMA %ld\n",
+			 PTR_ERR(lfport->dma_tx_chan));
+		lfport->dma_tx_chan = NULL;
+	}
+
+	lfport->dma_rx_chan = dma_request_chan(sport->dev, "rx");
+	if (IS_ERR(lfport->dma_rx_chan)) {
+		ret = PTR_ERR(lfport->dma_rx_chan);
+		if (ret == -EPROBE_DEFER) {
+			dma_release_channel(lfport->dma_tx_chan);
+			return ret;
+		}
+
+		dev_info(sport->dev,
+			 "DMA rx channel request failed, operating without rx DMA %ld\n",
+			 PTR_ERR(lfport->dma_rx_chan));
+		lfport->dma_rx_chan = NULL;
+	}
 
 	ret = of_alias_get_id(np, "serial");
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
-		return ret;
+		goto linflex_probe_free_dma;
 	}
 	if (ret >= UART_NR) {
 		dev_err(&pdev->dev, "driver limited to %d serial ports\n",
 			UART_NR);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto linflex_probe_free_dma;
 	}
 
 	sport->line = ret;
 
 	sport->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-	if (IS_ERR(sport->membase))
-		return PTR_ERR(sport->membase);
+	if (IS_ERR(sport->membase)) {
+		ret = PTR_ERR(sport->membase);
+		goto linflex_probe_free_dma;
+	}
 	sport->mapbase = res->start;
 
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0)
 		return ret;
 
-	sport->dev = &pdev->dev;
 	sport->iotype = UPIO_MEM;
 	sport->irq = ret;
 	sport->ops = &linflex_pops;
@@ -913,15 +1448,25 @@ static int linflex_probe(struct platform_device *pdev)
 
 	ret = linflex_init_clk(lfport);
 	if (ret)
-		return ret;
+		goto linflex_probe_free_dma;
 
 	linflex_ports[sport->line] = sport;
 
 	platform_set_drvdata(pdev, lfport);
 
 	ret = uart_add_one_port(&linflex_reg, sport);
-	if (ret)
+	if (ret) {
 		clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
+		goto linflex_probe_free_dma;
+	}
+
+	return 0;
+
+linflex_probe_free_dma:
+	if (lfport->dma_tx_chan)
+		dma_release_channel(lfport->dma_tx_chan);
+	if (lfport->dma_rx_chan)
+		dma_release_channel(lfport->dma_rx_chan);
 
 	return ret;
 }
@@ -933,6 +1478,13 @@ static void linflex_remove(struct platform_device *pdev)
 
 	uart_remove_one_port(&linflex_reg, sport);
 	clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
+
+	if (lfport->dma_tx_chan)
+		dma_release_channel(lfport->dma_tx_chan);
+
+	if (lfport->dma_rx_chan)
+		dma_release_channel(lfport->dma_rx_chan);
+
 }
 
 #ifdef CONFIG_PM_SLEEP
-- 
2.47.0
Re: [PATCH 12/13] serial: linflexuart: Add DMA support
Posted by Dan Carpenter 1 month, 1 week ago
Hi Larisa,

kernel test robot noticed the following build warnings:

https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Larisa-Grigore/serial-linflexuart-Fix-locking-in-set_termios/20260216-231403
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link:    https://lore.kernel.org/r/20260216150205.212318-13-larisa.grigore%40oss.nxp.com
patch subject: [PATCH 12/13] serial: linflexuart: Add DMA support
config: i386-randconfig-141-20260217 (https://download.01.org/0day-ci/archive/20260217/202602171109.6YSFXcJ3-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
smatch version: v0.5.0-8994-gd50c5a4c

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202602171109.6YSFXcJ3-lkp@intel.com/

smatch warnings:
drivers/tty/serial/fsl_linflexuart.c:1441 linflex_probe() warn: missing unwind goto?

vim +1441 drivers/tty/serial/fsl_linflexuart.c

09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1377  static int linflex_probe(struct platform_device *pdev)
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1378  {
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1379  	struct device_node *np = pdev->dev.of_node;
1d3f5f07fafc71 Radu Pirea           2026-02-16  1380  	struct linflex_port *lfport;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1381  	struct uart_port *sport;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1382  	struct resource *res;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1383  	int ret;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1384  
1d3f5f07fafc71 Radu Pirea           2026-02-16  1385  	lfport = devm_kzalloc(&pdev->dev, sizeof(*lfport), GFP_KERNEL);
1d3f5f07fafc71 Radu Pirea           2026-02-16  1386  	if (!lfport)
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1387  		return -ENOMEM;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1388  
1d3f5f07fafc71 Radu Pirea           2026-02-16  1389  	sport = &lfport->port;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1390  	sport->dev = &pdev->dev;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1391  
0b34325c5f79f1 Larisa Grigore       2026-02-16  1392  	lfport->dma_tx_chan = dma_request_chan(sport->dev, "tx");
0b34325c5f79f1 Larisa Grigore       2026-02-16  1393  	if (IS_ERR(lfport->dma_tx_chan)) {
0b34325c5f79f1 Larisa Grigore       2026-02-16  1394  		ret = PTR_ERR(lfport->dma_tx_chan);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1395  		if (ret == -EPROBE_DEFER)
0b34325c5f79f1 Larisa Grigore       2026-02-16  1396  			return ret;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1397  
0b34325c5f79f1 Larisa Grigore       2026-02-16  1398  		dev_info(sport->dev,
0b34325c5f79f1 Larisa Grigore       2026-02-16  1399  			 "DMA tx channel request failed, operating without tx DMA %ld\n",
0b34325c5f79f1 Larisa Grigore       2026-02-16  1400  			 PTR_ERR(lfport->dma_tx_chan));
0b34325c5f79f1 Larisa Grigore       2026-02-16  1401  		lfport->dma_tx_chan = NULL;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1402  	}
0b34325c5f79f1 Larisa Grigore       2026-02-16  1403  
0b34325c5f79f1 Larisa Grigore       2026-02-16  1404  	lfport->dma_rx_chan = dma_request_chan(sport->dev, "rx");
0b34325c5f79f1 Larisa Grigore       2026-02-16  1405  	if (IS_ERR(lfport->dma_rx_chan)) {
0b34325c5f79f1 Larisa Grigore       2026-02-16  1406  		ret = PTR_ERR(lfport->dma_rx_chan);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1407  		if (ret == -EPROBE_DEFER) {
0b34325c5f79f1 Larisa Grigore       2026-02-16  1408  			dma_release_channel(lfport->dma_tx_chan);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1409  			return ret;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1410  		}
0b34325c5f79f1 Larisa Grigore       2026-02-16  1411  
0b34325c5f79f1 Larisa Grigore       2026-02-16  1412  		dev_info(sport->dev,
0b34325c5f79f1 Larisa Grigore       2026-02-16  1413  			 "DMA rx channel request failed, operating without rx DMA %ld\n",
0b34325c5f79f1 Larisa Grigore       2026-02-16  1414  			 PTR_ERR(lfport->dma_rx_chan));
0b34325c5f79f1 Larisa Grigore       2026-02-16  1415  		lfport->dma_rx_chan = NULL;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1416  	}
1d3f5f07fafc71 Radu Pirea           2026-02-16  1417  
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1418  	ret = of_alias_get_id(np, "serial");
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1419  	if (ret < 0) {
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1420  		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1421  		goto linflex_probe_free_dma;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1422  	}
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1423  	if (ret >= UART_NR) {
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1424  		dev_err(&pdev->dev, "driver limited to %d serial ports\n",
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1425  			UART_NR);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1426  		ret = -ENOMEM;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1427  		goto linflex_probe_free_dma;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1428  	}
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1429  
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1430  	sport->line = ret;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1431  
8c6d7e5fd50b45 Yangtao Li           2023-07-12  1432  	sport->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1433  	if (IS_ERR(sport->membase)) {
0b34325c5f79f1 Larisa Grigore       2026-02-16  1434  		ret = PTR_ERR(sport->membase);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1435  		goto linflex_probe_free_dma;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1436  	}
8c6d7e5fd50b45 Yangtao Li           2023-07-12  1437  	sport->mapbase = res->start;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1438  
4e8da86fc1f767 Zhang Shurong        2023-08-26  1439  	ret = platform_get_irq(pdev, 0);
4e8da86fc1f767 Zhang Shurong        2023-08-26  1440  	if (ret < 0)
4e8da86fc1f767 Zhang Shurong        2023-08-26 @1441  		return ret;

No clean up?

4e8da86fc1f767 Zhang Shurong        2023-08-26  1442  
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1443  	sport->iotype = UPIO_MEM;
4e8da86fc1f767 Zhang Shurong        2023-08-26  1444  	sport->irq = ret;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1445  	sport->ops = &linflex_pops;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1446  	sport->flags = UPF_BOOT_AUTOCONF;
4151bbed79f98b Dmitry Safonov       2019-12-13  1447  	sport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE);
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1448  
1d3f5f07fafc71 Radu Pirea           2026-02-16  1449  	ret = linflex_init_clk(lfport);
1d3f5f07fafc71 Radu Pirea           2026-02-16  1450  	if (ret)
0b34325c5f79f1 Larisa Grigore       2026-02-16  1451  		goto linflex_probe_free_dma;
1d3f5f07fafc71 Radu Pirea           2026-02-16  1452  
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1453  	linflex_ports[sport->line] = sport;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1454  
1d3f5f07fafc71 Radu Pirea           2026-02-16  1455  	platform_set_drvdata(pdev, lfport);
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1456  
1d3f5f07fafc71 Radu Pirea           2026-02-16  1457  	ret = uart_add_one_port(&linflex_reg, sport);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1458  	if (ret) {
1d3f5f07fafc71 Radu Pirea           2026-02-16  1459  		clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1460  		goto linflex_probe_free_dma;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1461  	}
0b34325c5f79f1 Larisa Grigore       2026-02-16  1462  
0b34325c5f79f1 Larisa Grigore       2026-02-16  1463  	return 0;
0b34325c5f79f1 Larisa Grigore       2026-02-16  1464  
0b34325c5f79f1 Larisa Grigore       2026-02-16  1465  linflex_probe_free_dma:
0b34325c5f79f1 Larisa Grigore       2026-02-16  1466  	if (lfport->dma_tx_chan)
0b34325c5f79f1 Larisa Grigore       2026-02-16  1467  		dma_release_channel(lfport->dma_tx_chan);
0b34325c5f79f1 Larisa Grigore       2026-02-16  1468  	if (lfport->dma_rx_chan)
0b34325c5f79f1 Larisa Grigore       2026-02-16  1469  		dma_release_channel(lfport->dma_rx_chan);
1d3f5f07fafc71 Radu Pirea           2026-02-16  1470  
1d3f5f07fafc71 Radu Pirea           2026-02-16  1471  	return ret;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09  1472  }

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH 12/13] serial: linflexuart: Add DMA support
Posted by kernel test robot 1 month, 2 weeks ago
Hi Larisa,

kernel test robot noticed the following build warnings:

[auto build test WARNING on tty/tty-testing]
[also build test WARNING on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus robh/for-next linus/master v6.19 next-20260216]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Larisa-Grigore/serial-linflexuart-Fix-locking-in-set_termios/20260216-231403
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link:    https://lore.kernel.org/r/20260216150205.212318-13-larisa.grigore%40oss.nxp.com
patch subject: [PATCH 12/13] serial: linflexuart: Add DMA support
config: i386-buildonly-randconfig-002-20260217 (https://download.01.org/0day-ci/archive/20260217/202602171112.rMhRspEp-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260217/202602171112.rMhRspEp-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602171112.rMhRspEp-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/tty/serial/fsl_linflexuart.c:1095:6: warning: variable 'baud' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
    1095 |         if (port->uartclk) {
         |             ^~~~~~~~~~~~~
   drivers/tty/serial/fsl_linflexuart.c:1113:67: note: uninitialized use occurs here
    1113 |         lfport->dma_rx_timeout = msecs_to_jiffies(DIV_ROUND_UP(10000000, baud));
         |                                                                          ^~~~
   include/linux/math.h:49:22: note: expanded from macro 'DIV_ROUND_UP'
      49 | #define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP
         |                      ^
   include/uapi/linux/const.h:51:46: note: expanded from macro '__KERNEL_DIV_ROUND_UP'
      51 | #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
         |                                              ^
   drivers/tty/serial/fsl_linflexuart.c:1095:2: note: remove the 'if' if its condition is always true
    1095 |         if (port->uartclk) {
         |         ^~~~~~~~~~~~~~~~~~
   drivers/tty/serial/fsl_linflexuart.c:970:19: note: initialize the variable 'baud' to silence this warning
     970 |         unsigned int baud;
         |                          ^
         |                           = 0
   drivers/tty/serial/fsl_linflexuart.c:205:13: warning: unused function 'linflex_console_putchar' [-Wunused-function]
     205 | static void linflex_console_putchar(struct uart_port *port, unsigned char ch);
         |             ^~~~~~~~~~~~~~~~~~~~~~~
   2 warnings generated.


vim +1095 drivers/tty/serial/fsl_linflexuart.c

1d3f5f07fafc712 Radu Pirea           2026-02-16   959  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   960  static void
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   961  linflex_set_termios(struct uart_port *port, struct ktermios *termios,
bec5b814d46c2a7 Ilpo Järvinen        2022-08-16   962  		    const struct ktermios *old)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   963  {
0b34325c5f79f1f Larisa Grigore       2026-02-16   964  	struct linflex_port *lfport = to_linflex_port(port);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   965  	unsigned long flags;
1312e6586227421 Larisa Grigore       2026-02-16   966  	unsigned long cr, old_cr, cr1, gcr;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   967  	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
1d3f5f07fafc712 Radu Pirea           2026-02-16   968  	unsigned long ibr, fbr, divisr, dividr;
1d3f5f07fafc712 Radu Pirea           2026-02-16   969  	unsigned char ldiv_mul;
1d3f5f07fafc712 Radu Pirea           2026-02-16   970  	unsigned int baud;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   971  
a75137a58feb092 Radu Pirea           2026-02-16   972  	uart_port_lock_irqsave(port, &flags);
a75137a58feb092 Radu Pirea           2026-02-16   973  
0b34325c5f79f1f Larisa Grigore       2026-02-16   974  	_linflex_stop_rx(port);
0b34325c5f79f1f Larisa Grigore       2026-02-16   975  	_linflex_stop_tx(port);
0b34325c5f79f1f Larisa Grigore       2026-02-16   976  
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   977  	old_cr = readl(port->membase + UARTCR) &
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   978  		~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   979  	cr = old_cr;
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   980  
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   981  	/* In FIFO mode, we should make sure the fifo is empty
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   982  	 * before entering INITM.
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   983  	 */
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   984  	linflex_wait_tx_fifo_empty(port);
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   985  
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   986  	/* disable transmit and receive */
fb1da4d7f0bec28 Larisa Grigore       2026-02-16   987  	writel(old_cr, port->membase + UARTCR);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   988  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   989  	/* Enter initialization mode by setting INIT bit */
5e8e1ccacae0470 Larisa Grigore       2026-02-16   990  	cr1 = LINFLEXD_LINCR1_INIT | LINFLEXD_LINCR1_MME;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   991  	writel(cr1, port->membase + LINCR1);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   992  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   993  	/* wait for init mode entry */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   994  	while ((readl(port->membase + LINSR)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   995  		& LINFLEXD_LINSR_LINS_MASK)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   996  		!= LINFLEXD_LINSR_LINS_INITMODE)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   997  		;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   998  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09   999  	/*
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1000  	 * only support CS8 and CS7, and for CS7 must enable PE.
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1001  	 * supported mode:
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1002  	 *	- (7,e/o,1)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1003  	 *	- (8,n,1)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1004  	 *	- (8,e/o,1)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1005  	 */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1006  	/* enter the UART into configuration mode */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1007  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1008  	while ((termios->c_cflag & CSIZE) != CS8 &&
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1009  	       (termios->c_cflag & CSIZE) != CS7) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1010  		termios->c_cflag &= ~CSIZE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1011  		termios->c_cflag |= old_csize;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1012  		old_csize = CS8;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1013  	}
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1014  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1015  	if ((termios->c_cflag & CSIZE) == CS7) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1016  		/* Word length: WL1WL0:00 */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1017  		cr = old_cr & ~LINFLEXD_UARTCR_WL1 & ~LINFLEXD_UARTCR_WL0;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1018  	}
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1019  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1020  	if ((termios->c_cflag & CSIZE) == CS8) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1021  		/* Word length: WL1WL0:01 */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1022  		cr = (old_cr | LINFLEXD_UARTCR_WL0) & ~LINFLEXD_UARTCR_WL1;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1023  	}
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1024  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1025  	if (termios->c_cflag & CMSPAR) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1026  		if ((termios->c_cflag & CSIZE) != CS8) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1027  			termios->c_cflag &= ~CSIZE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1028  			termios->c_cflag |= CS8;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1029  		}
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1030  		/* has a space/sticky bit */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1031  		cr |= LINFLEXD_UARTCR_WL0;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1032  	}
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1033  
1312e6586227421 Larisa Grigore       2026-02-16  1034  	gcr = readl(port->membase + GCR);
1312e6586227421 Larisa Grigore       2026-02-16  1035  
1312e6586227421 Larisa Grigore       2026-02-16  1036  	if (termios->c_cflag & CSTOPB) {
1312e6586227421 Larisa Grigore       2026-02-16  1037  		/* Use 2 stop bits. */
1312e6586227421 Larisa Grigore       2026-02-16  1038  		cr = (cr & ~LINFLEXD_UARTCR_SBUR_MASK) |
1312e6586227421 Larisa Grigore       2026-02-16  1039  			LINFLEXD_UARTCR_SBUR_2SBITS;
1312e6586227421 Larisa Grigore       2026-02-16  1040  		/* Set STOP in GCR field for 2 stop bits. */
1312e6586227421 Larisa Grigore       2026-02-16  1041  		gcr = (gcr & ~LINFLEXD_GCR_STOP_MASK) |
1312e6586227421 Larisa Grigore       2026-02-16  1042  			LINFLEXD_GCR_STOP_2SBITS;
1312e6586227421 Larisa Grigore       2026-02-16  1043  	} else {
1312e6586227421 Larisa Grigore       2026-02-16  1044  		/* Use 1 stop bit. */
1312e6586227421 Larisa Grigore       2026-02-16  1045  		cr = (cr & ~LINFLEXD_UARTCR_SBUR_MASK) |
1312e6586227421 Larisa Grigore       2026-02-16  1046  			LINFLEXD_UARTCR_SBUR_1SBITS;
1312e6586227421 Larisa Grigore       2026-02-16  1047  		/* Set STOP in GCR field for 1 stop bit. */
1312e6586227421 Larisa Grigore       2026-02-16  1048  		gcr = (gcr & ~LINFLEXD_GCR_STOP_MASK) |
1312e6586227421 Larisa Grigore       2026-02-16  1049  			LINFLEXD_GCR_STOP_1SBITS;
1312e6586227421 Larisa Grigore       2026-02-16  1050  	}
1312e6586227421 Larisa Grigore       2026-02-16  1051  	/* Update GCR register. */
1312e6586227421 Larisa Grigore       2026-02-16  1052  	writel(gcr, port->membase + GCR);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1053  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1054  	/* parity must be enabled when CS7 to match 8-bits format */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1055  	if ((termios->c_cflag & CSIZE) == CS7)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1056  		termios->c_cflag |= PARENB;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1057  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1058  	if ((termios->c_cflag & PARENB)) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1059  		cr |= LINFLEXD_UARTCR_PCE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1060  		if (termios->c_cflag & PARODD)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1061  			cr = (cr | LINFLEXD_UARTCR_PC0) &
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1062  			     (~LINFLEXD_UARTCR_PC1);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1063  		else
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1064  			cr = cr & (~LINFLEXD_UARTCR_PC1 &
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1065  				   ~LINFLEXD_UARTCR_PC0);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1066  	} else {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1067  		cr &= ~LINFLEXD_UARTCR_PCE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1068  	}
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1069  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1070  	port->read_status_mask = 0;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1071  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1072  	if (termios->c_iflag & INPCK)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1073  		port->read_status_mask |=	(LINFLEXD_UARTSR_FEF |
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1074  						 LINFLEXD_UARTSR_PE0 |
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1075  						 LINFLEXD_UARTSR_PE1 |
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1076  						 LINFLEXD_UARTSR_PE2 |
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1077  						 LINFLEXD_UARTSR_PE3);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1078  	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1079  		port->read_status_mask |= LINFLEXD_UARTSR_FEF;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1080  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1081  	/* characters to ignore */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1082  	port->ignore_status_mask = 0;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1083  	if (termios->c_iflag & IGNPAR)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1084  		port->ignore_status_mask |= LINFLEXD_UARTSR_PE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1085  	if (termios->c_iflag & IGNBRK) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1086  		port->ignore_status_mask |= LINFLEXD_UARTSR_PE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1087  		/*
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1088  		 * if we're ignoring parity and break indicators,
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1089  		 * ignore overruns too (for real raw support).
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1090  		 */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1091  		if (termios->c_iflag & IGNPAR)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1092  			port->ignore_status_mask |= LINFLEXD_UARTSR_BOF;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1093  	}
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1094  
1d3f5f07fafc712 Radu Pirea           2026-02-16 @1095  	if (port->uartclk) {
1d3f5f07fafc712 Radu Pirea           2026-02-16  1096  		ldiv_mul = linflex_ldiv_multiplier(port);
1d3f5f07fafc712 Radu Pirea           2026-02-16  1097  		baud = uart_get_baud_rate(port, termios, old, 0,
1d3f5f07fafc712 Radu Pirea           2026-02-16  1098  					  port->uartclk / ldiv_mul);
1d3f5f07fafc712 Radu Pirea           2026-02-16  1099  
1d3f5f07fafc712 Radu Pirea           2026-02-16  1100  		/* update the per-port timeout */
1d3f5f07fafc712 Radu Pirea           2026-02-16  1101  		uart_update_timeout(port, termios->c_cflag, baud);
1d3f5f07fafc712 Radu Pirea           2026-02-16  1102  
1d3f5f07fafc712 Radu Pirea           2026-02-16  1103  		divisr = port->uartclk;
1d3f5f07fafc712 Radu Pirea           2026-02-16  1104  		dividr = ((unsigned long)baud * ldiv_mul);
1d3f5f07fafc712 Radu Pirea           2026-02-16  1105  
1d3f5f07fafc712 Radu Pirea           2026-02-16  1106  		ibr = divisr / dividr;
1d3f5f07fafc712 Radu Pirea           2026-02-16  1107  		fbr = ((divisr % dividr) * 16 / dividr) & 0xF;
1d3f5f07fafc712 Radu Pirea           2026-02-16  1108  
1d3f5f07fafc712 Radu Pirea           2026-02-16  1109  		writel(ibr, port->membase + LINIBRR);
1d3f5f07fafc712 Radu Pirea           2026-02-16  1110  		writel(fbr, port->membase + LINFBRR);
1d3f5f07fafc712 Radu Pirea           2026-02-16  1111  	}
1d3f5f07fafc712 Radu Pirea           2026-02-16  1112  
0b34325c5f79f1f Larisa Grigore       2026-02-16  1113  	lfport->dma_rx_timeout = msecs_to_jiffies(DIV_ROUND_UP(10000000, baud));
0b34325c5f79f1f Larisa Grigore       2026-02-16  1114  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1115  	writel(cr, port->membase + UARTCR);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1116  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1117  	cr1 &= ~(LINFLEXD_LINCR1_INIT);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1118  
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1119  	writel(cr1, port->membase + LINCR1);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1120  
fb1da4d7f0bec28 Larisa Grigore       2026-02-16  1121  	cr |= (LINFLEXD_UARTCR_TXEN) | (LINFLEXD_UARTCR_RXEN);
fb1da4d7f0bec28 Larisa Grigore       2026-02-16  1122  	writel(cr, port->membase + UARTCR);
fb1da4d7f0bec28 Larisa Grigore       2026-02-16  1123  
0b34325c5f79f1f Larisa Grigore       2026-02-16  1124  	_linflex_start_rx(port);
0b34325c5f79f1f Larisa Grigore       2026-02-16  1125  	_linflex_start_tx(port);
0b34325c5f79f1f Larisa Grigore       2026-02-16  1126  
7c6725ffd581335 Thomas Gleixner      2023-09-14  1127  	uart_port_unlock_irqrestore(port, flags);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1128  }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09  1129  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH 12/13] serial: linflexuart: Add DMA support
Posted by kernel test robot 1 month, 2 weeks ago
Hi Larisa,

kernel test robot noticed the following build warnings:

[auto build test WARNING on tty/tty-testing]
[also build test WARNING on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus robh/for-next linus/master v6.19 next-20260216]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Larisa-Grigore/serial-linflexuart-Fix-locking-in-set_termios/20260216-231403
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link:    https://lore.kernel.org/r/20260216150205.212318-13-larisa.grigore%40oss.nxp.com
patch subject: [PATCH 12/13] serial: linflexuart: Add DMA support
config: parisc-randconfig-001-20260217 (https://download.01.org/0day-ci/archive/20260217/202602170428.SOCWu0Wb-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260217/202602170428.SOCWu0Wb-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602170428.SOCWu0Wb-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/tty/serial/fsl_linflexuart.c:205:13: warning: 'linflex_console_putchar' declared 'static' but never defined [-Wunused-function]
     205 | static void linflex_console_putchar(struct uart_port *port, unsigned char ch);
         |             ^~~~~~~~~~~~~~~~~~~~~~~


vim +205 drivers/tty/serial/fsl_linflexuart.c

   202	
   203	static void linflex_dma_tx_complete(void *arg);
   204	static void linflex_dma_rx_complete(void *arg);
 > 205	static void linflex_console_putchar(struct uart_port *port, unsigned char ch);
   206	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH 12/13] serial: linflexuart: Add DMA support
Posted by Krzysztof Kozlowski 1 month, 2 weeks ago
On 16/02/2026 16:02, Larisa Grigore wrote:
> Add support for using DMA to avoid generating one interrupt per
> character and losing characters while copy-paste.
> In UART mode, the DMA capability can be used only if the UART Tx/Rx
> buffers are configured as FIFOs.
> If the DMA related properties are missing from the device tree, the
> driver will fall back to interrupt + Buffer mode.
> On the RX side, a timer is used to periodically poll for received data.
> 
> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> Co-developed-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
> Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
> Co-developed-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> Co-developed-by: Phu Luu An <phu.luuan@nxp.com>
> Signed-off-by: Phu Luu An <phu.luuan@nxp.com>
> Co-developed-by: Js Ha <js.ha@nxp.com>
> Signed-off-by: Js Ha <js.ha@nxp.com>
> Co-developed-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
> Signed-off-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>


Incorrect DCO chain. Please read submitting patches document.

Best regards,
Krzysztof