mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 08:14:15 +08: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);
|
mutex_unlock(&gsm->mutex);
|
||||||
/* Now wipe the queues */
|
/* Now wipe the queues */
|
||||||
tty_ldisc_flush(gsm->tty);
|
tty_ldisc_flush(gsm->tty);
|
||||||
|
|
||||||
|
guard(spinlock_irqsave)(&gsm->tx_lock);
|
||||||
list_for_each_entry_safe(txq, ntxq, &gsm->tx_ctrl_list, list)
|
list_for_each_entry_safe(txq, ntxq, &gsm->tx_ctrl_list, list)
|
||||||
kfree(txq);
|
kfree(txq);
|
||||||
INIT_LIST_HEAD(&gsm->tx_ctrl_list);
|
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);
|
imx_uart_writel(sport, USR1_RTSD, USR1);
|
||||||
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
|
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);
|
uart_handle_cts_change(&sport->port, usr1);
|
||||||
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
|
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 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)
|
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);
|
writel(c, uport->membase + SE_GENI_TX_FIFOn);
|
||||||
qcom_geni_serial_poll_tx_done(uport);
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
|
#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 */
|
#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 qcom_geni_serial_port *port = to_dev_port(uport);
|
||||||
struct tty_port *tport = &uport->state->port;
|
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);
|
ret = tty_insert_flip_string(tport, port->rx_buf, bytes);
|
||||||
if (ret != bytes) {
|
if (ret != bytes) {
|
||||||
dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n",
|
dev_err_ratelimited(uport->dev, "failed to push data (%d < %u)\n",
|
||||||
__func__, ret, bytes);
|
ret, bytes);
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
}
|
}
|
||||||
uport->icount.rx += ret;
|
uport->icount.rx += ret;
|
||||||
tty_flip_buffer_push(tport);
|
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)
|
static void qcom_geni_serial_stop_rx_dma(struct uart_port *uport)
|
||||||
{
|
{
|
||||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||||
|
bool done;
|
||||||
|
|
||||||
if (!qcom_geni_serial_secondary_active(uport))
|
if (!qcom_geni_serial_secondary_active(uport))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
geni_se_cancel_s_cmd(&port->se);
|
geni_se_cancel_s_cmd(&port->se);
|
||||||
qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
|
done = qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
|
||||||
S_CMD_CANCEL_EN, true);
|
RX_EOT, true);
|
||||||
|
if (done) {
|
||||||
if (qcom_geni_serial_secondary_active(uport))
|
writel(RX_EOT | RX_DMA_DONE,
|
||||||
|
uport->membase + SE_DMA_RX_IRQ_CLR);
|
||||||
|
} else {
|
||||||
qcom_geni_serial_abort_rx(uport);
|
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) {
|
if (port->rx_dma_addr) {
|
||||||
geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr,
|
geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr,
|
||||||
DMA_RX_BUF_SIZE);
|
DMA_RX_BUF_SIZE);
|
||||||
@ -846,7 +873,7 @@ static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!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,
|
ret = geni_se_rx_dma_prep(&port->se, port->rx_buf,
|
||||||
DMA_RX_BUF_SIZE,
|
DMA_RX_BUF_SIZE,
|
||||||
@ -1096,10 +1123,12 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
|
|||||||
{
|
{
|
||||||
disable_irq(uport->irq);
|
disable_irq(uport->irq);
|
||||||
|
|
||||||
|
uart_port_lock_irq(uport);
|
||||||
qcom_geni_serial_stop_tx(uport);
|
qcom_geni_serial_stop_tx(uport);
|
||||||
qcom_geni_serial_stop_rx(uport);
|
qcom_geni_serial_stop_rx(uport);
|
||||||
|
|
||||||
qcom_geni_serial_cancel_tx_cmd(uport);
|
qcom_geni_serial_cancel_tx_cmd(uport);
|
||||||
|
uart_port_unlock_irq(uport);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qcom_geni_serial_flush_buffer(struct uart_port *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);
|
false, true, true);
|
||||||
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
|
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
|
||||||
geni_se_select_mode(&port->se, port->dev_data->mode);
|
geni_se_select_mode(&port->se, port->dev_data->mode);
|
||||||
qcom_geni_serial_start_rx(uport);
|
|
||||||
port->setup = true;
|
port->setup = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1168,6 +1196,11 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uart_port_lock_irq(uport);
|
||||||
|
qcom_geni_serial_start_rx(uport);
|
||||||
|
uart_port_unlock_irq(uport);
|
||||||
|
|
||||||
enable_irq(uport->irq);
|
enable_irq(uport->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1253,7 +1286,6 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
|||||||
unsigned int avg_bw_core;
|
unsigned int avg_bw_core;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
|
|
||||||
qcom_geni_serial_stop_rx(uport);
|
|
||||||
/* baud rate */
|
/* baud rate */
|
||||||
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
|
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,
|
dev_err(port->se.dev,
|
||||||
"Couldn't find suitable clock rate for %u\n",
|
"Couldn't find suitable clock rate for %u\n",
|
||||||
baud * sampling_rate);
|
baud * sampling_rate);
|
||||||
goto out_restart_rx;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n",
|
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(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_M_CLK_CFG);
|
||||||
writel(ser_clk_cfg, uport->membase + GENI_SER_S_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
|
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
|
||||||
@ -1582,7 +1612,7 @@ static const struct uart_ops qcom_geni_console_pops = {
|
|||||||
#ifdef CONFIG_CONSOLE_POLL
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
.poll_get_char = qcom_geni_serial_get_char,
|
.poll_get_char = qcom_geni_serial_get_char,
|
||||||
.poll_put_char = qcom_geni_serial_poll_put_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
|
#endif
|
||||||
.pm = qcom_geni_serial_pm,
|
.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);
|
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 qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||||
struct uart_port *uport = &port->uport;
|
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);
|
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;
|
int ret;
|
||||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
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;
|
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 = {
|
static const struct qcom_geni_device_data qcom_geni_console_data = {
|
||||||
.console = true,
|
.console = true,
|
||||||
.mode = GENI_SE_FIFO,
|
.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 = {
|
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
|
||||||
.suspend = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
|
SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume)
|
||||||
.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),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id qcom_geni_serial_match_table[] = {
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
if (op->data) {
|
if (op->data) {
|
||||||
font.data = kvmalloc(max_font_size, GFP_KERNEL);
|
font.data = kvzalloc(max_font_size, GFP_KERNEL);
|
||||||
if (!font.data)
|
if (!font.data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
} else
|
} else
|
||||||
|
@ -258,8 +258,8 @@ struct geni_se {
|
|||||||
#define RX_DMA_PARITY_ERR BIT(5)
|
#define RX_DMA_PARITY_ERR BIT(5)
|
||||||
#define RX_DMA_BREAK GENMASK(8, 7)
|
#define RX_DMA_BREAK GENMASK(8, 7)
|
||||||
#define RX_GENI_GP_IRQ GENMASK(10, 5)
|
#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_GP_IRQ_EXT GENMASK(13, 12)
|
||||||
|
#define RX_GENI_CANCEL_IRQ BIT(14)
|
||||||
|
|
||||||
/* SE_HW_PARAM_0 fields */
|
/* SE_HW_PARAM_0 fields */
|
||||||
#define TX_FIFO_WIDTH_MSK GENMASK(29, 24)
|
#define TX_FIFO_WIDTH_MSK GENMASK(29, 24)
|
||||||
|
Loading…
Reference in New Issue
Block a user