Loading drivers/tty/serial/msm_geni_serial.c +103 −58 Original line number Diff line number Diff line Loading @@ -210,6 +210,7 @@ struct msm_geni_serial_port { bool s_cmd; struct completion m_cmd_timeout; struct completion s_cmd_timeout; spinlock_t rx_lock; }; static const struct uart_ops msm_geni_serial_pops; Loading @@ -236,6 +237,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev); static int msm_geni_serial_get_ver_info(struct uart_port *uport); static void msm_geni_serial_set_manual_flow(bool enable, struct msm_geni_serial_port *port); static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport); static int uart_line_id; #define GET_DEV_PORT(uport) \ Loading Loading @@ -1438,6 +1440,7 @@ static int stop_rx_sequencer(struct uart_port *uport) unsigned long flags = 0; bool is_rx_active; unsigned int stale_delay; u32 dma_rx_status, s_irq_status; IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__); Loading @@ -1462,6 +1465,25 @@ static int stop_rx_sequencer(struct uart_port *uport) stale_delay = (STALE_COUNT * SEC_TO_USEC) / port->cur_baud; stale_delay = (2 * stale_delay) + SYSTEM_DELAY; udelay(stale_delay); dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); /* The transfer is completed at HW level and the completion * interrupt is delayed. So process the transfer completion * before issuing the cancel command to resolve the race * btw cancel RX and completion interrupt. */ if (dma_rx_status) { s_irq_status = geni_read_reg_nolog(uport->membase, SE_GENI_S_IRQ_STATUS); geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR); geni_se_dump_dbg_regs(&port->serial_rsc, uport->membase, port->ipc_log_misc); IPC_LOG_MSG(port->ipc_log_misc, "%s: Interrupt delay\n", __func__); handle_rx_dma_xfer(s_irq_status, uport); } } IPC_LOG_MSG(port->ipc_log_misc, "%s: Start 0x%x\n", Loading Loading @@ -1863,6 +1885,77 @@ static int msm_geni_serial_handle_dma_tx(struct uart_port *uport) return 0; } static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) { bool ret = false; bool drop_rx = false; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); u32 dma_rx_status; spin_lock(&msm_port->rx_lock); dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); if (dma_rx_status) { geni_write_reg_nolog(dma_rx_status, uport->membase, SE_DMA_RX_IRQ_CLR); if (dma_rx_status & RX_RESET_DONE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Reset done. 0x%x.\n", __func__, dma_rx_status); ret = true; goto exit; } if (dma_rx_status & UART_DMA_RX_ERRS) { if (dma_rx_status & UART_DMA_RX_PARITY_ERR) uport->icount.parity++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x parity:%d\n", __func__, dma_rx_status, uport->icount.parity); drop_rx = true; } else if (dma_rx_status & UART_DMA_RX_BREAK) { uport->icount.brk++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x break:%d\n", __func__, dma_rx_status, 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)) { 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. not mapping rx dma\n", __func__); } } if (dma_rx_status & RX_SBE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x\n", __func__, dma_rx_status); WARN_ON(1); } if (dma_rx_status & (RX_EOT | RX_GENI_CANCEL_IRQ | RX_DMA_DONE)) ret = true; } if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) ret = true; exit: spin_unlock(&msm_port->rx_lock); return ret; } static void msm_geni_serial_handle_isr(struct uart_port *uport, unsigned long *flags, bool is_irq_masked) Loading Loading @@ -1994,70 +2087,19 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport, TX_GENI_CANCEL_IRQ)) m_cmd_done = true; if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN)) m_cmd_done = true; if ((dma_tx_status & TX_DMA_DONE) && !m_cmd_done) msm_geni_serial_handle_dma_tx(uport); } if (dma_rx_status) { geni_write_reg_nolog(dma_rx_status, uport->membase, SE_DMA_RX_IRQ_CLR); if (dma_rx_status & RX_RESET_DONE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Reset done. 0x%x.\n", __func__, dma_rx_status); s_cmd_done = true; goto exit_geni_serial_isr; } if (dma_rx_status & UART_DMA_RX_ERRS) { if (dma_rx_status & UART_DMA_RX_PARITY_ERR) uport->icount.parity++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x parity:%d\n", __func__, dma_rx_status, uport->icount.parity); drop_rx = true; } else if (dma_rx_status & UART_DMA_RX_BREAK) { uport->icount.brk++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x break:%d\n", __func__, dma_rx_status, 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)) { 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. not mapping rx dma\n", __func__); } } if (dma_rx_status & RX_SBE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x\n", __func__, dma_rx_status); WARN_ON(1); } if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN)) m_cmd_done = true; if (dma_rx_status & (RX_EOT | RX_GENI_CANCEL_IRQ | RX_DMA_DONE)) s_cmd_done = true; if (dma_rx_status) s_cmd_done = handle_rx_dma_xfer(s_irq_status, uport); if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) s_cmd_done = true; } } exit_geni_serial_isr: if (m_cmd_done) { Loading Loading @@ -3386,6 +3428,9 @@ static int msm_geni_serial_probe(struct platform_device *pdev) if (ret) goto exit_wakeup_unregister; if (!uart_console(uport)) spin_lock_init(&dev_port->rx_lock); IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: port:%s irq:%d\n", __func__, uport->name, uport->irq); Loading Loading
drivers/tty/serial/msm_geni_serial.c +103 −58 Original line number Diff line number Diff line Loading @@ -210,6 +210,7 @@ struct msm_geni_serial_port { bool s_cmd; struct completion m_cmd_timeout; struct completion s_cmd_timeout; spinlock_t rx_lock; }; static const struct uart_ops msm_geni_serial_pops; Loading @@ -236,6 +237,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev); static int msm_geni_serial_get_ver_info(struct uart_port *uport); static void msm_geni_serial_set_manual_flow(bool enable, struct msm_geni_serial_port *port); static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport); static int uart_line_id; #define GET_DEV_PORT(uport) \ Loading Loading @@ -1438,6 +1440,7 @@ static int stop_rx_sequencer(struct uart_port *uport) unsigned long flags = 0; bool is_rx_active; unsigned int stale_delay; u32 dma_rx_status, s_irq_status; IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__); Loading @@ -1462,6 +1465,25 @@ static int stop_rx_sequencer(struct uart_port *uport) stale_delay = (STALE_COUNT * SEC_TO_USEC) / port->cur_baud; stale_delay = (2 * stale_delay) + SYSTEM_DELAY; udelay(stale_delay); dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); /* The transfer is completed at HW level and the completion * interrupt is delayed. So process the transfer completion * before issuing the cancel command to resolve the race * btw cancel RX and completion interrupt. */ if (dma_rx_status) { s_irq_status = geni_read_reg_nolog(uport->membase, SE_GENI_S_IRQ_STATUS); geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR); geni_se_dump_dbg_regs(&port->serial_rsc, uport->membase, port->ipc_log_misc); IPC_LOG_MSG(port->ipc_log_misc, "%s: Interrupt delay\n", __func__); handle_rx_dma_xfer(s_irq_status, uport); } } IPC_LOG_MSG(port->ipc_log_misc, "%s: Start 0x%x\n", Loading Loading @@ -1863,6 +1885,77 @@ static int msm_geni_serial_handle_dma_tx(struct uart_port *uport) return 0; } static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) { bool ret = false; bool drop_rx = false; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); u32 dma_rx_status; spin_lock(&msm_port->rx_lock); dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); if (dma_rx_status) { geni_write_reg_nolog(dma_rx_status, uport->membase, SE_DMA_RX_IRQ_CLR); if (dma_rx_status & RX_RESET_DONE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Reset done. 0x%x.\n", __func__, dma_rx_status); ret = true; goto exit; } if (dma_rx_status & UART_DMA_RX_ERRS) { if (dma_rx_status & UART_DMA_RX_PARITY_ERR) uport->icount.parity++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x parity:%d\n", __func__, dma_rx_status, uport->icount.parity); drop_rx = true; } else if (dma_rx_status & UART_DMA_RX_BREAK) { uport->icount.brk++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x break:%d\n", __func__, dma_rx_status, 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)) { 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. not mapping rx dma\n", __func__); } } if (dma_rx_status & RX_SBE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x\n", __func__, dma_rx_status); WARN_ON(1); } if (dma_rx_status & (RX_EOT | RX_GENI_CANCEL_IRQ | RX_DMA_DONE)) ret = true; } if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) ret = true; exit: spin_unlock(&msm_port->rx_lock); return ret; } static void msm_geni_serial_handle_isr(struct uart_port *uport, unsigned long *flags, bool is_irq_masked) Loading Loading @@ -1994,70 +2087,19 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport, TX_GENI_CANCEL_IRQ)) m_cmd_done = true; if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN)) m_cmd_done = true; if ((dma_tx_status & TX_DMA_DONE) && !m_cmd_done) msm_geni_serial_handle_dma_tx(uport); } if (dma_rx_status) { geni_write_reg_nolog(dma_rx_status, uport->membase, SE_DMA_RX_IRQ_CLR); if (dma_rx_status & RX_RESET_DONE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Reset done. 0x%x.\n", __func__, dma_rx_status); s_cmd_done = true; goto exit_geni_serial_isr; } if (dma_rx_status & UART_DMA_RX_ERRS) { if (dma_rx_status & UART_DMA_RX_PARITY_ERR) uport->icount.parity++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x parity:%d\n", __func__, dma_rx_status, uport->icount.parity); drop_rx = true; } else if (dma_rx_status & UART_DMA_RX_BREAK) { uport->icount.brk++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x break:%d\n", __func__, dma_rx_status, 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)) { 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. not mapping rx dma\n", __func__); } } if (dma_rx_status & RX_SBE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Rx Errors. 0x%x\n", __func__, dma_rx_status); WARN_ON(1); } if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN)) m_cmd_done = true; if (dma_rx_status & (RX_EOT | RX_GENI_CANCEL_IRQ | RX_DMA_DONE)) s_cmd_done = true; if (dma_rx_status) s_cmd_done = handle_rx_dma_xfer(s_irq_status, uport); if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) s_cmd_done = true; } } exit_geni_serial_isr: if (m_cmd_done) { Loading Loading @@ -3386,6 +3428,9 @@ static int msm_geni_serial_probe(struct platform_device *pdev) if (ret) goto exit_wakeup_unregister; if (!uart_console(uport)) spin_lock_init(&dev_port->rx_lock); IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: port:%s irq:%d\n", __func__, uport->name, uport->irq); Loading