Skip to content

Commit b495021

Browse files
Jiri Slaby (SUSE)gregkh
authored andcommitted
tty: serial: 8250_omap: fix TX with DMA for am33xx
Commit 1788cf6 ("tty: serial: switch from circ_buf to kfifo") introduced an error in the TX DMA handling for 8250_omap. When the OMAP_DMA_TX_KICK flag is set, the "skip_byte" is pulled from the kfifo and emitted directly in order to start the DMA. While the kfifo is updated, dma->tx_size is not decreased. This leads to uart_xmit_advance() called in omap_8250_dma_tx_complete() advancing the kfifo by one too much. In practice, transmitting N bytes has been seen to result in the last N-1 bytes being sent repeatedly. This change fixes the problem by moving all of the dma setup after the OMAP_DMA_TX_KICK handling and using kfifo_len() instead of the DMA size for the 4-byte cutoff check. This slightly changes the behaviour at buffer wraparound, but it still transmits the correct bytes somehow. Now, the "skip_byte" would no longer be accounted to the stats. As previously, dma->tx_size included also this skip byte, up->icount.tx was updated by aforementioned uart_xmit_advance() in omap_8250_dma_tx_complete(). Fix this by using the uart_fifo_out() helper instead of bare kfifo_get(). Based on patch by Mans Rullgard <[email protected]> Signed-off-by: "Jiri Slaby (SUSE)" <[email protected]> Fixes: 1788cf6 ("tty: serial: switch from circ_buf to kfifo") Link: https://lore.kernel.org/all/[email protected]/ Reported-by: Mans Rullgard <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 81cf4d7 commit b495021

File tree

1 file changed

+10
-15
lines changed

1 file changed

+10
-15
lines changed

drivers/tty/serial/8250/8250_omap.c

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,16 +1173,6 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
11731173
return 0;
11741174
}
11751175

1176-
sg_init_table(&sg, 1);
1177-
ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
1178-
UART_XMIT_SIZE, dma->tx_addr);
1179-
if (ret != 1) {
1180-
serial8250_clear_THRI(p);
1181-
return 0;
1182-
}
1183-
1184-
dma->tx_size = sg_dma_len(&sg);
1185-
11861176
if (priv->habit & OMAP_DMA_TX_KICK) {
11871177
unsigned char c;
11881178
u8 tx_lvl;
@@ -1207,18 +1197,22 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
12071197
ret = -EBUSY;
12081198
goto err;
12091199
}
1210-
if (dma->tx_size < 4) {
1200+
if (kfifo_len(&tport->xmit_fifo) < 4) {
12111201
ret = -EINVAL;
12121202
goto err;
12131203
}
1214-
if (!kfifo_get(&tport->xmit_fifo, &c)) {
1204+
if (!uart_fifo_out(&p->port, &c, 1)) {
12151205
ret = -EINVAL;
12161206
goto err;
12171207
}
12181208
skip_byte = c;
1219-
/* now we need to recompute due to kfifo_get */
1220-
kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
1221-
UART_XMIT_SIZE, dma->tx_addr);
1209+
}
1210+
1211+
sg_init_table(&sg, 1);
1212+
ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, UART_XMIT_SIZE, dma->tx_addr);
1213+
if (ret != 1) {
1214+
ret = -EINVAL;
1215+
goto err;
12221216
}
12231217

12241218
desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV,
@@ -1228,6 +1222,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
12281222
goto err;
12291223
}
12301224

1225+
dma->tx_size = sg_dma_len(&sg);
12311226
dma->tx_running = 1;
12321227

12331228
desc->callback = omap_8250_dma_tx_complete;

0 commit comments

Comments
 (0)