TTY/Serial driver fixes for 5.0-rc4

Here are a number of small tty core and serial driver fixes for 5.0-rc4
 to resolve some reported issues.
 
 Nothing major, the small serial driver fixes, a tty core fixup for a
 crash that was reported, and some good vt fixes from Nicolas Pitre as he
 seems to be auditing that chunk of code a lot lately.
 
 All of these have been in linux-next for a while with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXEr9zw8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylgaQCcCpv3UHszx+ZemlyPUB3ZGEa1l48AoLd3VB46
 cRO5Cf78Dr/FO73bWjLR
 =zjYg
 -----END PGP SIGNATURE-----

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

Pull tty/serial driver fixes from Greg KH:
 "Here are a number of small tty core and serial driver fixes for
  5.0-rc4 to resolve some reported issues.

  Nothing major, the small serial driver fixes, a tty core fixup for a
  crash that was reported, and some good vt fixes from Nicolas Pitre as
  he seems to be auditing that chunk of code a lot lately.

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

* tag 'tty-5.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: fsl_lpuart: fix maximum acceptable baud rate with over-sampling
  tty: serial: qcom_geni_serial: Allow mctrl when flow control is disabled
  tty: Handle problem if line discipline does not have receive_buf
  vgacon: unconfuse vc_origin when using soft scrollback
  vt: invoke notifier on screen size change
  vt: always call notifier with the console lock held
  vt: make vt_console_print() compatible with the unicode screen buffer
  tty/n_hdlc: fix __might_sleep warning
  serial: 8250: Fix serial8250 initialization crash
  uart: Fix crash in uart_write and uart_put_char
This commit is contained in:
Linus Torvalds 2019-01-25 12:58:40 -10:00
commit 473721f9c6
8 changed files with 47 additions and 55 deletions

View File

@ -597,6 +597,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
/* too large for caller's buffer */ /* too large for caller's buffer */
ret = -EOVERFLOW; ret = -EOVERFLOW;
} else { } else {
__set_current_state(TASK_RUNNING);
if (copy_to_user(buf, rbuf->buf, rbuf->count)) if (copy_to_user(buf, rbuf->buf, rbuf->count))
ret = -EFAULT; ret = -EFAULT;
else else

View File

@ -1070,16 +1070,17 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
ret = 0; ret = 0;
} }
}
/* Initialise interrupt backoff work if required */ /* Initialise interrupt backoff work if required */
if (up->overrun_backoff_time_ms > 0) { if (up->overrun_backoff_time_ms > 0) {
uart->overrun_backoff_time_ms = up->overrun_backoff_time_ms; uart->overrun_backoff_time_ms =
up->overrun_backoff_time_ms;
INIT_DELAYED_WORK(&uart->overrun_backoff, INIT_DELAYED_WORK(&uart->overrun_backoff,
serial_8250_overrun_backoff_work); serial_8250_overrun_backoff_work);
} else { } else {
uart->overrun_backoff_time_ms = 0; uart->overrun_backoff_time_ms = 0;
} }
}
mutex_unlock(&serial_mutex); mutex_unlock(&serial_mutex);

View File

@ -1697,7 +1697,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
} }
/* ask the core to calculate the divisor */ /* ask the core to calculate the divisor */
baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 4);
spin_lock_irqsave(&sport->port.lock, flags); spin_lock_irqsave(&sport->port.lock, flags);

View File

