aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-12-05 12:05:16 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-12-05 12:05:16 -0500
commit84dda2965d2a8d319e5f47cef46697cf9153f272 (patch)
tree7070e11698da3f6e8f657ee09604d9141c1c3a02
parent6b0b3bda3d77c35fa9cf20067c0b62daff98c042 (diff)
parentc8ec2041f549e7f2dee0c34d25381be6f7805f99 (diff)
Merge tag 'tty-4.15-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver fixes from Greg KH: "Here are some small serdev and serial fixes for 4.15-rc3. They resolve some reported problems: - a number of serdev fixes to resolve crashes - MIPS build fixes for their serial port - a new 8250 device id All of these have been in linux-next for a while with no reported issues" * tag 'tty-4.15-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: MIPS: Add custom serial.h with BASE_BAUD override for generic kernel serdev: ttyport: fix tty locking in close serdev: ttyport: fix NULL-deref on hangup serdev: fix receive_buf return value when no callback serdev: ttyport: add missing receive_buf sanity checks serial: 8250_early: Only set divisor if valid clk & baud serial: 8250_pci: Add Amazon PCI serial device ID
-rw-r--r--arch/mips/include/asm/Kbuild1
-rw-r--r--arch/mips/include/asm/serial.h22
-rw-r--r--drivers/tty/serdev/serdev-ttyport.c26
-rw-r--r--drivers/tty/serial/8250/8250_early.c14
-rw-r--r--drivers/tty/serial/8250/8250_pci.c3
-rw-r--r--include/linux/serdev.h2
6 files changed, 57 insertions, 11 deletions
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 7c8aab23bce8..b1f66699677d 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -16,7 +16,6 @@ generic-y += qrwlock.h
16generic-y += qspinlock.h 16generic-y += qspinlock.h
17generic-y += sections.h 17generic-y += sections.h
18generic-y += segment.h 18generic-y += segment.h
19generic-y += serial.h
20generic-y += trace_clock.h 19generic-y += trace_clock.h
21generic-y += unaligned.h 20generic-y += unaligned.h
22generic-y += user.h 21generic-y += user.h
diff --git a/arch/mips/include/asm/serial.h b/arch/mips/include/asm/serial.h
new file mode 100644
index 000000000000..1d830c6666c2
--- /dev/null
+++ b/arch/mips/include/asm/serial.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2017 MIPS Tech, LLC
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 */
9#ifndef __ASM__SERIAL_H
10#define __ASM__SERIAL_H
11
12#ifdef CONFIG_MIPS_GENERIC
13/*
14 * Generic kernels cannot know a correct value for all platforms at
15 * compile time. Set it to 0 to prevent 8250_early using it
16 */
17#define BASE_BAUD 0
18#else
19#include <asm-generic/serial.h>
20#endif
21
22#endif /* __ASM__SERIAL_H */
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index ce7ad0acee7a..247788a16f0b 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -27,23 +27,41 @@ static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp,
27{ 27{
28 struct serdev_controller *ctrl = port->client_data; 28 struct serdev_controller *ctrl = port->client_data;
29 struct serport *serport = serdev_controller_get_drvdata(ctrl); 29 struct serport *serport = serdev_controller_get_drvdata(ctrl);
30 int ret;
30 31
31 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 32 if (!test_bit(SERPORT_ACTIVE, &serport->flags))
32 return 0; 33 return 0;
33 34
34 return serdev_controller_receive_buf(ctrl, cp, count); 35 ret = serdev_controller_receive_buf(ctrl, cp, count);
36
37 dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count,
38 "receive_buf returns %d (count = %zu)\n",
39 ret, count);
40 if (ret < 0)
41 return 0;
42 else if (ret > count)
43 return count;
44
45 return ret;
35} 46}
36 47
37static void ttyport_write_wakeup(struct tty_port *port) 48static void ttyport_write_wakeup(struct tty_port *port)
38{ 49{
39 struct serdev_controller *ctrl = port->client_data; 50 struct serdev_controller *ctrl = port->client_data;
40 struct serport *serport = serdev_controller_get_drvdata(ctrl); 51 struct serport *serport = serdev_controller_get_drvdata(ctrl);
52 struct tty_struct *tty;
53
54 tty = tty_port_tty_get(port);
55 if (!tty)
56 return;
41 57
42 if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &port->tty->flags) && 58 if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
43 test_bit(SERPORT_ACTIVE, &serport->flags)) 59 test_bit(SERPORT_ACTIVE, &serport->flags))
44 serdev_controller_write_wakeup(ctrl); 60 serdev_controller_write_wakeup(ctrl);
45 61
46 wake_up_interruptible_poll(&port->tty->write_wait, POLLOUT); 62 wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
63
64 tty_kref_put(tty);
47} 65}
48 66
49static const struct tty_port_client_operations client_ops = { 67static const struct tty_port_client_operations client_ops = {
@@ -136,8 +154,10 @@ static void ttyport_close(struct serdev_controller *ctrl)
136 154
137 clear_bit(SERPORT_ACTIVE, &serport->flags); 155 clear_bit(SERPORT_ACTIVE, &serport->flags);
138 156
157 tty_lock(tty);
139 if (tty->ops->close) 158 if (tty->ops->close)
140 tty->ops->close(tty, NULL); 159 tty->ops->close(tty, NULL);
160 tty_unlock(tty);
141 161
142 tty_release_struct(tty, serport->tty_idx); 162 tty_release_struct(tty, serport->tty_idx);
143} 163}
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 362c25ff188a..ae6a256524d8 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -122,12 +122,14 @@ static void __init init_port(struct earlycon_device *device)
122 serial8250_early_out(port, UART_FCR, 0); /* no fifo */ 122 serial8250_early_out(port, UART_FCR, 0); /* no fifo */
123 serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */ 123 serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */
124 124
125 divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); 125 if (port->uartclk && device->baud) {
126 c = serial8250_early_in(port, UART_LCR); 126 divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
127 serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB); 127 c = serial8250_early_in(port, UART_LCR);
128 serial8250_early_out(port, UART_DLL, divisor & 0xff); 128 serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB);
129 serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff); 129 serial8250_early_out(port, UART_DLL, divisor & 0xff);
130 serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); 130 serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff);
131 serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
132 }
131} 133}
132 134
133int __init early_serial8250_setup(struct earlycon_device *device, 135int __init early_serial8250_setup(struct earlycon_device *device,
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index b7e0e3416641..54adf8d56350 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -5135,6 +5135,9 @@ static const struct pci_device_id serial_pci_tbl[] = {
5135 { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 }, 5135 { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },
5136 { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 }, 5136 { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 },
5137 5137
5138 /* Amazon PCI serial device */
5139 { PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 },
5140
5138 /* 5141 /*
5139 * These entries match devices with class COMMUNICATION_SERIAL, 5142 * These entries match devices with class COMMUNICATION_SERIAL,
5140 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL 5143 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index e69402d4a8ae..d609e6dc5bad 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -184,7 +184,7 @@ static inline int serdev_controller_receive_buf(struct serdev_controller *ctrl,
184 struct serdev_device *serdev = ctrl->serdev; 184 struct serdev_device *serdev = ctrl->serdev;
185 185
186 if (!serdev || !serdev->ops->receive_buf) 186 if (!serdev || !serdev->ops->receive_buf)
187 return -EINVAL; 187 return 0;
188 188
189 return serdev->ops->receive_buf(serdev, data, count); 189 return serdev->ops->receive_buf(serdev, data, count);
190} 190}