All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Add improvements for STM32 USART DMA TX
@ 2022-01-04 18:24 ` Valentin Caron
  0 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

This series reworks STM32 USART DMA TX state management, and fix flow control.

Valentin Caron (4):
  serial: stm32: move tx dma terminate DMA to shutdown
  serial: stm32: rework TX DMA state condition
  serial: stm32: fix flow control transfer in DMA mode
  serial: stm32: correct loop for dma error handling

 drivers/tty/serial/stm32-usart.c | 74 ++++++++++++++++++++++++--------
 drivers/tty/serial/stm32-usart.h |  2 +-
 2 files changed, 56 insertions(+), 20 deletions(-)

-- 
2.17.1


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

* [PATCH 0/4] Add improvements for STM32 USART DMA TX
@ 2022-01-04 18:24 ` Valentin Caron
  0 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

This series reworks STM32 USART DMA TX state management, and fix flow control.

Valentin Caron (4):
  serial: stm32: move tx dma terminate DMA to shutdown
  serial: stm32: rework TX DMA state condition
  serial: stm32: fix flow control transfer in DMA mode
  serial: stm32: correct loop for dma error handling

 drivers/tty/serial/stm32-usart.c | 74 ++++++++++++++++++++++++--------
 drivers/tty/serial/stm32-usart.h |  2 +-
 2 files changed, 56 insertions(+), 20 deletions(-)

-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 1/4] serial: stm32: move tx dma terminate DMA to shutdown
  2022-01-04 18:24 ` Valentin Caron
@ 2022-01-04 18:24   ` Valentin Caron
  -1 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

Terminate DMA transaction and clear CR3_DMAT when shutdown is requested,
instead of when remove is requested. If DMA transfer is not stopped in
shutdown ops, driver will fail to start a new DMA transfer after next
startup ops.

Fixes: 3489187204eb ("serial: stm32: adding dma support")

Signed-off-by: Erwan Le Ray <erwan.leray@foss.st.com>
Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
---
 drivers/tty/serial/stm32-usart.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 3244e7f6818c..6cfc3bec6749 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -883,6 +883,11 @@ static void stm32_usart_shutdown(struct uart_port *port)
 	u32 val, isr;
 	int ret;
 
+	if (stm32_port->tx_dma_busy) {
+		dmaengine_terminate_async(stm32_port->tx_ch);
+		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+	}
+
 	/* Disable modem control interrupts */
 	stm32_usart_disable_ms(port);
 
@@ -1570,7 +1575,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
 	writel_relaxed(cr3, port->membase + ofs->cr3);
 
 	if (stm32_port->tx_ch) {
-		dmaengine_terminate_async(stm32_port->tx_ch);
 		stm32_usart_of_dma_tx_remove(stm32_port, pdev);
 		dma_release_channel(stm32_port->tx_ch);
 	}
-- 
2.17.1


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

* [PATCH 1/4] serial: stm32: move tx dma terminate DMA to shutdown
@ 2022-01-04 18:24   ` Valentin Caron
  0 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

Terminate DMA transaction and clear CR3_DMAT when shutdown is requested,
instead of when remove is requested. If DMA transfer is not stopped in
shutdown ops, driver will fail to start a new DMA transfer after next
startup ops.

Fixes: 3489187204eb ("serial: stm32: adding dma support")

Signed-off-by: Erwan Le Ray <erwan.leray@foss.st.com>
Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
---
 drivers/tty/serial/stm32-usart.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 3244e7f6818c..6cfc3bec6749 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -883,6 +883,11 @@ static void stm32_usart_shutdown(struct uart_port *port)
 	u32 val, isr;
 	int ret;
 
+	if (stm32_port->tx_dma_busy) {
+		dmaengine_terminate_async(stm32_port->tx_ch);
+		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+	}
+
 	/* Disable modem control interrupts */
 	stm32_usart_disable_ms(port);
 
@@ -1570,7 +1575,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
 	writel_relaxed(cr3, port->membase + ofs->cr3);
 
 	if (stm32_port->tx_ch) {
-		dmaengine_terminate_async(stm32_port->tx_ch);
 		stm32_usart_of_dma_tx_remove(stm32_port, pdev);
 		dma_release_channel(stm32_port->tx_ch);
 	}
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 2/4] serial: stm32: rework TX DMA state condition
  2022-01-04 18:24 ` Valentin Caron
