Loading drivers/tty/serial/msm_geni_serial.c +101 −50 Original line number Diff line number Diff line Loading @@ -172,7 +172,8 @@ struct msm_geni_serial_port { unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx); bool drop_rx, unsigned long *flags); struct device *wrapper_dev; struct se_geni_rsc serial_rsc; dma_addr_t tx_dma; Loading Loading @@ -212,12 +213,12 @@ static int handle_rx_console(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx); bool drop_rx, unsigned long *flags); static int handle_rx_hs(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx); bool drop_rx, unsigned long *flags); static unsigned int msm_geni_serial_tx_empty(struct uart_port *port); static int msm_geni_serial_power_on(struct uart_port *uport); static void msm_geni_serial_power_off(struct uart_port *uport); Loading @@ -236,7 +237,8 @@ static int uart_line_id; static struct msm_geni_serial_port msm_geni_console_port; static struct msm_geni_serial_port msm_geni_serial_ports[GENI_UART_NR_PORTS]; static void msm_geni_serial_handle_isr(struct uart_port *uport); static void msm_geni_serial_handle_isr(struct uart_port *uport, unsigned long *flags); /* * The below API is required to check if uport->lock (spinlock) Loading Loading @@ -297,8 +299,8 @@ static void msm_geni_serial_enable_interrupts(struct uart_port *uport) } } /* Disable the interrupts in order to do polling in an atomic contexts. */ static void msm_geni_serial_disable_interrupts(struct uart_port *uport) /* Try disabling interrupts in order to do polling in an atomic contexts. */ static bool msm_serial_try_disable_interrupts(struct uart_port *uport) { unsigned int geni_m_irq_en, geni_s_irq_en; unsigned int dma_m_irq_en, dma_s_irq_en; Loading @@ -309,7 +311,7 @@ static void msm_geni_serial_disable_interrupts(struct uart_port *uport) * by framework as we can rely on ISR. */ if (!msm_geni_serial_spinlocked(uport)) return; return false; geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); geni_s_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_S_IRQ_EN); Loading @@ -335,6 +337,8 @@ static void msm_geni_serial_disable_interrupts(struct uart_port *uport) geni_write_reg_nolog(dma_s_irq_en, uport->membase, SE_DMA_RX_IRQ_EN); } return true; } /* Loading @@ -343,17 +347,18 @@ static void msm_geni_serial_disable_interrupts(struct uart_port *uport) * in a non-atomic context. This API decides wheather to poll for * interrupt or depend on the isr based on in_atomic() call. */ bool geni_wait_for_cmd_done(struct uart_port *uport) bool geni_wait_for_cmd_done(struct uart_port *uport, bool is_irq_masked) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned long timeout = POLL_ITERATIONS; unsigned long ret; unsigned long flags = 0; /* * We need to do polling if spinlock is taken * by framework as we cannot rely on ISR. */ if (msm_geni_serial_spinlocked(uport)) { if (is_irq_masked) { /* * Polling is done for 1000 iterrations with * 10 usecs interval which in total accumulates Loading @@ -361,13 +366,13 @@ bool geni_wait_for_cmd_done(struct uart_port *uport) */ if (msm_port->m_cmd) { while (!msm_port->m_cmd_done && timeout > 0) { msm_geni_serial_handle_isr(uport); msm_geni_serial_handle_isr(uport, &flags); timeout--; udelay(100); } } else if (msm_port->s_cmd) { while (!msm_port->s_cmd_done && timeout > 0) { msm_geni_serial_handle_isr(uport); msm_geni_serial_handle_isr(uport, &flags); timeout--; udelay(100); } Loading Loading @@ -870,7 +875,7 @@ static void msm_geni_serial_poll_put_char(struct uart_port *uport, * Ensure FIFO write goes through before polling for status but. */ mb(); msm_geni_serial_disable_interrupts(uport); msm_serial_try_disable_interrupts(uport); msm_geni_serial_poll_tx_done(uport); msm_geni_serial_enable_interrupts(uport); } Loading Loading @@ -933,7 +938,7 @@ __msm_geni_serial_console_write(struct uart_port *uport, const char *s, mb(); i += chars_to_write; } msm_geni_serial_disable_interrupts(uport); msm_serial_try_disable_interrupts(uport); msm_geni_serial_poll_tx_done(uport); msm_geni_serial_enable_interrupts(uport); } Loading @@ -947,6 +952,7 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, unsigned long flags; unsigned int geni_status; bool timeout; bool is_irq_masked; int irq_en; /* Max 1 port supported as of now */ Loading @@ -965,14 +971,19 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); /* Cancel the current write to log the fault */ if (!locked) { if ((geni_status & M_GENI_CMD_ACTIVE) && !locked) { port->m_cmd_done = false; port->m_cmd = true; reinit_completion(&port->m_cmd_timeout); msm_geni_serial_disable_interrupts(uport); is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); /* * console should be in polling mode. Hence directly pass true * as argument for wait_for_cmd_done here to handle cancel tx * in polling mode. */ timeout = geni_wait_for_cmd_done(uport, true); if (timeout) { IPC_LOG_MSG(port->console_log, "%s: tx_cancel failed 0x%x\n", Loading @@ -981,7 +992,7 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, reinit_completion(&port->m_cmd_timeout); geni_abort_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, true); if (timeout) IPC_LOG_MSG(port->console_log, "%s: tx abort failed 0x%x\n", __func__, Loading @@ -996,7 +1007,7 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, /* It seems we can interrupt existing transfers unless all data * has been sent, in which case we need to look for done first. */ msm_geni_serial_disable_interrupts(uport); msm_serial_try_disable_interrupts(uport); msm_geni_serial_poll_tx_done(uport); msm_geni_serial_enable_interrupts(uport); Loading @@ -1022,13 +1033,13 @@ static int handle_rx_console(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx) bool drop_rx, unsigned long *flags) { int i, c; unsigned char *rx_char; unsigned long flags; struct tty_port *tport; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); bool locked; tport = &uport->state->port; for (i = 0; i < rx_fifo_wc; i++) { Loading Loading @@ -1062,9 +1073,14 @@ static int handle_rx_console(struct uart_port *uport, * release the port lock before calling tty_flip_buffer_push() * to avoid deadlock scenarios. */ spin_unlock_irqrestore(&uport->lock, flags); locked = msm_geni_serial_spinlocked(uport); if (locked) { spin_unlock_irqrestore(&uport->lock, *flags); tty_flip_buffer_push(tport); spin_lock_irqsave(&uport->lock, flags); spin_lock_irqsave(&uport->lock, *flags); } else { tty_flip_buffer_push(tport); } } return 0; } Loading @@ -1073,7 +1089,7 @@ static int handle_rx_console(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx) bool drop_rx, unsigned long *flags) { return -EPERM; } Loading @@ -1086,7 +1102,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) struct circ_buf *xmit = &uport->state->xmit; unsigned int xmit_size; unsigned int dma_dbg; bool timeout; bool timeout, is_irq_masked; int ret = 0; xmit_size = uart_circ_chars_pending(xmit); Loading Loading @@ -1117,13 +1133,13 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) reinit_completion(&msm_port->m_cmd_timeout); /* * Disabling the interrupts before giving the * Try disabling interrupts before giving the * cancel command as this might be in an atomic context. */ msm_geni_serial_disable_interrupts(uport); is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { IPC_LOG_MSG(msm_port->console_log, "%s: tx_cancel fail 0x%x\n", __func__, Loading @@ -1138,7 +1154,8 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) /* Give abort command as cancel command failed */ geni_abort_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { IPC_LOG_MSG(msm_port->console_log, "%s: tx abort failed 0x%x\n", __func__, Loading @@ -1160,7 +1177,8 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) geni_write_reg_nolog(1, uport->membase, SE_DMA_TX_FSM_RST); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: tx fsm reset failed\n", __func__); Loading Loading @@ -1243,7 +1261,7 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) static void stop_tx_sequencer(struct uart_port *uport) { unsigned int geni_status; bool timeout; bool timeout, is_irq_masked; unsigned int dma_dbg; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); Loading @@ -1258,9 +1276,15 @@ static void stop_tx_sequencer(struct uart_port *uport) port->m_cmd_done = false; port->m_cmd = true; reinit_completion(&port->m_cmd_timeout); /* * Try to mask the interrupts before giving the * cancel command as this might be in an atomic context * from framework driver. */ is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { IPC_LOG_MSG(port->console_log, "%s: tx_cancel failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); Loading @@ -1271,7 +1295,7 @@ static void stop_tx_sequencer(struct uart_port *uport) reinit_completion(&port->m_cmd_timeout); geni_abort_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { IPC_LOG_MSG(port->console_log, "%s: tx abort failed 0x%x\n", __func__, Loading @@ -1290,7 +1314,8 @@ static void stop_tx_sequencer(struct uart_port *uport) geni_write_reg_nolog(1, uport->membase, SE_DMA_TX_FSM_RST); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) IPC_LOG_MSG(port->ipc_log_misc, "%s: tx fsm reset failed\n", __func__); Loading @@ -1302,6 +1327,8 @@ static void stop_tx_sequencer(struct uart_port *uport) port->tx_dma = (dma_addr_t)NULL; } } /* Unmask the interrupts once the cancel operation is done. */ msm_geni_serial_enable_interrupts(uport); port->m_cmd = false; port->xmit_size = 0; Loading Loading @@ -1441,8 +1468,9 @@ static void msm_geni_serial_set_manual_flow(bool enable, static void stop_rx_sequencer(struct uart_port *uport) { unsigned int geni_status; bool timeout; bool timeout, is_irq_masked; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); unsigned long flags = 0; IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__); Loading @@ -1462,10 +1490,10 @@ static void stop_rx_sequencer(struct uart_port *uport) IPC_LOG_MSG(port->ipc_log_misc, "%s: Start 0x%x\n", __func__, geni_status); /* * Disabling the interrupts before giving the * Try disabling interrupts before giving the * cancel command as this might be in an atomic context. */ msm_geni_serial_disable_interrupts(uport); is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_s_cmd(uport->membase); /* Loading @@ -1473,21 +1501,35 @@ static void stop_rx_sequencer(struct uart_port *uport) * cancel control bit. */ mb(); timeout = geni_wait_for_cmd_done(uport); 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); /* * Possible that stop_rx is called from system resume context * for console usecase. In early resume, irq remains disabled * in the system. call msm_geni_serial_handle_isr to clear * the interrupts. */ is_rx_active = geni_status & S_GENI_CMD_ACTIVE; IPC_LOG_MSG(port->ipc_log_misc, "%s cancel failed 0x%x\n", __func__, geni_status); "%s cancel failed is_rx_active:%d 0x%x\n", __func__, is_rx_active, geni_status); IPC_LOG_MSG(port->console_log, "%s cancel failed 0x%x\n", __func__, geni_status); "%s cancel failed is_rx_active:%d 0x%x\n", __func__, is_rx_active, geni_status); if (uart_console(uport) && !is_rx_active) { msm_geni_serial_handle_isr(uport, &flags); goto exit_rx_seq; } port->s_cmd_done = false; reinit_completion(&port->s_cmd_timeout); geni_abort_s_cmd(uport->membase); /* Ensure this goes through before polling. */ mb(); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); Loading Loading @@ -1526,7 +1568,7 @@ static int handle_rx_hs(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx) bool drop_rx, unsigned long *flags) { unsigned char *rx_char; struct tty_port *tport; Loading Loading @@ -1558,7 +1600,8 @@ static int handle_rx_hs(struct uart_port *uport, return ret; } static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx) static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx, unsigned long *flags) { int ret = 0; unsigned int rx_fifo_status; Loading @@ -1577,7 +1620,7 @@ static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx) rx_last = rx_fifo_status & RX_LAST; if (rx_fifo_wc) ret = port->handle_rx(uport, rx_fifo_wc, rx_last_byte_valid, rx_last, drop_rx); rx_last, drop_rx, flags); return ret; } Loading Loading @@ -1759,7 +1802,8 @@ static int msm_geni_serial_handle_dma_tx(struct uart_port *uport) return 0; } static void msm_geni_serial_handle_isr(struct uart_port *uport) static void msm_geni_serial_handle_isr(struct uart_port *uport, unsigned long *flags) { unsigned int m_irq_status; unsigned int s_irq_status; Loading Loading @@ -1833,13 +1877,20 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport) "%s.sirq 0x%x break:%d\n", __func__, s_irq_status, uport->icount.brk); } if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) /* * In case of stop_rx handling there is a chance * for RX data can come in parallel. set drop_rx to * avoid data push to framework from handle_rx_console() * API for stop_rx case. */ if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) { s_cmd_done = true; drop_rx = true; } if (s_irq_status & (S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN)) msm_geni_serial_handle_rx(uport, drop_rx); msm_geni_serial_handle_rx(uport, drop_rx, flags); } else { dma_tx_status = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_STAT); Loading Loading @@ -1933,7 +1984,7 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) unsigned long flags; spin_lock_irqsave(&uport->lock, flags); msm_geni_serial_handle_isr(uport); msm_geni_serial_handle_isr(uport, &flags); spin_unlock_irqrestore(&uport->lock, flags); return IRQ_HANDLED; } Loading Loading @@ -2102,7 +2153,7 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) * it else we could end up in data loss scenarios. */ msm_port->xfer_mode = FIFO_MODE; msm_geni_serial_disable_interrupts(uport); msm_serial_try_disable_interrupts(uport); msm_geni_serial_poll_tx_done(uport); msm_geni_serial_enable_interrupts(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); Loading Loading
drivers/tty/serial/msm_geni_serial.c +101 −50 Original line number Diff line number Diff line Loading @@ -172,7 +172,8 @@ struct msm_geni_serial_port { unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx); bool drop_rx, unsigned long *flags); struct device *wrapper_dev; struct se_geni_rsc serial_rsc; dma_addr_t tx_dma; Loading Loading @@ -212,12 +213,12 @@ static int handle_rx_console(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx); bool drop_rx, unsigned long *flags); static int handle_rx_hs(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx); bool drop_rx, unsigned long *flags); static unsigned int msm_geni_serial_tx_empty(struct uart_port *port); static int msm_geni_serial_power_on(struct uart_port *uport); static void msm_geni_serial_power_off(struct uart_port *uport); Loading @@ -236,7 +237,8 @@ static int uart_line_id; static struct msm_geni_serial_port msm_geni_console_port; static struct msm_geni_serial_port msm_geni_serial_ports[GENI_UART_NR_PORTS]; static void msm_geni_serial_handle_isr(struct uart_port *uport); static void msm_geni_serial_handle_isr(struct uart_port *uport, unsigned long *flags); /* * The below API is required to check if uport->lock (spinlock) Loading Loading @@ -297,8 +299,8 @@ static void msm_geni_serial_enable_interrupts(struct uart_port *uport) } } /* Disable the interrupts in order to do polling in an atomic contexts. */ static void msm_geni_serial_disable_interrupts(struct uart_port *uport) /* Try disabling interrupts in order to do polling in an atomic contexts. */ static bool msm_serial_try_disable_interrupts(struct uart_port *uport) { unsigned int geni_m_irq_en, geni_s_irq_en; unsigned int dma_m_irq_en, dma_s_irq_en; Loading @@ -309,7 +311,7 @@ static void msm_geni_serial_disable_interrupts(struct uart_port *uport) * by framework as we can rely on ISR. */ if (!msm_geni_serial_spinlocked(uport)) return; return false; geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); geni_s_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_S_IRQ_EN); Loading @@ -335,6 +337,8 @@ static void msm_geni_serial_disable_interrupts(struct uart_port *uport) geni_write_reg_nolog(dma_s_irq_en, uport->membase, SE_DMA_RX_IRQ_EN); } return true; } /* Loading @@ -343,17 +347,18 @@ static void msm_geni_serial_disable_interrupts(struct uart_port *uport) * in a non-atomic context. This API decides wheather to poll for * interrupt or depend on the isr based on in_atomic() call. */ bool geni_wait_for_cmd_done(struct uart_port *uport) bool geni_wait_for_cmd_done(struct uart_port *uport, bool is_irq_masked) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned long timeout = POLL_ITERATIONS; unsigned long ret; unsigned long flags = 0; /* * We need to do polling if spinlock is taken * by framework as we cannot rely on ISR. */ if (msm_geni_serial_spinlocked(uport)) { if (is_irq_masked) { /* * Polling is done for 1000 iterrations with * 10 usecs interval which in total accumulates Loading @@ -361,13 +366,13 @@ bool geni_wait_for_cmd_done(struct uart_port *uport) */ if (msm_port->m_cmd) { while (!msm_port->m_cmd_done && timeout > 0) { msm_geni_serial_handle_isr(uport); msm_geni_serial_handle_isr(uport, &flags); timeout--; udelay(100); } } else if (msm_port->s_cmd) { while (!msm_port->s_cmd_done && timeout > 0) { msm_geni_serial_handle_isr(uport); msm_geni_serial_handle_isr(uport, &flags); timeout--; udelay(100); } Loading Loading @@ -870,7 +875,7 @@ static void msm_geni_serial_poll_put_char(struct uart_port *uport, * Ensure FIFO write goes through before polling for status but. */ mb(); msm_geni_serial_disable_interrupts(uport); msm_serial_try_disable_interrupts(uport); msm_geni_serial_poll_tx_done(uport); msm_geni_serial_enable_interrupts(uport); } Loading Loading @@ -933,7 +938,7 @@ __msm_geni_serial_console_write(struct uart_port *uport, const char *s, mb(); i += chars_to_write; } msm_geni_serial_disable_interrupts(uport); msm_serial_try_disable_interrupts(uport); msm_geni_serial_poll_tx_done(uport); msm_geni_serial_enable_interrupts(uport); } Loading @@ -947,6 +952,7 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, unsigned long flags; unsigned int geni_status; bool timeout; bool is_irq_masked; int irq_en; /* Max 1 port supported as of now */ Loading @@ -965,14 +971,19 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); /* Cancel the current write to log the fault */ if (!locked) { if ((geni_status & M_GENI_CMD_ACTIVE) && !locked) { port->m_cmd_done = false; port->m_cmd = true; reinit_completion(&port->m_cmd_timeout); msm_geni_serial_disable_interrupts(uport); is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); /* * console should be in polling mode. Hence directly pass true * as argument for wait_for_cmd_done here to handle cancel tx * in polling mode. */ timeout = geni_wait_for_cmd_done(uport, true); if (timeout) { IPC_LOG_MSG(port->console_log, "%s: tx_cancel failed 0x%x\n", Loading @@ -981,7 +992,7 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, reinit_completion(&port->m_cmd_timeout); geni_abort_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, true); if (timeout) IPC_LOG_MSG(port->console_log, "%s: tx abort failed 0x%x\n", __func__, Loading @@ -996,7 +1007,7 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, /* It seems we can interrupt existing transfers unless all data * has been sent, in which case we need to look for done first. */ msm_geni_serial_disable_interrupts(uport); msm_serial_try_disable_interrupts(uport); msm_geni_serial_poll_tx_done(uport); msm_geni_serial_enable_interrupts(uport); Loading @@ -1022,13 +1033,13 @@ static int handle_rx_console(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx) bool drop_rx, unsigned long *flags) { int i, c; unsigned char *rx_char; unsigned long flags; struct tty_port *tport; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); bool locked; tport = &uport->state->port; for (i = 0; i < rx_fifo_wc; i++) { Loading Loading @@ -1062,9 +1073,14 @@ static int handle_rx_console(struct uart_port *uport, * release the port lock before calling tty_flip_buffer_push() * to avoid deadlock scenarios. */ spin_unlock_irqrestore(&uport->lock, flags); locked = msm_geni_serial_spinlocked(uport); if (locked) { spin_unlock_irqrestore(&uport->lock, *flags); tty_flip_buffer_push(tport); spin_lock_irqsave(&uport->lock, flags); spin_lock_irqsave(&uport->lock, *flags); } else { tty_flip_buffer_push(tport); } } return 0; } Loading @@ -1073,7 +1089,7 @@ static int handle_rx_console(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx) bool drop_rx, unsigned long *flags) { return -EPERM; } Loading @@ -1086,7 +1102,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) struct circ_buf *xmit = &uport->state->xmit; unsigned int xmit_size; unsigned int dma_dbg; bool timeout; bool timeout, is_irq_masked; int ret = 0; xmit_size = uart_circ_chars_pending(xmit); Loading Loading @@ -1117,13 +1133,13 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) reinit_completion(&msm_port->m_cmd_timeout); /* * Disabling the interrupts before giving the * Try disabling interrupts before giving the * cancel command as this might be in an atomic context. */ msm_geni_serial_disable_interrupts(uport); is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { IPC_LOG_MSG(msm_port->console_log, "%s: tx_cancel fail 0x%x\n", __func__, Loading @@ -1138,7 +1154,8 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) /* Give abort command as cancel command failed */ geni_abort_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { IPC_LOG_MSG(msm_port->console_log, "%s: tx abort failed 0x%x\n", __func__, Loading @@ -1160,7 +1177,8 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) geni_write_reg_nolog(1, uport->membase, SE_DMA_TX_FSM_RST); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: tx fsm reset failed\n", __func__); Loading Loading @@ -1243,7 +1261,7 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) static void stop_tx_sequencer(struct uart_port *uport) { unsigned int geni_status; bool timeout; bool timeout, is_irq_masked; unsigned int dma_dbg; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); Loading @@ -1258,9 +1276,15 @@ static void stop_tx_sequencer(struct uart_port *uport) port->m_cmd_done = false; port->m_cmd = true; reinit_completion(&port->m_cmd_timeout); /* * Try to mask the interrupts before giving the * cancel command as this might be in an atomic context * from framework driver. */ is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { IPC_LOG_MSG(port->console_log, "%s: tx_cancel failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); Loading @@ -1271,7 +1295,7 @@ static void stop_tx_sequencer(struct uart_port *uport) reinit_completion(&port->m_cmd_timeout); geni_abort_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { IPC_LOG_MSG(port->console_log, "%s: tx abort failed 0x%x\n", __func__, Loading @@ -1290,7 +1314,8 @@ static void stop_tx_sequencer(struct uart_port *uport) geni_write_reg_nolog(1, uport->membase, SE_DMA_TX_FSM_RST); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) IPC_LOG_MSG(port->ipc_log_misc, "%s: tx fsm reset failed\n", __func__); Loading @@ -1302,6 +1327,8 @@ static void stop_tx_sequencer(struct uart_port *uport) port->tx_dma = (dma_addr_t)NULL; } } /* Unmask the interrupts once the cancel operation is done. */ msm_geni_serial_enable_interrupts(uport); port->m_cmd = false; port->xmit_size = 0; Loading Loading @@ -1441,8 +1468,9 @@ static void msm_geni_serial_set_manual_flow(bool enable, static void stop_rx_sequencer(struct uart_port *uport) { unsigned int geni_status; bool timeout; bool timeout, is_irq_masked; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); unsigned long flags = 0; IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__); Loading @@ -1462,10 +1490,10 @@ static void stop_rx_sequencer(struct uart_port *uport) IPC_LOG_MSG(port->ipc_log_misc, "%s: Start 0x%x\n", __func__, geni_status); /* * Disabling the interrupts before giving the * Try disabling interrupts before giving the * cancel command as this might be in an atomic context. */ msm_geni_serial_disable_interrupts(uport); is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_s_cmd(uport->membase); /* Loading @@ -1473,21 +1501,35 @@ static void stop_rx_sequencer(struct uart_port *uport) * cancel control bit. */ mb(); timeout = geni_wait_for_cmd_done(uport); 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); /* * Possible that stop_rx is called from system resume context * for console usecase. In early resume, irq remains disabled * in the system. call msm_geni_serial_handle_isr to clear * the interrupts. */ is_rx_active = geni_status & S_GENI_CMD_ACTIVE; IPC_LOG_MSG(port->ipc_log_misc, "%s cancel failed 0x%x\n", __func__, geni_status); "%s cancel failed is_rx_active:%d 0x%x\n", __func__, is_rx_active, geni_status); IPC_LOG_MSG(port->console_log, "%s cancel failed 0x%x\n", __func__, geni_status); "%s cancel failed is_rx_active:%d 0x%x\n", __func__, is_rx_active, geni_status); if (uart_console(uport) && !is_rx_active) { msm_geni_serial_handle_isr(uport, &flags); goto exit_rx_seq; } port->s_cmd_done = false; reinit_completion(&port->s_cmd_timeout); geni_abort_s_cmd(uport->membase); /* Ensure this goes through before polling. */ mb(); timeout = geni_wait_for_cmd_done(uport); timeout = geni_wait_for_cmd_done(uport, is_irq_masked); if (timeout) { geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); Loading Loading @@ -1526,7 +1568,7 @@ static int handle_rx_hs(struct uart_port *uport, unsigned int rx_fifo_wc, unsigned int rx_last_byte_valid, unsigned int rx_last, bool drop_rx) bool drop_rx, unsigned long *flags) { unsigned char *rx_char; struct tty_port *tport; Loading Loading @@ -1558,7 +1600,8 @@ static int handle_rx_hs(struct uart_port *uport, return ret; } static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx) static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx, unsigned long *flags) { int ret = 0; unsigned int rx_fifo_status; Loading @@ -1577,7 +1620,7 @@ static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx) rx_last = rx_fifo_status & RX_LAST; if (rx_fifo_wc) ret = port->handle_rx(uport, rx_fifo_wc, rx_last_byte_valid, rx_last, drop_rx); rx_last, drop_rx, flags); return ret; } Loading Loading @@ -1759,7 +1802,8 @@ static int msm_geni_serial_handle_dma_tx(struct uart_port *uport) return 0; } static void msm_geni_serial_handle_isr(struct uart_port *uport) static void msm_geni_serial_handle_isr(struct uart_port *uport, unsigned long *flags) { unsigned int m_irq_status; unsigned int s_irq_status; Loading Loading @@ -1833,13 +1877,20 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport) "%s.sirq 0x%x break:%d\n", __func__, s_irq_status, uport->icount.brk); } if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) /* * In case of stop_rx handling there is a chance * for RX data can come in parallel. set drop_rx to * avoid data push to framework from handle_rx_console() * API for stop_rx case. */ if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) { s_cmd_done = true; drop_rx = true; } if (s_irq_status & (S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN)) msm_geni_serial_handle_rx(uport, drop_rx); msm_geni_serial_handle_rx(uport, drop_rx, flags); } else { dma_tx_status = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_STAT); Loading Loading @@ -1933,7 +1984,7 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) unsigned long flags; spin_lock_irqsave(&uport->lock, flags); msm_geni_serial_handle_isr(uport); msm_geni_serial_handle_isr(uport, &flags); spin_unlock_irqrestore(&uport->lock, flags); return IRQ_HANDLED; } Loading Loading @@ -2102,7 +2153,7 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) * it else we could end up in data loss scenarios. */ msm_port->xfer_mode = FIFO_MODE; msm_geni_serial_disable_interrupts(uport); msm_serial_try_disable_interrupts(uport); msm_geni_serial_poll_tx_done(uport); msm_geni_serial_enable_interrupts(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); Loading