mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
TTY/Serial driver fixes for 6.12-rc4
Here are some small tty and serial driver fixes for 6.12-rc4. Included in here are: - qcom-geni serial driver fixes, wow what a mess of a UART chip that thing is... - vt infoleak fix for odd font sizes - imx serial driver bugfix - yet-another n_gsm ldisc bugfix, slowly chipping down the issues in that piece of code. 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----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZxUGDQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymS+ACfQaKXHHy0WZ/kB22Eif7KgKsx+D0AnjxH+H5l knORLhrVW+V41wyk9QM/ =qbdY -----END PGP SIGNATURE----- Merge tag 'tty-6.12-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver fixes from Greg KH: "Here are some small tty and serial driver fixes for 6.12-rc4: - qcom-geni serial driver fixes, wow what a mess of a UART chip that thing is... - vt infoleak fix for odd font sizes - imx serial driver bugfix - yet-another n_gsm ldisc bugfix, slowly chipping down the issues in that piece of code All of these have been in linux-next for over a week with no reported issues" * tag 'tty-6.12-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: serial: qcom-geni: rename suspend functions serial: qcom-geni: drop unused receive parameter serial: qcom-geni: drop flip buffer WARN() serial: qcom-geni: fix rx cancel dma status bit serial: qcom-geni: fix receiver enable serial: qcom-geni: fix dma rx cancellation serial: qcom-geni: fix shutdown race serial: qcom-geni: revert broken hibernation support serial: qcom-geni: fix polled console initialisation serial: imx: Update mctrl old_status on RTSD interrupt tty: n_gsm: Fix use-after-free in gsm_cleanup_mux vt: prevent kernel-infoleak in con_font_get()
This commit is contained in:
commit
c01ac4b944
@ -3157,6 +3157,8 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
|
||||
mutex_unlock(&gsm->mutex);
|
||||
/* Now wipe the queues */
|
||||
tty_ldisc_flush(gsm->tty);
|
||||
|
||||
guard(spinlock_irqsave)(&gsm->tx_lock);
|
||||
list_for_each_entry_safe(txq, ntxq, &gsm->tx_ctrl_list, list)
|
||||
kfree(txq);
|
||||
INIT_LIST_HEAD(&gsm->tx_ctrl_list);
|
||||
|
@ -762,6 +762,21 @@ static irqreturn_t __imx_uart_rtsint(int irq, void *dev_id)
|
||||
|
||||
imx_uart_writel(sport, USR1_RTSD, USR1);
|
||||
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
|
||||
/*
|
||||
* Update sport->old_status here, so any follow-up calls to
|
||||
* imx_uart_mctrl_check() will be able to recognize that RTS
|
||||
* state changed since last imx_uart_mctrl_check() call.
|
||||
*
|
||||
* In case RTS has been detected as asserted here and later on
|
||||
* deasserted by the time imx_uart_mctrl_check() was called,
|
||||
* imx_uart_mctrl_check() can detect the RTS state change and
|
||||
* trigger uart_handle_cts_change() to unblock the port for
|
||||
* further TX transfers.
|
||||
*/
|
||||
if (usr1 & USR1_RTSS)
|
||||
sport->old_status |= TIOCM_CTS;
|
||||
else
|
||||
sport->old_status &= ~TIOCM_CTS;
|
||||
uart_handle_cts_change(&sport->port, usr1);
|
||||
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
|
||||
|
||||
|
@ -147,6 +147,7 @@ static struct uart_driver qcom_geni_uart_driver;
|
||||
|
||||
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);
|
||||
|
||||
static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport)
|
||||
{
|
||||
@ -395,6 +396,23 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
|
||||
writel(c, uport->membase + SE_GENI_TX_FIFOn);
|
||||
qcom_geni_serial_poll_tx_done(uport);
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_poll_init(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
int ret;
|
||||
|
||||
if (!port->setup) {
|
||||
ret = qcom_geni_serial_port_setup(uport);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!qcom_geni_serial_secondary_active(uport))
|
||||
geni_se_setup_s_cmd(&port->se, UART_START_READ, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
|
||||
@ -562,7 +580,7 @@ static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
|
||||
}
|
||||
#endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
|
||||
|
||||
static void handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
|
||||
static void handle_rx_uart(struct uart_port *uport, u32 bytes)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
struct tty_port *tport = &uport->state->port;
|
||||
@ -570,9 +588,8 @@ static void handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
|
||||
|
||||
ret = tty_insert_flip_string(tport, port->rx_buf, bytes);
|
||||
if (ret != bytes) {
|
||||
dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n",
|
||||
__func__, ret, bytes);
|
||||
WARN_ON_ONCE(1);
|
||||
dev_err_ratelimited(uport->dev, "failed to push data (%d < %u)\n",
|
||||
ret, bytes);
|
||||
}
|
||||
uport->icount.rx += ret;
|
||||
tty_flip_buffer_push(tport);
|
||||
@ -787,17 +804,27 @@ static void qcom_geni_serial_start_rx_fifo(struct uart_port *uport)
|
||||
static void qcom_geni_serial_stop_rx_dma(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
bool done;
|
||||
|
||||
if (!qcom_geni_serial_secondary_active(uport))
|
||||
return;
|
||||
|
||||
geni_se_cancel_s_cmd(&port->se);
|
||||
qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
|
||||
S_CMD_CANCEL_EN, true);
|
||||
|
||||
if (qcom_geni_serial_secondary_active(uport))
|
||||
done = qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
|
||||
RX_EOT, true);
|
||||
if (done) {
|
||||
writel(RX_EOT | RX_DMA_DONE,
|
||||
uport->membase + SE_DMA_RX_IRQ_CLR);
|
||||
} else {
|
||||
qcom_geni_serial_abort_rx(uport);
|
||||
|
||||
writel(1, uport->membase + SE_DMA_RX_FSM_RST);
|
||||
qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
|
||||
RX_RESET_DONE, true);
|
||||
writel(RX_RESET_DONE | RX_DMA_DONE,
|
||||
uport->membase + SE_DMA_RX_IRQ_CLR);
|
||||
}
|
||||
|
||||
if (port->rx_dma_addr) {
|
||||
geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr,
|
||||
DMA_RX_BUF_SIZE);
|
||||
@ -846,7 +873,7 @@ static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop)
|
||||
}
|
||||
|
||||
if (!drop)
|
||||
handle_rx_uart(uport, rx_in, drop);
|
||||
handle_rx_uart(uport, rx_in);
|
||||
|
||||
ret = geni_se_rx_dma_prep(&port->se, port->rx_buf,
|
||||
DMA_RX_BUF_SIZE,
|
||||
@ -1096,10 +1123,12 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
|
||||
{
|
||||
disable_irq(uport->irq);
|
||||
|
||||
uart_port_lock_irq(uport);
|
||||
qcom_geni_serial_stop_tx(uport);
|
||||
qcom_geni_serial_stop_rx(uport);
|
||||
|
||||
qcom_geni_serial_cancel_tx_cmd(uport);
|
||||
uart_port_unlock_irq(uport);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_flush_buffer(struct uart_port *uport)
|
||||
@ -1152,7 +1181,6 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
|
||||
false, true, true);
|
||||
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
|
||||
geni_se_select_mode(&port->se, port->dev_data->mode);
|
||||
qcom_geni_serial_start_rx(uport);
|
||||
port->setup = true;
|
||||
|
||||
return 0;
|
||||
@ -1168,6 +1196,11 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uart_port_lock_irq(uport);
|
||||
qcom_geni_serial_start_rx(uport);
|
||||
uart_port_unlock_irq(uport);
|
||||
|
||||
enable_irq(uport->irq);
|
||||
|
||||
return 0;
|
||||
@ -1253,7 +1286,6 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
||||
unsigned int avg_bw_core;
|
||||
unsigned long timeout;
|
||||
|
||||
qcom_geni_serial_stop_rx(uport);
|
||||
/* baud rate */
|
||||
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
|
||||
|
||||
@ -1269,7 +1301,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
||||
dev_err(port->se.dev,
|
||||
"Couldn't find suitable clock rate for %u\n",
|
||||
baud * sampling_rate);
|
||||
goto out_restart_rx;
|
||||
return;
|
||||
}
|
||||
|
||||
dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n",
|
||||
@ -1360,8 +1392,6 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
||||
writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
|
||||
writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
|
||||
writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
|
||||
out_restart_rx:
|
||||
qcom_geni_serial_start_rx(uport);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
|
||||
@ -1582,7 +1612,7 @@ static const struct uart_ops qcom_geni_console_pops = {
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = qcom_geni_serial_get_char,
|
||||
.poll_put_char = qcom_geni_serial_poll_put_char,
|
||||
.poll_init = qcom_geni_serial_port_setup,
|
||||
.poll_init = qcom_geni_serial_poll_init,
|
||||
#endif
|
||||
.pm = qcom_geni_serial_pm,
|
||||
};
|
||||
@ -1749,7 +1779,7 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
|
||||
uart_remove_one_port(drv, &port->uport);
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_sys_suspend(struct device *dev)
|
||||
static int qcom_geni_serial_suspend(struct device *dev)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||
struct uart_port *uport = &port->uport;
|
||||
@ -1766,7 +1796,7 @@ static int qcom_geni_serial_sys_suspend(struct device *dev)
|
||||
return uart_suspend_port(private_data->drv, uport);
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_sys_resume(struct device *dev)
|
||||
static int qcom_geni_serial_resume(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||
@ -1781,38 +1811,6 @@ static int qcom_geni_serial_sys_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_sys_hib_resume(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct uart_port *uport;
|
||||
struct qcom_geni_private_data *private_data;
|
||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||
|
||||
uport = &port->uport;
|
||||
private_data = uport->private_data;
|
||||
|
||||
if (uart_console(uport)) {
|
||||
geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS);
|
||||
geni_icc_set_bw(&port->se);
|
||||
ret = uart_resume_port(private_data->drv, uport);
|
||||
/*
|
||||
* For hibernation usecase clients for
|
||||
* console UART won't call port setup during restore,
|
||||
* hence call port setup for console uart.
|
||||
*/
|
||||
qcom_geni_serial_port_setup(uport);
|
||||
} else {
|
||||
/*
|
||||
* Peripheral register settings are lost during hibernation.
|
||||
* Update setup flag such that port setup happens again
|
||||
* during next session. Clients of HS-UART will close and
|
||||
* open the port during hibernation.
|
||||
*/
|
||||
port->setup = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct qcom_geni_device_data qcom_geni_console_data = {
|
||||
.console = true,
|
||||
.mode = GENI_SE_FIFO,
|
||||
@ -1824,12 +1822,7 @@ static const struct qcom_geni_device_data qcom_geni_uart_data = {
|
||||
};
|
||||
|
||||
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
|
||||
.suspend = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
|
||||
.resume = pm_sleep_ptr(qcom_geni_serial_sys_resume),
|
||||
.freeze = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
|
||||
.poweroff = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
|
||||
.restore = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume),
|
||||
.thaw = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume),
|
||||
SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_geni_serial_match_table[] = {
|
||||
|
@ -4726,7 +4726,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
|
||||
return -EINVAL;
|
||||
|
||||
if (op->data) {
|
||||
font.data = kvmalloc(max_font_size, GFP_KERNEL);
|
||||
font.data = kvzalloc(max_font_size, GFP_KERNEL);
|
||||
if (!font.data)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
|
@ -258,8 +258,8 @@ struct geni_se {
|
||||
#define RX_DMA_PARITY_ERR BIT(5)
|
||||
#define RX_DMA_BREAK GENMASK(8, 7)
|
||||
#define RX_GENI_GP_IRQ GENMASK(10, 5)
|
||||
#define RX_GENI_CANCEL_IRQ BIT(11)
|
||||
#define RX_GENI_GP_IRQ_EXT GENMASK(13, 12)
|
||||
#define RX_GENI_CANCEL_IRQ BIT(14)
|
||||
|
||||
/* SE_HW_PARAM_0 fields */
|
||||
#define TX_FIFO_WIDTH_MSK GENMASK(29, 24)
|
||||
|
Loading…
Reference in New Issue
Block a user