@ 2022-01-04 18:24   ` Valentin Caron
  -1 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

TX DMA state condition is handled by tx_dma_busy boolean.
This boolean is set when dma descriptor is requested and reset when dma
channel is stopped (dma_terminate).

In stm32_usart_serial_remove(), stm32_usart_stop_tx() and
stm32_usart_transmit_chars_dma() fallback error case, DMA channel is
stopped but tx_dma_busy is not handled.

Rework the driver by using two new functions to solve this issue:
- stm32_usart_tx_dma_started return true if DMA TX have a descriptor.
- stm32_usart_tx_dma_enabled return true if DMAT bit is set.

stm32_usart_tx_dma_started uses tx_dma_busy flag to prevent dual DMA
transaction at the same time. This flag is set when a DMA transaction
begins and is unset when dmaengine_terminate_async function is called.
A new DMA transaction cannot be created if this flag is set.

Create a new function "stm32_usart_tx_dma_terminate" to be sure the flag
is unset after each call of dmaengine_terminate_async.

Signed-off-by: Erwan Le Ray <erwan.leray@foss.st.com>
Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
---
 drivers/tty/serial/stm32-usart.c | 66 +++++++++++++++++++++++---------
 drivers/tty/serial/stm32-usart.h |  2 +-
 2 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 6cfc3bec6749..52755a576bc2 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -365,6 +365,31 @@ static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force
 	return size;
 }
 
+static void stm32_usart_tx_dma_terminate(struct stm32_port *stm32_port)
+{
+	dmaengine_terminate_async(stm32_port->tx_ch);
+	stm32_port->tx_dma_busy = false;
+}
+
+static bool stm32_usart_tx_dma_started(struct stm32_port *stm32_port)
+{
+	/*
+	 * We cannot use the function "dmaengine_tx_status" to know the
+	 * status of DMA. This function does not show if the "dma complete"
+	 * callback of the DMA transaction has been called. So we prefer
+	 * to use "tx_dma_busy" flag to prevent dual DMA transaction at the
+	 * same time.
+	 */
+	return stm32_port->tx_dma_busy;
+}
+
+static bool stm32_usart_tx_dma_enabled(struct stm32_port *stm32_port)
+{
+	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+	return !!(readl_relaxed(stm32_port->port.membase + ofs->cr3) & USART_CR3_DMAT);
+}
+
 static void stm32_usart_tx_dma_complete(void *arg)
 {
 	struct uart_port *port = arg;
@@ -372,9 +397,8 @@ static void stm32_usart_tx_dma_complete(void *arg)
 	const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
 	unsigned long flags;
 
-	dmaengine_terminate_async(stm32port->tx_ch);
 	stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
-	stm32port->tx_dma_busy = false;
+	stm32_usart_tx_dma_terminate(stm32port);
 
 	/* Let's see if we have pending data to send */
 	spin_lock_irqsave(&port->lock, flags);
@@ -428,10 +452,8 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
 	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
 	struct circ_buf *xmit = &port->state->xmit;
 
-	if (stm32_port->tx_dma_busy) {
+	if (stm32_usart_tx_dma_enabled(stm32_port))
 		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
-		stm32_port->tx_dma_busy = false;
-	}
 
 	while (!uart_circ_empty(xmit)) {
 		/* Check that TDR is empty before filling FIFO */
@@ -457,10 +479,11 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
 	struct dma_async_tx_descriptor *desc = NULL;
 	unsigned int count, i;
 
-	if (stm32port->tx_dma_busy)
+	if (stm32_usart_tx_dma_started(stm32port)) {
+		if (!stm32_usart_tx_dma_enabled(stm32port))
+			stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
 		return;
-
-	stm32port->tx_dma_busy = true;
+	}
 
 	count = uart_circ_chars_pending(xmit);
 
@@ -491,13 +514,21 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
 	if (!desc)
 		goto fallback_err;
 
+	/*
+	 * Set "tx_dma_busy" flag. This flag will be released when
+	 * dmaengine_terminate_async will be called. This flag helps
+	 * transmit_chars_dma not to start another DMA transaction
+	 * if the callback of the previous is not yet called.
+	 */
+	stm32port->tx_dma_busy = true;
+
 	desc->callback = stm32_usart_tx_dma_complete;
 	desc->callback_param = port;
 
 	/* Push current DMA TX transaction in the pending queue */
 	if (dma_submit_error(dmaengine_submit(desc))) {
 		/* dma no yet started, safe to free resources */
-		dmaengine_terminate_async(stm32port->tx_ch);
+		stm32_usart_tx_dma_terminate(stm32port);
 		goto fallback_err;
 	}
 
@@ -522,12 +553,13 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
 	struct circ_buf *xmit = &port->state->xmit;
 
 	if (port->x_char) {
-		if (stm32_port->tx_dma_busy)
+		if (stm32_usart_tx_dma_started(stm32_port) &&
+		    stm32_usart_tx_dma_enabled(stm32_port))
 			stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
 		writel_relaxed(port->x_char, port->membase + ofs->tdr);
 		port->x_char = 0;
 		port->icount.tx++;
-		if (stm32_port->tx_dma_busy)
+		if (stm32_usart_tx_dma_started(stm32_port))
 			stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
 		return;
 	}
@@ -719,9 +751,8 @@ static void stm32_usart_flush_buffer(struct uart_port *port)
 	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
 
 	if (stm32_port->tx_ch) {
-		dmaengine_terminate_async(stm32_port->tx_ch);
+		stm32_usart_tx_dma_terminate(stm32_port);
 		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
-		stm32_port->tx_dma_busy = false;
 	}
 }
 
@@ -883,10 +914,11 @@ static void stm32_usart_shutdown(struct uart_port *port)
 	u32 val, isr;
 	int ret;
 
-	if (stm32_port->tx_dma_busy) {
-		dmaengine_terminate_async(stm32_port->tx_ch);
+	if (stm32_usart_tx_dma_enabled(stm32_port))
 		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
-	}
+
+	if (stm32_usart_tx_dma_started(stm32_port))
+		stm32_usart_tx_dma_terminate(stm32_port);
 
 	/* Disable modem control interrupts */
 	stm32_usart_disable_ms(port);
@@ -1424,8 +1456,6 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port,
 	struct dma_slave_config config;
 	int ret;
 
-	stm32port->tx_dma_busy = false;
-
 	stm32port->tx_buf = dma_alloc_coherent(dev, TX_BUF_L,
 					       &stm32port->tx_dma_buf,
 					       GFP_KERNEL);
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index e23916bfbb60..feab952aec16 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -264,7 +264,7 @@ struct stm32_port {
 	u32 cr1_irq;		 /* USART_CR1_RXNEIE or RTOIE */
 	u32 cr3_irq;		 /* USART_CR3_RXFTIE */
 	int last_res;
-	bool tx_dma_busy;	 /* dma tx busy               */
+	bool tx_dma_busy;	 /* dma tx transaction in progress */
 	bool throttled;		 /* port throttled            */
 	bool hw_flow_control;
 	bool swap;		 /* swap RX & TX pins */
-- 
2.17.1


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

* [PATCH 2/4] serial: stm32: rework TX DMA state condition
@ 2022-01-04 18:24   ` Valentin Caron
  0 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

