mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 08:02:27 +02:00
TTY/Serial fixes for 6.10-final
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.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-----BEGIN PGP SIGNATURE-----
iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZpEGgA8cZ3JlZ0Brcm9h
aC5jb20ACgkQMUfUDdst+yn/gQCgu2z2ZX6CieclImaog1PxSH5/cuwAn3QILaoo
CvVx+1vTMQZQqJbaJ7i1
=ZU5W
-----END PGP SIGNATURE-----
Merge tag 'tty-6.10-final' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
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
This commit is contained in:
commit
1cb67bcc21
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,7 +2005,10 @@ 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) {
|
||||
imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -688,12 +688,13 @@ static int ma35d1serial_probe(struct platform_device *pdev)
|
|||
struct uart_ma35d1_port *up;
|
||||
int ret = 0;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
|
||||
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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user