diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-05 12:05:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-05 12:05:16 -0500 |
commit | 84dda2965d2a8d319e5f47cef46697cf9153f272 (patch) | |
tree | 7070e11698da3f6e8f657ee09604d9141c1c3a02 | |
parent | 6b0b3bda3d77c35fa9cf20067c0b62daff98c042 (diff) | |
parent | c8ec2041f549e7f2dee0c34d25381be6f7805f99 (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/Kbuild | 1 | ||||
-rw-r--r-- | arch/mips/include/asm/serial.h | 22 | ||||
-rw-r--r-- | drivers/tty/serdev/serdev-ttyport.c | 26 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_early.c | 14 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 3 | ||||
-rw-r--r-- | include/linux/serdev.h | 2 |
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 | |||
16 | generic-y += qspinlock.h | 16 | generic-y += qspinlock.h |
17 | generic-y += sections.h | 17 | generic-y += sections.h |
18 | generic-y += segment.h | 18 | generic-y += segment.h |
19 | generic-y += serial.h | ||
20 | generic-y += trace_clock.h | 19 | generic-y += trace_clock.h |
21 | generic-y += unaligned.h | 20 | generic-y += unaligned.h |
22 | generic-y += user.h | 21 | generic-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 | ||
37 | static void ttyport_write_wakeup(struct tty_port *port) | 48 | static 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 | ||
49 | static const struct tty_port_client_operations client_ops = { | 67 | static 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 | ||
133 | int __init early_serial8250_setup(struct earlycon_device *device, | 135 | int __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 | } |