TX DMA state condition is handled by tx_dma_busy boolean.
This boolean is set when dma descriptor is requested and reset when dma
channel is stopped (dma_terminate).

In stm32_usart_serial_remove(), stm32_usart_stop_tx() and
stm32_usart_transmit_chars_dma() fallback error case, DMA channel is
stopped but tx_dma_busy is not handled.

Rework the driver by using two new functions to solve this issue:
- stm32_usart_tx_dma_started return true if DMA TX have a descriptor.
- stm32_usart_tx_dma_enabled return true if DMAT bit is set.

stm32_usart_tx_dma_started uses tx_dma_busy flag to prevent dual DMA
transaction at the same time. This flag is set when a DMA transaction
begins and is unset when dmaengine_terminate_async function is called.
A new DMA transaction cannot be created if this flag is set.

Create a new function "stm32_usart_tx_dma_terminate" to be sure the flag
is unset after each call of dmaengine_terminate_async.

Signed-off-by: Erwan Le Ray <erwan.leray@foss.st.com>
Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
---
 drivers/tty/serial/stm32-usart.c | 66 +++++++++++++++++++++++---------
 drivers/tty/serial/stm32-usart.h |  2 +-
 2 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 6cfc3bec6749..52755a576bc2 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -365,6 +365,31 @@ static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force
 	return size;
 }
 
