Linux Serial subsystem development
 help / color / mirror / Atom feed
* [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev
@ 2026-09-25 20:08 Frank.Li
  2026-09-25 20:08 ` [PATCH 2/2] serial: amba-pl011: use dmaengine public API instead of raw ops Frank.Li
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Frank.Li @ 2026-09-25 20:08 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Russell King, Krzysztof Kozlowski,
	Peter Griffin, Alim Akhtar, Cunhao Lu, Frank Li, Raul E Rangel,
	Moteen Shah, Kendall Willis, Dhruva Gole, Andy Shevchenko,
	Matthias Feser, Kartik Rajput, Fan Wu, Karl Mehltretter,
	Peter Maydell, Stefan Dösinger, Haoxiang Li,
	Mike Rapoport (Microsoft), Zhaoyang Yu, Kees Cook, John Ogness,
	Biju Das, Geert Uytterhoeven, Lad Prabhakar, Cosmin Tanislav,
	open list:TTY LAYER AND SERIAL DRIVERS,
	open list:TTY LAYER AND SERIAL DRIVERS,
	moderated list:ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES,
	open list:ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES
  Cc: vkoul, imx

From: Frank Li <Frank.Li@nxp.com>

Replace direct dma_chan::device::dev access with the proper
dmaengine_get_dma_device() for consumer API

chan->device->dev is not always the device used for DMA mapping.
Some DMA engines support per-channel IOMMU mappings, so different
channels may use different DMA devices.  dmaengine_get_dma_device()
returns the correct device for each channel.

This also prepares for making the DMA engine provider data structures
private. DMA consumers should not access DMA engine internals directly.

Assisted-by: LLM
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Check all unders driver/tty/ by rename device to _device in dma_chan struct
with all yes config.

Still few left, one for copy_align access, which need new API. some filter
DMA channel, need new API to get provider devices.

In https://lore.kernel.org/imx/67966b47-22cb-4b07-80c7-2044f557dbcb@app.fastmail.com/
There are better idea to move map singe/sg into dma prep functions.

But it takes more times, not straightforward works. Let replace this firstly,
---
 drivers/tty/serial/8250/8250_dma.c  | 21 +++++++++++++--------
 drivers/tty/serial/8250/8250_omap.c |  4 ++--
 drivers/tty/serial/amba-pl011.c     | 10 +++++-----
 drivers/tty/serial/pch_uart.c       |  2 +-
 drivers/tty/serial/samsung_tty.c    | 27 +++++++++++++++------------
 drivers/tty/serial/sh-sci.c         | 14 ++++++++------
 6 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index 5a83e5269b415..dc7fb3db1584d 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -19,7 +19,7 @@ static void __dma_tx_complete(void *param)
 	unsigned long	flags;
 	int		ret;
 
-	dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
+	dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
 				UART_XMIT_SIZE, DMA_TO_DEVICE);
 
 	uart_port_lock_irqsave(&p->port, &flags);
@@ -136,7 +136,7 @@ int serial8250_tx_dma(struct uart_8250_port *p)
 
 	dma->tx_cookie = dmaengine_submit(desc);
 
-	dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
+	dma_sync_single_for_device(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
 				   UART_XMIT_SIZE, DMA_TO_DEVICE);
 
 	dma_async_issue_pending(dma->txchan);
@@ -223,6 +223,8 @@ EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
 int serial8250_request_dma(struct uart_8250_port *p)
 {
 	struct uart_8250_dma	*dma = p->dma;
+	struct device *rx_dev;
+	struct device *tx_dev;
 	phys_addr_t rx_dma_addr = dma->rx_dma_addr ?
 				  dma->rx_dma_addr : p->port.mapbase;
 	phys_addr_t tx_dma_addr = dma->tx_dma_addr ?
@@ -282,11 +284,14 @@ int serial8250_request_dma(struct uart_8250_port *p)
 
 	dmaengine_slave_config(dma->txchan, &dma->txconf);
 
+	rx_dev = dmaengine_get_dma_device(dma->rxchan);
+	tx_dev = dmaengine_get_dma_device(dma->txchan);
+
 	/* RX buffer */
 	if (!dma->rx_size)
 		dma->rx_size = PAGE_SIZE;
 
-	dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
+	dma->rx_buf = dma_alloc_coherent(rx_dev, dma->rx_size,
 					&dma->rx_addr, GFP_KERNEL);
 	if (!dma->rx_buf) {
 		ret = -ENOMEM;
@@ -294,12 +299,12 @@ int serial8250_request_dma(struct uart_8250_port *p)
 	}
 
 	/* TX buffer */
-	dma->tx_addr = dma_map_single(dma->txchan->device->dev,
+	dma->tx_addr = dma_map_single(tx_dev,
 					p->port.state->port.xmit_buf,
 					UART_XMIT_SIZE,
 					DMA_TO_DEVICE);
-	if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
-		dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
+	if (dma_mapping_error(tx_dev, dma->tx_addr)) {
+		dma_free_coherent(rx_dev, dma->rx_size,
 				  dma->rx_buf, dma->rx_addr);
 		ret = -ENOMEM;
 		goto err;
@@ -326,14 +331,14 @@ void serial8250_release_dma(struct uart_8250_port *p)
 	/* Release RX resources */
 	dmaengine_terminate_sync(dma->rxchan);
 	dma->rx_running = 0;
-	dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
+	dma_free_coherent(dmaengine_get_dma_device(dma->rxchan), dma->rx_size, dma->rx_buf,
 			  dma->rx_addr);
 	dma_release_channel(dma->rxchan);
 	dma->rxchan = NULL;
 
 	/* Release TX resources */
 	dmaengine_terminate_sync(dma->txchan);
-	dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
+	dma_unmap_single(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
 			 UART_XMIT_SIZE, DMA_TO_DEVICE);
 	dma_release_channel(dma->txchan);
 	dma->txchan = NULL;
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index ceecb39fb82da..3a1473bf54d0f 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1076,7 +1076,7 @@ static void omap_8250_dma_tx_complete(void *param)
 	bool			en_thri = false;
 	struct omap8250_priv	*priv = p->port.private_data;
 
-	dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
+	dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
 				UART_XMIT_SIZE, DMA_TO_DEVICE);
 
 	guard(uart_port_lock_irqsave)(&p->port);
@@ -1193,7 +1193,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
 
 	dma->tx_cookie = dmaengine_submit(desc);
 
-	dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
+	dma_sync_single_for_device(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
 				   UART_XMIT_SIZE, DMA_TO_DEVICE);
 
 	dma_async_issue_pending(dma->txchan);
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index c4824c201e1c3..86729ddbdadc8 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -435,7 +435,7 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
 static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
 			     enum dma_data_direction dir)
 {
-	db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
+	db->buf = dma_alloc_coherent(dmaengine_get_dma_device(chan), PL011_DMA_BUFFER_SIZE,
 				     &db->dma, GFP_KERNEL);
 	if (!db->buf)
 		return -ENOMEM;
@@ -448,7 +448,7 @@ static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
 			      enum dma_data_direction dir)
 {
 	if (db->buf) {
-		dma_free_coherent(chan->device->dev,
+		dma_free_coherent(dmaengine_get_dma_device(chan),
 				  PL011_DMA_BUFFER_SIZE, db->buf, db->dma);
 	}
 }
@@ -609,7 +609,7 @@ static void pl011_dma_tx_callback(void *data)
 
 	uart_port_lock_irqsave(&uap->port, &flags);
 	if (uap->dmatx.queued)
-		dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
+		dma_unmap_single(dmaengine_get_dma_device(dmatx->chan), dmatx->dma,
 				 dmatx->len, DMA_TO_DEVICE);
 
 	dmacr = uap->dmacr;
@@ -867,7 +867,7 @@ __acquires(&uap->port.lock)
 	dmaengine_terminate_async(uap->dmatx.chan);
 
 	if (uap->dmatx.queued) {
-		dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma,
+		dma_unmap_single(dmaengine_get_dma_device(uap->dmatx.chan), uap->dmatx.dma,
 				 uap->dmatx.len, DMA_TO_DEVICE);
 		uap->dmatx.queued = false;
 		uap->dmacr &= ~UART011_TXDMAE;
@@ -1249,7 +1249,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
 		/* In theory, this should already be done by pl011_dma_flush_buffer */
 		dmaengine_terminate_sync(uap->dmatx.chan);
 		if (uap->dmatx.queued) {
-			dma_unmap_single(uap->dmatx.chan->device->dev,
+			dma_unmap_single(dmaengine_get_dma_device(uap->dmatx.chan),
 					 uap->dmatx.dma, uap->dmatx.len,
 					 DMA_TO_DEVICE);
 			uap->dmatx.queued = false;
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index db5c62b0322f6..5e8540e835351 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -656,7 +656,7 @@ static bool filter(struct dma_chan *chan, void *slave)
 	struct pch_dma_slave *param = slave;
 
 	if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
-						  chan->device->dev)) {
+						  dmaengine_get_dma_device(chan))) {
 		chan->private = param;
 		return true;
 	} else {
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 63d0232dffc20..640f85e2d636b 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -300,7 +300,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
 		dmaengine_pause(dma->tx_chan);
 		dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
 		dmaengine_terminate_all(dma->tx_chan);
-		dma_sync_single_for_cpu(dma->tx_chan->device->dev,
+		dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->tx_chan),
 					dma->tx_transfer_addr, dma->tx_size,
 					DMA_TO_DEVICE);
 		async_tx_ack(dma->tx_desc);
@@ -333,7 +333,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
 	count = dma->tx_bytes_requested - state.residue;
 	async_tx_ack(dma->tx_desc);
 
-	dma_sync_single_for_cpu(dma->tx_chan->device->dev,
+	dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->tx_chan),
 				dma->tx_transfer_addr, dma->tx_size,
 				DMA_TO_DEVICE);
 
@@ -435,7 +435,7 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
 	dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
 	dma->tx_transfer_addr = dma->tx_addr + tail;
 
-	dma_sync_single_for_device(dma->tx_chan->device->dev,
+	dma_sync_single_for_device(dmaengine_get_dma_device(dma->tx_chan),
 				   dma->tx_transfer_addr, dma->tx_size,
 				   DMA_TO_DEVICE);
 
@@ -509,7 +509,7 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
 	if (!count)
 		return;
 
-	dma_sync_single_for_cpu(dma->rx_chan->device->dev, dma->rx_addr,
+	dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
 				dma->rx_size, DMA_FROM_DEVICE);
 
 	ourport->port.icount.rx += count;
@@ -631,7 +631,7 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
 {
 	struct s3c24xx_uart_dma *dma = ourport->dma;
 
-	dma_sync_single_for_device(dma->rx_chan->device->dev, dma->rx_addr,
+	dma_sync_single_for_device(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
 				   dma->rx_size, DMA_FROM_DEVICE);
 
 	dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
@@ -1101,20 +1101,23 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
 		goto err_release_tx;
 	}
 
-	dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+	struct device *rx_dev = dmaengine_get_dma_device(dma->rx_chan);
+	struct device *tx_dev = dmaengine_get_dma_device(dma->tx_chan);
+
+	dma->rx_addr = dma_map_single(rx_dev, dma->rx_buf,
 				      dma->rx_size, DMA_FROM_DEVICE);
-	if (dma_mapping_error(dma->rx_chan->device->dev, dma->rx_addr)) {
+	if (dma_mapping_error(rx_dev, dma->rx_addr)) {
 		reason = "DMA mapping error for RX buffer";
 		ret = -EIO;
 		goto err_free_rx;
 	}
 
 	/* TX buffer */
-	dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
+	dma->tx_addr = dma_map_single(tx_dev,
 				      p->port.state->port.xmit_buf,
 				      UART_XMIT_SIZE,
 				      DMA_TO_DEVICE);
-	if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) {
+	if (dma_mapping_error(tx_dev, dma->tx_addr)) {
 		reason = "DMA mapping error for TX buffer";
 		ret = -EIO;
 		goto err_unmap_rx;
@@ -1123,7 +1126,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
 	return 0;
 
 err_unmap_rx:
-	dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+	dma_unmap_single(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
 			 dma->rx_size, DMA_FROM_DEVICE);
 err_free_rx:
 	kfree(dma->rx_buf);
@@ -1143,7 +1146,7 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
 
 	if (dma->rx_chan) {
 		dmaengine_terminate_all(dma->rx_chan);
-		dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+		dma_unmap_single(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
 				 dma->rx_size, DMA_FROM_DEVICE);
 		kfree(dma->rx_buf);
 		dma_release_channel(dma->rx_chan);
@@ -1152,7 +1155,7 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
 
 	if (dma->tx_chan) {
 		dmaengine_terminate_all(dma->tx_chan);
-		dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+		dma_unmap_single(dmaengine_get_dma_device(dma->tx_chan), dma->tx_addr,
 				 UART_XMIT_SIZE, DMA_TO_DEVICE);
 		dma_release_channel(dma->tx_chan);
 		dma->tx_chan = NULL;
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 50ae9aae6b614..bd58bbfa65aa7 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1495,7 +1495,7 @@ static void sci_dma_rx_release(struct sci_port *s)
 	uart_port_unlock_irqrestore(port, flags);
 
 	dmaengine_terminate_sync(chan);
-	dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
+	dma_free_coherent(dmaengine_get_dma_device(chan), s->buf_len_rx * 2, s->rx_buf[0],
 			  sg_dma_address(&s->sg_rx[0]));
 	dma_release_channel(chan);
 }
@@ -1591,7 +1591,7 @@ static void sci_dma_tx_release(struct sci_port *s)
 	s->chan_tx_saved = s->chan_tx = NULL;
 	s->cookie_tx = -EINVAL;
 	dmaengine_terminate_sync(chan);
-	dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
+	dma_unmap_single(dmaengine_get_dma_device(chan), s->tx_dma_addr, UART_XMIT_SIZE,
 			 DMA_TO_DEVICE);
 	dma_release_channel(chan);
 }
@@ -1676,7 +1676,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
 		goto switch_to_pio;
 	}
 
-	dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
+	dma_sync_single_for_device(dmaengine_get_dma_device(chan), buf, s->tx_dma_len,
 				   DMA_TO_DEVICE);
 
 	desc->callback = sci_dma_tx_complete;
@@ -1832,12 +1832,13 @@ static void sci_request_dma(struct uart_port *port)
 	chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV);
 	dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
 	if (chan) {
+		struct device *dma_dev = dmaengine_get_dma_device(chan);
 		/* UART circular tx buffer is an aligned page. */
-		s->tx_dma_addr = dma_map_single(chan->device->dev,
+		s->tx_dma_addr = dma_map_single(dma_dev,
 						tport->xmit_buf,
 						UART_XMIT_SIZE,
 						DMA_TO_DEVICE);
-		if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
+		if (dma_mapping_error(dma_dev, s->tx_dma_addr)) {
 			dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n");
 			dma_release_channel(chan);
 		} else {
@@ -1853,12 +1854,13 @@ static void sci_request_dma(struct uart_port *port)
 	chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM);
 	dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
 	if (chan) {
+		struct device *dma_dev = dmaengine_get_dma_device(chan);
 		unsigned int i;
 		dma_addr_t dma;
 		void *buf;
 
 		s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize);
-		buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2,
+		buf = dma_alloc_coherent(dma_dev, s->buf_len_rx * 2,
 					 &dma, GFP_KERNEL);
 		if (!buf) {
 			dev_warn(port->dev,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] serial: amba-pl011: use dmaengine public API instead of raw ops
  2026-09-25 20:08 [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev Frank.Li
@ 2026-09-25 20:08 ` Frank.Li
  2026-09-25 20:16   ` sashiko-bot
  2026-09-25 20:19 ` [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev sashiko-bot
  2026-09-28  8:51 ` Andy Shevchenko
  2 siblings, 1 reply; 5+ messages in thread
From: Frank.Li @ 2026-09-25 20:08 UTC (permalink / raw)
  To: Russell King, Greg Kroah-Hartman, Jiri Slaby, Kartik Rajput,
	Fan Wu, Karl Mehltretter, Frank Li, Stefan Dösinger,
	Peter Maydell, open list:TTY LAYER AND SERIAL DRIVERS,
	open list:TTY LAYER AND SERIAL DRIVERS
  Cc: vkoul, imx

From: Frank Li <Frank.Li@nxp.com>

Replace direct calls to the internal DMA device ops
(device->device_tx_status() and device->device_issue_pending())
with the proper public DMA engine wrappers:
  - dmaengine_tx_status()
  - dma_async_issue_pending()

Drivers must not call device ops directly; the wrappers provide
locking, debug checks, and a stable interface that hides internal
implementation details of the DMA controller driver.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 drivers/tty/serial/amba-pl011.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 86729ddbdadc8..cd9128b213c94 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -721,7 +721,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
 	dmaengine_submit(desc);
 
 	/* Fire the DMA transaction */
-	dma_dev->device_issue_pending(chan);
+	dma_async_issue_pending(chan);
 
 	uap->dmacr |= UART011_TXDMAE;
 	pl011_write(uap->dmacr, uap, REG_DMACR);
@@ -1011,8 +1011,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
 	 */
 	if (dmaengine_pause(rxchan))
 		dev_err(uap->port.dev, "unable to pause DMA transfer\n");
-	dmastat = rxchan->device->device_tx_status(rxchan,
-						   dmarx->cookie, &state);
+	dmastat = dmaengine_tx_status(rxchan, dmarx->cookie, &state);
 	if (dmastat != DMA_PAUSED)
 		dev_err(uap->port.dev, "unable to pause DMA transfer\n");
 
@@ -1066,7 +1065,7 @@ static void pl011_dma_rx_callback(void *data)
 	 * Rx data can be taken by the UART interrupts during
 	 * the DMA irq handler. So we check the residue here.
 	 */
-	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
+	dmaengine_tx_status(rxchan, dmarx->cookie, &state);
 	pending = dbuf->len - state.residue;
 	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
 	/* Then we terminate the transfer - we now know our residue */
@@ -1124,7 +1123,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
 	struct dma_tx_state state;
 
 	dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
-	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
+	dmaengine_tx_status(rxchan, dmarx->cookie, &state);
 	if (likely(state.residue < dmarx->last_residue)) {
 		dmataken = dbuf->len - dmarx->last_residue;
 		size = dmarx->last_residue - state.residue;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] serial: amba-pl011: use dmaengine public API instead of raw ops
  2026-09-25 20:08 ` [PATCH 2/2] serial: amba-pl011: use dmaengine public API instead of raw ops Frank.Li
@ 2026-09-25 20:16   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-25 20:16 UTC (permalink / raw)
  To: Frank.Li; +Cc: Frank.Li, imx, linux-serial

> From: Frank Li <Frank.Li@nxp.com>
> 
> Replace direct calls to the internal DMA device ops
> (device->device_tx_status() and device->device_issue_pending())
> with the proper public DMA engine wrappers:
>   - dmaengine_tx_status()
>   - dma_async_issue_pending()
> 
> Drivers must not call device ops directly; the wrappers provide
> locking, debug checks, and a stable interface that hides internal
> implementation details of the DMA controller driver.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260925200850.1678179-1-Frank.Li@oss.nxp.com?part=2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev
  2026-09-25 20:08 [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev Frank.Li
  2026-09-25 20:08 ` [PATCH 2/2] serial: amba-pl011: use dmaengine public API instead of raw ops Frank.Li
@ 2026-09-25 20:19 ` sashiko-bot
  2026-09-28  8:51 ` Andy Shevchenko
  2 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-25 20:19 UTC (permalink / raw)
  To: Frank.Li; +Cc: Frank.Li, imx, linux-serial

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] dma-mapping: asymmetric dma_map_single/unmap pair in pl011
--

commit fb77536d75ed603638aebc851f73960ddf8efe10
Author: Frank Li <Frank.Li@nxp.com>

serial: use dmaengine_get_dma_device() instead of chan->device->dev

This commit replaces direct access to chan->device->dev with the
dmaengine_get_dma_device() API across multiple serial drivers. This correctly
handles per-channel IOMMU mappings and prepares for making DMA engine
provider structures private.

Link: https://lore.kernel.org/imx/67966b47-22cb-4b07-80c7-2044f557dbcb@app.fastmail.com/

> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index c4824c201e1c3..86729ddbdadc8 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c

[ ... ]

> @@ -609,7 +609,7 @@ static void pl011_dma_tx_callback(void *data)
>  
>  	uart_port_lock_irqsave(&uap->port, &flags);
>  	if (uap->dmatx.queued)
> -		dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
> +		dma_unmap_single(dmaengine_get_dma_device(dmatx->chan), dmatx->dma,

[Severity: High]
Does this change create an asymmetric map/unmap pair in the PL011 driver?

By updating pl011_dma_tx_callback() to use dmaengine_get_dma_device() for the
unmap operation, it appears to no longer match the map operation in
pl011_dma_tx_refill() which was not updated in this patch:

drivers/tty/serial/amba-pl011.c:pl011_dma_tx_refill() {
    ...
	dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
				    DMA_TO_DEVICE);
    ...
}

The DMA API requires the exact same device pointer to be used for both
mapping and unmapping. On platforms where the DMA engine provides per-channel
devices, dmaengine_get_dma_device() will return a different device pointer
than the raw device pointer used during mapping.

Could this break DMA tracking or cause IOMMU faults during standard TX
operations? Should the map operation in pl011_dma_tx_refill() be updated to
use the new API as well?

>  				 dmatx->len, DMA_TO_DEVICE);
>  
>  	dmacr = uap->dmacr;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260925200850.1678179-1-Frank.Li@oss.nxp.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev
  2026-09-25 20:08 [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev Frank.Li
  2026-09-25 20:08 ` [PATCH 2/2] serial: amba-pl011: use dmaengine public API instead of raw ops Frank.Li
  2026-09-25 20:19 ` [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev sashiko-bot
@ 2026-09-28  8:51 ` Andy Shevchenko
  2 siblings, 0 replies; 5+ messages in thread
From: Andy Shevchenko @ 2026-09-28  8:51 UTC (permalink / raw)
  To: Frank.Li
  Cc: Greg Kroah-Hartman, Jiri Slaby, Russell King, Krzysztof Kozlowski,
	Peter Griffin, Alim Akhtar, Cunhao Lu, Frank Li, Raul E Rangel,
	Moteen Shah, Kendall Willis, Dhruva Gole, Matthias Feser,
	Kartik Rajput, Fan Wu, Karl Mehltretter, Peter Maydell,
	Stefan Dösinger, Haoxiang Li, Mike Rapoport (Microsoft),
	Zhaoyang Yu, Kees Cook, John Ogness, Biju Das, Geert Uytterhoeven,
	Lad Prabhakar, Cosmin Tanislav,
	open list:TTY LAYER AND SERIAL DRIVERS,
	open list:TTY LAYER AND SERIAL DRIVERS,
	moderated list:ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES,
	open list:ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES,
	vkoul, imx

On Fri, Sep 25, 2026 at 04:08:30PM -0400, Frank.Li@oss.nxp.com wrote:
> From: Frank Li <Frank.Li@nxp.com>
> 
> Replace direct dma_chan::device::dev access with the proper
> dmaengine_get_dma_device() for consumer API
> 
> chan->device->dev is not always the device used for DMA mapping.
> Some DMA engines support per-channel IOMMU mappings, so different
> channels may use different DMA devices.  dmaengine_get_dma_device()
> returns the correct device for each channel.
> 
> This also prepares for making the DMA engine provider data structures
> private. DMA consumers should not access DMA engine internals directly.

...

>  	/* RX buffer */
>  	if (!dma->rx_size)
>  		dma->rx_size = PAGE_SIZE;
>  
> -	dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
> +	dma->rx_buf = dma_alloc_coherent(rx_dev, dma->rx_size,
>  					&dma->rx_addr, GFP_KERNEL);

Now one parameter can be moved up and positive outcome the split becomes logical
(on a logic boundaries).

>  	if (!dma->rx_buf) {
>  		ret = -ENOMEM;

...

>  	/* TX buffer */
> -	dma->tx_addr = dma_map_single(dma->txchan->device->dev,
> +	dma->tx_addr = dma_map_single(tx_dev,
>  					p->port.state->port.xmit_buf,
>  					UART_XMIT_SIZE,
>  					DMA_TO_DEVICE);

You can fix indentation while at it.

> -	if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
> -		dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
> +	if (dma_mapping_error(tx_dev, dma->tx_addr)) {
> +		dma_free_coherent(rx_dev, dma->rx_size,
>  				  dma->rx_buf, dma->rx_addr);
>  		ret = -ENOMEM;

...

>  	/* Release RX resources */
>  	dmaengine_terminate_sync(dma->rxchan);
>  	dma->rx_running = 0;
> -	dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
> +	dma_free_coherent(dmaengine_get_dma_device(dma->rxchan), dma->rx_size, dma->rx_buf,
>  			  dma->rx_addr);

And here the last parameter of the previous line can be moved to the next line.

...

> +	db->buf = dma_alloc_coherent(dmaengine_get_dma_device(chan), PL011_DMA_BUFFER_SIZE,
>  				     &db->dma, GFP_KERNEL);

^^^ (1)

>  	if (!db->buf)
>  		return -ENOMEM;

...

>  {
>  	if (db->buf) {
> -		dma_free_coherent(chan->device->dev,
> +		dma_free_coherent(dmaengine_get_dma_device(chan),
>  				  PL011_DMA_BUFFER_SIZE, db->buf, db->dma);

Perhaps you want both (1) and this be consistent, either (1) be rewrapped,
or this one

		dma_free_coherent(dmaengine_get_dma_device(chan), PL011_DMA_BUFFER_SIZE,
				  db->buf, db->dma);

>  	}

...

>  	struct pch_dma_slave *param = slave;
>  
>  	if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
> -						  chan->device->dev)) {
> +						  dmaengine_get_dma_device(chan))) {

Even original code has broken indentation. What about rewrapping it?

	if ((chan->chan_id == param->chan_id) &&
	    (param->dma_dev == dmaengine_get_dma_device(chan))) {

>  		chan->private = param;
>  		return true;

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-28  8:51 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-25 20:08 [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev Frank.Li
2026-09-25 20:08 ` [PATCH 2/2] serial: amba-pl011: use dmaengine public API instead of raw ops Frank.Li
2026-09-25 20:16   ` sashiko-bot
2026-09-25 20:19 ` [PATCH 1/2] serial: use dmaengine_get_dma_device() instead of chan->device->dev sashiko-bot
2026-09-28  8:51 ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox