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

Commit 967b6fb1 authored by Karthikeyan Ramasubramanian's avatar Karthikeyan Ramasubramanian
Browse files

tty: serial: msm_geni_serial: Update framework fifo after draining



Currently the tail pointer in the UART framework's circular buffer gets
updated everytime data is transmitted. This enables the framework to
constantly fill the circular buffer if large amount of data needs to be
transmitted. This leads to starvation when there is continuous transmission
at a lesser baud rate.

Update the framework's tail pointer when the entire circular buffer is
drained. This will provide a soft flow control and avoid any starvation.

Change-Id: Icc1fd7071e94917d35bb0edd30e35b14030a648c
Signed-off-by: default avatarKarthikeyan Ramasubramanian <kramasub@codeaurora.org>
parent 54d765eb
Loading
Loading
Loading
Loading
+14 −24
Original line number Diff line number Diff line
@@ -127,7 +127,6 @@
} while (0)

#define DMA_RX_BUF_SIZE		(2048)
#define CONSOLE_YIELD_LEN	(8 * 1024)
struct msm_geni_serial_port {
	struct uart_port uport;
	char name[20];
@@ -163,7 +162,6 @@ struct msm_geni_serial_port {
	unsigned int cur_baud;
	int ioctl_count;
	int edge_count;
	unsigned int tx_yield_count;
	bool manual_flow;
};

@@ -1196,20 +1194,13 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport)
	unsigned int fifo_width_bytes =
		(uart_console(uport) ? 1 : (msm_port->tx_fifo_width >> 3));
	unsigned int geni_m_irq_en;
	int temp_tail = 0;

	xmit->tail = (xmit->tail + msm_port->xmit_size) & (UART_XMIT_SIZE - 1);
	msm_port->xmit_size = 0;
	if (uart_console(uport) &&
	    (uport->icount.tx - msm_port->tx_yield_count) > CONSOLE_YIELD_LEN) {
		msm_port->tx_yield_count = uport->icount.tx;
		msm_geni_serial_stop_tx(uport);
		uart_write_wakeup(uport);
		goto exit_handle_tx;
	}

	xmit_size = uart_circ_chars_pending(xmit);
	tx_fifo_status = geni_read_reg_nolog(uport->membase,
					SE_GENI_TX_FIFO_STATUS);
	if (uart_circ_empty(xmit) && !tx_fifo_status) {
	/* Both FIFO and framework buffer are drained */
	if ((xmit_size == msm_port->xmit_size) && !tx_fifo_status) {
		/*
		 * This will balance out the power vote put in during start_tx
		 * allowing the device to suspend.
@@ -1219,9 +1210,12 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport)
				"%s.Power Off.\n", __func__);
			msm_geni_serial_power_off(uport);
		}
		msm_port->xmit_size = 0;
		uart_circ_clear(xmit);
		msm_geni_serial_stop_tx(uport);
		goto exit_handle_tx;
	}
	xmit_size -= msm_port->xmit_size;

	if (!uart_console(uport)) {
		geni_m_irq_en = geni_read_reg_nolog(uport->membase,
@@ -1235,9 +1229,9 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport)

	avail_fifo_bytes = (msm_port->tx_fifo_depth - msm_port->tx_wm) *
							fifo_width_bytes;
	xmit_size = uart_circ_chars_pending(xmit);
	if (xmit_size > (UART_XMIT_SIZE - xmit->tail))
		xmit_size = UART_XMIT_SIZE - xmit->tail;
	temp_tail = (xmit->tail + msm_port->xmit_size) & (UART_XMIT_SIZE - 1);
	if (xmit_size > (UART_XMIT_SIZE - temp_tail))
		xmit_size = (UART_XMIT_SIZE - temp_tail);
	if (xmit_size > avail_fifo_bytes)
		xmit_size = avail_fifo_bytes;

@@ -1247,33 +1241,29 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport)
	msm_geni_serial_setup_tx(uport, xmit_size);

	bytes_remaining = xmit_size;
	dump_ipc(msm_port->ipc_log_tx, "Tx", (char *)&xmit->buf[xmit->tail], 0,
	dump_ipc(msm_port->ipc_log_tx, "Tx", (char *)&xmit->buf[temp_tail], 0,
								xmit_size);
	while (i < xmit_size) {
		unsigned int tx_bytes;
		unsigned int buf = 0;
		int temp_tail;
		int c;

		tx_bytes = ((bytes_remaining < fifo_width_bytes) ?
					bytes_remaining : fifo_width_bytes);

		temp_tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1);
		for (c = 0; c < tx_bytes ; c++)
			buf |= (xmit->buf[temp_tail + c] << (c * 8));
		geni_write_reg_nolog(buf, uport->membase, SE_GENI_TX_FIFOn);
		i += tx_bytes;
		temp_tail = (temp_tail + tx_bytes) & (UART_XMIT_SIZE - 1);
		uport->icount.tx += tx_bytes;
		bytes_remaining -= tx_bytes;
		/* Ensure FIFO write goes through */
		wmb();
	}
	if (uart_console(uport)) {
	if (uart_console(uport))
		msm_geni_serial_poll_cancel_tx(uport);
		xmit->tail = (xmit->tail + xmit_size) & (UART_XMIT_SIZE - 1);
	} else {
		msm_port->xmit_size = xmit_size;
	}
	msm_port->xmit_size += xmit_size;
exit_handle_tx:
	uart_write_wakeup(uport);
	return ret;