Commit 15bc20c6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-5.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg KH:
 "Here are a few small TTY/Serial/vt fixes for 5.9-rc3

  Included in here are:
   - qcom serial fixes
   - vt ioctl and core bugfixes
   - pl011 serial driver fixes
   - 8250 serial driver fixes
   - other misc serial driver fixes

  and for good measure:
   - fbcon fix for syzbot found problem.

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

* tag 'tty-5.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: serial: imx: add dependence and build for earlycon
  serial: samsung: Removes the IRQ not found warning
  serial: 8250: change lock order in serial8250_do_startup()
  serial: stm32: avoid kernel warning on absence of optional IRQ
  serial: pl011: Fix oops on -EPROBE_DEFER
  serial: pl011: Don't leak amba_ports entry on driver register error
  serial: 8250_exar: Fix number of ports for Commtech PCIe cards
  tty: serial: qcom_geni_serial: Drop __init from qcom_geni_console_setup
  serial: qcom_geni_serial: Fix recent kdb hang
  vt_ioctl: change VT_RESIZEX ioctl to check for error return from vc_resize()
  fbcon: prevent user font height or width change from causing potential out-of-bounds access
  vt: defer kfree() of vc_screenbuf in vc_do_resize()
parents 27563ab6 ea1fc02e
...@@ -744,6 +744,24 @@ static const struct exar8250_board pbn_exar_XR17V35x = { ...@@ -744,6 +744,24 @@ static const struct exar8250_board pbn_exar_XR17V35x = {
.exit = pci_xr17v35x_exit, .exit = pci_xr17v35x_exit,
}; };
static const struct exar8250_board pbn_fastcom35x_2 = {
.num_ports = 2,
.setup = pci_xr17v35x_setup,
.exit = pci_xr17v35x_exit,
};
static const struct exar8250_board pbn_fastcom35x_4 = {
.num_ports = 4,
.setup = pci_xr17v35x_setup,
.exit = pci_xr17v35x_exit,
};
static const struct exar8250_board pbn_fastcom35x_8 = {
.num_ports = 8,
.setup = pci_xr17v35x_setup,
.exit = pci_xr17v35x_exit,
};
static const struct exar8250_board pbn_exar_XR17V4358 = { static const struct exar8250_board pbn_exar_XR17V4358 = {
.num_ports = 12, .num_ports = 12,
.setup = pci_xr17v35x_setup, .setup = pci_xr17v35x_setup,
...@@ -811,9 +829,9 @@ static const struct pci_device_id exar_pci_tbl[] = { ...@@ -811,9 +829,9 @@ static const struct pci_device_id exar_pci_tbl[] = {
EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x), EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x),
EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358), EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358),
EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358), EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358),
EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_exar_XR17V35x), EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_fastcom35x_2),
EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_exar_XR17V35x), EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_fastcom35x_4),
EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_exar_XR17V35x), EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_fastcom35x_8),
EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2), EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2),
EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4), EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4),
......
...@@ -2275,6 +2275,10 @@ int serial8250_do_startup(struct uart_port *port) ...@@ -2275,6 +2275,10 @@ int serial8250_do_startup(struct uart_port *port)
if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) {
unsigned char iir1; unsigned char iir1;
if (port->irqflags & IRQF_SHARED)
disable_irq_nosync(port->irq);
/* /*
* Test for UARTs that do not reassert THRE when the * Test for UARTs that do not reassert THRE when the
* transmitter is idle and the interrupt has already * transmitter is idle and the interrupt has already
...@@ -2284,8 +2288,6 @@ int serial8250_do_startup(struct uart_port *port) ...@@ -2284,8 +2288,6 @@ int serial8250_do_startup(struct uart_port *port)
* allow register changes to become visible. * allow register changes to become visible.
*/ */
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
if (up->port.irqflags & IRQF_SHARED)
disable_irq_nosync(port->irq);
wait_for_xmitr(up, UART_LSR_THRE); wait_for_xmitr(up, UART_LSR_THRE);
serial_port_out_sync(port, UART_IER, UART_IER_THRI); serial_port_out_sync(port, UART_IER, UART_IER_THRI);
...@@ -2297,9 +2299,10 @@ int serial8250_do_startup(struct uart_port *port) ...@@ -2297,9 +2299,10 @@ int serial8250_do_startup(struct uart_port *port)
iir = serial_port_in(port, UART_IIR); iir = serial_port_in(port, UART_IIR);
serial_port_out(port, UART_IER, 0); serial_port_out(port, UART_IER, 0);
spin_unlock_irqrestore(&port->lock, flags);
if (port->irqflags & IRQF_SHARED) if (port->irqflags & IRQF_SHARED)
enable_irq(port->irq); enable_irq(port->irq);
spin_unlock_irqrestore(&port->lock, flags);
/* /*
* If the interrupt is not reasserted, or we otherwise * If the interrupt is not reasserted, or we otherwise
......
...@@ -517,6 +517,7 @@ config SERIAL_IMX_CONSOLE ...@@ -517,6 +517,7 @@ config SERIAL_IMX_CONSOLE
config SERIAL_IMX_EARLYCON config SERIAL_IMX_EARLYCON
bool "Earlycon on IMX serial port" bool "Earlycon on IMX serial port"
depends on ARCH_MXC || COMPILE_TEST
depends on OF depends on OF
select SERIAL_EARLYCON select SERIAL_EARLYCON
help help
......
...@@ -43,6 +43,7 @@ obj-$(CONFIG_SERIAL_ZS) += zs.o ...@@ -43,6 +43,7 @@ obj-$(CONFIG_SERIAL_ZS) += zs.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_CPM) += cpm_uart/ obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
obj-$(CONFIG_SERIAL_IMX) += imx.o obj-$(CONFIG_SERIAL_IMX) += imx.o
obj-$(CONFIG_SERIAL_IMX_EARLYCON) += imx_earlycon.o
obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
obj-$(CONFIG_SERIAL_ICOM) += icom.o obj-$(CONFIG_SERIAL_ICOM) += icom.o
obj-$(CONFIG_SERIAL_MESON) += meson_uart.o obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
......
...@@ -2241,9 +2241,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) ...@@ -2241,9 +2241,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
clk_disable(uap->clk); clk_disable(uap->clk);
} }
static void __init static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
pl011_console_get_options(struct uart_amba_port *uap, int *baud, int *parity, int *bits)
int *parity, int *bits)
{ {
if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) { if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) {
unsigned int lcr_h, ibrd, fbrd; unsigned int lcr_h, ibrd, fbrd;
...@@ -2276,7 +2275,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, ...@@ -2276,7 +2275,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
} }
} }
static int __init pl011_console_setup(struct console *co, char *options) static int pl011_console_setup(struct console *co, char *options)
{ {
struct uart_amba_port *uap; struct uart_amba_port *uap;
int baud = 38400; int baud = 38400;
...@@ -2344,8 +2343,8 @@ static int __init pl011_console_setup(struct console *co, char *options) ...@@ -2344,8 +2343,8 @@ static int __init pl011_console_setup(struct console *co, char *options)
* *
* Returns 0 if console matches; otherwise non-zero to use default matching * Returns 0 if console matches; otherwise non-zero to use default matching
*/ */
static int __init pl011_console_match(struct console *co, char *name, int idx, static int pl011_console_match(struct console *co, char *name, int idx,
char *options) char *options)
{ {
unsigned char iotype; unsigned char iotype;
resource_size_t addr; resource_size_t addr;
...@@ -2615,7 +2614,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, ...@@ -2615,7 +2614,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
static int pl011_register_port(struct uart_amba_port *uap) static int pl011_register_port(struct uart_amba_port *uap)
{ {
int ret; int ret, i;
/* Ensure interrupts from this UART are masked and cleared */ /* Ensure interrupts from this UART are masked and cleared */
pl011_write(0, uap, REG_IMSC); pl011_write(0, uap, REG_IMSC);
...@@ -2626,6 +2625,9 @@ static int pl011_register_port(struct uart_amba_port *uap) ...@@ -2626,6 +2625,9 @@ static int pl011_register_port(struct uart_amba_port *uap)
if (ret < 0) { if (ret < 0) {
dev_err(uap->port.dev, dev_err(uap->port.dev,
"Failed to register AMBA-PL011 driver\n"); "Failed to register AMBA-PL011 driver\n");
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
if (amba_ports[i] == uap)
amba_ports[i] = NULL;
return ret; return ret;
} }
} }
......
...@@ -361,11 +361,16 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) ...@@ -361,11 +361,16 @@ static int qcom_geni_serial_get_char(struct uart_port *uport)
return NO_POLL_CHAR; return NO_POLL_CHAR;
if (word_cnt == 1 && (status & RX_LAST)) if (word_cnt == 1 && (status & RX_LAST))
/*
* NOTE: If RX_LAST_BYTE_VALID is 0 it needs to be
* treated as if it was BYTES_PER_FIFO_WORD.
*/
private_data->poll_cached_bytes_cnt = private_data->poll_cached_bytes_cnt =
(status & RX_LAST_BYTE_VALID_MSK) >> (status & RX_LAST_BYTE_VALID_MSK) >>
RX_LAST_BYTE_VALID_SHFT; RX_LAST_BYTE_VALID_SHFT;
else
private_data->poll_cached_bytes_cnt = 4; if (private_data->poll_cached_bytes_cnt == 0)
private_data->poll_cached_bytes_cnt = BYTES_PER_FIFO_WORD;
private_data->poll_cached_bytes = private_data->poll_cached_bytes =
readl(uport->membase + SE_GENI_RX_FIFOn); readl(uport->membase + SE_GENI_RX_FIFOn);
...@@ -1098,7 +1103,7 @@ static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport) ...@@ -1098,7 +1103,7 @@ static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
} }
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
static int __init qcom_geni_console_setup(struct console *co, char *options) static int qcom_geni_console_setup(struct console *co, char *options)
{ {
struct uart_port *uport; struct uart_port *uport;
struct qcom_geni_serial_port *port; struct qcom_geni_serial_port *port;
......
...@@ -1905,9 +1905,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ...@@ -1905,9 +1905,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
ourport->tx_irq = ret + 1; ourport->tx_irq = ret + 1;
} }
ret = platform_get_irq(platdev, 1); if (!s3c24xx_serial_has_interrupt_mask(port)) {
if (ret > 0) ret = platform_get_irq(platdev, 1);
ourport->tx_irq = ret; if (ret > 0)
ourport->tx_irq = ret;
}
/* /*
* DMA is currently supported only on DT platforms, if DMA properties * DMA is currently supported only on DT platforms, if DMA properties
* are specified. * are specified.
......
...@@ -970,7 +970,7 @@ static int stm32_init_port(struct stm32_port *stm32port, ...@@ -970,7 +970,7 @@ static int stm32_init_port(struct stm32_port *stm32port,
return ret; return ret;
if (stm32port->info->cfg.has_wakeup) { if (stm32port->info->cfg.has_wakeup) {
stm32port->wakeirq = platform_get_irq(pdev, 1); stm32port->wakeirq = platform_get_irq_optional(pdev, 1);
if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO)
return stm32port->wakeirq ? : -ENODEV; return stm32port->wakeirq ? : -ENODEV;
} }
......
...@@ -1201,7 +1201,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, ...@@ -1201,7 +1201,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
unsigned int old_rows, old_row_size, first_copied_row; unsigned int old_rows, old_row_size, first_copied_row;
unsigned int new_cols, new_rows, new_row_size, new_screen_size; unsigned int new_cols, new_rows, new_row_size, new_screen_size;
unsigned int user; unsigned int user;
unsigned short *newscreen; unsigned short *oldscreen, *newscreen;
struct uni_screen *new_uniscr = NULL; struct uni_screen *new_uniscr = NULL;
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
...@@ -1299,10 +1299,11 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, ...@@ -1299,10 +1299,11 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (new_scr_end > new_origin) if (new_scr_end > new_origin)
scr_memsetw((void *)new_origin, vc->vc_video_erase_char, scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
new_scr_end - new_origin); new_scr_end - new_origin);
kfree(vc->vc_screenbuf); oldscreen = vc->vc_screenbuf;
vc->vc_screenbuf = newscreen; vc->vc_screenbuf = newscreen;
vc->vc_screenbuf_size = new_screen_size; vc->vc_screenbuf_size = new_screen_size;
set_origin(vc); set_origin(vc);
kfree(oldscreen);
/* do part of a reset_terminal() */ /* do part of a reset_terminal() */
vc->vc_top = 0; vc->vc_top = 0;
......
...@@ -806,12 +806,22 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs) ...@@ -806,12 +806,22 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
console_lock(); console_lock();
vcp = vc_cons[i].d; vcp = vc_cons[i].d;
if (vcp) { if (vcp) {
int ret;
int save_scan_lines = vcp->vc_scan_lines;
int save_font_height = vcp->vc_font.height;
if (v.v_vlin) if (v.v_vlin)
vcp->vc_scan_lines = v.v_vlin; vcp->vc_scan_lines = v.v_vlin;
if (v.v_clin) if (v.v_clin)
vcp->vc_font.height = v.v_clin; vcp->vc_font.height = v.v_clin;
vcp->vc_resize_user = 1; vcp->vc_resize_user = 1;
vc_resize(vcp, v.v_cols, v.v_rows); ret = vc_resize(vcp, v.v_cols, v.v_rows);
if (ret) {
vcp->vc_scan_lines = save_scan_lines;
vcp->vc_font.height = save_font_height;
console_unlock();
return ret;
}
} }
console_unlock(); console_unlock();
} }
......
...@@ -2191,6 +2191,9 @@ static void updatescrollmode(struct fbcon_display *p, ...@@ -2191,6 +2191,9 @@ static void updatescrollmode(struct fbcon_display *p,
} }
} }
#define PITCH(w) (((w) + 7) >> 3)
#define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
static int fbcon_resize(struct vc_data *vc, unsigned int width, static int fbcon_resize(struct vc_data *vc, unsigned int width,
unsigned int height, unsigned int user) unsigned int height, unsigned int user)
{ {
...@@ -2200,6 +2203,24 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, ...@@ -2200,6 +2203,24 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
struct fb_var_screeninfo var = info->var; struct fb_var_screeninfo var = info->var;
int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
if (ops->p && ops->p->userfont && FNTSIZE(vc->vc_font.data)) {
int size;
int pitch = PITCH(vc->vc_font.width);
/*
* If user font, ensure that a possible change to user font
* height or width will not allow a font data out-of-bounds access.
* NOTE: must use original charcount in calculation as font
* charcount can change and cannot be used to determine the
* font data allocated size.
*/
if (pitch <= 0)
return -EINVAL;
size = CALC_FONTSZ(vc->vc_font.height, pitch, FNTCHARCNT(vc->vc_font.data));
if (size > FNTSIZE(vc->vc_font.data))
return -EINVAL;
}
virt_w = FBCON_SWAP(ops->rotate, width, height); virt_w = FBCON_SWAP(ops->rotate, width, height);
virt_h = FBCON_SWAP(ops->rotate, height, width); virt_h = FBCON_SWAP(ops->rotate, height, width);
virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width, virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
...@@ -2652,7 +2673,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, ...@@ -2652,7 +2673,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
int size; int size;
int i, csum; int i, csum;
u8 *new_data, *data = font->data; u8 *new_data, *data = font->data;
int pitch = (font->width+7) >> 3; int pitch = PITCH(font->width);
/* Is there a reason why fbconsole couldn't handle any charcount >256? /* Is there a reason why fbconsole couldn't handle any charcount >256?
* If not this check should be changed to charcount < 256 */ * If not this check should be changed to charcount < 256 */
...@@ -2668,7 +2689,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, ...@@ -2668,7 +2689,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
if (fbcon_invalid_charcount(info, charcount)) if (fbcon_invalid_charcount(info, charcount))
return -EINVAL; return -EINVAL;
size = h * pitch * charcount; size = CALC_FONTSZ(h, pitch, charcount);
new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment