mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-11 07:03:09 -04:00
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: Prudhvi Yarlagadda <pyarlaga@codeaurora.org>
This commit is contained in:
parent
8f9bea1d7c
commit
152e037894
1 changed files with 34 additions and 11 deletions
|
|
@ -1424,12 +1424,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__);
|
||||
|
||||
|
|
@ -1439,7 +1440,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;
|
||||
|
|
@ -1462,8 +1463,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);
|
||||
/*
|
||||
|
|
@ -1520,18 +1519,28 @@ exit_rx_seq:
|
|||
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,
|
||||
|
|
@ -1902,6 +1911,7 @@ static bool handle_tx_dma_xfer(u32 m_irq_status, struct uart_port *uport)
|
|||
|
||||
static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport)
|
||||
{
|
||||
u32 rx_dma_len;
|
||||
bool ret = false;
|
||||
bool drop_rx = false;
|
||||
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
|
||||
|
|
@ -1934,14 +1944,22 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport)
|
|||
uport->icount.brk);
|
||||
}
|
||||
|
||||
if (dma_rx_status & RX_EOT || dma_rx_status & RX_DMA_DONE) {
|
||||
msm_geni_serial_handle_dma_rx(uport, drop_rx);
|
||||
if (!(dma_rx_status & RX_GENI_CANCEL_IRQ)) {
|
||||
if (dma_rx_status & RX_EOT ||
|
||||
dma_rx_status & RX_DMA_DONE) {
|
||||
msm_geni_serial_handle_dma_rx(uport,
|
||||
drop_rx);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (dma_rx_status & RX_SBE) {
|
||||
IPC_LOG_MSG(msm_port->ipc_log_misc,
|
||||
"%s.Rx Errors. 0x%x\n",
|
||||
|
|
@ -3208,7 +3226,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))
|
||||
|
|
|
|||
Loading…
Reference in a new issue