Commit 7d22af6c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-5.8-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty into master

Pull tty/serial/fbcon fixes from Greg KH:
 "Here are some small tty and serial and fbcon fixes for 5.8-rc7 to
  resolve some reported issues.

  The fbcon fix is in here as it was simpler to take it this way (and it
  was acked by the maintainer) as it was related to the vt console fix
  as well, both of which resolve syzbot-found issues in the console
  handling code.

  The other serial driver fixes are for small issues reported in the -rc
  releases.

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

* tag 'tty-5.8-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: exar: Fix GPIO configuration for Sealevel cards based on XR17V35X
  fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins.
  serial: 8250_mtk: Fix high-speed baud rates clamping
  serial: 8250: fix null-ptr-deref in serial8250_start_tx()
  serial: tegra: drop bogus NULL tty-port checks
  serial: tegra: fix CREAD handling for PIO
  tty: xilinx_uartps: Really fix id assignment
  vt: Reject zero-sized screen buffer size.
parents 17f50e28 5fdbe136
...@@ -524,6 +524,7 @@ static void __init serial8250_isa_init_ports(void) ...@@ -524,6 +524,7 @@ static void __init serial8250_isa_init_ports(void)
*/ */
up->mcr_mask = ~ALPHA_KLUDGE_MCR; up->mcr_mask = ~ALPHA_KLUDGE_MCR;
up->mcr_force = ALPHA_KLUDGE_MCR; up->mcr_force = ALPHA_KLUDGE_MCR;
serial8250_set_defaults(up);
} }
/* chain base port ops to support Remote Supervisor Adapter */ /* chain base port ops to support Remote Supervisor Adapter */
...@@ -547,7 +548,6 @@ static void __init serial8250_isa_init_ports(void) ...@@ -547,7 +548,6 @@ static void __init serial8250_isa_init_ports(void)
port->membase = old_serial_port[i].iomem_base; port->membase = old_serial_port[i].iomem_base;
port->iotype = old_serial_port[i].io_type; port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift; port->regshift = old_serial_port[i].iomem_reg_shift;
serial8250_set_defaults(up);
port->irqflags |= irqflag; port->irqflags |= irqflag;
if (serial8250_isa_config != NULL) if (serial8250_isa_config != NULL)
......
...@@ -326,7 +326,17 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p) ...@@ -326,7 +326,17 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
* devices will export them as GPIOs, so we pre-configure them safely * devices will export them as GPIOs, so we pre-configure them safely
* as inputs. * as inputs.
*/ */
u8 dir = pcidev->vendor == PCI_VENDOR_ID_EXAR ? 0xff : 0x00;
u8 dir = 0x00;
if ((pcidev->vendor == PCI_VENDOR_ID_EXAR) &&
(pcidev->subsystem_vendor != PCI_VENDOR_ID_SEALEVEL)) {
// Configure GPIO as inputs for Commtech adapters
dir = 0xff;
} else {
// Configure GPIO as outputs for SeaLevel adapters
dir = 0x00;
}
writeb(0x00, p + UART_EXAR_MPIOINT_7_0); writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0); writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
......
...@@ -306,8 +306,21 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -306,8 +306,21 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
} }
#endif #endif
/*
* Store the requested baud rate before calling the generic 8250
* set_termios method. Standard 8250 port expects bauds to be
* no higher than (uartclk / 16) so the baud will be clamped if it
* gets out of that bound. Mediatek 8250 port supports speed
* higher than that, therefore we'll get original baud rate back
* after calling the generic set_termios method and recalculate
* the speed later in this method.
*/
baud = tty_termios_baud_rate(termios);
serial8250_do_set_termios(port, termios, old); serial8250_do_set_termios(port, termios, old);
tty_termios_encode_baud_rate(termios, baud, baud);
/* /*
* Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS) * Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS)
* *
...@@ -339,6 +352,11 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -339,6 +352,11 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
*/ */
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
/* set DLAB we have cval saved in up->lcr from the call to the core */ /* set DLAB we have cval saved in up->lcr from the call to the core */
serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
serial_dl_write(up, quot); serial_dl_write(up, quot);
......
...@@ -635,7 +635,7 @@ static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup) ...@@ -635,7 +635,7 @@ static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
} }
static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
struct tty_port *tty) struct tty_port *port)
{ {
do { do {
char flag = TTY_NORMAL; char flag = TTY_NORMAL;
...@@ -653,16 +653,18 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, ...@@ -653,16 +653,18 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
ch = (unsigned char) tegra_uart_read(tup, UART_RX); ch = (unsigned char) tegra_uart_read(tup, UART_RX);
tup->uport.icount.rx++; tup->uport.icount.rx++;
if (!uart_handle_sysrq_char(&tup->uport, ch) && tty) if (uart_handle_sysrq_char(&tup->uport, ch))
tty_insert_flip_char(tty, ch, flag); continue;
if (tup->uport.ignore_status_mask & UART_LSR_DR) if (tup->uport.ignore_status_mask & UART_LSR_DR)
continue; continue;
tty_insert_flip_char(port, ch, flag);
} while (1); } while (1);
} }
static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
struct tty_port *tty, struct tty_port *port,
unsigned int count) unsigned int count)
{ {
int copied; int copied;
...@@ -672,17 +674,13 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, ...@@ -672,17 +674,13 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
return; return;
tup->uport.icount.rx += count; tup->uport.icount.rx += count;
if (!tty) {
dev_err(tup->uport.dev, "No tty port\n");
return;
}
if (tup->uport.ignore_status_mask & UART_LSR_DR) if (tup->uport.ignore_status_mask & UART_LSR_DR)
return; return;
dma_sync_single_for_cpu(tup->uport.dev, tup->rx_dma_buf_phys, dma_sync_single_for_cpu(tup->uport.dev, tup->rx_dma_buf_phys,
count, DMA_FROM_DEVICE); count, DMA_FROM_DEVICE);
copied = tty_insert_flip_string(tty, copied = tty_insert_flip_string(port,
((unsigned char *)(tup->rx_dma_buf_virt)), count); ((unsigned char *)(tup->rx_dma_buf_virt)), count);
if (copied != count) { if (copied != count) {
WARN_ON(1); WARN_ON(1);
......
...@@ -1580,8 +1580,10 @@ static int cdns_uart_probe(struct platform_device *pdev) ...@@ -1580,8 +1580,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
* If register_console() don't assign value, then console_port pointer * If register_console() don't assign value, then console_port pointer
* is cleanup. * is cleanup.
*/ */
if (!console_port) if (!console_port) {
cdns_uart_console.index = id;
console_port = port; console_port = port;
}
#endif #endif
rc = uart_add_one_port(&cdns_uart_uart_driver, port); rc = uart_add_one_port(&cdns_uart_uart_driver, port);
...@@ -1594,8 +1596,10 @@ static int cdns_uart_probe(struct platform_device *pdev) ...@@ -1594,8 +1596,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/* This is not port which is used for console that's why clean it up */ /* This is not port which is used for console that's why clean it up */
if (console_port == port && if (console_port == port &&
!(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) !(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) {
console_port = NULL; console_port = NULL;
cdns_uart_console.index = -1;
}
#endif #endif
cdns_uart_data->cts_override = of_property_read_bool(pdev->dev.of_node, cdns_uart_data->cts_override = of_property_read_bool(pdev->dev.of_node,
......
...@@ -1092,10 +1092,19 @@ static const struct tty_port_operations vc_port_ops = { ...@@ -1092,10 +1092,19 @@ static const struct tty_port_operations vc_port_ops = {
.destruct = vc_port_destruct, .destruct = vc_port_destruct,
}; };
/*
* Change # of rows and columns (0 means unchanged/the size of fg_console)
* [this is to be used together with some user program
* like resize that changes the hardware videomode]
*/
#define VC_MAXCOL (32767)
#define VC_MAXROW (32767)
int vc_allocate(unsigned int currcons) /* return 0 on success */ int vc_allocate(unsigned int currcons) /* return 0 on success */
{ {
struct vt_notifier_param param; struct vt_notifier_param param;
struct vc_data *vc; struct vc_data *vc;
int err;
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
...@@ -1125,6 +1134,11 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ ...@@ -1125,6 +1134,11 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
if (!*vc->vc_uni_pagedir_loc) if (!*vc->vc_uni_pagedir_loc)
con_set_default_unimap(vc); con_set_default_unimap(vc);
err = -EINVAL;
if (vc->vc_cols > VC_MAXCOL || vc->vc_rows > VC_MAXROW ||
vc->vc_screenbuf_size > KMALLOC_MAX_SIZE || !vc->vc_screenbuf_size)
goto err_free;
err = -ENOMEM;
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL); vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) if (!vc->vc_screenbuf)
goto err_free; goto err_free;
...@@ -1143,7 +1157,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ ...@@ -1143,7 +1157,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
visual_deinit(vc); visual_deinit(vc);
kfree(vc); kfree(vc);
vc_cons[currcons].d = NULL; vc_cons[currcons].d = NULL;
return -ENOMEM; return err;
} }
static inline int resize_screen(struct vc_data *vc, int width, int height, static inline int resize_screen(struct vc_data *vc, int width, int height,
...@@ -1158,14 +1172,6 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, ...@@ -1158,14 +1172,6 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
return err; return err;
} }
/*
* Change # of rows and columns (0 means unchanged/the size of fg_console)
* [this is to be used together with some user program
* like resize that changes the hardware videomode]
*/
#define VC_RESIZE_MAXCOL (32767)
#define VC_RESIZE_MAXROW (32767)
/** /**
* vc_do_resize - resizing method for the tty * vc_do_resize - resizing method for the tty
* @tty: tty being resized * @tty: tty being resized
...@@ -1201,7 +1207,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, ...@@ -1201,7 +1207,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
user = vc->vc_resize_user; user = vc->vc_resize_user;
vc->vc_resize_user = 0; vc->vc_resize_user = 0;
if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) if (cols > VC_MAXCOL || lines > VC_MAXROW)
return -EINVAL; return -EINVAL;
new_cols = (cols ? cols : vc->vc_cols); new_cols = (cols ? cols : vc->vc_cols);
...@@ -1212,7 +1218,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, ...@@ -1212,7 +1218,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
return 0; return 0;
if (new_screen_size > KMALLOC_MAX_SIZE) if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size)
return -EINVAL; return -EINVAL;
newscreen = kzalloc(new_screen_size, GFP_USER); newscreen = kzalloc(new_screen_size, GFP_USER);
if (!newscreen) if (!newscreen)
...@@ -3393,6 +3399,7 @@ static int __init con_init(void) ...@@ -3393,6 +3399,7 @@ static int __init con_init(void)
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
tty_port_init(&vc->port); tty_port_init(&vc->port);
visual_init(vc, currcons, 1); visual_init(vc, currcons, 1);
/* Assuming vc->vc_{cols,rows,screenbuf_size} are sane here. */
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT); vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
vc_init(vc, vc->vc_rows, vc->vc_cols, vc_init(vc, vc->vc_rows, vc->vc_cols,
currcons || !vc->vc_sw->con_save_screen); currcons || !vc->vc_sw->con_save_screen);
......
...@@ -216,7 +216,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -216,7 +216,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
region.color = color; region.color = color;
region.rop = ROP_COPY; region.rop = ROP_COPY;
if (rw && !bottom_only) { if ((int) rw > 0 && !bottom_only) {
region.dx = info->var.xoffset + rs; region.dx = info->var.xoffset + rs;
region.dy = 0; region.dy = 0;
region.width = rw; region.width = rw;
...@@ -224,7 +224,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -224,7 +224,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_fillrect(info, &region); info->fbops->fb_fillrect(info, &region);
} }
if (bh) { if ((int) bh > 0) {
region.dx = info->var.xoffset; region.dx = info->var.xoffset;
region.dy = info->var.yoffset + bs; region.dy = info->var.yoffset + bs;
region.width = rs; region.width = rs;
......
...@@ -201,7 +201,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -201,7 +201,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
region.color = color; region.color = color;
region.rop = ROP_COPY; region.rop = ROP_COPY;
if (rw && !bottom_only) { if ((int) rw > 0 && !bottom_only) {
region.dx = 0; region.dx = 0;
region.dy = info->var.yoffset; region.dy = info->var.yoffset;
region.height = rw; region.height = rw;
...@@ -209,7 +209,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -209,7 +209,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_fillrect(info, &region); info->fbops->fb_fillrect(info, &region);
} }
if (bh) { if ((int) bh > 0) {
region.dx = info->var.xoffset + bs; region.dx = info->var.xoffset + bs;
region.dy = 0; region.dy = 0;
region.height = info->var.yres_virtual; region.height = info->var.yres_virtual;
......
...@@ -184,7 +184,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -184,7 +184,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
region.color = color; region.color = color;
region.rop = ROP_COPY; region.rop = ROP_COPY;
if (rw && !bottom_only) { if ((int) rw > 0 && !bottom_only) {
region.dx = 0; region.dx = 0;
region.dy = info->var.yoffset + rs; region.dy = info->var.yoffset + rs;
region.height = rw; region.height = rw;
...@@ -192,7 +192,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -192,7 +192,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_fillrect(info, &region); info->fbops->fb_fillrect(info, &region);
} }
if (bh) { if ((int) bh > 0) {
region.dx = info->var.xoffset; region.dx = info->var.xoffset;
region.dy = info->var.yoffset; region.dy = info->var.yoffset;
region.height = info->var.yres; region.height = info->var.yres;
......
...@@ -231,7 +231,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -231,7 +231,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
region.color = color; region.color = color;
region.rop = ROP_COPY; region.rop = ROP_COPY;
if (rw && !bottom_only) { if ((int) rw > 0 && !bottom_only) {
region.dy = 0; region.dy = 0;
region.dx = info->var.xoffset; region.dx = info->var.xoffset;
region.width = rw; region.width = rw;
...@@ -239,7 +239,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -239,7 +239,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_fillrect(info, &region); info->fbops->fb_fillrect(info, &region);
} }
if (bh) { if ((int) bh > 0) {
region.dy = info->var.yoffset; region.dy = info->var.yoffset;
region.dx = info->var.xoffset; region.dx = info->var.xoffset;
region.height = bh; region.height = bh;
......
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