Commit 1cb67bcc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull tty / serial fixes from Greg KH:
 "Here are some small serial driver fixes for 6.10-final. Included in
  here are:

   - qcom-geni fixes for a much much much discussed issue and everyone
     now seems to be agreed that this is the proper way forward to
     resolve the reported lockups

   - imx serial driver bugfixes

   - 8250_omap errata fix

   - ma35d1 serial driver bugfix

  All of these have been in linux-next for over a week with no reported
  issues"

* tag 'tty-6.10-final' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: qcom-geni: do not kill the machine on fifo underrun
  serial: qcom-geni: fix hard lockup on buffer flush
  serial: qcom-geni: fix soft lockup on sw flow control and suspend
  serial: imx: ensure RTS signal is not left active after shutdown
  tty: serial: ma35d1: Add a NULL check for of_node
  serial: 8250_omap: Fix Errata i2310 with RX FIFO level check
  serial: imx: only set receiver level if it is zero
parents 1293147a 2ac33975
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -672,7 +672,8 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
	 * https://www.ti.com/lit/pdf/sprz536
	 */
	if (priv->habit & UART_RX_TIMEOUT_QUIRK &&
		(iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT) {
	    (iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT &&
	    serial_port_in(port, UART_OMAP_RX_LVL) == 0) {
		unsigned char efr2, timeout_h, timeout_l;

		efr2 = serial_in(up, UART_OMAP_EFR2);
+57 −2
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@
#define UCR4_OREN	(1<<1)	/* Receiver overrun interrupt enable */
#define UCR4_DREN	(1<<0)	/* Recv data ready interrupt enable */
#define UFCR_RXTL_SHF	0	/* Receiver trigger level shift */
#define UFCR_RXTL_MASK	0x3F	/* Receiver trigger 6 bits wide */
#define UFCR_DCEDTE	(1<<6)	/* DCE/DTE mode select */
#define UFCR_RFDIV	(7<<7)	/* Reference freq divider mask */
#define UFCR_RFDIV_REG(x)	(((x) < 7 ? 6 - (x) : 6) << 7)
@@ -1551,6 +1552,7 @@ static void imx_uart_shutdown(struct uart_port *port)
	struct imx_port *sport = (struct imx_port *)port;
	unsigned long flags;
	u32 ucr1, ucr2, ucr4, uts;
	int loops;

	if (sport->dma_is_enabled) {
		dmaengine_terminate_sync(sport->dma_chan_tx);
@@ -1613,6 +1615,56 @@ static void imx_uart_shutdown(struct uart_port *port)
	ucr4 &= ~UCR4_TCEN;
	imx_uart_writel(sport, ucr4, UCR4);

	/*
	 * We have to ensure the tx state machine ends up in OFF. This
	 * is especially important for rs485 where we must not leave
	 * the RTS signal high, blocking the bus indefinitely.
	 *
	 * All interrupts are now disabled, so imx_uart_stop_tx() will
	 * no longer be called from imx_uart_transmit_buffer(). It may
	 * still be called via the hrtimers, and if those are in play,
	 * we have to honour the delays.
	 */
	if (sport->tx_state == WAIT_AFTER_RTS || sport->tx_state == SEND)
		imx_uart_stop_tx(port);

	/*
	 * In many cases (rs232 mode, or if tx_state was
	 * WAIT_AFTER_RTS, or if tx_state was SEND and there is no
	 * delay_rts_after_send), this will have moved directly to
	 * OFF. In rs485 mode, tx_state might already have been
	 * WAIT_AFTER_SEND and the hrtimer thus already started, or
	 * the above imx_uart_stop_tx() call could have started it. In
	 * those cases, we have to wait for the hrtimer to fire and
	 * complete the transition to OFF.
	 */
	loops = port->rs485.flags & SER_RS485_ENABLED ?
		port->rs485.delay_rts_after_send : 0;
	while (sport->tx_state != OFF && loops--) {
		uart_port_unlock_irqrestore(&sport->port, flags);
		msleep(1);
		uart_port_lock_irqsave(&sport->port, &flags);
	}

	if (sport->tx_state != OFF) {
		dev_warn(sport->port.dev, "unexpected tx_state %d\n",
			 sport->tx_state);
		/*
		 * This machine may be busted, but ensure the RTS
		 * signal is inactive in order not to block other
		 * devices.
		 */
		if (port->rs485.flags & SER_RS485_ENABLED) {
			ucr2 = imx_uart_readl(sport, UCR2);
			if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
				imx_uart_rts_active(sport, &ucr2);
			else
				imx_uart_rts_inactive(sport, &ucr2);
			imx_uart_writel(sport, ucr2, UCR2);
		}
		sport->tx_state = OFF;
	}

	uart_port_unlock_irqrestore(&sport->port, flags);

	clk_disable_unprepare(sport->clk_per);
@@ -1933,7 +1985,7 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
				 struct serial_rs485 *rs485conf)
{
	struct imx_port *sport = (struct imx_port *)port;
	u32 ucr2;
	u32 ucr2, ufcr;

	if (rs485conf->flags & SER_RS485_ENABLED) {
		/* Enable receiver if low-active RTS signal is requested */
@@ -1953,6 +2005,9 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
	/* Make sure Rx is enabled in case Tx is active with Rx disabled */
	if (!(rs485conf->flags & SER_RS485_ENABLED) ||
	    rs485conf->flags & SER_RS485_RX_DURING_TX) {
		/* If the receiver trigger is 0, set it to a default value */
		ufcr = imx_uart_readl(sport, UFCR);
		if ((ufcr & UFCR_RXTL_MASK) == 0)
			imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
		imx_uart_start_rx(port);
	}
+7 −6
Original line number Diff line number Diff line
@@ -688,13 +688,14 @@ static int ma35d1serial_probe(struct platform_device *pdev)
	struct uart_ma35d1_port *up;
	int ret = 0;

	if (pdev->dev.of_node) {
	if (!pdev->dev.of_node)
		return -ENODEV;

	ret = of_alias_get_id(pdev->dev.of_node, "serial");
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", ret);
		return ret;
	}
	}
	up = &ma35d1serial_ports[ret];
	up->port.line = ret;
	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+38 −13
Original line number Diff line number Diff line
@@ -649,15 +649,25 @@ static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)

static void qcom_geni_serial_start_tx_fifo(struct uart_port *uport)
{
	unsigned char c;
	u32 irq_en;

	if (qcom_geni_serial_main_active(uport) ||
	    !qcom_geni_serial_tx_empty(uport))
		return;
	/*
	 * Start a new transfer in case the previous command was cancelled and
	 * left data in the FIFO which may prevent the watermark interrupt
	 * from triggering. Note that the stale data is discarded.
	 */
	if (!qcom_geni_serial_main_active(uport) &&
	    !qcom_geni_serial_tx_empty(uport)) {
		if (uart_fifo_out(uport, &c, 1) == 1) {
			writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
			qcom_geni_serial_setup_tx(uport, 1);
			writel(c, uport->membase + SE_GENI_TX_FIFOn);
		}
	}

	irq_en = readl(uport->membase +	SE_GENI_M_IRQ_EN);
	irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN;

	writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
	writel(irq_en, uport->membase +	SE_GENI_M_IRQ_EN);
}
@@ -665,13 +675,17 @@ static void qcom_geni_serial_start_tx_fifo(struct uart_port *uport)
static void qcom_geni_serial_stop_tx_fifo(struct uart_port *uport)
{
	u32 irq_en;
	struct qcom_geni_serial_port *port = to_dev_port(uport);

	irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
	irq_en &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
	writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG);
	writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
	/* Possible stop tx is called multiple times. */
}

static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport)
{
	struct qcom_geni_serial_port *port = to_dev_port(uport);

	if (!qcom_geni_serial_main_active(uport))
		return;

@@ -684,6 +698,8 @@ static void qcom_geni_serial_stop_tx_fifo(struct uart_port *uport)
		writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
	}
	writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);

	port->tx_remaining = 0;
}

