Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8145a2fc authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "tty: serial: qcom_geni_serial: Fix UART hang"

parents 0ec08e07 5f9a8203
Loading
Loading
Loading
Loading
+36 −1
Original line number Diff line number Diff line
@@ -777,6 +777,7 @@ static void msm_geni_serial_console_write(struct console *co, const char *s,
	bool locked = true;
	unsigned long flags;
	unsigned int geni_status;
	int irq_en;

	/* Max 1 port supported as of now */
	WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
@@ -806,12 +807,22 @@ static void msm_geni_serial_console_write(struct console *co, const char *s,
		}
		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)
	} 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_poll_cancel_tx(uport);

		/* Enable WM interrupt for every new console write op */
		if (uart_circ_chars_pending(&uport->state->xmit)) {
			irq_en = geni_read_reg_nolog(uport->membase,
						SE_GENI_M_IRQ_EN);
			geni_write_reg_nolog(irq_en | M_TX_FIFO_WATERMARK_EN,
					uport->membase, SE_GENI_M_IRQ_EN);
		}
	}

	__msm_geni_serial_console_write(uport, s, count);

	if (port->cur_tx_remaining)
@@ -1310,6 +1321,7 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport, bool done,
	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);
@@ -1340,6 +1352,12 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport, bool done,
	if (!msm_port->cur_tx_remaining) {
		msm_geni_serial_setup_tx(uport, pending);
		msm_port->cur_tx_remaining = pending;

		/* Re-enable WM interrupt when 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;
@@ -1367,7 +1385,24 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport, bool done,
		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) {
		irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
		/* Clear WM interrupt post each transfer completion */
		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 0;