Skip to content

Commit 9a135f1

Browse files
VCASTMgregkh
authored andcommitted
serial: stm32: rework TX DMA state condition
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 <[email protected]> Signed-off-by: Valentin Caron <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 56a23f9 commit 9a135f1

File tree

2 files changed

+49
-19
lines changed

2 files changed

+49
-19
lines changed

drivers/tty/serial/stm32-usart.c

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -365,16 +365,40 @@ static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force
365365
return size;
366366
}
367367

368+
static void stm32_usart_tx_dma_terminate(struct stm32_port *stm32_port)
369+
{
370+
dmaengine_terminate_async(stm32_port->tx_ch);
371+
stm32_port->tx_dma_busy = false;
372+
}
373+
374+
static bool stm32_usart_tx_dma_started(struct stm32_port *stm32_port)
375+
{
376+
/*
377+
* We cannot use the function "dmaengine_tx_status" to know the
378+
* status of DMA. This function does not show if the "dma complete"
379+
* callback of the DMA transaction has been called. So we prefer
380+
* to use "tx_dma_busy" flag to prevent dual DMA transaction at the
381+
* same time.
382+
*/
383+
return stm32_port->tx_dma_busy;
384+
}
385+
386+
static bool stm32_usart_tx_dma_enabled(struct stm32_port *stm32_port)
387+
{
388+
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
389+
390+
return !!(readl_relaxed(stm32_port->port.membase + ofs->cr3) & USART_CR3_DMAT);
391+
}
392+
368393
static void stm32_usart_tx_dma_complete(void *arg)
369394
{
370395
struct uart_port *port = arg;
371396
struct stm32_port *stm32port = to_stm32_port(port);
372397
const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
373398
unsigned long flags;
374399

375-
dmaengine_terminate_async(stm32port->tx_ch);
376400
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
377-
stm32port->tx_dma_busy = false;
401+
stm32_usart_tx_dma_terminate(stm32port);
378402

379403
/* Let's see if we have pending data to send */
380404
spin_lock_irqsave(&port->lock, flags);
@@ -428,10 +452,8 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
428452
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
429453
struct circ_buf *xmit = &port->state->xmit;
430454

431-
if (stm32_port->tx_dma_busy) {
455+
if (stm32_usart_tx_dma_enabled(stm32_port))
432456
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
433-
stm32_port->tx_dma_busy = false;
434-
}
435457

436458
while (!uart_circ_empty(xmit)) {
437459
/* Check that TDR is empty before filling FIFO */
@@ -457,10 +479,11 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
457479
struct dma_async_tx_descriptor *desc = NULL;
458480
unsigned int count, i;
459481

460-
if (stm32port->tx_dma_busy)
482+
if (stm32_usart_tx_dma_started(stm32port)) {
483+
if (!stm32_usart_tx_dma_enabled(stm32port))
484+
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
461485
return;
462-
463-
stm32port->tx_dma_busy = true;
486+
}
464487

465488
count = uart_circ_chars_pending(xmit);
466489

@@ -491,13 +514,21 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
491514
if (!desc)
492515
goto fallback_err;
493516

517+
/*
518+
* Set "tx_dma_busy" flag. This flag will be released when
519+
* dmaengine_terminate_async will be called. This flag helps
520+
* transmit_chars_dma not to start another DMA transaction
521+
* if the callback of the previous is not yet called.
522+
*/
523+
stm32port->tx_dma_busy = true;
524+
494525
desc->callback = stm32_usart_tx_dma_complete;
495526
desc->callback_param = port;
496527

497528
/* Push current DMA TX transaction in the pending queue */
498529
if (dma_submit_error(dmaengine_submit(desc))) {
499530
/* dma no yet started, safe to free resources */
500-
dmaengine_terminate_async(stm32port->tx_ch);
531+
stm32_usart_tx_dma_terminate(stm32port);
501532
goto fallback_err;
502533
}
503534

@@ -522,12 +553,13 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
522553
struct circ_buf *xmit = &port->state->xmit;
523554

524555
if (port->x_char) {
525-
if (stm32_port->tx_dma_busy)
556+
if (stm32_usart_tx_dma_started(stm32_port) &&
557+
stm32_usart_tx_dma_enabled(stm32_port))
526558
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
527559
writel_relaxed(port->x_char, port->membase + ofs->tdr);
528560
port->x_char = 0;
529561
port->icount.tx++;
530-
if (stm32_port->tx_dma_busy)
562+
if (stm32_usart_tx_dma_started(stm32_port))
531563
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
532564
return;
533565
}
@@ -719,9 +751,8 @@ static void stm32_usart_flush_buffer(struct uart_port *port)
719751
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
720752

721753
if (stm32_port->tx_ch) {
722-
dmaengine_terminate_async(stm32_port->tx_ch);
754+
stm32_usart_tx_dma_terminate(stm32_port);
723755
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
724-
stm32_port->tx_dma_busy = false;
725756
}
726757
}
727758

@@ -883,10 +914,11 @@ static void stm32_usart_shutdown(struct uart_port *port)
883914
u32 val, isr;
884915
int ret;
885916

886-
if (stm32_port->tx_dma_busy) {
887-
dmaengine_terminate_async(stm32_port->tx_ch);
917+
if (stm32_usart_tx_dma_enabled(stm32_port))
888918
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
889-
}
919+
920+
if (stm32_usart_tx_dma_started(stm32_port))
921+
stm32_usart_tx_dma_terminate(stm32_port);
890922

891923
/* Disable modem control interrupts */
892924
stm32_usart_disable_ms(port);
@@ -1424,8 +1456,6 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port,
14241456
struct dma_slave_config config;
14251457
int ret;
14261458

1427-
stm32port->tx_dma_busy = false;
1428-
14291459
stm32port->tx_buf = dma_alloc_coherent(dev, TX_BUF_L,
14301460
&stm32port->tx_dma_buf,
14311461
GFP_KERNEL);

drivers/tty/serial/stm32-usart.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ struct stm32_port {
264264
u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */
265265
u32 cr3_irq; /* USART_CR3_RXFTIE */
266266
int last_res;
267-
bool tx_dma_busy; /* dma tx busy */
267+
bool tx_dma_busy; /* dma tx transaction in progress */
268268
bool throttled; /* port throttled */
269269
bool hw_flow_control;
270270
bool swap; /* swap RX & TX pins */

0 commit comments

Comments
 (0)