@ -225,7 +225,7 @@ static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport)
unsigned int mctrl = TIOCM_DSR | TIOCM_CAR; unsigned int mctrl = TIOCM_DSR | TIOCM_CAR;
u32 geni_ios; u32 geni_ios;
if (uart_console(uport) || !uart_cts_enabled(uport)) { if (uart_console(uport)) {
mctrl |= TIOCM_CTS; mctrl |= TIOCM_CTS;
} else { } else {
geni_ios = readl_relaxed(uport->membase + SE_GENI_IOS); geni_ios = readl_relaxed(uport->membase + SE_GENI_IOS);
@ -241,7 +241,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport,
{ {
u32 uart_manual_rfr = 0; u32 uart_manual_rfr = 0;
if (uart_console(uport) || !uart_cts_enabled(uport)) if (uart_console(uport))
return; return;
if (!(mctrl & TIOCM_RTS)) if (!(mctrl & TIOCM_RTS))

View File

@ -550,10 +550,12 @@ static int uart_put_char(struct tty_struct *tty, unsigned char c)
int ret = 0; int ret = 0;
circ = &state->xmit; circ = &state->xmit;
if (!circ->buf)
return 0;
port = uart_port_lock(state, flags); port = uart_port_lock(state, flags);
if (!circ->buf) {
uart_port_unlock(port, flags);
return 0;
}
if (port && uart_circ_chars_free(circ) != 0) { if (port && uart_circ_chars_free(circ) != 0) {
circ->buf[circ->head] = c; circ->buf[circ->head] = c;
circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
@ -586,11 +588,13 @@ static int uart_write(struct tty_struct *tty,
return -EL3HLT; return -EL3HLT;
} }
circ = &state->xmit;
if (!circ->buf)
return 0;
port = uart_port_lock(state, flags); port = uart_port_lock(state, flags);
circ = &state->xmit;
if (!circ->buf) {
uart_port_unlock(port, flags);
return 0;
}
while (port) { while (port) {
c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
if (count < c) if (count < c)

View File

@ -2189,6 +2189,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
ld = tty_ldisc_ref_wait(tty); ld = tty_ldisc_ref_wait(tty);
if (!ld) if (!ld)
return -EIO; return -EIO;
if (ld->ops->receive_buf)
ld->ops->receive_buf(tty, &ch, &mbz, 1); ld->ops->receive_buf(tty, &ch, &mbz, 1);
tty_ldisc_deref(ld); tty_ldisc_deref(ld);
return 0; return 0;

View File

@ -1272,6 +1272,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (con_is_visible(vc)) if (con_is_visible(vc))
update_screen(vc); update_screen(vc);
vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
notify_update(vc);
return err; return err;
} }
@ -2764,8 +2765,8 @@ rescan_last_byte:
con_flush(vc, draw_from, draw_to, &draw_x); con_flush(vc, draw_from, draw_to, &draw_x);
vc_uniscr_debug_check(vc); vc_uniscr_debug_check(vc);
console_conditional_schedule(); console_conditional_schedule();
console_unlock();
notify_update(vc); notify_update(vc);
console_unlock();
return n; return n;
} }
@ -2884,8 +2885,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
unsigned char c; unsigned char c;
static DEFINE_SPINLOCK(printing_lock); static DEFINE_SPINLOCK(printing_lock);
const ushort *start; const ushort *start;
ushort cnt = 0; ushort start_x, cnt;
ushort myx;
int kmsg_console; int kmsg_console;
/* console busy or not yet initialized */ /* console busy or not yet initialized */
@ -2898,10 +2898,6 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
if (kmsg_console && vc_cons_allocated(kmsg_console - 1)) if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
vc = vc_cons[kmsg_console - 1].d; vc = vc_cons[kmsg_console - 1].d;
/* read `x' only after setting currcons properly (otherwise
the `x' macro will read the x of the foreground console). */
myx = vc->vc_x;
if (!vc_cons_allocated(fg_console)) { if (!vc_cons_allocated(fg_console)) {
/* impossible */ /* impossible */
/* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
@ -2916,53 +2912,41 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
hide_cursor(vc); hide_cursor(vc);
start = (ushort *)vc->vc_pos; start = (ushort *)vc->vc_pos;
start_x = vc->vc_x;
/* Contrived structure to try to emulate original need_wrap behaviour cnt = 0;
* Problems caused when we have need_wrap set on '\n' character */
while (count--) { while (count--) {
c = *b++; c = *b++;
if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
if (cnt > 0) { if (cnt && con_is_visible(vc))
if (con_is_visible(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
vc->vc_x += cnt;
if (vc->vc_need_wrap)
vc->vc_x--;
cnt = 0; cnt = 0;
}
if (c == 8) { /* backspace */ if (c == 8) { /* backspace */
bs(vc); bs(vc);
start = (ushort *)vc->vc_pos; start = (ushort *)vc->vc_pos;
myx = vc->vc_x; start_x = vc->vc_x;
continue; continue;
} }
if (c != 13) if (c != 13)
lf(vc); lf(vc);
cr(vc); cr(vc);
start = (ushort *)vc->vc_pos; start = (ushort *)vc->vc_pos;
myx = vc->vc_x; start_x = vc->vc_x;
if (c == 10 || c == 13) if (c == 10 || c == 13)
continue; continue;
} }
vc_uniscr_putc(vc, c);
scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos); scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
notify_write(vc, c); notify_write(vc, c);
cnt++; cnt++;
if (myx == vc->vc_cols - 1) { if (vc->vc_x == vc->vc_cols - 1) {
vc->vc_need_wrap = 1; vc->vc_need_wrap = 1;
continue; } else {
}
vc->vc_pos += 2; vc->vc_pos += 2;
myx++; vc->vc_x++;
}
if (cnt > 0) {
if (con_is_visible(vc))
vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
vc->vc_x += cnt;
if (vc->vc_x == vc->vc_cols) {
vc->vc_x--;
vc->vc_need_wrap = 1;
} }
} }
if (cnt && con_is_visible(vc))
vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
set_cursor(vc); set_cursor(vc);
notify_update(vc); notify_update(vc);

View File

@ -271,6 +271,7 @@ static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
static void vgacon_restore_screen(struct vc_data *c) static void vgacon_restore_screen(struct vc_data *c)
{ {
c->vc_origin = c->vc_visible_origin;
vgacon_scrollback_cur->save = 0; vgacon_scrollback_cur->save = 0;
if (!vga_is_gfx && !vgacon_scrollback_cur->restore) { if (!vga_is_gfx && !vgacon_scrollback_cur->restore) {
@ -287,8 +288,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines)
int start, end, count, soff; int start, end, count, soff;
if (!lines) { if (!lines) {
c->vc_visible_origin = c->vc_origin; vgacon_restore_screen(c);
vga_set_mem_top(c);
return; return;
} }
@ -298,6 +298,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines)
if (!vgacon_scrollback_cur->save) { if (!vgacon_scrollback_cur->save) {
vgacon_cursor(c, CM_ERASE); vgacon_cursor(c, CM_ERASE);
vgacon_save_screen(c); vgacon_save_screen(c);
c->vc_origin = (unsigned long)c->vc_screenbuf;
vgacon_scrollback_cur->save = 1; vgacon_scrollback_cur->save = 1;
} }
@ -335,7 +336,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines)
int copysize; int copysize;
int diff = c->vc_rows - count; int diff = c->vc_rows - count;
void *d = (void *) c->vc_origin; void *d = (void *) c->vc_visible_origin;
void *s = (void *) c->vc_screenbuf; void *s = (void *) c->vc_screenbuf;
count *= c->vc_size_row; count *= c->vc_size_row;