Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 396f7894 authored by Prudhvi Yarlagadda's avatar Prudhvi Yarlagadda Committed by Gerrit - the friendly Code Review server
Browse files

serial: msm_geni_serial: Don't queue the rx dma buffer in stop rx



Don't queue a new dma rx buffer only when the rx_length_in register
is zero and dma_done interrupt bit is set. The rx_length_in register
shows number of bytes received and this can be zero when dma_done
interrupt bit is set when we give a cancel command.

This helps when there is a race condition between rx data coming into
rx fifo and a cancel_s_cmd is given. The rx data will end up consuming
the rx dma buffer mapped for cancel command and due to this dma engine
will be in active state even though geni goes to inactive state.

Issue is that we get a dma_done interrupt for the previously pending
EOT byte which came for cancel command. And this interrupt will come
when we queue the rx buffer in start_rx and this might cause uart
to read partial data from rx fifo.

Change-Id: Id3d9b32330c1ac4205100a30936bd4015e20f24d
Signed-off-by: default avatarPrudhvi Yarlagadda <pyarlaga@codeaurora.org>
parent 9e329357
Loading
Loading
Loading
Loading
+29 −6
Original line number Diff line number Diff line
@@ -1444,12 +1444,13 @@ static void msm_geni_serial_set_manual_flow(bool enable,
	}
}

static void stop_rx_sequencer(struct uart_port *uport)
static int stop_rx_sequencer(struct uart_port *uport)
{
	unsigned int geni_status;
	bool timeout, is_irq_masked;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	unsigned long flags = 0;
	bool is_rx_active;

	IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__);

@@ -1459,7 +1460,7 @@ static void stop_rx_sequencer(struct uart_port *uport)
		IPC_LOG_MSG(port->ipc_log_misc,
			"%s: RX is Inactive, geni_sts: 0x%x\n",
						__func__, geni_status);
		return;
		return 0;
	}

	port->s_cmd_done = false;
@@ -1482,7 +1483,6 @@ static void stop_rx_sequencer(struct uart_port *uport)
	mb();
	timeout = geni_wait_for_cmd_done(uport, is_irq_masked);
	if (timeout) {
		bool is_rx_active;
		geni_status = geni_read_reg_nolog(uport->membase,
							SE_GENI_STATUS);
		/*
@@ -1539,18 +1539,28 @@ static void stop_rx_sequencer(struct uart_port *uport)
	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	IPC_LOG_MSG(port->ipc_log_misc, "%s: End 0x%x\n",
		    __func__, geni_status);

	is_rx_active = geni_status & S_GENI_CMD_ACTIVE;
	if (is_rx_active)
		return -EBUSY;
	else
		return 0;
}

static void msm_geni_serial_stop_rx(struct uart_port *uport)
{
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	int ret;

	if (!uart_console(uport) && device_pending_suspend(uport)) {
		IPC_LOG_MSG(port->ipc_log_misc,
				"%s.Device is suspended.\n", __func__);
		return;
	}
	stop_rx_sequencer(uport);
	ret = stop_rx_sequencer(uport);
	if (ret)
		IPC_LOG_MSG(port->ipc_log_misc, "%s: stop rx failed %d\n",
							__func__, ret);
}

static int handle_rx_hs(struct uart_port *uport,
@@ -1847,6 +1857,7 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport,
	unsigned int dma_rx_status;
	unsigned int m_irq_en;
	unsigned int geni_status;
	u32 rx_dma_len;
	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
	struct tty_port *tport = &uport->state->port;
	bool drop_rx = false;
@@ -1998,9 +2009,16 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport,
					dma_rx_status & RX_DMA_DONE) {
				msm_geni_serial_handle_dma_rx(uport,
							drop_rx);
				if (!(dma_rx_status & RX_GENI_CANCEL_IRQ)) {
				rx_dma_len =
				geni_read_reg_nolog(uport->membase,
							SE_DMA_RX_LEN_IN);
				if (rx_dma_len != 0) {
					geni_se_rx_dma_start(uport->membase,
					DMA_RX_BUF_SIZE, &msm_port->rx_dma);
				} else {
					IPC_LOG_MSG(msm_port->ipc_log_misc,
						"%s.stop dma Rx 0x%x\n",
						__func__, dma_rx_status);
				}
			}

@@ -3398,7 +3416,12 @@ static int msm_geni_serial_runtime_suspend(struct device *dev)
	 * Disable Interrupt
	 * Resources off
	 */
	stop_rx_sequencer(&port->uport);
	ret = stop_rx_sequencer(&port->uport);
	if (ret) {
		IPC_LOG_MSG(port->ipc_log_pwr, "%s: stop rx failed %d\n",
							__func__, ret);
		return -EBUSY;
	}
	geni_status = geni_read_reg_nolog(port->uport.membase, SE_GENI_STATUS);

	if ((geni_status & M_GENI_CMD_ACTIVE))