mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
TTY / Serial / VT driver fixes for 7.2-rc7
Here are some small serial and vt tty driver fixes for 7.2-rc7 that resolve some reported problems. Included in here are: - 2 vt core fixes - amba-pl011 serial driver fixes - 8250_of and 8250_dma driver fixes - qcom-geni serial driver fix - sc16is7xx serial driver fix All of these have been in linux-next this week with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCandKkg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylnjQCeND+mnhXzo7wmT4E2vHER2FG8UEEAmwXRTNe6 QzKAPXT2BgHPFW7Gy8dk =UY5p -----END PGP SIGNATURE----- Merge tag 'tty-7.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty / serial / vt driver fixes from Greg KH: "Here are some small serial and vt tty driver fixes for 7.2-rc7 that resolve some reported problems. Included in here are: - two vt core fixes - amba-pl011 serial driver fixes - 8250_of and 8250_dma driver fixes - qcom-geni serial driver fix - sc16is7xx serial driver fix All of these have been in linux-next this week with no reported issues" * tag 'tty-7.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: serial: amba-pl011: synchronize DMA teardown serial: amba-pl011: cancel RS485 hrtimers after freeing IRQ serial: amba-pl011: fix indefinite RS485 post-send delay vt: add permission check for KDSKBMETA ioctl vt: stabilize tty reference in kbd_keycode with tty_port_tty_get serial: 8250_of: clear stuck empty-FIFO RX-timeout on LPC32xx serial: qcom-geni: fix TX DMA buffer flush serial: 8250_dma: Clear stale RX state on shutdown serial: sc16is7xx: enable THRI before filling TX FIFO
This commit is contained in:
commit
e4836b67ba
|
|
@ -211,11 +211,12 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p)
|
|||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
|
||||
if (dma->rx_running) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_complete(p);
|
||||
dmaengine_terminate_async(dma->rxchan);
|
||||
}
|
||||
if (!dma || !dma->rxchan || !dma->rx_running)
|
||||
return;
|
||||
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_complete(p);
|
||||
dmaengine_terminate_async(dma->rxchan);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
|
||||
|
||||
|
|
@ -324,6 +325,7 @@ void serial8250_release_dma(struct uart_8250_port *p)
|
|||
|
||||
/* Release RX resources */
|
||||
dmaengine_terminate_sync(dma->rxchan);
|
||||
dma->rx_running = 0;
|
||||
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
|
||||
dma->rx_addr);
|
||||
dma_release_channel(dma->rxchan);
|
||||
|
|
|
|||
|
|
@ -81,6 +81,40 @@ static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigne
|
|||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int lpc32xx_handle_irq(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned int iir;
|
||||
u16 status;
|
||||
|
||||
guard(serial8250_rpm)(up);
|
||||
|
||||
iir = serial_port_in(port, UART_IIR);
|
||||
if (iir & UART_IIR_NO_INT)
|
||||
return 0;
|
||||
|
||||
guard(uart_port_lock_check_sysrq_irqsave)(port);
|
||||
|
||||
/*
|
||||
* The LPC32xx UART can assert an RX character-timeout interrupt while
|
||||
* the RX FIFO is empty: IIR reports UART_IIR_RX_TIMEOUT but LSR.DR is
|
||||
* clear. The timeout is only cleared by reading RHR, but the core RX
|
||||
* path skips that read when the FIFO is empty, so the level-triggered
|
||||
* IRQ re-fires forever and livelocks this single-core SoC. Do one
|
||||
* throwaway RHR read to clear it; a healthy UART never reports a
|
||||
* timeout with DR/BI clear, so no received data is ever discarded.
|
||||
*/
|
||||
if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
|
||||
status = serial_lsr_in(up);
|
||||
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
|
||||
serial_port_in(port, UART_RX);
|
||||
}
|
||||
|
||||
serial8250_handle_irq_locked(port, iir);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a struct uart_port for a given device node
|
||||
*/
|
||||
|
|
@ -173,6 +207,9 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
|||
case PORT_NPCM:
|
||||
ret = npcm_setup(port);
|
||||
break;
|
||||
case PORT_LPC3220:
|
||||
port->handle_irq = lpc32xx_handle_irq;
|
||||
break;
|
||||
default:
|
||||
/* Nothing to do */
|
||||
ret = 0;
|
||||
|
|
@ -369,6 +406,7 @@ static struct platform_driver of_platform_serial_driver = {
|
|||
|
||||
module_platform_driver(of_platform_serial_driver);
|
||||
|
||||
MODULE_IMPORT_NS("SERIAL_8250");
|
||||
MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ enum pl011_rs485_tx_state {
|
|||
WAIT_AFTER_RTS,
|
||||
SEND,
|
||||
WAIT_AFTER_SEND,
|
||||
WAIT_AFTER_SEND_DELAY,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1246,7 +1247,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
|
|||
|
||||
if (uap->using_tx_dma) {
|
||||
/* In theory, this should already be done by pl011_dma_flush_buffer */
|
||||
dmaengine_terminate_all(uap->dmatx.chan);
|
||||
dmaengine_terminate_sync(uap->dmatx.chan);
|
||||
if (uap->dmatx.queued) {
|
||||
dma_unmap_single(uap->dmatx.chan->device->dev,
|
||||
uap->dmatx.dma, uap->dmatx.len,
|
||||
|
|
@ -1259,12 +1260,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
|
|||
}
|
||||
|
||||
if (uap->using_rx_dma) {
|
||||
dmaengine_terminate_all(uap->dmarx.chan);
|
||||
if (uap->dmarx.poll_rate)
|
||||
timer_delete_sync(&uap->dmarx.timer);
|
||||
dmaengine_terminate_sync(uap->dmarx.chan);
|
||||
/* Clean up the RX DMA */
|
||||
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
|
||||
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
|
||||
if (uap->dmarx.poll_rate)
|
||||
timer_delete_sync(&uap->dmarx.timer);
|
||||
uap->using_rx_dma = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1333,33 +1334,11 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
|
|||
#define pl011_dma_flush_buffer NULL
|
||||
#endif
|
||||
|
||||
static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
|
||||
static void pl011_rs485_tx_stop_now(struct uart_amba_port *uap)
|
||||
{
|
||||
struct uart_port *port = &uap->port;
|
||||
u32 cr;
|
||||
|
||||
if (uap->rs485_tx_state == SEND)
|
||||
uap->rs485_tx_state = WAIT_AFTER_SEND;
|
||||
|
||||
if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
|
||||
/* Schedule hrtimer if tx queue not empty */
|
||||
if (!pl011_tx_empty(port)) {
|
||||
hrtimer_start(&uap->trigger_stop_tx,
|
||||
uap->rs485_tx_drain_interval,
|
||||
HRTIMER_MODE_REL);
|
||||
return;
|
||||
}
|
||||
if (port->rs485.delay_rts_after_send > 0) {
|
||||
hrtimer_start(&uap->trigger_stop_tx,
|
||||
ms_to_ktime(port->rs485.delay_rts_after_send),
|
||||
HRTIMER_MODE_REL);
|
||||
return;
|
||||
}
|
||||
/* Continue without any delay */
|
||||
} else if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
|
||||
hrtimer_try_to_cancel(&uap->trigger_start_tx);
|
||||
}
|
||||
|
||||
cr = pl011_read(uap, REG_CR);
|
||||
|
||||
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
|
|
@ -1375,6 +1354,36 @@ static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
|
|||
uap->rs485_tx_state = OFF;
|
||||
}
|
||||
|
||||
static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
|
||||
{
|
||||
struct uart_port *port = &uap->port;
|
||||
|
||||
if (uap->rs485_tx_state == SEND)
|
||||
uap->rs485_tx_state = WAIT_AFTER_SEND;
|
||||
|
||||
if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
|
||||
/* Schedule hrtimer if tx queue not empty */
|
||||
if (!pl011_tx_empty(port)) {
|
||||
hrtimer_start(&uap->trigger_stop_tx,
|
||||
uap->rs485_tx_drain_interval,
|
||||
HRTIMER_MODE_REL);
|
||||
return;
|
||||
}
|
||||
if (port->rs485.delay_rts_after_send > 0) {
|
||||
uap->rs485_tx_state = WAIT_AFTER_SEND_DELAY;
|
||||
hrtimer_start(&uap->trigger_stop_tx,
|
||||
ms_to_ktime(port->rs485.delay_rts_after_send),
|
||||
HRTIMER_MODE_REL);
|
||||
return;
|
||||
}
|
||||
/* Continue without any delay */
|
||||
} else if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
|
||||
hrtimer_try_to_cancel(&uap->trigger_start_tx);
|
||||
}
|
||||
|
||||
pl011_rs485_tx_stop_now(uap);
|
||||
}
|
||||
|
||||
static void pl011_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
|
|
@ -1415,7 +1424,8 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
|
|||
uap->rs485_tx_state = SEND;
|
||||
return;
|
||||
}
|
||||
if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
|
||||
if (uap->rs485_tx_state == WAIT_AFTER_SEND ||
|
||||
uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY) {
|
||||
hrtimer_try_to_cancel(&uap->trigger_stop_tx);
|
||||
uap->rs485_tx_state = SEND;
|
||||
return;
|
||||
|
|
@ -1482,7 +1492,8 @@ static enum hrtimer_restart pl011_trigger_stop_tx(struct hrtimer *t)
|
|||
unsigned long flags;
|
||||
|
||||
uart_port_lock_irqsave(&uap->port, &flags);
|
||||
if (uap->rs485_tx_state == WAIT_AFTER_SEND)
|
||||
if (uap->rs485_tx_state == WAIT_AFTER_SEND ||
|
||||
uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY)
|
||||
pl011_rs485_tx_stop(uap);
|
||||
uart_port_unlock_irqrestore(&uap->port, flags);
|
||||
|
||||
|
|
@ -2080,11 +2091,20 @@ static void pl011_shutdown(struct uart_port *port)
|
|||
|
||||
pl011_dma_shutdown(uap);
|
||||
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED && uap->rs485_tx_state != OFF))
|
||||
pl011_rs485_tx_stop(uap);
|
||||
|
||||
free_irq(uap->port.irq, uap);
|
||||
|
||||
/*
|
||||
* free_irq() drains the UART interrupt handler, which can arm either
|
||||
* timer. Cancel the timers afterwards to drain their callbacks too.
|
||||
*/
|
||||
hrtimer_cancel(&uap->trigger_start_tx);
|
||||
hrtimer_cancel(&uap->trigger_stop_tx);
|
||||
|
||||
uart_port_lock_irq(port);
|
||||
if (uap->rs485_tx_state != OFF)
|
||||
pl011_rs485_tx_stop_now(uap);
|
||||
uart_port_unlock_irq(port);
|
||||
|
||||
pl011_disable_uart(uap);
|
||||
|
||||
/*
|
||||
|
|
@ -3063,6 +3083,8 @@ static void pl011_remove(struct amba_device *dev)
|
|||
struct uart_amba_port *uap = amba_get_drvdata(dev);
|
||||
|
||||
uart_remove_one_port(&amba_reg, &uap->port);
|
||||
hrtimer_cancel(&uap->trigger_start_tx);
|
||||
hrtimer_cancel(&uap->trigger_stop_tx);
|
||||
pl011_unregister_port(uap);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ static const struct uart_ops qcom_geni_uart_pops;
|
|||
static struct uart_driver qcom_geni_console_driver;
|
||||
static struct uart_driver qcom_geni_uart_driver;
|
||||
|
||||
static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport);
|
||||
static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
|
||||
static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
|
||||
static int qcom_geni_serial_port_setup(struct uart_port *uport);
|
||||
|
|
@ -636,35 +637,34 @@ static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
|
|||
return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_flush_buffer_dma(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
|
||||
qcom_geni_serial_stop_tx_dma(uport);
|
||||
port->tx_remaining = 0;
|
||||
port->tx_queued = 0;
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
bool done;
|
||||
|
||||
if (!qcom_geni_serial_main_active(uport))
|
||||
return;
|
||||
if (qcom_geni_serial_main_active(uport))
|
||||
__qcom_geni_serial_cancel_tx_cmd(uport);
|
||||
|
||||
if (port->tx_dma_addr) {
|
||||
writel(1, uport->membase + SE_DMA_TX_FSM_RST);
|
||||
if (!qcom_geni_serial_poll_bit(uport, SE_DMA_TX_IRQ_STAT,
|
||||
TX_RESET_DONE, true))
|
||||
dev_err_ratelimited(uport->dev, "TX DMA reset failed");
|
||||
writel(TX_RESET_DONE | TX_DMA_DONE,
|
||||
uport->membase + SE_DMA_TX_IRQ_CLR);
|
||||
|
||||
geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr,
|
||||
port->tx_remaining);
|
||||
port->tx_dma_addr = 0;
|
||||
port->tx_remaining = 0;
|
||||
}
|
||||
|
||||
geni_se_cancel_m_cmd(&port->se);
|
||||
|
||||
done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
|
||||
M_CMD_CANCEL_EN, true);
|
||||
if (!done) {
|
||||
geni_se_abort_m_cmd(&port->se);
|
||||
done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
|
||||
M_CMD_ABORT_EN, true);
|
||||
if (!done)
|
||||
dev_err_ratelimited(uport->dev, "M_CMD_ABORT_EN not set");
|
||||
writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
}
|
||||
|
||||
writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
|
||||
|
|
@ -1180,7 +1180,7 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
|
|||
uart_port_unlock_irq(uport);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_flush_buffer(struct uart_port *uport)
|
||||
static void qcom_geni_serial_flush_buffer_fifo(struct uart_port *uport)
|
||||
{
|
||||
qcom_geni_serial_cancel_tx_cmd(uport);
|
||||
}
|
||||
|
|
@ -1769,7 +1769,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,
|
||||
.flush_buffer = qcom_geni_serial_flush_buffer_fifo,
|
||||
.type = qcom_geni_serial_get_type,
|
||||
.set_mctrl = qcom_geni_serial_set_mctrl,
|
||||
.get_mctrl = qcom_geni_serial_get_mctrl,
|
||||
|
|
@ -1792,6 +1792,7 @@ static const struct uart_ops qcom_geni_uart_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_dma,
|
||||
.type = qcom_geni_serial_get_type,
|
||||
.set_mctrl = qcom_geni_serial_set_mctrl,
|
||||
.get_mctrl = qcom_geni_serial_get_mctrl,
|
||||
|
|
|
|||
|
|
@ -827,6 +827,9 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)
|
|||
msleep(port->rs485.delay_rts_before_send);
|
||||
|
||||
guard(mutex)(&one->lock);
|
||||
sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
|
||||
SC16IS7XX_IER_THRI_BIT,
|
||||
SC16IS7XX_IER_THRI_BIT);
|
||||
sc16is7xx_handle_tx(port);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1437,7 +1437,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
|
|||
struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
|
||||
int rc;
|
||||
|
||||
tty = vc->port.tty;
|
||||
tty = tty_port_tty_get(&vc->port);
|
||||
|
||||
if (tty && (!tty->driver_data)) {
|
||||
/* No driver data? Strange. Okay we fix it then. */
|
||||
|
|
@ -1497,9 +1497,12 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
|
|||
* characters get aren't echoed locally. This makes key repeat
|
||||
* usable with slow applications and under heavy loads.
|
||||
*/
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
|
||||
tty_kref_put(tty);
|
||||
|
||||
param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
|
||||
param.ledstate = kbd->ledflagstate;
|
||||
key_map = key_maps[shift_final];
|
||||
|
|
|
|||
|
|
@ -406,6 +406,8 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd,
|
|||
/* this could be folded into KDSKBMODE, but for compatibility
|
||||
reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
|
||||
case KDSKBMETA:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
return vt_do_kdskbmeta(console, arg);
|
||||
|
||||
case KDGKBMETA:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user