aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandana Kishori Chiluveru <cchiluve@codeaurora.org>2020-05-22 11:53:48 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2020-05-25 04:36:25 -0700
commitc942c752b1cf0835e9a3bf402ae40246c69b04be (patch)
tree8cb4c2ae78de09602c98709fac5f4bd68a5bf311
parentc5bf1a935972370ee3bea390cfa999de462e4ac8 (diff)
Revert "msm-geni-serial: Correct the interrupt polling logic in uart"LA.UM.8.12.r1-11700-sm8250.0
This reverts commit 5780bc67aa8b32d9cc31ffe2e3a52738936a8b71. Change-Id: I8a2579c66c2bbaf13a2a787a1ff829be6d0d60d4 Signed-off-by: Chandana Kishori Chiluveru <cchiluve@codeaurora.org>
-rw-r--r--drivers/tty/serial/msm_geni_serial.c849
-rw-r--r--include/linux/qcom-geni-se.h9
2 files changed, 272 insertions, 586 deletions
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 095e5cba5fa2..0d4c0e6b2616 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -118,26 +118,6 @@
#define IPC_LOG_TX_RX_PAGES (10)
#define DATA_BYTES_PER_LINE (32)
-#define M_IRQ_BITS (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN |\
- M_CMD_CANCEL_EN | M_CMD_ABORT_EN)
-#define S_IRQ_BITS (S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN |\
- S_CMD_CANCEL_EN | S_CMD_ABORT_EN)
-#define DMA_TX_IRQ_BITS (TX_RESET_DONE | TX_DMA_DONE |\
- TX_GENI_CANCEL_IRQ)
-#define DMA_RX_IRQ_BITS (RX_EOT | RX_GENI_CANCEL_IRQ |\
- RX_RESET_DONE | UART_DMA_RX_ERRS |\
- UART_DMA_RX_PARITY_ERR | UART_DMA_RX_BREAK |\
- RX_DMA_DONE)
-
-/* Required for polling for 100 msecs */
-#define POLL_WAIT_TIMEOUT_MSEC 100
-
-/*
- * Number of iterrations required while polling
- * where each iterration has a delay of 100 usecs
- */
-#define POLL_ITERATIONS 1000
-
#define IPC_LOG_MSG(ctx, x...) do { \
if (ctx) \
ipc_log_string(ctx, x); \
@@ -156,7 +136,7 @@ struct msm_geni_serial_ver_info {
struct msm_geni_serial_port {
struct uart_port uport;
- const char *name;
+ char name[20];
unsigned int tx_fifo_depth;
unsigned int tx_fifo_width;
unsigned int rx_fifo_depth;
@@ -196,12 +176,6 @@ struct msm_geni_serial_port {
bool startup_in_progress;
bool is_console;
bool rumi_platform;
- bool m_cmd_done;
- bool s_cmd_done;
- bool m_cmd;
- bool s_cmd;
- struct completion m_cmd_timeout;
- struct completion s_cmd_timeout;
};
static const struct uart_ops msm_geni_serial_pops;
@@ -235,156 +209,6 @@ 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);
-
-/*
- * The below API is required to check if uport->lock (spinlock)
- * is taken by the serial layer or not. If the lock is not taken
- * then we can rely on the isr to be fired and if the lock is taken
- * by the serial layer then we need to poll for the interrupts.
- *
- * Returns true(1) if spinlock is already taken by framework (serial layer)
- * Return false(0) if spinlock is not taken by framework.
- */
-static int msm_geni_serial_spinlocked(struct uart_port *uport)
-{
- unsigned long flags;
- bool locked;
-
- locked = spin_trylock_irqsave(&uport->lock, flags);
- if (locked)
- spin_unlock_irqrestore(&uport->lock, flags);
-
- return !locked;
-}
-
-/*
- * We are enabling the interrupts once the polling operations
- * is completed.
- */
-static void msm_geni_serial_enable_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;
- struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
-
- 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);
- if (port->xfer_mode == SE_DMA) {
- dma_m_irq_en = geni_read_reg_nolog(uport->membase,
- SE_DMA_TX_IRQ_EN);
- dma_s_irq_en = geni_read_reg_nolog(uport->membase,
- SE_DMA_RX_IRQ_EN);
- }
-
- geni_m_irq_en |= M_IRQ_BITS;
- geni_s_irq_en |= S_IRQ_BITS;
- if (port->xfer_mode == SE_DMA) {
- dma_m_irq_en |= DMA_TX_IRQ_BITS;
- dma_s_irq_en |= DMA_RX_IRQ_BITS;
- }
-
- geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
- geni_write_reg_nolog(geni_s_irq_en, uport->membase, SE_GENI_S_IRQ_EN);
- if (port->xfer_mode == SE_DMA) {
- geni_write_reg_nolog(dma_m_irq_en, uport->membase,
- SE_DMA_TX_IRQ_EN);
- geni_write_reg_nolog(dma_s_irq_en, uport->membase,
- SE_DMA_RX_IRQ_EN);
- }
-}
-
-/* Disable the interrupts in order to do polling in an atomic contexts. */
-static void msm_geni_serial_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;
- struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
-
- /*
- * We don't need to disable interrupts if spinlock is not taken
- * by framework as we can rely on ISR.
- */
- if (!msm_geni_serial_spinlocked(uport))
- return;
-
- 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);
- if (port->xfer_mode == SE_DMA) {
- dma_m_irq_en = geni_read_reg_nolog(uport->membase,
- SE_DMA_TX_IRQ_EN);
- dma_s_irq_en = geni_read_reg_nolog(uport->membase,
- SE_DMA_RX_IRQ_EN);
- }
-
- geni_m_irq_en &= ~M_IRQ_BITS;
- geni_s_irq_en &= ~S_IRQ_BITS;
- if (port->xfer_mode == SE_DMA) {
- dma_m_irq_en &= ~DMA_TX_IRQ_BITS;
- dma_s_irq_en &= ~DMA_RX_IRQ_BITS;
- }
-
- geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
- geni_write_reg_nolog(geni_s_irq_en, uport->membase, SE_GENI_S_IRQ_EN);
- if (port->xfer_mode == SE_DMA) {
- geni_write_reg_nolog(dma_m_irq_en, uport->membase,
- SE_DMA_TX_IRQ_EN);
- geni_write_reg_nolog(dma_s_irq_en, uport->membase,
- SE_DMA_RX_IRQ_EN);
- }
-}
-
-/*
- * We need to poll for interrupt if we are in an atomic context
- * as serial framework might be taking spinlocks and depend on the isr
- * 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)
-{
- struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
- unsigned long timeout = POLL_ITERATIONS;
- unsigned long ret;
-
- /*
- * We need to do polling if spinlock is taken
- * by framework as we cannot rely on ISR.
- */
- if (msm_geni_serial_spinlocked(uport)) {
- /*
- * Polling is done for 1000 iterrations with
- * 10 usecs interval which in total accumulates
- * to 10 msecs
- */
- if (msm_port->m_cmd) {
- while (!msm_port->m_cmd_done && timeout > 0) {
- msm_geni_serial_handle_isr(uport);
- timeout--;
- udelay(100);
- }
- } else if (msm_port->s_cmd) {
- while (!msm_port->s_cmd_done && timeout > 0) {
- msm_geni_serial_handle_isr(uport);
- timeout--;
- udelay(100);
- }
- }
- } else {
- /* Waiting for 10 milli second for interrupt to be fired */
- if (msm_port->m_cmd)
- ret = wait_for_completion_timeout
- (&msm_port->m_cmd_timeout,
- msecs_to_jiffies(POLL_WAIT_TIMEOUT_MSEC));
- else if (msm_port->s_cmd)
- ret = wait_for_completion_timeout
- (&msm_port->s_cmd_timeout,
- msecs_to_jiffies(POLL_WAIT_TIMEOUT_MSEC));
- }
-
- return ret ? 0 : 1;
-}
static void msm_geni_serial_config_port(struct uart_port *uport, int cfg_flags)
{
@@ -704,6 +528,7 @@ static int msm_geni_serial_power_on(struct uart_port *uport)
} else {
pm_runtime_get_noresume(uport->dev);
pm_runtime_set_active(uport->dev);
+ enable_irq(uport->irq);
}
pm_runtime_enable(uport->dev);
if (lock)
@@ -748,6 +573,7 @@ static int msm_geni_serial_poll_bit(struct uart_port *uport,
unsigned int fifo_bits = DEF_FIFO_DEPTH_WORDS * DEF_FIFO_WIDTH_BITS;
unsigned long total_iter = 1000;
+
if (uport->private_data && !uart_console(uport)) {
port = GET_DEV_PORT(uport);
baud = (port->cur_baud ? port->cur_baud : 115200);
@@ -788,34 +614,60 @@ static void msm_geni_serial_setup_tx(struct uart_port *uport,
mb();
}
-static void msm_geni_serial_poll_tx_done(struct uart_port *uport)
+static void msm_geni_serial_poll_cancel_tx(struct uart_port *uport)
{
int done = 0;
- unsigned int irq_clear = 0;
+ unsigned int irq_clear = M_CMD_DONE_EN;
done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_DONE_EN, true);
if (!done) {
- /*
- * Failure IPC logs are not added as this API is
- * used by early console and it doesn't have log handle.
- */
- geni_write_reg(S_GENI_CMD_CANCEL, uport->membase,
- SE_GENI_S_CMD_CTRL_REG);
- done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
- M_CMD_CANCEL_EN, true);
- if (!done) {
- geni_write_reg_nolog(M_GENI_CMD_ABORT, uport->membase,
- SE_GENI_M_CMD_CTRL_REG);
- msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
- M_CMD_ABORT_EN, true);
- }
+ geni_write_reg_nolog(M_GENI_CMD_ABORT, uport->membase,
+ SE_GENI_M_CMD_CTRL_REG);
+ irq_clear |= M_CMD_ABORT_EN;
+ msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
}
-
- irq_clear = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_STATUS);
geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_M_IRQ_CLEAR);
}
+static void msm_geni_serial_abort_rx(struct uart_port *uport)
+{
+ unsigned int irq_clear = S_CMD_DONE_EN;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+
+ geni_abort_s_cmd(uport->membase);
+ /* Ensure this goes through before polling. */
+ mb();
+ irq_clear |= S_CMD_ABORT_EN;
+ msm_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
+ S_GENI_CMD_ABORT, false);
+ geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_S_IRQ_CLEAR);
+ /* FORCE_DEFAULT makes RFR default high, hence set manually Low */
+ msm_geni_serial_set_manual_flow(true, port);
+ geni_write_reg(FORCE_DEFAULT, uport->membase, GENI_FORCE_DEFAULT_REG);
+}
+
+static void msm_geni_serial_complete_rx_eot(struct uart_port *uport)
+{
+ int poll_done = 0, tries = 0;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+
+ do {
+ poll_done = msm_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
+ RX_EOT, true);
+ tries++;
+ } while (!poll_done && tries < 5);
+
+ if (!poll_done)
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s: RX_EOT, GENI:0x%x, DMA_DEBUG:0x%x\n", __func__,
+ geni_read_reg_nolog(uport->membase, SE_GENI_STATUS),
+ geni_read_reg_nolog(uport->membase, SE_DMA_DEBUG_REG0));
+ else
+ geni_write_reg_nolog(RX_EOT, uport->membase, SE_DMA_RX_IRQ_CLR);
+}
+
#ifdef CONFIG_CONSOLE_POLL
static int msm_geni_serial_get_char(struct uart_port *uport)
{
@@ -869,9 +721,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_geni_serial_poll_tx_done(uport);
- msm_geni_serial_enable_interrupts(uport);
+ msm_geni_serial_poll_cancel_tx(uport);
}
#endif
@@ -907,7 +757,6 @@ __msm_geni_serial_console_write(struct uart_port *uport, const char *s,
SE_GENI_TX_WATERMARK_REG);
msm_geni_serial_setup_tx(uport, bytes_to_send);
i = 0;
-
while (i < count) {
u32 chars_to_write = 0;
u32 avail_fifo_bytes = (fifo_depth - tx_wm);
@@ -932,9 +781,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_geni_serial_poll_tx_done(uport);
- msm_geni_serial_enable_interrupts(uport);
+ msm_geni_serial_poll_cancel_tx(uport);
}
static void msm_geni_serial_console_write(struct console *co, const char *s,
@@ -945,7 +792,6 @@ static void msm_geni_serial_console_write(struct console *co, const char *s,
bool locked = true;
unsigned long flags;
unsigned int geni_status;
- bool timeout;
int irq_en;
/* Max 1 port supported as of now */
@@ -965,39 +811,23 @@ static void msm_geni_serial_console_write(struct console *co, const char *s,
/* Cancel the current write to log the fault */
if (!locked) {
- port->m_cmd_done = false;
- port->m_cmd = true;
- reinit_completion(&port->m_cmd_timeout);
- msm_geni_serial_disable_interrupts(uport);
geni_cancel_m_cmd(uport->membase);
-
- timeout = geni_wait_for_cmd_done(uport);
- 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));
-
- reinit_completion(&port->m_cmd_timeout);
+ if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_CANCEL_EN, true)) {
geni_abort_m_cmd(uport->membase);
- timeout = geni_wait_for_cmd_done(uport);
- if (timeout)
- IPC_LOG_MSG(port->console_log,
- "%s: tx abort failed 0x%x\n", __func__,
- geni_read_reg_nolog(uport->membase,
- SE_GENI_STATUS));
+ msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
+ geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase,
+ SE_GENI_M_IRQ_CLEAR);
}
-
- msm_geni_serial_enable_interrupts(uport);
- port->m_cmd = false;
+ writel_relaxed(M_CMD_CANCEL_EN, uport->membase +
+ SE_GENI_M_IRQ_CLEAR);
} else if ((geni_status & M_GENI_CMD_ACTIVE) &&
!port->cur_tx_remaining) {
/* 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_geni_serial_poll_tx_done(uport);
- msm_geni_serial_enable_interrupts(uport);
+ msm_geni_serial_poll_cancel_tx(uport);
/* Enable WM interrupt for every new console write op */
if (uart_circ_chars_pending(&uport->state->xmit)) {
@@ -1025,7 +855,6 @@ static int handle_rx_console(struct uart_port *uport,
{
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);
@@ -1061,9 +890,9 @@ 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);
+ spin_unlock(&uport->lock);
tty_flip_buffer_push(tport);
- spin_lock_irqsave(&uport->lock, flags);
+ spin_lock(&uport->lock);
}
return 0;
}
@@ -1084,8 +913,8 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
struct circ_buf *xmit = &uport->state->xmit;
unsigned int xmit_size;
- unsigned int dma_dbg;
- bool timeout;
+ u32 geni_status;
+ bool done = false;
int ret = 0;
xmit_size = uart_circ_chars_pending(xmit);
@@ -1103,80 +932,41 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)
msm_geni_serial_setup_tx(uport, xmit_size);
ret = geni_se_tx_dma_prep(msm_port->wrapper_dev, uport->membase,
&xmit->buf[xmit->tail], xmit_size, &msm_port->tx_dma);
-
if (!ret) {
msm_port->xmit_size = xmit_size;
- } else {
- IPC_LOG_MSG(msm_port->ipc_log_misc,
- "%s: TX DMA map Fail %d\n", __func__, ret);
-
- geni_write_reg_nolog(0, uport->membase, SE_UART_TX_TRANS_LEN);
- msm_port->m_cmd_done = false;
- msm_port->m_cmd = true;
- reinit_completion(&msm_port->m_cmd_timeout);
-
- /*
- * Disabling the interrupts before giving the
- * cancel command as this might be in an atomic context.
- */
- msm_geni_serial_disable_interrupts(uport);
- geni_cancel_m_cmd(uport->membase);
-
- timeout = geni_wait_for_cmd_done(uport);
- if (timeout) {
- IPC_LOG_MSG(msm_port->console_log,
- "%s: tx_cancel fail 0x%x\n", __func__,
- geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));
-
- IPC_LOG_MSG(msm_port->ipc_log_misc,
- "%s: tx_cancel failed 0x%x\n", __func__,
- geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));
-
- msm_port->m_cmd_done = false;
- reinit_completion(&msm_port->m_cmd_timeout);
- /* Give abort command as cancel command failed */
- geni_abort_m_cmd(uport->membase);
+ return ret;
+ }
- timeout = geni_wait_for_cmd_done(uport);
- if (timeout) {
- IPC_LOG_MSG(msm_port->console_log,
- "%s: tx abort failed 0x%x\n", __func__,
- geni_read_reg_nolog(uport->membase,
- SE_GENI_STATUS));
- IPC_LOG_MSG(msm_port->ipc_log_misc,
- "%s: tx abort failed 0x%x\n", __func__,
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s: TX DMA map Fail %d\n", __func__, ret);
+ geni_write_reg_nolog(0, uport->membase,
+ SE_UART_TX_TRANS_LEN);
+ geni_cancel_m_cmd(uport->membase);
+ if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_CANCEL_EN, true)) {
+ geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s: TX Cancel Fail 0x%x\n",
+ __func__, geni_status);
+ geni_abort_m_cmd(uport->membase);
+ done = msm_geni_serial_poll_bit(uport,
+ SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true);
+ if (!done) {
+ geni_status =
geni_read_reg_nolog(uport->membase,
- SE_GENI_STATUS));
- }
- }
-
- if (msm_port->xfer_mode == SE_DMA) {
- dma_dbg = geni_read_reg(uport->membase,
- SE_DMA_DEBUG_REG0);
- if (dma_dbg & DMA_TX_ACTIVE) {
- msm_port->m_cmd_done = false;
- reinit_completion(&msm_port->m_cmd_timeout);
- geni_write_reg_nolog(1, uport->membase,
- SE_DMA_TX_FSM_RST);
-
- timeout = geni_wait_for_cmd_done(uport);
- if (timeout)
- IPC_LOG_MSG(msm_port->ipc_log_misc,
- "%s: tx fsm reset failed\n", __func__);
- }
-
- if (msm_port->tx_dma) {
- geni_se_tx_dma_unprep(msm_port->wrapper_dev,
- msm_port->tx_dma, msm_port->xmit_size);
- msm_port->tx_dma = (dma_addr_t)NULL;
- }
+ SE_GENI_STATUS);
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s: TX Abort fail 0x%x\n",
+ __func__, geni_status);
}
- msm_port->xmit_size = 0;
- /* Enable the interrupts once the cancel operation is done. */
- msm_geni_serial_enable_interrupts(uport);
- msm_port->m_cmd = false;
+ geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase,
+ SE_GENI_M_IRQ_CLEAR);
}
-
+ geni_write_reg_nolog(M_CMD_CANCEL_EN, uport->membase,
+ SE_GENI_M_IRQ_CLEAR);
+ msm_port->tx_dma = (dma_addr_t)NULL;
+ msm_port->xmit_size = 0;
return ret;
}
@@ -1239,14 +1029,50 @@ exit_start_tx:
msm_geni_serial_power_off(uport);
}
+static void msm_geni_serial_tx_fsm_rst(struct uart_port *uport)
+{
+ unsigned int tx_irq_en;
+ int done = 0;
+ int tries = 0;
+
+ tx_irq_en = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_EN);
+ geni_write_reg_nolog(0, uport->membase, SE_DMA_TX_IRQ_EN_SET);
+ geni_write_reg_nolog(1, uport->membase, SE_DMA_TX_FSM_RST);
+ do {
+ done = msm_geni_serial_poll_bit(uport, SE_DMA_TX_IRQ_STAT,
+ TX_RESET_DONE, true);
+ tries++;
+ } while (!done && tries < 5);
+ geni_write_reg_nolog(TX_DMA_DONE | TX_RESET_DONE, uport->membase,
+ SE_DMA_TX_IRQ_CLR);
+ geni_write_reg_nolog(tx_irq_en, uport->membase, SE_DMA_TX_IRQ_EN_SET);
+}
+
static void stop_tx_sequencer(struct uart_port *uport)
{
+ unsigned int geni_m_irq_en;
unsigned int geni_status;
- bool timeout;
- unsigned int dma_dbg;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+ bool done = false;
- geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
+ geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
+ geni_m_irq_en &= ~M_CMD_DONE_EN;
+ if (port->xfer_mode == FIFO_MODE) {
+ geni_m_irq_en &= ~M_TX_FIFO_WATERMARK_EN;
+ geni_write_reg_nolog(0, uport->membase,
+ SE_GENI_TX_WATERMARK_REG);
+ } else if (port->xfer_mode == SE_DMA) {
+ if (port->tx_dma) {
+ msm_geni_serial_tx_fsm_rst(uport);
+ geni_se_tx_dma_unprep(port->wrapper_dev, port->tx_dma,
+ port->xmit_size);
+ port->tx_dma = (dma_addr_t)NULL;
+ }
+ }
+ port->xmit_size = 0;
+ geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
+ geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
/* Possible stop tx is called multiple times. */
if (!(geni_status & M_GENI_CMD_ACTIVE))
return;
@@ -1254,56 +1080,28 @@ static void stop_tx_sequencer(struct uart_port *uport)
IPC_LOG_MSG(port->ipc_log_misc,
"%s: Start GENI: 0x%x\n", __func__, geni_status);
- port->m_cmd_done = false;
- port->m_cmd = true;
- reinit_completion(&port->m_cmd_timeout);
geni_cancel_m_cmd(uport->membase);
-
- timeout = geni_wait_for_cmd_done(uport);
- 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));
- IPC_LOG_MSG(port->ipc_log_misc, "%s: tx_cancel failed 0x%x\n",
- __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));
-
- port->m_cmd_done = false;
- reinit_completion(&port->m_cmd_timeout);
+ if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_CANCEL_EN, true)) {
+ geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s: TX Cancel Fail 0x%x\n", __func__, geni_status);
geni_abort_m_cmd(uport->membase);
-
- timeout = geni_wait_for_cmd_done(uport);
- if (timeout) {
- IPC_LOG_MSG(port->console_log,
- "%s: tx abort failed 0x%x\n", __func__,
- geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));
+ done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
+ if (!done) {
+ geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
IPC_LOG_MSG(port->ipc_log_misc,
- "%s: tx abort failed 0x%x\n", __func__,
- geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));
- }
- }
-
- if (port->xfer_mode == SE_DMA) {
- dma_dbg = geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0);
- if (dma_dbg & DMA_TX_ACTIVE) {
- port->m_cmd_done = false;
- reinit_completion(&port->m_cmd_timeout);
- geni_write_reg_nolog(1, uport->membase,
- SE_DMA_TX_FSM_RST);
-
- timeout = geni_wait_for_cmd_done(uport);
- if (timeout)
- IPC_LOG_MSG(port->ipc_log_misc,
- "%s: tx fsm reset failed\n", __func__);
- }
-
- if (port->tx_dma) {
- geni_se_tx_dma_unprep(port->wrapper_dev,
- port->tx_dma, port->xmit_size);
- port->tx_dma = (dma_addr_t)NULL;
+ "%s TX Abort fail 0x%x\n",
+ __func__, geni_status);
}
+ geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase,
+ SE_GENI_M_IRQ_CLEAR);
}
- port->m_cmd = false;
- port->xmit_size = 0;
-
+ geni_write_reg_nolog(M_CMD_CANCEL_EN, uport->membase,
+ SE_GENI_M_IRQ_CLEAR);
/*
* If we end up having to cancel an on-going Tx for non-console usecase
* then it means there was some unsent data in the Tx FIFO, consequently
@@ -1315,7 +1113,6 @@ static void stop_tx_sequencer(struct uart_port *uport)
IPC_LOG_MSG(port->ipc_log_misc, "%s:Removing vote\n", __func__);
msm_geni_serial_power_off(uport);
}
-
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
IPC_LOG_MSG(port->ipc_log_misc, "%s: End GENI:0x%x\n",
__func__, geni_status);
@@ -1336,6 +1133,8 @@ static void msm_geni_serial_stop_tx(struct uart_port *uport)
static void start_rx_sequencer(struct uart_port *uport)
{
+ unsigned int geni_s_irq_en;
+ unsigned int geni_m_irq_en;
unsigned int geni_status;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
u32 geni_se_param = UART_PARAM_RFR_OPEN;
@@ -1358,14 +1157,29 @@ static void start_rx_sequencer(struct uart_port *uport)
}
/* Start RX with the RFR_OPEN to keep RFR in always ready state */
- msm_geni_serial_enable_interrupts(uport);
geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param);
- if (port->xfer_mode == SE_DMA)
+ if (port->xfer_mode == FIFO_MODE) {
+ geni_s_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_S_IRQ_EN);
+ geni_m_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_M_IRQ_EN);
+
+ geni_s_irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
+ geni_m_irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
+
+ geni_write_reg_nolog(geni_s_irq_en, uport->membase,
+ SE_GENI_S_IRQ_EN);
+ geni_write_reg_nolog(geni_m_irq_en, uport->membase,
+ SE_GENI_M_IRQ_EN);
+ } else if (port->xfer_mode == SE_DMA) {
geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE,
&port->rx_dma);
-
- /* Ensure that the above writes go through */
+ }
+ /*
+ * Ensure the writes to the secondary sequencer and interrupt enables
+ * go through.
+ */
mb();
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x, dma_dbg:0x%x\n", __func__,
@@ -1439,68 +1253,61 @@ static void msm_geni_serial_set_manual_flow(bool enable,
static void stop_rx_sequencer(struct uart_port *uport)
{
+ unsigned int geni_s_irq_en;
+ unsigned int geni_m_irq_en;
unsigned int geni_status;
- bool timeout;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+ u32 irq_clear = S_CMD_CANCEL_EN;
+ bool done;
- IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__);
+ if (port->xfer_mode == FIFO_MODE) {
+ geni_s_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_S_IRQ_EN);
+ geni_m_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_M_IRQ_EN);
+ geni_s_irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
+ geni_m_irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+
+ geni_write_reg_nolog(geni_s_irq_en, uport->membase,
+ SE_GENI_S_IRQ_EN);
+ geni_write_reg_nolog(geni_m_irq_en, uport->membase,
+ SE_GENI_M_IRQ_EN);
+ }
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
/* Possible stop rx is called multiple times. */
- if (!(geni_status & S_GENI_CMD_ACTIVE)) {
- IPC_LOG_MSG(port->ipc_log_misc,
- "%s: RX is Inactive, geni_sts: 0x%x\n",
- __func__, geni_status);
+ if (!(geni_status & S_GENI_CMD_ACTIVE))
goto exit_rx_seq;
- }
-
- port->s_cmd_done = false;
- port->s_cmd = true;
- reinit_completion(&port->s_cmd_timeout);
IPC_LOG_MSG(port->ipc_log_misc, "%s: Start 0x%x\n",
__func__, geni_status);
- /*
- * Disabling the interrupts before giving the
- * cancel command as this might be in an atomic context.
- */
- msm_geni_serial_disable_interrupts(uport);
geni_cancel_s_cmd(uport->membase);
-
/*
* Ensure that the cancel goes through before polling for the
* cancel control bit.
*/
mb();
- timeout = geni_wait_for_cmd_done(uport);
- if (timeout) {
- geni_status = geni_read_reg_nolog(uport->membase,
- SE_GENI_STATUS);
- IPC_LOG_MSG(port->ipc_log_misc,
- "%s cancel failed 0x%x\n", __func__, geni_status);
- IPC_LOG_MSG(port->console_log,
- "%s cancel failed 0x%x\n", __func__, geni_status);
- port->s_cmd_done = false;
- reinit_completion(&port->s_cmd_timeout);
- geni_abort_s_cmd(uport->membase);
- /* Ensure this goes through before polling. */
- mb();
+ if (!uart_console(uport))
+ msm_geni_serial_complete_rx_eot(uport);
- timeout = geni_wait_for_cmd_done(uport);
- if (timeout) {
- geni_status = geni_read_reg_nolog(uport->membase,
- SE_GENI_STATUS);
- IPC_LOG_MSG(port->ipc_log_misc,
- "%s abort fail 0x%x\n", __func__, geni_status);
- IPC_LOG_MSG(port->console_log,
- "%s abort fail 0x%x\n", __func__, geni_status);
- }
+ done = msm_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
+ S_GENI_CMD_CANCEL, false);
+ if (done) {
+ geni_write_reg_nolog(irq_clear, uport->membase,
+ SE_GENI_S_IRQ_CLEAR);
+ goto exit_rx_seq;
+ } else {
+ IPC_LOG_MSG(port->ipc_log_misc, "%s Cancel fail 0x%x\n",
+ __func__, geni_status);
}
- /* Enable the interrupts once the cancel operation is done. */
- msm_geni_serial_enable_interrupts(uport);
- port->s_cmd = false;
+ geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
+ if ((geni_status & S_GENI_CMD_ACTIVE)) {
+ IPC_LOG_MSG(port->ipc_log_misc, "%s:Abort Rx, GENI:0x%x\n",
+ __func__, geni_status);
+ msm_geni_serial_abort_rx(uport);
+ }
exit_rx_seq:
if (port->xfer_mode == SE_DMA && port->rx_dma)
msm_geni_serial_rx_fsm_rst(uport);
@@ -1726,6 +1533,8 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
dump_ipc(msm_port->ipc_log_rx, "DMA Rx", (char *)msm_port->rx_buf, 0,
rx_bytes);
exit_handle_dma_rx:
+ geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE,
+ &msm_port->rx_dma);
return ret;
}
@@ -1759,27 +1568,32 @@ 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 irqreturn_t msm_geni_serial_isr(int isr, void *dev)
{
unsigned int m_irq_status;
unsigned int s_irq_status;
unsigned int dma;
unsigned int dma_tx_status;
unsigned int dma_rx_status;
+ struct uart_port *uport = dev;
unsigned int m_irq_en;
unsigned int geni_status;
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
struct tty_port *tport = &uport->state->port;
bool drop_rx = false;
- bool s_cmd_done = false;
- bool m_cmd_done = false;
+ spin_lock(&uport->lock);
if (uart_console(uport) && uport->suspended) {
IPC_LOG_MSG(msm_port->console_log,
"%s. Console in suspend state\n", __func__);
goto exit_geni_serial_isr;
}
-
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
+ goto exit_geni_serial_isr;
+ }
m_irq_status = geni_read_reg_nolog(uport->membase,
SE_GENI_M_IRQ_STATUS);
s_irq_status = geni_read_reg_nolog(uport->membase,
@@ -1787,13 +1601,16 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport)
if (uart_console(uport))
IPC_LOG_MSG(msm_port->console_log,
"%s. sirq 0x%x mirq:0x%x\n", __func__, s_irq_status,
- m_irq_status);
-
- geni_write_reg_nolog(m_irq_status, uport->membase,
- SE_GENI_M_IRQ_CLEAR);
- geni_write_reg_nolog(s_irq_status, uport->membase,
- SE_GENI_S_IRQ_CLEAR);
+ m_irq_status);
m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
+ dma = geni_read_reg_nolog(uport->membase, SE_GENI_DMA_MODE_EN);
+ dma_tx_status = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_STAT);
+ dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT);
+ geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS);
+
+ geni_write_reg_nolog(m_irq_status, uport->membase, SE_GENI_M_IRQ_CLEAR);
+ geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR);
+
if ((m_irq_status & M_ILLEGAL_CMD_EN)) {
WARN_ON(1);
goto exit_geni_serial_isr;
@@ -1807,72 +1624,49 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport)
__func__, s_irq_status, uport->icount.buf_overrun);
}
- dma = geni_read_reg_nolog(uport->membase, SE_GENI_DMA_MODE_EN);
if (!dma) {
- geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS);
-
if ((m_irq_status & m_irq_en) &
(M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
msm_geni_serial_handle_tx(uport,
m_irq_status & M_CMD_DONE_EN,
geni_status & M_GENI_CMD_ACTIVE);
- if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN))
- m_cmd_done = true;
-
- if (s_irq_status & (S_GP_IRQ_0_EN | S_GP_IRQ_1_EN)) {
+ if ((s_irq_status & S_GP_IRQ_0_EN) ||
+ (s_irq_status & S_GP_IRQ_1_EN)) {
if (s_irq_status & S_GP_IRQ_0_EN)
uport->icount.parity++;
IPC_LOG_MSG(msm_port->ipc_log_misc,
"%s.sirq 0x%x parity:%d\n",
__func__, s_irq_status, uport->icount.parity);
drop_rx = true;
- } else if (s_irq_status & (S_GP_IRQ_2_EN | S_GP_IRQ_3_EN)) {
+ } else if ((s_irq_status & S_GP_IRQ_2_EN) ||
+ (s_irq_status & S_GP_IRQ_3_EN)) {
uport->icount.brk++;
IPC_LOG_MSG(msm_port->ipc_log_misc,
"%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))
- s_cmd_done = true;
-
- if (s_irq_status & (S_RX_FIFO_WATERMARK_EN |
- S_RX_FIFO_LAST_EN))
+ if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
+ (s_irq_status & S_RX_FIFO_LAST_EN))
msm_geni_serial_handle_rx(uport, drop_rx);
} else {
- dma_tx_status = geni_read_reg_nolog(uport->membase,
- SE_DMA_TX_IRQ_STAT);
- dma_rx_status = geni_read_reg_nolog(uport->membase,
- SE_DMA_RX_IRQ_STAT);
-
if (dma_tx_status) {
-
geni_write_reg_nolog(dma_tx_status, uport->membase,
- SE_DMA_TX_IRQ_CLR);
-
+ SE_DMA_TX_IRQ_CLR);
if (dma_tx_status & TX_DMA_DONE)
msm_geni_serial_handle_dma_tx(uport);
-
- if (dma_tx_status & (TX_RESET_DONE |
- 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_rx_status) {
geni_write_reg_nolog(dma_rx_status, uport->membase,
- SE_DMA_RX_IRQ_CLR);
-
+ 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);
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++;
@@ -1888,53 +1682,13 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport)
__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);
- }
- }
-
- 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))
- s_cmd_done = true;
-
- if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN))
- s_cmd_done = true;
+ if (dma_rx_status & RX_DMA_DONE)
+ msm_geni_serial_handle_dma_rx(uport, drop_rx);
}
}
exit_geni_serial_isr:
- if (m_cmd_done) {
- msm_port->m_cmd_done = true;
- complete(&msm_port->m_cmd_timeout);
- }
-
- if (s_cmd_done) {
- msm_port->s_cmd_done = true;
- complete(&msm_port->s_cmd_timeout);
- }
-}
-
-static irqreturn_t msm_geni_serial_isr(int isr, void *dev)
-{
- struct uart_port *uport = dev;
- unsigned long flags;
-
- spin_lock_irqsave(&uport->lock, flags);
- msm_geni_serial_handle_isr(uport);
- spin_unlock_irqrestore(&uport->lock, flags);
+ spin_unlock(&uport->lock);
return IRQ_HANDLED;
}
@@ -2026,6 +1780,9 @@ static void msm_geni_serial_shutdown(struct uart_port *uport)
wait_for_transfers_inflight(uport);
}
+ disable_irq(uport->irq);
+ free_irq(uport->irq, uport);
+
if (!uart_console(uport)) {
if (msm_port->ioctl_count) {
int i;
@@ -2101,9 +1858,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_geni_serial_poll_tx_done(uport);
- msm_geni_serial_enable_interrupts(uport);
+ msm_geni_serial_poll_cancel_tx(uport);
se_get_packing_config(8, 1, false, &cfg0, &cfg1);
geni_write_reg_nolog(cfg0, uport->membase,
SE_GENI_TX_PACKING_CFG0);
@@ -2115,7 +1870,6 @@ static int msm_geni_serial_port_setup(struct uart_port *uport)
geni_write_reg_nolog(cfg1, uport->membase,
SE_GENI_RX_PACKING_CFG1);
}
-
ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr);
if (ret) {
dev_err(uport->dev, "%s: Fail\n", __func__);
@@ -2150,6 +1904,8 @@ static int msm_geni_serial_startup(struct uart_port *uport)
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
IPC_LOG_MSG(msm_port->ipc_log_misc, "%s:\n", __func__);
+ scnprintf(msm_port->name, sizeof(msm_port->name), "msm_serial_geni%d",
+ uport->line);
msm_port->startup_in_progress = true;
@@ -2178,6 +1934,13 @@ static int msm_geni_serial_startup(struct uart_port *uport)
* before returning to the framework.
*/
mb();
+ ret = request_irq(uport->irq, msm_geni_serial_isr, IRQF_TRIGGER_HIGH,
+ msm_port->name, uport);
+ if (unlikely(ret)) {
+ dev_err(uport->dev, "%s: Failed to get IRQ ret %d\n",
+ __func__, ret);
+ goto exit_startup;
+ }
if (msm_port->wakeup_irq > 0) {
ret = request_irq(msm_port->wakeup_irq, msm_geni_wakeup_isr,
@@ -2291,6 +2054,7 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
unsigned long ser_clk_cfg = 0;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
unsigned long clk_rate;
+ unsigned long flags;
unsigned long desired_rate;
unsigned int clk_idx;
int uart_sampling;
@@ -2312,9 +2076,16 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
__func__, ret);
return;
}
+ disable_irq(uport->irq);
msm_geni_serial_set_manual_flow(false, port);
}
+ /* Take a spinlock else stop_rx causes a race with an ISR due to Cancel
+ * and FSM_RESET. This also has a potential race with the dma_map/unmap
+ * operations of ISR.
+ */
+ spin_lock_irqsave(&uport->lock, flags);
msm_geni_serial_stop_rx(uport);
+ spin_unlock_irqrestore(&uport->lock, flags);
/* baud rate */
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
port->cur_baud = baud;
@@ -2434,9 +2205,10 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
IPC_LOG_MSG(port->ipc_log_misc, "BitsChar%d stop bit%d\n",
bits_per_char, stop_bit_len);
exit_set_termios:
- if (!uart_console(uport))
+ if (!uart_console(uport)) {
msm_geni_serial_set_manual_flow(true, port);
-
+ enable_irq(uport->irq);
+ }
msm_geni_serial_start_rx(uport);
if (!uart_console(uport))
msm_geni_serial_power_off(uport);
@@ -2504,9 +2276,9 @@ static ssize_t xfer_mode_store(struct device *dev,
return size;
msm_geni_serial_power_on(uport);
+ spin_lock_irqsave(&uport->lock, flags);
msm_geni_serial_stop_tx(uport);
msm_geni_serial_stop_rx(uport);
- spin_lock_irqsave(&uport->lock, flags);
port->xfer_mode = xfer_mode;
geni_se_select_mode(uport->membase, port->xfer_mode);
spin_unlock_irqrestore(&uport->lock, flags);
@@ -2590,45 +2362,6 @@ msm_geni_serial_early_console_write(struct console *con, const char *s,
__msm_geni_serial_console_write(&dev->port, s, n);
}
-static void msm_geni_serial_cancel_rx(struct uart_port *uport)
-{
- int done = 0;
- int i = 0;
- unsigned int irq_status;
- u32 rx_fifo_status;
- u32 rx_fifo_wc;
-
- geni_cancel_s_cmd(uport->membase);
- /* Ensure this goes through before polling. */
- mb();
-
- done = msm_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
- S_CMD_CANCEL_EN, true);
- if (!done) {
- geni_abort_s_cmd(uport->membase);
- /* Ensure this goes through before polling. */
- mb();
- msm_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
- S_CMD_ABORT_EN, false);
- } else if (msm_geni_serial_poll_bit(uport,
- SE_GENI_S_IRQ_STATUS, S_RX_FIFO_LAST_EN, true)) {
- rx_fifo_status = geni_read_reg_nolog(uport->membase,
- SE_GENI_RX_FIFO_STATUS);
- rx_fifo_wc = rx_fifo_status & RX_FIFO_WC_MSK;
- for (i = 0; i < rx_fifo_wc; i++)
- geni_read_reg_nolog(uport->membase,
- SE_GENI_RX_FIFOn);
- }
-
- irq_status = geni_read_reg_nolog(uport->membase,
- SE_GENI_S_IRQ_STATUS);
- geni_write_reg_nolog(irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR);
-
- if (!done)
- geni_write_reg(FORCE_DEFAULT, uport->membase,
- GENI_FORCE_DEFAULT_REG);
-}
-
static int __init
msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
const char *opt)
@@ -2675,7 +2408,6 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
stop_bit = 0;
rx_stale = 0x18;
clk_div = get_clk_div_rate(baud, &clk_rate);
-
if (clk_div <= 0) {
ret = -EINVAL;
goto exit_geni_serial_earlyconsetup;
@@ -2688,17 +2420,10 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
s_clk_cfg |= (clk_div << CLK_DIV_SHFT);
/*
- * Here we need to poll for command done which indicates that
- * the previous tx transfer is done. And if the command done interrupt
- * is not getting set, then we need to cancel the command.
+ * Make an unconditional cancel on the main sequencer to reset
+ * it else we could end up in data loss scenarios.
*/
- msm_geni_serial_poll_tx_done(uport);
-
- /*
- * Here cancel rx is done in polling mode as there is
- * no isr support during early console time.
- */
- msm_geni_serial_cancel_rx(uport);
+ msm_geni_serial_poll_cancel_tx(uport);
/* Only for earlyconsole */
if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING)) {
@@ -2717,14 +2442,8 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
SE_UART_TX_TRANS_CFG);
geni_write_reg_nolog(tx_parity_cfg, uport->membase,
SE_UART_TX_PARITY_CFG);
- geni_write_reg_nolog(rx_trans_cfg, uport->membase,
- SE_UART_RX_TRANS_CFG);
- geni_write_reg_nolog(rx_parity_cfg, uport->membase,
- SE_UART_RX_PARITY_CFG);
geni_write_reg_nolog(bits_per_char, uport->membase,
SE_UART_TX_WORD_LEN);
- geni_write_reg_nolog(bits_per_char, uport->membase,
- SE_UART_RX_WORD_LEN);
geni_write_reg_nolog(stop_bit, uport->membase, SE_UART_TX_STOP_BIT_LEN);
geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_M_CLK_CFG);
geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_S_CLK_CFG);
@@ -2938,8 +2657,6 @@ static int msm_geni_serial_get_ver_info(struct uart_port *uport)
__func__, msm_port->ver_info.hw_major_ver,
msm_port->ver_info.hw_minor_ver,
msm_port->ver_info.hw_step_ver);
-
- msm_geni_serial_enable_interrupts(uport);
exit_ver_info:
if (!msm_port->is_console)
se_geni_clks_off(&msm_port->serial_rsc);
@@ -3140,9 +2857,6 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
dev_port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
uport->fifosize =
((dev_port->tx_fifo_depth * dev_port->tx_fifo_width) >> 3);
- /* Complete signals to handle cancel cmd completion */
- init_completion(&dev_port->m_cmd_timeout);
- init_completion(&dev_port->s_cmd_timeout);
uport->irq = platform_get_irq(pdev, 0);
if (uport->irq < 0) {
@@ -3151,22 +2865,6 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
goto exit_geni_serial_probe;
}
- dev_port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
- "msm_serial_geni%d", uport->line);
- ret = devm_request_irq(uport->dev, uport->irq, msm_geni_serial_isr,
- IRQF_TRIGGER_HIGH, dev_port->name, uport);
- if (ret) {
- dev_err(uport->dev, "%s: Failed to get IRQ ret %d\n",
- __func__, ret);
- goto exit_geni_serial_probe;
- }
- /*
- * Console usecase requires irq to be in enable state to handle RX data.
- * disable irq only for HSUART case from here.
- */
- if (!is_console)
- disable_irq(dev_port->uport.irq);
-
uport->private_data = (void *)drv;
platform_set_drvdata(pdev, dev_port);
if (is_console) {
@@ -3189,12 +2887,6 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "Serial port%d added.FifoSize %d is_console%d\n",
line, uport->fifosize, is_console);
- /*
- * We are using this spinlock before the serial layer initialises it.
- * Hence, we are initializing it.
- */
- spin_lock_init(&uport->lock);
-
device_create_file(uport->dev, &dev_attr_loopback);
device_create_file(uport->dev, &dev_attr_xfer_mode);
device_create_file(uport->dev, &dev_attr_ver_info);
@@ -3239,24 +2931,21 @@ static int msm_geni_serial_runtime_suspend(struct device *dev)
wait_for_transfers_inflight(&port->uport);
/*
+ * Disable Interrupt
* Manual RFR On.
* Stop Rx.
- * Disable Interrupt
* Resources off
*/
+ disable_irq(port->uport.irq);
stop_rx_sequencer(&port->uport);
geni_status = geni_read_reg_nolog(port->uport.membase, SE_GENI_STATUS);
-
if ((geni_status & M_GENI_CMD_ACTIVE))
stop_tx_sequencer(&port->uport);
-
- disable_irq(port->uport.irq);
ret = se_geni_resources_off(&port->serial_rsc);
if (ret) {
dev_err(dev, "%s: Error ret %d\n", __func__, ret);
goto exit_runtime_suspend;
}
-
if (port->wakeup_irq > 0) {
port->edge_count = 0;
enable_irq(port->wakeup_irq);
@@ -3296,9 +2985,12 @@ static int msm_geni_serial_runtime_resume(struct device *dev)
start_rx_sequencer(&port->uport);
/* Ensure that the Rx is running before enabling interrupts */
mb();
- /* Enable interrupt */
- enable_irq(port->uport.irq);
-
+ /*
+ * Do not enable irq before interrupt registration which happens
+ * at port open time.
+ */
+ if (pm_runtime_enabled(dev) && port->xfer_mode != INVALID)
+ enable_irq(port->uport.irq);
IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
exit_runtime_resume:
return ret;
@@ -3343,6 +3035,7 @@ static int msm_geni_serial_sys_resume_noirq(struct device *dev)
console_suspend_enabled && uport->suspended) {
uart_resume_port((struct uart_driver *)uport->private_data,
uport);
+ disable_irq(uport->irq);
}
return 0;
}
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index 3e2888af87c3..1fd68e38cf2f 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -330,7 +330,6 @@ struct se_geni_rsc {
#define TX_EOT (BIT(1))
#define TX_SBE (BIT(2))
#define TX_RESET_DONE (BIT(3))
-#define TX_GENI_CANCEL_IRQ (BIT(14))
/* SE_DMA_RX_IRQ_STAT Register fields */
#define RX_DMA_DONE (BIT(0))
@@ -339,15 +338,9 @@ struct se_geni_rsc {
#define RX_RESET_DONE (BIT(3))
#define RX_FLUSH_DONE (BIT(4))
#define RX_GENI_GP_IRQ (GENMASK(10, 5))
-#define RX_GENI_CANCEL_IRQ (BIT(14))
+#define RX_GENI_CANCEL_IRQ (BIT(11))
#define RX_GENI_GP_IRQ_EXT (GENMASK(13, 12))
-/* DMA DEBUG Register fields */
-#define DMA_TX_ACTIVE (BIT(0))
-#define DMA_RX_ACTIVE (BIT(1))
-#define DMA_TX_STATE (GENMASK(7, 4))
-#define DMA_RX_STATE (GENMASK(11, 8))
-
#define DEFAULT_BUS_WIDTH (4)
#define DEFAULT_SE_CLK (19200000)