static void qcom_geni_serial_handle_rx_fifo(struct uart_port *uport, bool drop)
@@ -862,7 +878,7 @@ static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport,
		memset(buf, 0, sizeof(buf));
		tx_bytes = min(remaining, BYTES_PER_FIFO_WORD);

		tx_bytes = uart_fifo_out(uport, buf, tx_bytes);
		uart_fifo_out(uport, buf, tx_bytes);

		iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);

@@ -890,13 +906,17 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
	else
		pending = kfifo_len(&tport->xmit_fifo);

	/* All data has been transmitted and acknowledged as received */
	if (!pending && !status && done) {
	/* All data has been transmitted or command has been cancelled */
	if (!pending && done) {
		qcom_geni_serial_stop_tx_fifo(uport);
		goto out_write_wakeup;
	}

	if (active)
		avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
	else
		avail = port->tx_fifo_depth;

	avail *= BYTES_PER_FIFO_WORD;

	chunk = min(avail, pending);
@@ -1069,11 +1089,15 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
{
	disable_irq(uport->irq);

	if (uart_console(uport))
		return;

	qcom_geni_serial_stop_tx(uport);
	qcom_geni_serial_stop_rx(uport);

	qcom_geni_serial_cancel_tx_cmd(uport);
}

static void qcom_geni_serial_flush_buffer(struct uart_port *uport)
{
	qcom_geni_serial_cancel_tx_cmd(uport);
}

static int qcom_geni_serial_port_setup(struct uart_port *uport)
@@ -1532,6 +1556,7 @@ static const struct uart_ops qcom_geni_console_pops = {
	.request_port = qcom_geni_serial_request_port,
	.config_port = qcom_geni_serial_config_port,
	.shutdown = qcom_geni_serial_shutdown,
	.flush_buffer = qcom_geni_serial_flush_buffer,
	.type = qcom_geni_serial_get_type,
	.set_mctrl = qcom_geni_serial_set_mctrl,
	.get_mctrl = qcom_geni_serial_get_mctrl,