+static void stm32_usart_tx_dma_terminate(struct stm32_port *stm32_port)
+{
+	dmaengine_terminate_async(stm32_port->tx_ch);
+	stm32_port->tx_dma_busy = false;
+}
+
+static bool stm32_usart_tx_dma_started(struct stm32_port *stm32_port)
+{
+	/*
+	 * We cannot use the function "dmaengine_tx_status" to know the
+	 * status of DMA. This function does not show if the "dma complete"
+	 * callback of the DMA transaction has been called. So we prefer
+	 * to use "tx_dma_busy" flag to prevent dual DMA transaction at the
+	 * same time.
+	 */
+	return stm32_port->tx_dma_busy;
+}
+
+static bool stm32_usart_tx_dma_enabled(struct stm32_port *stm32_port)
+{
+	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+	return !!(readl_relaxed(stm32_port->port.membase + ofs->cr3) & USART_CR3_DMAT);
+}
+
 static void stm32_usart_tx_dma_complete(void *arg)
 {
 	struct uart_port *port = arg;
@@ -372,9 +397,8 @@ static void stm32_usart_tx_dma_complete(void *arg)
 	const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
 	unsigned long flags;
 
-	dmaengine_terminate_async(stm32port->tx_ch);
 	stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
-	stm32port->tx_dma_busy = false;
+	stm32_usart_tx_dma_terminate(stm32port);
 
 	/* Let's see if we have pending data to send */
 	spin_lock_irqsave(&port->lock, flags);
@@ -428,10 +452,8 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
 	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
 	struct circ_buf *xmit = &port->state->xmit;
 
-	if (stm32_port->tx_dma_busy) {
+	if (stm32_usart_tx_dma_enabled(stm32_port))
 		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
-		stm32_port->tx_dma_busy = false;
-	}
 
 	while (!uart_circ_empty(xmit)) {
 		/* Check that TDR is empty before filling FIFO */
@@ -457,10 +479,11 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
 	struct dma_async_tx_descriptor *desc = NULL;
 	unsigned int count, i;
 
-	if (stm32port->tx_dma_busy)
+	if (stm32_usart_tx_dma_started(stm32port)) {
+		if (!stm32_usart_tx_dma_enabled(stm32port))
+			stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
 		return;
-
-	stm32port->tx_dma_busy = true;
+	}
 
 	count = uart_circ_chars_pending(xmit);
 
@@ -491,13 +514,21 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
 	if (!desc)
 		goto fallback_err;
 
+	/*
+	 * Set "tx_dma_busy" flag. This flag will be released when
+	 * dmaengine_terminate_async will be called. This flag helps
+	 * transmit_chars_dma not to start another DMA transaction
+	 * if the callback of the previous is not yet called.
+	 */
+	stm32port->tx_dma_busy = true;
+
 	desc->callback = stm32_usart_tx_dma_complete;
 	desc->callback_param = port;
 
 	/* Push current DMA TX transaction in the pending queue */
 	if (dma_submit_error(dmaengine_submit(desc))) {
 		/* dma no yet started, safe to free resources */
-		dmaengine_terminate_async(stm32port->tx_ch);
+		stm32_usart_tx_dma_terminate(stm32port);
 		goto fallback_err;
 	}
 
@@ -522,12 +553,13 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
 	struct circ_buf *xmit = &port->state->xmit;
 
 	if (port->x_char) {
-		if (stm32_port->tx_dma_busy)
+		if (stm32_usart_tx_dma_started(stm32_port) &&
+		    stm32_usart_tx_dma_enabled(stm32_port))
 			stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
 		writel_relaxed(port->x_char, port->membase + ofs->tdr);
 		port->x_char = 0;
 		port->icount.tx++;
-		if (stm32_port->tx_dma_busy)
+		if (stm32_usart_tx_dma_started(stm32_port))
 			stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
 		return;
 	}
@@ -719,9 +751,8 @@ static void stm32_usart_flush_buffer(struct uart_port *port)
 	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
 
 	if (stm32_port->tx_ch) {
-		dmaengine_terminate_async(stm32_port->tx_ch);
+		stm32_usart_tx_dma_terminate(stm32_port);
 		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
-		stm32_port->tx_dma_busy = false;
 	}
 }
 
@@ -883,10 +914,11 @@ static void stm32_usart_shutdown(struct uart_port *port)
 	u32 val, isr;
 	int ret;
 
-	if (stm32_port->tx_dma_busy) {
-		dmaengine_terminate_async(stm32_port->tx_ch);
+	if (stm32_usart_tx_dma_enabled(stm32_port))
 		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
-	}
+
+	if (stm32_usart_tx_dma_started(stm32_port))
+		stm32_usart_tx_dma_terminate(stm32_port);
 
 	/* Disable modem control interrupts */
 	stm32_usart_disable_ms(port);
@@ -1424,8 +1456,6 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port,
 	struct dma_slave_config config;
 	int ret;
 
-	stm32port->tx_dma_busy = false;
-
 	stm32port->tx_buf = dma_alloc_coherent(dev, TX_BUF_L,
 					       &stm32port->tx_dma_buf,
 					       GFP_KERNEL);
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index e23916bfbb60..feab952aec16 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -264,7 +264,7 @@ struct stm32_port {
 	u32 cr1_irq;		 /* USART_CR1_RXNEIE or RTOIE */
 	u32 cr3_irq;		 /* USART_CR3_RXFTIE */
 	int last_res;
-	bool tx_dma_busy;	 /* dma tx busy               */
+	bool tx_dma_busy;	 /* dma tx transaction in progress */
 	bool throttled;		 /* port throttled            */
 	bool hw_flow_control;
 	bool swap;		 /* swap RX & TX pins */
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 3/4] serial: stm32: fix flow control transfer in DMA mode
  2022-01-04 18:24 ` Valentin Caron
@ 2022-01-04 18:24   ` Valentin Caron
  -1 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

If flow control is enabled, framework will call stop_tx to
pause transfer and then call start_tx to resume transfer.

Clear USART_CR3_DMAT bit in stop_tx ops to pause DMA transfer.

Signed-off-by: Erwan Le Ray <erwan.leray@foss.st.com>
Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
---
 drivers/tty/serial/stm32-usart.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 52755a576bc2..788e002688f2 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -707,8 +707,11 @@ static void stm32_usart_stop_tx(struct uart_port *port)
 {
 	struct stm32_port *stm32_port = to_stm32_port(port);
 	struct serial_rs485 *rs485conf = &port->rs485;
+	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
 
 	stm32_usart_tx_interrupt_disable(port);
+	if (stm32_usart_tx_dma_started(stm32_port) && stm32_usart_tx_dma_enabled(stm32_port))
+		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
 
 	if (rs485conf->flags & SER_RS485_ENABLED) {
 		if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
-- 
2.17.1


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

* [PATCH 3/4] serial: stm32: fix flow control transfer in DMA mode
@ 2022-01-04 18:24   ` Valentin Caron
  0 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

If flow control is enabled, framework will call stop_tx to
pause transfer and then call start_tx to resume transfer.

Clear USART_CR3_DMAT bit in stop_tx ops to pause DMA transfer.

Signed-off-by: Erwan Le Ray <erwan.leray@foss.st.com>
Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
---
 drivers/tty/serial/stm32-usart.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 52755a576bc2..788e002688f2 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -707,8 +707,11 @@ static void stm32_usart_stop_tx(struct uart_port *port)
 {
 	struct stm32_port *stm32_port = to_stm32_port(port);
 	struct serial_rs485 *rs485conf = &port->rs485;
+	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
 
 	stm32_usart_tx_interrupt_disable(port);
+	if (stm32_usart_tx_dma_started(stm32_port) && stm32_usart_tx_dma_enabled(stm32_port))
+		stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
 
 	if (rs485conf->flags & SER_RS485_ENABLED) {
 		if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 4/4] serial: stm32: correct loop for dma error handling
  2022-01-04 18:24 ` Valentin Caron
@ 2022-01-04 18:24   ` Valentin Caron
  -1 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

In this error handling, "transmit_chars_dma" function will call
"transmit_chars_pio" once per characters. But "transmit_chars_pio" will
continue to send characters while xmit buffer is not empty.

Remove this useless loop, one call is sufficient.

Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
---
 drivers/tty/serial/stm32-usart.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 788e002688f2..1f89ab0e49ac 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -477,7 +477,7 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
 	const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
 	struct circ_buf *xmit = &port->state->xmit;
 	struct dma_async_tx_descriptor *desc = NULL;
-	unsigned int count, i;
+	unsigned int count;
 
 	if (stm32_usart_tx_dma_started(stm32port)) {
 		if (!stm32_usart_tx_dma_enabled(stm32port))
@@ -542,8 +542,7 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
 	return;
 
 fallback_err:
-	for (i = count; i > 0; i--)
-		stm32_usart_transmit_chars_pio(port);
+	stm32_usart_transmit_chars_pio(port);
 }
 
 static void stm32_usart_transmit_chars(struct uart_port *port)
-- 
2.17.1


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

* [PATCH 4/4] serial: stm32: correct loop for dma error handling
@ 2022-01-04 18:24   ` Valentin Caron
  0 siblings, 0 replies; 10+ messages in thread
From: Valentin Caron @ 2022-01-04 18:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jiri Slaby, Maxime Coquelin, Alexandre Torgue, Gerald Baeza,
	Erwan Le Ray, Valentin Caron, linux-serial, linux-stm32,
	linux-arm-kernel, linux-kernel

In this error handling, "transmit_chars_dma" function will call
"transmit_chars_pio" once per characters. But "transmit_chars_pio" will
continue to send characters while xmit buffer is not empty.

Remove this useless loop, one call is sufficient.

Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
---
 drivers/tty/serial/stm32-usart.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 788e002688f2..1f89ab0e49ac 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -477,7 +477,7 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
 	const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
 	struct circ_buf *xmit = &port->state->xmit;
 	struct dma_async_tx_descriptor *desc = NULL;
-	unsigned int count, i;
+	unsigned int count;
 
 	if (stm32_usart_tx_dma_started(stm32port)) {
 		if (!stm32_usart_tx_dma_enabled(stm32port))
@@ -542,8 +542,7 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
 	return;
 
 fallback_err:
-	for (i = count; i > 0; i--)
-		stm32_usart_transmit_chars_pio(port);
+	stm32_usart_transmit_chars_pio(port);
 }
 
 static void stm32_usart_transmit_chars(struct uart_port *port)
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2022-01-04 18:28 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-04 18:24 [PATCH 0/4] Add improvements for STM32 USART DMA TX Valentin Caron
2022-01-04 18:24 ` Valentin Caron
2022-01-04 18:24 ` [PATCH 1/4] serial: stm32: move tx dma terminate DMA to shutdown Valentin Caron
2022-01-04 18:24   ` Valentin Caron
2022-01-04 18:24 ` [PATCH 2/4] serial: stm32: rework TX DMA state condition Valentin Caron
2022-01-04 18:24   ` Valentin Caron
2022-01-04 18:24 ` [PATCH 3/4] serial: stm32: fix flow control transfer in DMA mode Valentin Caron
2022-01-04 18:24   ` Valentin Caron
2022-01-04 18:24 ` [PATCH 4/4] serial: stm32: correct loop for dma error handling Valentin Caron
2022-01-04 18:24   ` Valentin Caron

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.