Merge "serial: msm_geni_serial: Remove interrupt storm"
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 02dd8e4..c9df7a6 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -1302,6 +1302,7 @@
unsigned int fifo_width_bytes =
(uart_console(uport) ? 1 : (msm_port->tx_fifo_width >> 3));
int temp_tail = 0;
+ int irq_en;
tx_fifo_status = geni_read_reg_nolog(uport->membase,
SE_GENI_TX_FIFO_STATUS);
@@ -1332,6 +1333,12 @@
if (!msm_port->cur_tx_remaining) {
msm_geni_serial_setup_tx(uport, pending);
msm_port->cur_tx_remaining = pending;
+
+ /* Re-Enable WATERMARK interrupt while starting new transfer */
+ irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
+ if (!(irq_en & M_TX_FIFO_WATERMARK_EN))
+ geni_write_reg_nolog(irq_en | M_TX_FIFO_WATERMARK_EN,
+ uport->membase, SE_GENI_M_IRQ_EN);
}
bytes_remaining = xmit_size;
@@ -1359,7 +1366,24 @@
wmb();
}
xmit->tail = temp_tail;
+
+ /*
+ * The tx fifo watermark is level triggered and latched. Though we had
+ * cleared it in qcom_geni_serial_isr it will have already reasserted
+ * so we must clear it again here after our writes.
+ */
+ geni_write_reg_nolog(M_TX_FIFO_WATERMARK_EN, uport->membase,
+ SE_GENI_M_IRQ_CLEAR);
+
exit_handle_tx:
+ if (!msm_port->cur_tx_remaining) {
+ /* Clear WATERMARK interrupt for each transfer completion */
+ irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
+ if (irq_en & M_TX_FIFO_WATERMARK_EN)
+ geni_write_reg_nolog(irq_en & ~M_TX_FIFO_WATERMARK_EN,
+ uport->membase, SE_GENI_M_IRQ_EN);
+ }
+
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(uport);
return ret;
@@ -1497,7 +1521,7 @@
if (!dma) {
if ((m_irq_status & m_irq_en) &
- (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_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);