Commit 4bcf59a5 authored by Vignesh Raghavendra's avatar Vignesh Raghavendra Committed by Greg Kroah-Hartman
Browse files

serial: 8250: 8250_omap: Account for data in flight during DMA teardown



Take into account data stuck in DMA internal buffers before pushing data
to higher layer. dma_tx_state has "in_flight_bytes" member that provides
this information.

Signed-off-by: default avatarVignesh Raghavendra <vigneshr@ti.com>
Link: https://lore.kernel.org/r/20200319110344.21348-3-vigneshr@ti.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7cf4df30
Loading
Loading
Loading
Loading
+23 −4
Original line number Diff line number Diff line
@@ -741,6 +741,8 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
	struct omap8250_priv	*priv = p->port.private_data;
	struct uart_8250_dma    *dma = p->dma;
	struct tty_port         *tty_port = &p->port.state->port;
	struct dma_chan		*rxchan = dma->rxchan;
	dma_cookie_t		cookie;
	struct dma_tx_state     state;
	int                     count;
	unsigned long		flags;
@@ -751,12 +753,29 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
	if (!dma->rx_running)
		goto unlock;

	cookie = dma->rx_cookie;
	dma->rx_running = 0;
	dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
	dmaengine_tx_status(rxchan, cookie, &state);

	count = dma->rx_size - state.residue;
	if (count < dma->rx_size)
		dmaengine_terminate_async(dma->rxchan);
	count = dma->rx_size - state.residue + state.in_flight_bytes;
	if (count < dma->rx_size) {
		dmaengine_terminate_async(rxchan);

		/*
		 * Poll for teardown to complete which guarantees in
		 * flight data is drained.
		 */
		if (state.in_flight_bytes) {
			int poll_count = 25;

			while (dmaengine_tx_status(rxchan, cookie, NULL) &&
			       poll_count--)
				cpu_relax();

			if (!poll_count)
				dev_err(p->port.dev, "teardown incomplete\n");
		}
	}
	if (!count)
		goto unlock;
	ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);