summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2020-02-09 19:44:15 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-01-18 11:30:56 +0100
commitd2f24ad71fa409c9a7058232e6e0bc55742d6487 (patch)
tree647147e0d0ae92241aeccf05f413cfbdee4614f4
parentba8825b173389223bc0e2ba808cfc689b3404d72 (diff)
downloadlinux-stable-d2f24ad71fa409c9a7058232e6e0bc55742d6487.tar.gz
linux-stable-d2f24ad71fa409c9a7058232e6e0bc55742d6487.tar.bz2
linux-stable-d2f24ad71fa409c9a7058232e6e0bc55742d6487.zip
tty: serial: tegra: Handle RX transfer in PIO mode if DMA wasn't started
commit 1f69a1273b3f204a9c00dc3bbdcc4afcd0787428 upstream. It is possible to get an instant RX timeout or end-of-transfer interrupt before RX DMA was started, if transaction is less than 16 bytes. Transfer should be handled in PIO mode in this case because DMA can't handle it. This patch brings back the original behaviour of the driver that was changed by accident by a previous commit, it fixes occasional Bluetooth HW initialization failures which I started to notice recently. Fixes: d5e3fadb7012 ("tty: serial: tegra: Activate RX DMA transfer by request") Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Link: https://lore.kernel.org/r/20200209164415.9632-1-digetx@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/serial-tegra.c35
1 files changed, 16 insertions, 19 deletions
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index cc613240a351..47c00767aeab 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -638,11 +638,22 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
TEGRA_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
}
+static void do_handle_rx_pio(struct tegra_uart_port *tup)
+{
+ struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
+ struct tty_port *port = &tup->uport.state->port;
+
+ tegra_uart_handle_rx_pio(tup, port);
+ if (tty) {
+ tty_flip_buffer_push(port);
+ tty_kref_put(tty);
+ }
+}
+
static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup,
unsigned int residue)
{
struct tty_port *port = &tup->uport.state->port;
- struct tty_struct *tty = tty_port_tty_get(port);
unsigned int count;
async_tx_ack(tup->rx_dma_desc);
@@ -651,11 +662,7 @@ static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup,
/* If we are here, DMA is stopped */
tegra_uart_copy_rx_to_tty(tup, port, count);
- tegra_uart_handle_rx_pio(tup, port);
- if (tty) {
- tty_flip_buffer_push(port);
- tty_kref_put(tty);
- }
+ do_handle_rx_pio(tup);
}
static void tegra_uart_rx_dma_complete(void *args)
@@ -695,8 +702,10 @@ static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup)
{
struct dma_tx_state state;
- if (!tup->rx_dma_active)
+ if (!tup->rx_dma_active) {
+ do_handle_rx_pio(tup);
return;
+ }
dmaengine_pause(tup->rx_dma_chan);
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
@@ -765,18 +774,6 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u)
uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
}
-static void do_handle_rx_pio(struct tegra_uart_port *tup)
-{
- struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
- struct tty_port *port = &tup->uport.state->port;
-
- tegra_uart_handle_rx_pio(tup, port);
- if (tty) {
- tty_flip_buffer_push(port);
- tty_kref_put(tty);
- }
-}
-
static irqreturn_t tegra_uart_isr(int irq, void *data)
{
struct tegra_uart_port *tup = data;