From df3d9a5b771fa40689bbbdf54bd575d2817fe028 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 10 Nov 2017 16:05:45 -0600 Subject: tty: vt: replace _manual_ swap with swap macro in set_selection Make use of the swap macro instead of _manually_ swapping values and remove unnecessary variable tmp. This makes the code easier to read and maintain. This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index af4da9507180..7851383fbd6c 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -186,11 +186,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t } if (ps > pe) /* make sel_start <= sel_end */ - { - int tmp = ps; - ps = pe; - pe = tmp; - } + swap(ps, pe); if (sel_cons != vc_cons[fg_console].d) { clear_selection(); -- cgit From bcfab39df88e31992371818eb8753f4b2b94ca80 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 8 Nov 2017 14:03:25 -0200 Subject: dt-bindings: serial: fsl-imx-uart: Remove 'fsl,irda-mode' property 'fsl,irda-mode' property has been removed since commit afe9cbb1a6ad ("serial: imx: drop support for IRDA"), so remove it from the binding document. Signed-off-by: Fabio Estevam Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/fsl-imx-uart.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt index 860a9559839a..6b789f2ee879 100644 --- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt @@ -6,7 +6,6 @@ Required properties: - interrupts : Should contain uart interrupt Optional properties: -- fsl,irda-mode : Indicate the uart supports irda mode - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works in DCE mode by default. - rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt -- cgit From 98869f9f9e7dfca97de3505bcdfa1115abe9b893 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 9 Nov 2017 08:05:52 -0800 Subject: serdev: Make .remove in struct serdev_device_driver optional Using devres infrastructure it is possible to write a serdev driver that doesn't have any code that needs to be called as a part of .remove. Add code to make .remove optional. Cc: linux-kernel@vger.kernel.org Cc: linux-serial@vger.kernel.org Cc: Rob Herring Cc: cphealy@gmail.com Cc: Guenter Roeck Cc: Lucas Stach Cc: Nikita Yushchenko Cc: Lee Jones Cc: Greg Kroah-Hartman Cc: Pavel Machek Cc: Andy Shevchenko Cc: Johan Hovold Cc: Sebastian Reichel Acked-by: Rob Herring Reviewed-by: Sebastian Reichel Reviewed-by: Guenter Roeck Signed-off-by: Andrey Smirnov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 1bef39828ca7..34050b439c1f 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -268,8 +268,8 @@ static int serdev_drv_probe(struct device *dev) static int serdev_drv_remove(struct device *dev) { const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver); - - sdrv->remove(to_serdev_device(dev)); + if (sdrv->remove) + sdrv->remove(to_serdev_device(dev)); return 0; } -- cgit From 525ba62c96abec9130b8edb877d1128864cee01c Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 9 Nov 2017 08:05:53 -0800 Subject: serdev: Introduce devm_serdev_device_open() Add code implementing managed version of serdev_device_open() for serdev device drivers that "open" the device during driver's lifecycle only once (e.g. opened in .probe() and closed in .remove()). Cc: linux-kernel@vger.kernel.org Cc: linux-serial@vger.kernel.org Cc: Rob Herring Cc: cphealy@gmail.com Cc: Guenter Roeck Cc: Lucas Stach Cc: Nikita Yushchenko Cc: Lee Jones Cc: Greg Kroah-Hartman Cc: Pavel Machek Cc: Andy Shevchenko Cc: Johan Hovold Cc: Sebastian Reichel Acked-by: Rob Herring Reviewed-by: Sebastian Reichel Reviewed-by: Guenter Roeck Signed-off-by: Andrey Smirnov Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/devres.txt | 3 +++ drivers/tty/serdev/core.c | 27 +++++++++++++++++++++++++++ include/linux/serdev.h | 1 + 3 files changed, 31 insertions(+) diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index c180045eb43b..7c1bb3d0c222 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -384,6 +384,9 @@ RESET devm_reset_control_get() devm_reset_controller_register() +SERDEV + devm_serdev_device_open() + SLAVE DMA ENGINE devm_acpi_dma_controller_register() diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 34050b439c1f..28133dbd2808 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -132,6 +132,33 @@ void serdev_device_close(struct serdev_device *serdev) } EXPORT_SYMBOL_GPL(serdev_device_close); +static void devm_serdev_device_release(struct device *dev, void *dr) +{ + serdev_device_close(*(struct serdev_device **)dr); +} + +int devm_serdev_device_open(struct device *dev, struct serdev_device *serdev) +{ + struct serdev_device **dr; + int ret; + + dr = devres_alloc(devm_serdev_device_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + ret = serdev_device_open(serdev); + if (ret) { + devres_free(dr); + return ret; + } + + *dr = serdev; + devres_add(dev, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_serdev_device_open); + void serdev_device_write_wakeup(struct serdev_device *serdev) { complete(&serdev->write_comp); diff --git a/include/linux/serdev.h b/include/linux/serdev.h index e69402d4a8ae..9929063bd45d 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -193,6 +193,7 @@ static inline int serdev_controller_receive_buf(struct serdev_controller *ctrl, int serdev_device_open(struct serdev_device *); void serdev_device_close(struct serdev_device *); +int devm_serdev_device_open(struct device *, struct serdev_device *); unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int); void serdev_device_set_flow_control(struct serdev_device *, bool); int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t); -- cgit From dc88922e0a2fab90c478fbea61880acef8a06a32 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 7 Nov 2017 11:56:56 +0000 Subject: tty: n_gsm: remove redundant pointer gsm Pointer gsm is assigned a value that is never read, hence it is redundant and can be removed. Cleans up clang warning: drivers/tty/n_gsm.c:2979:2: warning: Value stored to 'gsm' is never read Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 5131bdc9e765..48e791d95f76 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2955,7 +2955,6 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) static void gsmtty_close(struct tty_struct *tty, struct file *filp) { struct gsm_dlci *dlci = tty->driver_data; - struct gsm_mux *gsm; if (dlci == NULL) return; @@ -2964,7 +2963,6 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp) mutex_lock(&dlci->mutex); gsm_destroy_network(dlci); mutex_unlock(&dlci->mutex); - gsm = dlci->gsm; if (tty_port_close_start(&dlci->port, tty, filp) == 0) return; gsm_dlci_begin_close(dlci); -- cgit From c0f0b8c51f674d10981704563475020604214fae Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 17 Nov 2017 19:17:59 +0100 Subject: tty: serial: meson: remove duplicate "clear error" bit definition The "clear error" bit in the AML_UART_CONTROL register is defined twice. Remove the AML_UART_CLR_ERR definition and replace it with AML_UART_CLEAR_ERR. AML_UART_CLEAR_ERR was chosen to be kept since the datasheet's description for this bit is "Clear Error" (so developer's don't have to translate this to "CLR_ERR"). No functional changes intended. Signed-off-by: Martin Blumenstingl Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index daafe60175da..78b5d2d15a97 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -36,7 +36,6 @@ #define AML_UART_RX_EN BIT(13) #define AML_UART_TX_RST BIT(22) #define AML_UART_RX_RST BIT(23) -#define AML_UART_CLR_ERR BIT(24) #define AML_UART_RX_INT_EN BIT(27) #define AML_UART_TX_INT_EN BIT(28) #define AML_UART_DATA_LEN_MASK (0x03 << 20) @@ -263,10 +262,10 @@ static void meson_uart_reset(struct uart_port *port) u32 val; val = readl(port->membase + AML_UART_CONTROL); - val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR); + val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLEAR_ERR); writel(val, port->membase + AML_UART_CONTROL); - val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR); + val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLEAR_ERR); writel(val, port->membase + AML_UART_CONTROL); } @@ -276,9 +275,9 @@ static int meson_uart_startup(struct uart_port *port) int ret = 0; val = readl(port->membase + AML_UART_CONTROL); - val |= AML_UART_CLR_ERR; + val |= AML_UART_CLEAR_ERR; writel(val, port->membase + AML_UART_CONTROL); - val &= ~AML_UART_CLR_ERR; + val &= ~AML_UART_CLEAR_ERR; writel(val, port->membase + AML_UART_CONTROL); val |= (AML_UART_RX_EN | AML_UART_TX_EN); -- cgit From 44137e400c8f8b4f8b0c834d0b156c44cebc6743 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 17 Nov 2017 19:18:00 +0100 Subject: tty: serial: meson: merge the two register sections for AML_UART_CONTROL In the code there are two separate sections which each describe some of the bits in the AML_UART_CONTROL register. Merge these into one section to make the code easier to read. No functional changes intended. Signed-off-by: Martin Blumenstingl Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 78b5d2d15a97..72d425579a4d 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -34,8 +34,15 @@ /* AML_UART_CONTROL bits */ #define AML_UART_TX_EN BIT(12) #define AML_UART_RX_EN BIT(13) +#define AML_UART_TWO_WIRE_EN BIT(15) +#define AML_UART_STOP_BIN_LEN_MASK (0x03 << 16) +#define AML_UART_STOP_BIN_1SB (0x00 << 16) +#define AML_UART_STOP_BIN_2SB (0x01 << 16) +#define AML_UART_PARITY_TYPE BIT(18) +#define AML_UART_PARITY_EN BIT(19) #define AML_UART_TX_RST BIT(22) #define AML_UART_RX_RST BIT(23) +#define AML_UART_CLEAR_ERR BIT(24) #define AML_UART_RX_INT_EN BIT(27) #define AML_UART_TX_INT_EN BIT(28) #define AML_UART_DATA_LEN_MASK (0x03 << 20) @@ -56,15 +63,6 @@ AML_UART_FRAME_ERR | \ AML_UART_TX_FIFO_WERR) -/* AML_UART_CONTROL bits */ -#define AML_UART_TWO_WIRE_EN BIT(15) -#define AML_UART_PARITY_TYPE BIT(18) -#define AML_UART_PARITY_EN BIT(19) -#define AML_UART_CLEAR_ERR BIT(24) -#define AML_UART_STOP_BIN_LEN_MASK (0x03 << 16) -#define AML_UART_STOP_BIN_1SB (0x00 << 16) -#define AML_UART_STOP_BIN_2SB (0x01 << 16) - /* AML_UART_MISC bits */ #define AML_UART_XMIT_IRQ(c) (((c) & 0xff) << 8) #define AML_UART_RECV_IRQ(c) ((c) & 0xff) -- cgit From f859722a8f3f145b79c4371303f3d3ea7da5c4e0 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 17 Nov 2017 19:18:01 +0100 Subject: tty: serial: meson: fix typo in the "stop bit" register definition This simply fixes a typo in the preprocessor macros. No functional changes intended. Signed-off-by: Martin Blumenstingl Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 72d425579a4d..8a842591b37c 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -35,9 +35,9 @@ #define AML_UART_TX_EN BIT(12) #define AML_UART_RX_EN BIT(13) #define AML_UART_TWO_WIRE_EN BIT(15) -#define AML_UART_STOP_BIN_LEN_MASK (0x03 << 16) -#define AML_UART_STOP_BIN_1SB (0x00 << 16) -#define AML_UART_STOP_BIN_2SB (0x01 << 16) +#define AML_UART_STOP_BIT_LEN_MASK (0x03 << 16) +#define AML_UART_STOP_BIT_1SB (0x00 << 16) +#define AML_UART_STOP_BIT_2SB (0x01 << 16) #define AML_UART_PARITY_TYPE BIT(18) #define AML_UART_PARITY_EN BIT(19) #define AML_UART_TX_RST BIT(22) @@ -351,11 +351,11 @@ static void meson_uart_set_termios(struct uart_port *port, else val &= ~AML_UART_PARITY_TYPE; - val &= ~AML_UART_STOP_BIN_LEN_MASK; + val &= ~AML_UART_STOP_BIT_LEN_MASK; if (cflags & CSTOPB) - val |= AML_UART_STOP_BIN_2SB; + val |= AML_UART_STOP_BIT_2SB; else - val |= AML_UART_STOP_BIN_1SB; + val |= AML_UART_STOP_BIT_1SB; if (cflags & CRTSCTS) val &= ~AML_UART_TWO_WIRE_EN; -- cgit From e73be92d82e6a842eda6adac339963a3560ca0e4 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 25 Nov 2017 00:40:49 +0100 Subject: serial: pl011: Drop duplicate loop counter pl011_fifo_to_tty() has two counters (max_count and fifotaken) for the same loop. One counter should suffice. This saves one subtraction per character read from the RX FIFO. Cc: Mathias Duckeck Cc: Phil Elwell Cc: Stefan Wahren Cc: Linus Walleij Cc: Russell King Signed-off-by: Lukas Wunner Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 04af8de8617e..7c8f9804f585 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -314,10 +314,9 @@ static void pl011_write(unsigned int val, const struct uart_amba_port *uap, static int pl011_fifo_to_tty(struct uart_amba_port *uap) { u16 status; - unsigned int ch, flag, max_count = 256; - int fifotaken = 0; + unsigned int ch, flag, fifotaken; - while (max_count--) { + for (fifotaken = 0; fifotaken != 256; fifotaken++) { status = pl011_read(uap, REG_FR); if (status & UART01x_FR_RXFE) break; @@ -326,7 +325,6 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) ch = pl011_read(uap, REG_DR) | UART_DUMMY_DR_RX; flag = TTY_NORMAL; uap->port.icount.rx++; - fifotaken++; if (unlikely(ch & UART_DR_ERROR)) { if (ch & UART011_DR_BE) { -- cgit From d8dcbdd08c653d9a6754b3c775f13cb987fa91ec Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Tue, 28 Nov 2017 11:55:17 +0100 Subject: tty: moxa: Add support for CMSPAR The mode constants are taken from the GPL-2.0+ driver available in the driver section of the Moxa homepage. It is tested on a C320Turbo PCI card per logic analyzer and per a device which requires 9 bit character communication. The vendors driver supports CMSPAR unconditionally, so that all other available firmware versions seems to support mark/space parity modes as well. Signed-off-by: Lars Kanis Signed-off-by: Greg Kroah-Hartman --- drivers/tty/moxa.c | 17 +++++++++++------ drivers/tty/moxa.h | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 68cbc03aab4b..250a19f042d7 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1487,8 +1487,6 @@ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_term if (ts->c_iflag & IXANY) xany = 1; - /* Clear the features we don't support */ - ts->c_cflag &= ~CMSPAR; MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany); baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty)); if (baud == -1) @@ -1781,10 +1779,17 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio, mode |= MX_STOP1; if (termio->c_cflag & PARENB) { - if (termio->c_cflag & PARODD) - mode |= MX_PARODD; - else - mode |= MX_PAREVEN; + if (termio->c_cflag & PARODD) { + if (termio->c_cflag & CMSPAR) + mode |= MX_PARMARK; + else + mode |= MX_PARODD; + } else { + if (termio->c_cflag & CMSPAR) + mode |= MX_PARSPACE; + else + mode |= MX_PAREVEN; + } } else mode |= MX_PARNONE; diff --git a/drivers/tty/moxa.h b/drivers/tty/moxa.h index 8ce89fd36c7b..563d2dce80b3 100644 --- a/drivers/tty/moxa.h +++ b/drivers/tty/moxa.h @@ -301,5 +301,7 @@ #define MX_PARNONE 0x00 #define MX_PAREVEN 0x40 #define MX_PARODD 0xC0 +#define MX_PARMARK 0xA0 +#define MX_PARSPACE 0x20 #endif -- cgit From d3a96c94163b7c577f4505168d0041ce9ee32a96 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 25 Nov 2017 00:33:27 +0100 Subject: serial: pl011: Use cached copy of IMSC register Commit 075167ed71b7 ("drivers: PL011: replace UART_MIS reading with _RIS & _IMSC") amended this driver's interrupt handler to read the Raw Interrupt Status (RIS) and Interrupt Mask Set/Clear (IMSC) registers instead of the Masked Interrupt Status (MIS) register. The change was made to attain compatibility with SBSA UARTs which lack the MIS register. However the IMSC register is cached by the driver. Using the cached copy saves one register read per interrupt. I've tested this change successfully on a BCM2837 (Raspberry Pi CM3). Cc: Mathias Duckeck Cc: Phil Elwell Cc: Stefan Wahren Cc: Andre Przywara Cc: Mark Langsdorf Cc: Naresh Bhat Cc: Russell King Signed-off-by: Lukas Wunner Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 7c8f9804f585..4b40a5b449ee 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1480,12 +1480,10 @@ static irqreturn_t pl011_int(int irq, void *dev_id) struct uart_amba_port *uap = dev_id; unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; - u16 imsc; int handled = 0; spin_lock_irqsave(&uap->port.lock, flags); - imsc = pl011_read(uap, REG_IMSC); - status = pl011_read(uap, REG_RIS) & imsc; + status = pl011_read(uap, REG_RIS) & uap->im; if (status) { do { check_apply_cts_event_workaround(uap); @@ -1509,7 +1507,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (pass_counter-- == 0) break; - status = pl011_read(uap, REG_RIS) & imsc; + status = pl011_read(uap, REG_RIS) & uap->im; } while (status != 0); handled = 1; } -- cgit From 1f043572cbbee03f1de814e312f9dc11251fdc5a Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 16 Nov 2017 11:14:53 -0700 Subject: tty: serial: imx: remove imx_disable_rx_int Since imx_disable_rx_int is only called by imx_startup, let's integrate it into that function. Notice UCR2_ATEN is never set by the driver. The bit is still cleaned to make this patch a noop. Signed-off-by: Troy Kisky Acked-by: Uwe Kleine-Koenig Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e4b3d9123a03..16311a24b483 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -703,25 +703,6 @@ out: return IRQ_HANDLED; } -static void imx_disable_rx_int(struct imx_port *sport) -{ - unsigned long temp; - - /* disable the receiver ready and aging timer interrupts */ - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RRDYEN); - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR2); - temp &= ~(UCR2_ATEN); - writel(temp, sport->port.membase + UCR2); - - /* disable the rx errors interrupts */ - temp = readl(sport->port.membase + UCR4); - temp &= ~UCR4_OREN; - writel(temp, sport->port.membase + UCR4); -} - static void clear_rx_errors(struct imx_port *sport); /* @@ -1252,18 +1233,21 @@ static int imx_startup(struct uart_port *port) if (sport->dma_is_inited && !sport->dma_is_enabled) imx_enable_dma(sport); - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN | UCR1_UARTEN; + temp = readl(sport->port.membase + UCR1) & ~UCR1_RRDYEN; + if (!sport->dma_is_enabled) + temp |= UCR1_RRDYEN; + temp |= UCR1_UARTEN; if (sport->have_rtscts) temp |= UCR1_RTSDEN; writel(temp, sport->port.membase + UCR1); - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_OREN; + temp = readl(sport->port.membase + UCR4) & ~UCR4_OREN; + if (!sport->dma_is_enabled) + temp |= UCR4_OREN; writel(temp, sport->port.membase + UCR4); - temp = readl(sport->port.membase + UCR2); + temp = readl(sport->port.membase + UCR2) & ~UCR2_ATEN; temp |= (UCR2_RXEN | UCR2_TXEN); if (!sport->have_rtscts) temp |= UCR2_IRTS; @@ -1297,10 +1281,8 @@ static int imx_startup(struct uart_port *port) * In our iMX53 the average delay for the first reception dropped from * approximately 35000 microseconds to 1000 microseconds. */ - if (sport->dma_is_enabled) { - imx_disable_rx_int(sport); + if (sport->dma_is_enabled) start_rx_dma(sport); - } spin_unlock_irqrestore(&sport->port.lock, flags); -- cgit From 10f9e033c1e0e8563699b5839a2ff7f565dd72b2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 3 Nov 2017 15:30:54 +0100 Subject: serdev: document driver callbacks Amend the driver-callback kerneldoc with calling context and expected return values. Note that this is based on the requirements and characteristics of the tty-port controller implementation which receives data in workqueue context and whose write_wakeup callback must not sleep. Also note that while the receive_buf callback returns an integer, the returned value is still expected to be non-negative (and no greater than the buffer-size argument). Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- include/linux/serdev.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/serdev.h b/include/linux/serdev.h index 9929063bd45d..d7a9713e9883 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -27,8 +27,10 @@ struct serdev_device; /** * struct serdev_device_ops - Callback operations for a serdev device - * @receive_buf: Function called with data received from device. - * @write_wakeup: Function called when ready to transmit more data. + * @receive_buf: Function called with data received from device; + * returns number of bytes accepted; may sleep. + * @write_wakeup: Function called when ready to transmit more data; must + * not sleep. */ struct serdev_device_ops { int (*receive_buf)(struct serdev_device *, const unsigned char *, size_t); -- cgit From 51899a63b42ee01df676b0624df4e81a517c3571 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 3 Nov 2017 15:30:57 +0100 Subject: serdev: ttyport: release tty lock sooner on open Release the tty lock once tty-driver open returns to make it clear that it does not protect neither tty->termios or the serport flags. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/serdev-ttyport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index ce7ad0acee7a..f76a8e044e4e 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -104,6 +104,8 @@ static int ttyport_open(struct serdev_controller *ctrl) if (ret) goto err_close; + tty_unlock(serport->tty); + /* Bring the UART into a known 8 bits no parity hw fc state */ ktermios = tty->termios; ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | @@ -117,7 +119,6 @@ static int ttyport_open(struct serdev_controller *ctrl) set_bit(SERPORT_ACTIVE, &serport->flags); - tty_unlock(serport->tty); return 0; err_close: -- cgit From cda64188ca918fcddc8c6e89bbee5a38b029117a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 3 Nov 2017 15:30:58 +0100 Subject: serdev: ttyport: ignore carrier detect to avoid hangups Serdev currently does not support hangups so make sure to set CLOCAL to prevent loss of carrier from triggering one. Note however that not all tty drivers honour CLOCAL. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/serdev-ttyport.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index f76a8e044e4e..75f312ed96e8 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -115,6 +115,8 @@ static int ttyport_open(struct serdev_controller *ctrl) ktermios.c_cflag &= ~(CSIZE | PARENB); ktermios.c_cflag |= CS8; ktermios.c_cflag |= CRTSCTS; + /* Hangups are not supported so make sure to ignore carrier detect. */ + ktermios.c_cflag |= CLOCAL; tty_set_termios(tty, &ktermios); set_bit(SERPORT_ACTIVE, &serport->flags); -- cgit From 743f93f822be1b54f3f9bd53d13f02192e65ce0b Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 24 Nov 2017 23:26:40 +0100 Subject: serial: Make retrieval of rs485 properties platform-agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit ef838a81dd4d ("serial: Add common rs485 device tree parsing function") consolidated retrieval of rs485 OF properties in a common helper function but did not #ifdef it to CONFIG_OF. The function is therefore included on ACPI platforms as well even though it's not used. On the other hand ACPI platforms with rs485 do exist (e.g. Siemens IOT2040) and they may leverage _DSD to store rs485 properties. Likewise, UART platform devices instantiated from an MFD should be able to specify rs485 properties. In fact, the tty subsystem maintainer had asked for a "generic" function during review of commit ef838a81dd4d: https://marc.info/?l=linux-serial&m=150143441725194&w=4 Thus, instead of constraining the helper to OF platforms, make it platform-agnostic by converting it to device_property_*() functions and renaming it accordingly. In imx.c, move the invocation of uart_get_rs485_mode() from serial_imx_probe_dt() to serial_imx_probe() so that it also gets called for non-OF devices. In omap-serial.c, move its invocation further up within serial_omap_probe_rs485() so that the RTS polarity can be overridden with the driver-specific "rs485-rts-active-high" property once we introduce a generic "rs485-rts-active-low" property. Cc: Jan Kiszka Cc: Richard Genoud Cc: Sascha Hauer Signed-off-by: Lukas Wunner Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 2 +- drivers/tty/serial/fsl_lpuart.c | 2 +- drivers/tty/serial/imx.c | 4 ++-- drivers/tty/serial/omap-serial.c | 4 ++-- drivers/tty/serial/serial_core.c | 15 ++++++++------- include/linux/serial_core.h | 6 +----- 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index efa25611ca0c..df46a9e88c34 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2345,7 +2345,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, atmel_init_property(atmel_port, pdev); atmel_set_ops(port); - of_get_rs485_mode(pdev->dev.of_node, &port->rs485); + uart_get_rs485_mode(&pdev->dev, &port->rs485); port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 1c4d3f387138..38e76f95490e 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2206,7 +2206,7 @@ static int lpuart_probe(struct platform_device *pdev) if (ret) goto failed_attach_port; - of_get_rs485_mode(np, &sport->port.rs485); + uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX) { dev_err(&pdev->dev, "driver doesn't support RX during TX\n"); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 16311a24b483..aca3b7dbd09c 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1999,8 +1999,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "rts-gpios", NULL)) sport->have_rtsgpio = 1; - of_get_rs485_mode(np, &sport->port.rs485); - return 0; } #else @@ -2093,6 +2091,8 @@ static int serial_imx_probe(struct platform_device *pdev) return ret; } + uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); + /* Disable interrupts before requesting them */ reg = readl_relaxed(sport->port.membase + UCR1); reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 53d59e9b944a..227347548fff 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1611,6 +1611,8 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, if (!np) return 0; + uart_get_rs485_mode(up->dev, rs485conf); + if (of_property_read_bool(np, "rs485-rts-active-high")) rs485conf->flags |= SER_RS485_RTS_ON_SEND; else @@ -1632,8 +1634,6 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, up->rts_gpio = -EINVAL; } - of_get_rs485_mode(np, rs485conf); - return 0; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 854995e1cae7..a59184a7afb0 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3013,19 +3013,20 @@ EXPORT_SYMBOL(uart_add_one_port); EXPORT_SYMBOL(uart_remove_one_port); /** - * of_get_rs485_mode() - Implement parsing rs485 properties - * @np: uart node + * uart_get_rs485_mode() - retrieve rs485 properties for given uart + * @dev: uart device * @rs485conf: output parameter * * This function implements the device tree binding described in * Documentation/devicetree/bindings/serial/rs485.txt. */ -void of_get_rs485_mode(struct device_node *np, struct serial_rs485 *rs485conf) +void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf) { u32 rs485_delay[2]; int ret; - ret = of_property_read_u32_array(np, "rs485-rts-delay", rs485_delay, 2); + ret = device_property_read_u32_array(dev, "rs485-rts-delay", + rs485_delay, 2); if (!ret) { rs485conf->delay_rts_before_send = rs485_delay[0]; rs485conf->delay_rts_after_send = rs485_delay[1]; @@ -3040,13 +3041,13 @@ void of_get_rs485_mode(struct device_node *np, struct serial_rs485 *rs485conf) */ rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED); - if (of_property_read_bool(np, "rs485-rx-during-tx")) + if (device_property_read_bool(dev, "rs485-rx-during-tx")) rs485conf->flags |= SER_RS485_RX_DURING_TX; - if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) + if (device_property_read_bool(dev, "linux,rs485-enabled-at-boot-time")) rs485conf->flags |= SER_RS485_ENABLED; } -EXPORT_SYMBOL_GPL(of_get_rs485_mode); +EXPORT_SYMBOL_GPL(uart_get_rs485_mode); MODULE_DESCRIPTION("Serial driver core"); MODULE_LICENSE("GPL"); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 37b044e78333..b60b225c0a59 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -501,9 +501,5 @@ static inline int uart_handle_break(struct uart_port *port) (cflag) & CRTSCTS || \ !((cflag) & CLOCAL)) -/* - * Common device tree parsing helpers - */ -void of_get_rs485_mode(struct device_node *np, struct serial_rs485 *rs485conf); - +void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf); #endif /* LINUX_SERIAL_CORE_H */ -- cgit From 6abe9ea8a5a5904d935b8a482117a7fd9b25f09e Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 24 Nov 2017 23:26:40 +0100 Subject: dt-bindings: serial: Add common rs485 binding for RTS polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rs485 allows for robust half-duplex serial communication. It is often implemented by attaching an rs485 transceiver to a UART. The UART's RTS line is wired to the transceiver's Transmit Enable pin and determines whether the transceiver is sending or receiving. Examples for such transceivers are Maxim MAX13451E and TI SN65HVD1781A: https://datasheets.maximintegrated.com/en/ds/MAX13450E-MAX13451E.pdf http://www.ti.com/lit/ds/symlink/sn65hvd1781a-q1.pdf In the devicetree, the transceiver itself is not represented, only the UART is. A few rs485-specific dt-bindings already exist and these go into the UART's device node. This commit adds a binding to set the RTS polarity. Most (if not all) transceivers require the Transmit Enable pin be driven high for sending, but in some cases boards may negate the pin and RTS must then be driven low. Consequently the polarity defaults to active high but can be inverted with the newly added "rs485-rts-active-low" binding. Document this binding in rs485.txt and in the two drivers fsl-imx-uart and fsl-lpuart that are about to be amended with support for it. Curiously, the omap_serial driver defaults to active low and already supports an "rs485-rts-active-high" binding to invert the polarity. This is left unchanged to retain compatibility, but the binding is herewith documented. Cc: Mark Jackson Cc: Michał Oleszczyk Cc: Rafael Gago Castano Cc: Sascha Hauer Acked-by: Rob Herring Signed-off-by: Lukas Wunner Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/fsl-imx-uart.txt | 3 ++- Documentation/devicetree/bindings/serial/fsl-lpuart.txt | 3 ++- Documentation/devicetree/bindings/serial/omap_serial.txt | 1 + Documentation/devicetree/bindings/serial/rs485.txt | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt index 6b789f2ee879..afcfbc34e243 100644 --- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt @@ -8,7 +8,8 @@ Required properties: Optional properties: - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works in DCE mode by default. -- rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt +- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx, + linux,rs485-enabled-at-boot-time: see rs485.txt Please check Documentation/devicetree/bindings/serial/serial.txt for the complete list of generic properties. diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt index 59567b51cf09..6bd3f2e93d61 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt @@ -16,7 +16,8 @@ Required properties: Optional properties: - dmas: A list of two dma specifiers, one for each entry in dma-names. - dma-names: should contain "tx" and "rx". -- rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt +- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx, + linux,rs485-enabled-at-boot-time: see rs485.txt Note: Optional properties for DMA support. Write them both or both not. diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index 43eac675f21f..4b0f05adb228 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -20,6 +20,7 @@ Optional properties: node and a DMA channel number. - dma-names : "rx" for receive channel, "tx" for transmit channel. - rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt +- rs485-rts-active-high: drive RTS high when sending (default is low). Example: diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt index b8415936dfdb..b7c29f74ebb2 100644 --- a/Documentation/devicetree/bindings/serial/rs485.txt +++ b/Documentation/devicetree/bindings/serial/rs485.txt @@ -12,6 +12,7 @@ Optional properties: * b is the delay between end of data sent and rts signal in milliseconds it corresponds to the delay after sending data and actual release of the line. If this property is not specified, <0 0> is assumed. +- rs485-rts-active-low: drive RTS low when sending (default is high). - linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485 feature at boot time. It can be disabled later with proper ioctl. - rs485-rx-during-tx: empty property that enables the receiving of data even -- cgit From f1e5b618c1c26cb8b5818e36f996e8c2fbedbeb7 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 24 Nov 2017 23:26:40 +0100 Subject: serial: core: Support common rs485 binding for RTS polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a driver invokes the uart_get_rs485_mode() helper, set the RTS polarity to active high by default unless the newly introduced "rs485-rts-active-low" property was specified. imx contains a line to set the default RTS polarity to active high, it is now superfluous and hence deleted. omap-serial historically defaults to active low and supports an "rs485-rts-active-high" property to inverse the polarity. Retain that behavior for compatibility. Cc: Mark Jackson Cc: Michał Oleszczyk Cc: Rafael Gago Castano Cc: Sascha Hauer Signed-off-by: Lukas Wunner Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 1 - drivers/tty/serial/omap-serial.c | 7 +++++-- drivers/tty/serial/serial_core.c | 13 ++++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index aca3b7dbd09c..d2c7d88d5774 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2060,7 +2060,6 @@ static int serial_imx_probe(struct platform_device *pdev) sport->port.fifosize = 32; sport->port.ops = &imx_pops; sport->port.rs485_config = imx_rs485_config; - sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND; sport->port.flags = UPF_BOOT_AUTOCONF; timer_setup(&sport->timer, imx_timeout, 0); diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 227347548fff..56e683373d6d 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1613,10 +1613,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, uart_get_rs485_mode(up->dev, rs485conf); - if (of_property_read_bool(np, "rs485-rts-active-high")) + if (of_property_read_bool(np, "rs485-rts-active-high")) { rs485conf->flags |= SER_RS485_RTS_ON_SEND; - else + rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + rs485conf->flags &= ~SER_RS485_RTS_ON_SEND; rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } /* check for tx enable gpio */ up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a59184a7afb0..f57969de2f1c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3036,16 +3036,23 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf) } /* - * clear full-duplex and enabled flags to get to a defined state with - * the two following properties. + * Clear full-duplex and enabled flags, set RTS polarity to active high + * to get to a defined state with the following properties: */ - rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED); + rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED | + SER_RS485_RTS_AFTER_SEND); + rs485conf->flags |= SER_RS485_RTS_ON_SEND; if (device_property_read_bool(dev, "rs485-rx-during-tx")) rs485conf->flags |= SER_RS485_RX_DURING_TX; if (device_property_read_bool(dev, "linux,rs485-enabled-at-boot-time")) rs485conf->flags |= SER_RS485_ENABLED; + + if (device_property_read_bool(dev, "rs485-rts-active-low")) { + rs485conf->flags &= ~SER_RS485_RTS_ON_SEND; + rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } } EXPORT_SYMBOL_GPL(uart_get_rs485_mode); -- cgit From 01d845352a81df133234a106f34cc93937dcb7bd Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 24 Nov 2017 23:26:40 +0100 Subject: serial: fsl_lpuart: Support common rs485 binding for RTS polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invoke the ->rs485_config callback on probe to set UARTMODEM_TXRTSPOL appropriately based on the UART's device properties. This implicitly sets UARTMODEM_TXRTSE if rs485 was enabled in the device properties, so drop the identical code from lpuart_probe(). It also fixes a bug: If an unsupported rs485 property was specified (rs485-rx-during-tx or rs485-rts-delay), the driver returns -ENOSYS without performing any cleanup, in particular without calling uart_remove_one_port() or clk_disable_unprepare(), thus leaking the uart_port. But with the invocation of ->rs485_config, the unsupported properties are now cleared in struct serial_rs485 and thus ignored. It therefore seems sufficient to just log an error instead of bailing out. Cc: Sascha Hauer Signed-off-by: Lukas Wunner Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 38e76f95490e..8cf112f2efc3 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2208,21 +2208,14 @@ static int lpuart_probe(struct platform_device *pdev) uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); - if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX) { + if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX) dev_err(&pdev->dev, "driver doesn't support RX during TX\n"); - return -ENOSYS; - } if (sport->port.rs485.delay_rts_before_send || - sport->port.rs485.delay_rts_after_send) { + sport->port.rs485.delay_rts_after_send) dev_err(&pdev->dev, "driver doesn't support RTS delays\n"); - return -ENOSYS; - } - if (sport->port.rs485.flags & SER_RS485_ENABLED) { - sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND; - writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM); - } + lpuart_config_rs485(&sport->port, &sport->port.rs485); sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx"); if (!sport->dma_tx_chan) -- cgit From b8f3bff057b017309fbd61fe74712b1f185b5399 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 24 Nov 2017 23:26:40 +0100 Subject: serial: imx: Support common rs485 binding for RTS polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invoke the ->rs485_config callback on probe to adjust the initial RTS polarity based on the UART's device properties. This implicitly fixes a bug: If RTS control is not available, rs485 should be disabled even if it was enabled through a device property. Log an error when that occurs. Cc: Sascha Hauer Signed-off-by: Lukas Wunner Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d2c7d88d5774..c2b29fd66e8a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2092,6 +2092,12 @@ static int serial_imx_probe(struct platform_device *pdev) uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); + if (sport->port.rs485.flags & SER_RS485_ENABLED && + (!sport->have_rtscts || !sport->have_rtsgpio)) + dev_err(&pdev->dev, "no RTS control, disabling rs485\n"); + + imx_rs485_config(&sport->port, &sport->port.rs485); + /* Disable interrupts before requesting them */ reg = readl_relaxed(sport->port.membase + UCR1); reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | -- cgit From 1598e38c0770b08c4d6371b670f9ee61a42ec68b Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 12 Dec 2017 09:08:35 +0100 Subject: serial: forbid 8250 on s390 Using "make kvmconfig" results in a potentially unusable linux image on s390. The reason is that both the (default on s390) sclp consoles as well as the 8250 console register a ttyS as console. Since there will be no 8250 on s390 let's fence 8250. This will ensure that there is always a working sclp console. Reported-by: Alice Frosi Signed-off-by: Christian Borntraeger Reviewed-by: Hendrik Brueckner Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index a5c0ef1e7695..16b1496e6105 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -5,6 +5,7 @@ config SERIAL_8250 tristate "8250/16550 and compatible serial support" + depends on !S390 select SERIAL_CORE ---help--- This selects whether you want to include the driver for the standard -- cgit From f6731485a51978ca0931c787fcb8a0bc4dcc9303 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 30 Nov 2017 14:11:58 +0100 Subject: tty: serial: sh-sci: Hide number of ports config question Auto-configure the maximum number of serial ports based on how many can be present on the architecture: - 3 on H8/300, - 10 on SuperH, - 18 on Reneas ARM. The default can still be overridden if CONFIG_EXPERT is enabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b788fee54249..bd96046d7f94 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -761,9 +761,11 @@ config SERIAL_SH_SCI select SERIAL_MCTRL_GPIO if GPIOLIB config SERIAL_SH_SCI_NR_UARTS - int "Maximum number of SCI(F) serial ports" + int "Maximum number of SCI(F) serial ports" if EXPERT depends on SERIAL_SH_SCI - default "2" + default "3" if H8300 + default "10" if SUPERH + default "18" if ARCH_RENESAS config SERIAL_SH_SCI_CONSOLE bool "Support for console on SuperH SCI(F)" -- cgit From c5bb576d5e21e91a6380b8dd927ee4ceadbc23d5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 30 Nov 2017 14:11:59 +0100 Subject: tty: serial: sh-sci: Hide serial console config question Most users will want to use a serial console. Hence make that the default, unless CONFIG_EXPERT is enabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index bd96046d7f94..0c75562d620f 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -768,9 +768,10 @@ config SERIAL_SH_SCI_NR_UARTS default "18" if ARCH_RENESAS config SERIAL_SH_SCI_CONSOLE - bool "Support for console on SuperH SCI(F)" + bool "Support for console on SuperH SCI(F)" if EXPERT depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE + default y config SERIAL_SH_SCI_EARLYCON bool "Support for early console on SuperH SCI(F)" -- cgit From 3a987e7354eae9c1a0a298bc523647aa421149e5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 30 Nov 2017 14:12:00 +0100 Subject: tty: serial: sh-sci: Hide earlycon config question Renesas H8/300 and ARM platforms use DT and support earlycon, so most users want earlycon support to be enabled. On SuperH platforms, earlycon is not yet supported. Hence follow the above rationale to configure the default, unless CONFIG_EXPERT is enabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 0c75562d620f..952a2c6a9da0 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -774,10 +774,11 @@ config SERIAL_SH_SCI_CONSOLE default y config SERIAL_SH_SCI_EARLYCON - bool "Support for early console on SuperH SCI(F)" + bool "Support for early console on SuperH SCI(F)" if EXPERT depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON + default ARCH_RENESAS || H8300 config SERIAL_SH_SCI_DMA bool "DMA support" -- cgit From be7e251d20e6c800b3b9ee79d1da6059438c34f8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 30 Nov 2017 14:12:01 +0100 Subject: tty: serial: sh-sci: Hide DMA config question On most Renesas ARM platforms, the SCIF serial ports can be used with DMA, so most users will want DMA support to be enabled. On SuperH platforms, SCI(F) serial ports cannot be used with DMA yet (see also commit 219fb0c1436e4893 ("serial: sh-sci: Remove the platform data dma slave rx/tx channel IDs")), so users will want it disabled to reduce kernel size. Hence follow the above rationale to configure the default, unless CONFIG_EXPERT is enabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 952a2c6a9da0..4e6dfb0a762b 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -781,8 +781,9 @@ config SERIAL_SH_SCI_EARLYCON default ARCH_RENESAS || H8300 config SERIAL_SH_SCI_DMA - bool "DMA support" + bool "DMA support" if EXPERT depends on SERIAL_SH_SCI && DMA_ENGINE + default ARCH_RENESAS config SERIAL_PNX8XXX bool "Enable PNX8XXX SoCs' UART Support" -- cgit From fe8e7acea2426dcd1130fd5c9710b74217c90dd0 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Tue, 12 Dec 2017 21:24:56 +0800 Subject: tty/isicom: Fix a possible sleep-in-atomic bug in WaitTillCardIsFree The driver may sleep under a spinlock. The function call paths are: isicom_activate (acquire the spinlock) isicom_setup_board drop_dtr_rts WaitTillCardIsFree msleep --> may sleep isicom_set_termios isicom_config_port drop_dtr WaitTillCardIsFree msleep --> may sleep isicom_tiocmset drop_dtr WaitTillCardIsFree msleep --> may sleep Though "in_atomic" is used to check atomic context, but it is not recommended to use in driver code (see include/linux/preempt.h). To fix it, only using mdelay instead. This bug is found by my static analysis tool(DSAC) and checked by my code review. Signed-off-by: Jia-Ju Bai Signed-off-by: Greg Kroah-Hartman --- drivers/tty/isicom.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 015686ff4825..bdd3027ef01b 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -219,13 +219,9 @@ static struct isi_port isi_ports[PORT_COUNT]; static int WaitTillCardIsFree(unsigned long base) { unsigned int count = 0; - unsigned int a = in_atomic(); /* do we run under spinlock? */ while (!(inw(base + 0xe) & 0x1) && count++ < 100) - if (a) - mdelay(1); - else - msleep(1); + mdelay(1); return !(inw(base + 0xe) & 0x1); } -- cgit From 0858fe3c9c8bf0e4a73da7b2759950ee75ed8995 Mon Sep 17 00:00:00 2001 From: Ludovic Barre Date: Fri, 1 Dec 2017 17:36:51 +0100 Subject: serial: stm32: fix name conflict with 8250 This patch replaces stm32 tty name ttyS by ttySTM to avoid a name conflict when Serial: 8250/16550 driver is activated. sysfs: cannot create duplicate filename '/class/tty/ttyS3' Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.0-12903-gb392521-dirty #1 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x90/0xa4) [] (dump_stack) from [] (__warn+0xf8/0x110) [] (__warn) from [] (warn_slowpath_fmt+0x38/0x48) [] (warn_slowpath_fmt) from [] (sysfs_warn_dup+0x68/0x78) [] (sysfs_warn_dup) from [] (sysfs_do_create_link_sd+0xb4/0xc4) [] (sysfs_do_create_link_sd) from [] (device_add+0x204/0x574) [] (device_add) from [] (tty_register_device_attr+0xc8/0x1bc) [] (tty_register_device_attr) from [] (uart_add_one_port+0x22c/0x4f4) Signed-off-by: Ludovic Barre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 8a5ff54d0f42..2294d0f05872 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -236,7 +236,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_ICR_CMCF BIT(17) /* F7 */ #define USART_ICR_WUCF BIT(20) /* H7 */ -#define STM32_SERIAL_NAME "ttyS" +#define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 #define RX_BUF_L 200 /* dma rx buffer length */ -- cgit From 8af016aa5a27c6a2505460eb4d83f1e70c38dc43 Mon Sep 17 00:00:00 2001 From: Stefan Potyra Date: Wed, 6 Dec 2017 16:46:12 +0100 Subject: serial: 8250_dw: Disable clock on error If there is no clock rate for uartclk defined, disable the previously enabled clock again. Found by Linux Driver Verification project (linuxtesting.org). Fixes: 23f5b3fdd04e serial: 8250_dw: only get the clock rate in one place Signed-off-by: Stefan Potyra Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5bb0c42c88dd..bda75d317d24 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -515,7 +515,8 @@ static int dw8250_probe(struct platform_device *pdev) /* If no clock rate is defined, fail. */ if (!p->uartclk) { dev_err(dev, "clock rate not defined\n"); - return -EINVAL; + err = -EINVAL; + goto err_clk; } data->pclk = devm_clk_get(dev, "apb_pclk"); -- cgit From 93ad86735d68c6809566a6091a170dc6edf5875a Mon Sep 17 00:00:00 2001 From: Rolf Evers-Fischer Date: Wed, 6 Dec 2017 16:52:23 +0100 Subject: serial: 8250: 8250_omap: Fix spelling error. Fixed a spelling error in a comment. Signed-off-by: Rolf Evers-Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index bd40ba402410..57f6eba47f44 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -414,7 +414,7 @@ static void omap_8250_set_termios(struct uart_port *port, /* Up to here it was mostly serial8250_do_set_termios() */ /* - * We enable TRIG_GRANU for RX and TX and additionaly we set + * We enable TRIG_GRANU for RX and TX and additionally we set * SCR_TX_EMPTY bit. The result is the following: * - RX_TRIGGER amount of bytes in the FIFO will cause an interrupt. * - less than RX_TRIGGER number of bytes will also cause an interrupt -- cgit From 6a28fd2bbc94bfca105632e5ef8a9dbe63ba0b39 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 30 Nov 2017 09:16:31 +0100 Subject: tty: goldfish: Enable 'earlycon' only if built-in Commit 3840ed9548f7 ("tty: goldfish: Implement support for kernel 'earlycon' parameter") breaks an allmodconfig config on x86: | LD vmlinux.o | MODPOST vmlinux.o |drivers/tty/serial/earlycon.o: In function `parse_options': |drivers/tty/serial/earlycon.c:97: undefined reference to `uart_parse_earlycon' |Makefile:1005: recipe for target 'vmlinux' failed earlycon.c::parse_options() invokes uart_parse_earlycon() from serial_core.c which is compiled=m because GOLDFISH_TTY itself (and most others) are =m. To avoid that, I'm adding the _CONSOLE config option which is selected if the GOLDFISH module itself is =y since it doesn't need the early bits for the =m case (other drivers do the same dance). The alternative would be to move uart_parse_earlycon() from serial_core.c to earlycon.c (we don't have that many users of that function). Fixes: 3840ed9548f7 ("tty: goldfish: Implement support for kernel 'earlycon' parameter") Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: Miodrag Dinic Acked-by: Miodrag Dinic Signed-off-by: Greg Kroah-Hartman --- drivers/tty/Kconfig | 6 +++++- drivers/tty/goldfish.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index cc2b4d9433ed..b811442c5ce6 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -394,10 +394,14 @@ config GOLDFISH_TTY depends on GOLDFISH select SERIAL_CORE select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON help Console and system TTY driver for the Goldfish virtual platform. +config GOLDFISH_TTY_EARLY_CONSOLE + bool + default y if GOLDFISH_TTY=y + select SERIAL_EARLYCON + config DA_TTY bool "DA TTY" depends on METAG_DA diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 7f657bb5113c..1c1bd0afcd48 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -433,6 +433,7 @@ static int goldfish_tty_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE static void gf_early_console_putchar(struct uart_port *port, int ch) { __raw_writel(ch, port->membase); @@ -456,6 +457,7 @@ static int __init gf_earlycon_setup(struct earlycon_device *device, } OF_EARLYCON_DECLARE(early_gf_tty, "google,goldfish-tty", gf_earlycon_setup); +#endif static const struct of_device_id goldfish_tty_of_match[] = { { .compatible = "google,goldfish-tty", }, -- cgit From 5c3055393f5fdd0bdc4b69b1fb362b1c3f4266b4 Mon Sep 17 00:00:00 2001 From: Branislav Radocaj Date: Thu, 7 Dec 2017 14:11:47 +0100 Subject: tty: serial: mxs-auart: fix error handling in mxs_auart_probe If uart_add_one_port() fails in mxs_auart_probe, the clks has to be disabled.Two clks are previously enabled in mxs_get_clks(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Branislav Radocaj Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mxs-auart.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index efb4fd3784ed..5b470406bf9d 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1721,7 +1721,7 @@ static int mxs_auart_probe(struct platform_device *pdev) ret = uart_add_one_port(&auart_driver, &s->port); if (ret) - goto out_free_gpio_irq; + goto out_disable_clks_free_qpio_irq; /* ASM9260 don't have version reg */ if (is_asm9260_auart(s)) { @@ -1735,7 +1735,11 @@ static int mxs_auart_probe(struct platform_device *pdev) return 0; -out_free_gpio_irq: +out_disable_clks_free_qpio_irq: + if (s->clk) + clk_disable_unprepare(s->clk_ahb); + if (s->clk_ahb) + clk_disable_unprepare(s->clk_ahb); mxs_auart_free_gpio_irq(s); auart_port[pdev->id] = NULL; return ret; -- cgit From d160c34134782dbd9b0dc06664d2f283c19f0dfa Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 7 Dec 2017 11:12:59 +0100 Subject: dt-bindings: mvebu-uart: update documentation with extended UART Update the device tree binding documentation for the Marvell EBU UART, in order to allow describing the extended UART IP block, in addition to the already supported standard UART IP. This requires adding a new compatible string, the introduction of a clocks property, and extensions to the interrupts property. Signed-off-by: Miquel Raynal Reviewed-by: Gregory CLEMENT Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/mvebu-uart.txt | 50 +++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt index d37fabe17bd1..2ae2fee7e023 100644 --- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt +++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt @@ -1,13 +1,53 @@ -* Marvell UART : Non standard UART used in some of Marvell EBU SoCs (e.g., Armada-3700) +* Marvell UART : Non standard UART used in some of Marvell EBU SoCs + e.g., Armada-3700. Required properties: -- compatible: "marvell,armada-3700-uart" +- compatible: + - "marvell,armada-3700-uart" for the standard variant of the UART + (32 bytes FIFO, no DMA, level interrupts, 8-bit access to the + FIFO, baudrate limited to 230400). + - "marvell,armada-3700-uart-ext" for the extended variant of the + UART (128 bytes FIFO, DMA, front interrupts, 8-bit or 32-bit + accesses to the FIFO, baudrate unlimited by the dividers). - reg: offset and length of the register set for the device. -- interrupts: device interrupt +- clocks: UART reference clock used to derive the baudrate. If no clock + is provided (possible only with the "marvell,armada-3700-uart" + compatible string for backward compatibility), it will only work + if the baudrate was initialized by the bootloader and no baudrate + change will then be possible. +- interrupts: + - Must contain three elements for the standard variant of the IP + (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx", + respectively the UART sum interrupt, the UART TX interrupt and + UART RX interrupt. A corresponding interrupt-names property must + be defined. + - Must contain two elements for the extended variant of the IP + (marvell,armada-3700-uart-ext): "uart-tx" and "uart-rx", + respectively the UART TX interrupt and the UART RX interrupt. A + corresponding interrupts-names property must be defined. + - For backward compatibility reasons, a single element interrupts + property is also supported for the standard variant of the IP, + containing only the UART sum interrupt. This form is deprecated + and should no longer be used. Example: - serial@12000 { + uart0: serial@12000 { compatible = "marvell,armada-3700-uart"; reg = <0x12000 0x200>; - interrupts = <43>; + clocks = <&xtalclk>; + interrupts = + , + , + ; + interrupt-names = "uart-sum", "uart-tx", "uart-rx"; + }; + + uart1: serial@12200 { + compatible = "marvell,armada-3700-uart-ext"; + reg = <0x12200 0x30>; + clocks = <&xtalclk>; + interrupts = + , + ; + interrupt-names = "uart-tx", "uart-rx"; }; -- cgit From 38d5583ff8900c543322a74471b436d1b8b4018a Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Fri, 8 Dec 2017 20:36:29 +0100 Subject: serial: max310x: Fix invalid memory access during GPIO init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `max310x_spi_probe` function attempted to setup the GPIO bits before the corresponding structs for each serial port were initialized. If the DTS file specified a GPIO hog, this led to a crash because the GPIO stack ended up calling `max310x_gpio_direction_output` which referenced uninitialized memory: [] (max310x_gpio_direction_output) from [] (_gpiod_direction_output_raw+0x94/0x2d4) [] (_gpiod_direction_output_raw) from [] (gpiod_hog+0x6c/0x154) [] (gpiod_hog) from [] (of_gpiochip_add+0x28c/0x444) [] (of_gpiochip_add) from [] (gpiochip_add_data+0x4f8/0x760) [] (gpiochip_add_data) from [] (devm_gpiochip_add_data+0x40/0x7c) [] (devm_gpiochip_add_data) from [] (max310x_spi_probe+0x530/0x894) [] (max310x_spi_probe) from [] (spi_drv_probe+0x7c/0xac) [] (spi_drv_probe) from [] (driver_probe_device+0x234/0x2e8) [] (driver_probe_device) from [] (bus_for_each_drv+0x60/0x94) [] (bus_for_each_drv) from [] (__device_attach+0xb0/0x114) [] (__device_attach) from [] (bus_probe_device+0x84/0x8c) [] (bus_probe_device) from [] (device_add+0x3f4/0x580) [] (device_add) from [] (spi_add_device+0x9c/0x134) [] (spi_add_device) from [] (spi_register_controller+0x484/0x910) [] (spi_register_controller) from [] (orion_spi_probe+0x2f4/0x3b4) [] (orion_spi_probe) from [] (platform_drv_probe+0x50/0xb0) [] (platform_drv_probe) from [] (driver_probe_device+0x234/0x2e8) [] (driver_probe_device) from [] (__driver_attach+0xb8/0xbc) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x104/0x210) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (do_one_initcall+0x44/0x168) [] (do_one_initcall) from [] (kernel_init_freeable+0x140/0x1cc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x108) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) This can be easily fixed by moving the corresponding code below. And because the UARTs are already there by the time we reach this point, the `goto` needs changing so that more stuff is freed. (I have not tested this error path.) Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ecb6513a6505..8971828d1f21 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1169,23 +1169,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, uartclk = max310x_set_ref_clk(s, freq, xtal); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); -#ifdef CONFIG_GPIOLIB - /* Setup GPIO cotroller */ - s->gpio.owner = THIS_MODULE; - s->gpio.parent = dev; - s->gpio.label = dev_name(dev); - s->gpio.direction_input = max310x_gpio_direction_input; - s->gpio.get = max310x_gpio_get; - s->gpio.direction_output= max310x_gpio_direction_output; - s->gpio.set = max310x_gpio_set; - s->gpio.base = -1; - s->gpio.ngpio = devtype->nr * 4; - s->gpio.can_sleep = 1; - ret = devm_gpiochip_add_data(dev, &s->gpio, s); - if (ret) - goto out_clk; -#endif - mutex_init(&s->mutex); for (i = 0; i < devtype->nr; i++) { @@ -1237,6 +1220,23 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, devtype->power(&s->p[i].port, 0); } +#ifdef CONFIG_GPIOLIB + /* Setup GPIO cotroller */ + s->gpio.owner = THIS_MODULE; + s->gpio.parent = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = max310x_gpio_direction_input; + s->gpio.get = max310x_gpio_get; + s->gpio.direction_output= max310x_gpio_direction_output; + s->gpio.set = max310x_gpio_set; + s->gpio.base = -1; + s->gpio.ngpio = devtype->nr * 4; + s->gpio.can_sleep = 1; + ret = devm_gpiochip_add_data(dev, &s->gpio, s); + if (ret) + goto out_uart; +#endif + /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, IRQF_ONESHOT | flags, dev_name(dev), s); -- cgit From 19ac50f655373c45f3cb548f510510282186a3dd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 18 Dec 2017 09:50:57 +0100 Subject: tty: serial: sh-sci: Add default for number of ports for compile-testing When compile-testing an allmodconfig kernel for a platform without sh-sci serial ports, the SERIAL_SH_SCI_NR_UARTS symbol of type "int" doesn't get assigned a numerical default value, but an empty string, leading to a build failure: .config:3814:warning: symbol value '' invalid for SERIAL_SH_SCI_NR_UARTS ... make[3]: *** [silentoldconfig] Error 1 Fix this by explicitly providing a default value of 2, like before. Reported-by: kbuild test robot Fixes: f6731485a51978ca ("tty: serial: sh-sci: Hide number of ports config question") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 4e6dfb0a762b..3682fd3e960c 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -766,6 +766,7 @@ config SERIAL_SH_SCI_NR_UARTS default "3" if H8300 default "10" if SUPERH default "18" if ARCH_RENESAS + default "2" config SERIAL_SH_SCI_CONSOLE bool "Support for console on SuperH SCI(F)" if EXPERT -- cgit From afe3eb60fa82a5d812378530b50755f58acc029c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 18 Dec 2017 12:00:19 +0100 Subject: serdev: ttyport: do not used keyed wakeup in write_wakeup Serdev does not use the file abstraction and specifically there will never be anyone polling a file descriptor for POLLOUT events. Just use plain wake_up_interruptible() in the write_wakeup callback and document why it's there. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/serdev-ttyport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index c2629ab1bbcf..a5abb05be67d 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -59,7 +59,8 @@ static void ttyport_write_wakeup(struct tty_port *port) test_bit(SERPORT_ACTIVE, &serport->flags)) serdev_controller_write_wakeup(ctrl); - wake_up_interruptible_poll(&tty->write_wait, POLLOUT); + /* Wake up any tty_wait_until_sent() */ + wake_up_interruptible(&tty->write_wait); tty_kref_put(tty); } -- cgit From 793ae04c46cf054a6342671de3fabb1b5131a880 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 15 Dec 2017 13:42:04 +0000 Subject: nvmem: meson-mx-efuse: fix reading from an offset other than 0 meson_mx_efuse_read calculates the address internal to the eFuse based on the offset and the word size. This works fine with any given offset. However, the offset is also included when writing to the output buffer. This means that reading 4 bytes at offset 500 tries to write beyond the array allocated by the nvmem core as it wants to write the 4 bytes to "buffer address + offset (500)". This issue did not show up in the previous tests since no driver uses any value from the eFuse yet and reading the eFuse via sysfs simply reads the whole eFuse, starting at offset 0. Fix this by only including the offset in the internal address calculation. Fixes: 8caef1fa9176 ("nvmem: add a driver for the Amlogic Meson6/Meson8/Meson8b SoCs") Signed-off-by: Martin Blumenstingl Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/meson-mx-efuse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/meson-mx-efuse.c b/drivers/nvmem/meson-mx-efuse.c index a346b4923550..41d3a3c1104e 100644 --- a/drivers/nvmem/meson-mx-efuse.c +++ b/drivers/nvmem/meson-mx-efuse.c @@ -156,8 +156,8 @@ static int meson_mx_efuse_read(void *context, unsigned int offset, MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE, MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE); - for (i = offset; i < offset + bytes; i += efuse->config.word_size) { - addr = i / efuse->config.word_size; + for (i = 0; i < bytes; i += efuse->config.word_size) { + addr = (offset + i) / efuse->config.word_size; err = meson_mx_efuse_read_addr(efuse, addr, &tmp); if (err) -- cgit From bceb483972cf6f4904aa563cd6f292a1f4c7a565 Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Fri, 8 Dec 2017 22:41:35 +0100 Subject: serial: max310x: Do not hard-code the IRQ type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As suggested by Russell King, a driver should not really care about bits such as the interrupt polarity or whether it is edge- or level- triggered. The reasons for that include: - an upstream IRQ controller which cannot support edge- or level-triggered interrupts, - board design with a built-in inverter The interrupt type is being already specified by the Device Tree, anyway. Other drivers (gpio/gpio-tc3589x.c for example) already work in this way, delegating the proper IRQ line setup to the DT and not specifying anything by hand. Also, there's no reason to have the IRQ flags split between two places. The SPI probing is the only entry point anyway. Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 8971828d1f21..828a2853bd4a 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1089,7 +1089,7 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, #endif static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, - struct regmap *regmap, int irq, unsigned long flags) + struct regmap *regmap, int irq) { int i, ret, fmin, fmax, freq, uartclk; struct clk *clk_osc, *clk_xtal; @@ -1239,7 +1239,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, - IRQF_ONESHOT | flags, dev_name(dev), s); + IRQF_ONESHOT, dev_name(dev), s); if (!ret) return 0; @@ -1304,7 +1304,6 @@ static struct regmap_config regcfg = { static int max310x_spi_probe(struct spi_device *spi) { struct max310x_devtype *devtype; - unsigned long flags = 0; struct regmap *regmap; int ret; @@ -1327,11 +1326,10 @@ static int max310x_spi_probe(struct spi_device *spi) devtype = (struct max310x_devtype *)id_entry->driver_data; } - flags = IRQF_TRIGGER_FALLING; regcfg.max_register = devtype->nr * 0x20 - 1; regmap = devm_regmap_init_spi(spi, ®cfg); - return max310x_probe(&spi->dev, devtype, regmap, spi->irq, flags); + return max310x_probe(&spi->dev, devtype, regmap, spi->irq); } static int max310x_spi_remove(struct spi_device *spi) -- cgit From 80313586356c8a06cc969724dea1cc58d2a04d99 Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Tue, 12 Dec 2017 16:15:21 +0100 Subject: serial: max310x: Use level-triggered interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I was getting this trace along with a disabled IRQ when I was generating heavy traffic over four daisy-chained UARTs (MAX14830) on my test kit (Marvell Armada AM388, Solidrun Clearfog Base): irq 51: nobody cared (try booting with the "irqpoll" option) CPU: 0 PID: 68 Comm: irq/51-spi1.2 Not tainted 4.14.4 #7 Hardware name: Marvell Armada 380/385 (Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x84/0x98) [] (dump_stack) from [] (__report_bad_irq+0x28/0xcc) [] (__report_bad_irq) from [] (note_interrupt+0x28c/0x2dc) [] (note_interrupt) from [] (handle_irq_event_percpu+0x4c/0x58) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x44/0x68) [] (handle_irq_event) from [] (handle_edge_irq+0x12c/0x1dc) [] (handle_edge_irq) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (mvebu_gpio_irq_handler+0xe0/0x184) [] (mvebu_gpio_irq_handler) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (__handle_domain_irq+0x5c/0xb4) [] (__handle_domain_irq) from [] (gic_handle_irq+0x4c/0x90) [] (gic_handle_irq) from [] (__irq_svc+0x6c/0x90) Exception stack(0xeea77c30 to 0xeea77c78) 7c20: 0000000a 018cba80 0000000a f098f680 7c40: 0000020a f098f680 00000008 0000020a 018cba80 00000001 ee9302a0 eea76000 7c60: ef2b2640 eea77c80 c050687c c0506894 80070013 ffffffff [] (__irq_svc) from [] (orion_spi_setup_transfer+0x118/0x20c) [] (orion_spi_setup_transfer) from [] (orion_spi_transfer_one+0x1c/0x26c) [] (orion_spi_transfer_one) from [] (spi_transfer_one_message+0xec/0x500) [] (spi_transfer_one_message) from [] (__spi_pump_messages+0x3f4/0x680) [] (__spi_pump_messages) from [] (__spi_sync+0x1fc/0x200) [] (__spi_sync) from [] (spi_sync+0x24/0x3c) [] (spi_sync) from [] (spi_write_then_read+0xd0/0x17c) [] (spi_write_then_read) from [] (_regmap_raw_read+0xb0/0x250) [] (_regmap_raw_read) from [] (_regmap_bus_read+0x24/0x4c) [] (_regmap_bus_read) from [] (_regmap_read+0x60/0x148) [] (_regmap_read) from [] (regmap_read+0x3c/0x5c) [] (regmap_read) from [] (max310x_port_irq+0x104/0x2dc) [] (max310x_port_irq) from [] (max310x_ist+0x68/0xc0) [] (max310x_ist) from [] (irq_thread_fn+0x1c/0x54) [] (irq_thread_fn) from [] (irq_thread+0x12c/0x1f0) [] (irq_thread) from [] (kthread+0x128/0x158) [] (kthread) from [] (ret_from_fork+0x14/0x24) handlers: [] irq_default_primary_handler threaded [] max310x_ist Disabling IRQ #51 On a multi-UART max310x, each UART has its own interrupt status register which automatically de-asserts the IRQ line upon read. (There are also top-level IRQ indicator registers which are not clear-on-read, but they are not relevant here.) It was quite possible to receive a pending IRQ for, e.g., UART0, enter the threaded IRQ handler, clear the ISR for UART0 which de-asserts the IRQ line, and then race with another event on the same chip, but a different UART channel. That resulted in another edge on the shared-within-the-chip IRQ line which got intercepted by the kernel. That all led to an edge-level interrupt which was not being handled by anybody because our threaded handler hasn't finished yet. As the chip actually uses *level* triggered IRQs, let's convert the example DT bindings to these. Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/maxim,max310x.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.txt b/Documentation/devicetree/bindings/serial/maxim,max310x.txt index 83a919c241b0..0c58052a18bb 100644 --- a/Documentation/devicetree/bindings/serial/maxim,max310x.txt +++ b/Documentation/devicetree/bindings/serial/maxim,max310x.txt @@ -30,7 +30,7 @@ Example: clocks = <&clk20m>; clock-names = "osc"; interrupt-parent = <&gpio3>; - interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; }; -- cgit From 78be70c8243ae6bfe8ca642dd19b2b411d4b466f Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Tue, 12 Dec 2017 16:17:59 +0100 Subject: serial: max310x: Support IRQ sharing with other devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to my chip's datasheet [1], the IRQ output is an open collector pin which is suitable for sharing with other chips. The chip also has a register which indicates which UART performed a change and the driver checks that register already, so we have everything what is needed to effectively share the IRQ GPIO. [1] https://datasheets.maximintegrated.com/en/ds/MAX14830.pdf Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 828a2853bd4a..9e4e70f864ea 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -685,9 +685,10 @@ static void max310x_handle_tx(struct uart_port *port) uart_write_wakeup(port); } -static void max310x_port_irq(struct max310x_port *s, int portno) +static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno) { struct uart_port *port = &s->p[portno].port; + irqreturn_t res = IRQ_NONE; do { unsigned int ists, lsr, rxlen; @@ -698,6 +699,8 @@ static void max310x_port_irq(struct max310x_port *s, int portno) if (!ists && !rxlen) break; + res = IRQ_HANDLED; + if (ists & MAX310X_IRQ_CTS_BIT) { lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); uart_handle_cts_change(port, @@ -711,11 +714,13 @@ static void max310x_port_irq(struct max310x_port *s, int portno) mutex_unlock(&s->mutex); } } while (1); + return res; } static irqreturn_t max310x_ist(int irq, void *dev_id) { struct max310x_port *s = (struct max310x_port *)dev_id; + bool handled = false; if (s->devtype->nr > 1) { do { @@ -726,12 +731,15 @@ static irqreturn_t max310x_ist(int irq, void *dev_id) val = ((1 << s->devtype->nr) - 1) & ~val; if (!val) break; - max310x_port_irq(s, fls(val) - 1); + if (max310x_port_irq(s, fls(val) - 1) == IRQ_HANDLED) + handled = true; } while (1); - } else - max310x_port_irq(s, 0); + } else { + if (max310x_port_irq(s, 0) == IRQ_HANDLED) + handled = true; + } - return IRQ_HANDLED; + return IRQ_RETVAL(handled); } static void max310x_wq_proc(struct work_struct *ws) @@ -1239,7 +1247,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, - IRQF_ONESHOT, dev_name(dev), s); + IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), s); if (!ret) return 0; -- cgit From b2497c1a7d864c5723e7abfdb1dffb5a9a0f092f Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Sat, 9 Dec 2017 00:54:33 +0100 Subject: serial: max310x: Document clock setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a kernel newcomer, I got bitten by lack of examples on this front. I had troubles figuring out where these clocks could be defined ("/clocks" is where the generic infrastructure expects them). One should also ensure that a unique name is used. Generic names such as "osc" tend to be already used by some board-wide clock crystals. Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/maxim,max310x.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.txt b/Documentation/devicetree/bindings/serial/maxim,max310x.txt index 0c58052a18bb..823f77dd7978 100644 --- a/Documentation/devicetree/bindings/serial/maxim,max310x.txt +++ b/Documentation/devicetree/bindings/serial/maxim,max310x.txt @@ -24,13 +24,27 @@ Optional properties: 1 = active low. Example: + +/ { + clocks { + spi_uart_clk: osc_max14830 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <3686400>; + }; + + }; +}; + +&spi0 { max14830: max14830@0 { compatible = "maxim,max14830"; reg = <0>; - clocks = <&clk20m>; + clocks = <&spi_uart_clk>; clock-names = "osc"; interrupt-parent = <&gpio3>; interrupts = <7 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; }; +}; -- cgit From d584b65c0ddf20acb769552f5fb64856d46ace4b Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Wed, 13 Dec 2017 14:20:39 +0100 Subject: serial: max310x: use a batch write op for UART transmit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The transmit register supports batched writes. The key is simply to keep sending additional bytes up to the FIFO size in the same SPI transaction with the CS pin still being held low. This duplicates the regmap infrastructure to a certain extent. There are some provisions for multiple writes in there, but there does not appear to be any support for those writes which are destined to the *same* register (and also no standard for SPI bus transfers of these, anyway). This patch does not solve every case (if the UART xmit circular buffer wraps around, we're still doing two SPI transactions), but at least it's not one-byte-per-transaction anymore. This change does not touch the receive path at this time. Doing that in the generic case appears to be impossible in the general case, because the chips' status register contains data about the *current* byte in the HW's Rx FIFO. We cannot read these two registers in one go, unfortunately. Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9e4e70f864ea..2a2c4ea16306 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -233,6 +233,7 @@ /* Misc definitions */ #define MAX310X_FIFO_SIZE (128) #define MAX310x_REV_MASK (0xf8) +#define MAX310X_WRITE_BIT 0x80 /* MAX3107 specific */ #define MAX3107_REV_ID (0xa0) @@ -593,6 +594,21 @@ static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq, return (int)bestfreq; } +static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) +{ + u8 header[] = { (port->iobase + MAX310X_THR_REG) | MAX310X_WRITE_BIT }; + struct spi_transfer xfer[] = { + { + .tx_buf = &header, + .len = sizeof(header), + }, { + .tx_buf = txbuf, + .len = len, + } + }; + spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); +} + static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) { unsigned int sts, ch, flag; @@ -652,7 +668,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) static void max310x_handle_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; - unsigned int txlen, to_send; + unsigned int txlen, to_send, until_end; if (unlikely(port->x_char)) { max310x_port_write(port, MAX310X_THR_REG, port->x_char); @@ -666,19 +682,25 @@ static void max310x_handle_tx(struct uart_port *port) /* Get length of data pending in circular buffer */ to_send = uart_circ_chars_pending(xmit); + until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); if (likely(to_send)) { /* Limit to size of TX FIFO */ txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG); txlen = port->fifosize - txlen; to_send = (to_send > txlen) ? txlen : to_send; + if (until_end < to_send) { + /* It's a circ buffer -- wrap around. + * We could do that in one SPI transaction, but meh. */ + max310x_batch_write(port, xmit->buf + xmit->tail, until_end); + max310x_batch_write(port, xmit->buf, to_send - until_end); + } else { + max310x_batch_write(port, xmit->buf + xmit->tail, to_send); + } + /* Add data to send */ port->icount.tx += to_send; - while (to_send--) { - max310x_port_write(port, MAX310X_THR_REG, - xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } + xmit->tail = (xmit->tail + to_send) & (UART_XMIT_SIZE - 1); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -1301,7 +1323,7 @@ MODULE_DEVICE_TABLE(of, max310x_dt_ids); static struct regmap_config regcfg = { .reg_bits = 8, .val_bits = 8, - .write_flag_mask = 0x80, + .write_flag_mask = MAX310X_WRITE_BIT, .cache_type = REGCACHE_RBTREE, .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, -- cgit From 2b4bac48c10848ccffd484e7cd025dc085c1bd32 Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Thu, 14 Dec 2017 16:02:54 +0100 Subject: serial: max310x: Use batched reads when reasonably safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware has a 128 byte RX FIFO buffer for each independent UART. Previously, the code was always reading that byte-by-byte via independent SPI transactions and the associated overhead. In practice, this led to up to eight bytes over SPI for just one byte in the UART's RX FIFO: - reading the global IRQ register (two bytes, one for command, the other for data) - reading one UART's ISR (again two bytes) - reading the byte count (two bytes yet again) - finally, reading one byte of the FIFO via another two-byte transaction We cannot always use a batched read. If the TTY is set to intercept break conditions or report framing or parity errors, then it is required to check the Line Status Register (LSR) for each byte which is read from the RX FIFO. The documentation does not show a way of doing that in a single SPI transaction; registers 0x00 and 0x04 are separate. In my testing, this is no silver bullet. I was feeding 2MB of random data over four daisy-chaned UARTs of MAX14830, and this is the distribution that I was getting: - R <= 1: 7437322 - R <= 2: 162093 - R <= 4: 4093 - R <= 8: 4196 - R <= 16: 645 - R <= 32: 165 - R <= 64: 58 - R <= 128: 0 For a reference, batching the write operations works much better: - W <= 1: 2664 - W <= 2: 1305 - W <= 4: 627 - W <= 8: 371 - W <= 16: 121 - W <= 32: 68 - W <= 64: 33 - W <= 128: 63139 That's probably because this HW/SW combination (Clearfog Base, Armada 388) is probably "good enough" to react to the chip's IRQ "fast enough" most of the time. Still, I was getting RX overruns every now and then. In future, I plan to improve this by letting the RX FIFO be filled a little more (the chip has support for that and also for a "stale timeout" to prevent additional starvation). Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 126 +++++++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 40 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 2a2c4ea16306..dc0e1ad351f9 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -609,57 +609,103 @@ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); } -static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) +static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { - unsigned int sts, ch, flag; + u8 header[] = { port->iobase + MAX310X_RHR_REG }; + struct spi_transfer xfer[] = { + { + .tx_buf = &header, + .len = sizeof(header), + }, { + .rx_buf = rxbuf, + .len = len, + } + }; + spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); +} - if (unlikely(rxlen >= port->fifosize)) { - dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n"); - port->icount.buf_overrun++; - /* Ensure sanity of RX level */ - rxlen = port->fifosize; - } +static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) +{ + unsigned int sts, ch, flag, i; + u8 buf[MAX310X_FIFO_SIZE]; + + if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) { + /* We are just reading, happily ignoring any error conditions. + * Break condition, parity checking, framing errors -- they + * are all ignored. That means that we can do a batch-read. + * + * There is a small opportunity for race if the RX FIFO + * overruns while we're reading the buffer; the datasheets says + * that the LSR register applies to the "current" character. + * That's also the reason why we cannot do batched reads when + * asked to check the individual statuses. + * */ - while (rxlen--) { - ch = max310x_port_read(port, MAX310X_RHR_REG); sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); + max310x_batch_read(port, buf, rxlen); - sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT | - MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT; - - port->icount.rx++; + port->icount.rx += rxlen; flag = TTY_NORMAL; + sts &= port->read_status_mask; - if (unlikely(sts)) { - if (sts & MAX310X_LSR_RXBRK_BIT) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (sts & MAX310X_LSR_RXPAR_BIT) - port->icount.parity++; - else if (sts & MAX310X_LSR_FRERR_BIT) - port->icount.frame++; - else if (sts & MAX310X_LSR_RXOVR_BIT) - port->icount.overrun++; - - sts &= port->read_status_mask; - if (sts & MAX310X_LSR_RXBRK_BIT) - flag = TTY_BREAK; - else if (sts & MAX310X_LSR_RXPAR_BIT) - flag = TTY_PARITY; - else if (sts & MAX310X_LSR_FRERR_BIT) - flag = TTY_FRAME; - else if (sts & MAX310X_LSR_RXOVR_BIT) - flag = TTY_OVERRUN; + if (sts & MAX310X_LSR_RXOVR_BIT) { + dev_warn_ratelimited(port->dev, "Hardware RX FIFO overrun\n"); + port->icount.overrun++; } - if (uart_handle_sysrq_char(port, ch)) - continue; + for (i = 0; i < rxlen; ++i) { + uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, buf[i], flag); + } - if (sts & port->ignore_status_mask) - continue; + } else { + if (unlikely(rxlen >= port->fifosize)) { + dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n"); + port->icount.buf_overrun++; + /* Ensure sanity of RX level */ + rxlen = port->fifosize; + } - uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, ch, flag); + while (rxlen--) { + ch = max310x_port_read(port, MAX310X_RHR_REG); + sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); + + sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT | + MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT; + + port->icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(sts)) { + if (sts & MAX310X_LSR_RXBRK_BIT) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (sts & MAX310X_LSR_RXPAR_BIT) + port->icount.parity++; + else if (sts & MAX310X_LSR_FRERR_BIT) + port->icount.frame++; + else if (sts & MAX310X_LSR_RXOVR_BIT) + port->icount.overrun++; + + sts &= port->read_status_mask; + if (sts & MAX310X_LSR_RXBRK_BIT) + flag = TTY_BREAK; + else if (sts & MAX310X_LSR_RXPAR_BIT) + flag = TTY_PARITY; + else if (sts & MAX310X_LSR_FRERR_BIT) + flag = TTY_FRAME; + else if (sts & MAX310X_LSR_RXOVR_BIT) + flag = TTY_OVERRUN; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + + if (sts & port->ignore_status_mask) + continue; + + uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, ch, flag); + } } tty_flip_buffer_push(&port->state->port); -- cgit From 2258761213cb239e5e6c11b4ec9b1700fcb4fdcd Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Fri, 8 Dec 2017 23:51:33 +0100 Subject: serial: max310x: Reduce RX work starvation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this patch, the code would happily trigger TX on some ports before having a chance of reading the RX buffer from the rest of them. When no flow control was used, this led to RX buffer overruns and therefore lost data under certain circumstances. I was able to reproduce this with MAX14830 (that's a quad channel one) and a simple daisy-chain of RX and TX ports on the eval board: - TX0 -> RX1 - TX1 -> RX2 - TX2 -> RX3 - TX3 -> RX0 I was testing this by transferring 2MB of data at 115200 baud via each port. I used a Solidrun Clearfog Base (Armada 388) which was talking to the UART over an SPI bus clocked at 26MHz (the chip's maximum). Without this patch, I would always get a "Possible RX FIFO overrun" in dmesg, and fewer-than-expected amount of bytes received over ttyMAX0. Results on ttyMAX{1,2,3} tended to be correct all the time, even without the previous patches in this series and with PIO SPI transfers ("indirect mode" as the Marvell datasheet calls it), so I assume that heavy congestion is needed in order to reproduce this. A drawback of this patch is that the throughput gets reduced "a bit". Previously, a 115200 baud resulted in about 11.2kBps throughput as reported by a simple `pv`. With this patch, the throughput of four parallel streams is roughly 7kBps each, and 9kBps for three streams. There is no slowdown for one or two parallel streams. Situation is worse if bytes are being read one-by-one (such as if the userspace wants to perform parity/framing/break checking) and therefore without the batched reads. With just this patch and no other modifications on top of 4.14, I was only getting roughly 3.6kBps with four parallel streams. The single-stream performance was the same, and I was seeing about 7.2kBps with two parallel streams. `perf top` said that a substantial amount of time was spent in `finish_task_switch`, `_raw_spin_unlock_irqrestore` and `__timer_delay`. Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index dc0e1ad351f9..97576ff791db 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -753,6 +753,14 @@ static void max310x_handle_tx(struct uart_port *port) uart_write_wakeup(port); } +static void max310x_start_tx(struct uart_port *port) +{ + struct max310x_one *one = container_of(port, struct max310x_one, port); + + if (!work_pending(&one->tx_work)) + schedule_work(&one->tx_work); +} + static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno) { struct uart_port *port = &s->p[portno].port; @@ -776,11 +784,8 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno) } if (rxlen) max310x_handle_rx(port, rxlen); - if (ists & MAX310X_IRQ_TXEMPTY_BIT) { - mutex_lock(&s->mutex); - max310x_handle_tx(port); - mutex_unlock(&s->mutex); - } + if (ists & MAX310X_IRQ_TXEMPTY_BIT) + max310x_start_tx(port); } while (1); return res; } @@ -820,14 +825,6 @@ static void max310x_wq_proc(struct work_struct *ws) mutex_unlock(&s->mutex); } -static void max310x_start_tx(struct uart_port *port) -{ - struct max310x_one *one = container_of(port, struct max310x_one, port); - - if (!work_pending(&one->tx_work)) - schedule_work(&one->tx_work); -} - static unsigned int max310x_tx_empty(struct uart_port *port) { unsigned int lvl, sts; -- cgit From 2b022ab7542df60021ab57854b3faaaf42552eaf Mon Sep 17 00:00:00 2001 From: Sahara Date: Wed, 13 Dec 2017 09:10:48 +0400 Subject: pty: cancel pty slave port buf's work in tty_release In case that CONFIG_SLUB_DEBUG is on and pty is used, races between release_one_tty and flush_to_ldisc work threads may happen and lead to use-after-free condition on tty->link->port. Because SLUB_DEBUG is turned on, freed tty->link->port is filled with POISON_FREE value. So far without SLUB_DEBUG, port was filled with zero and flush_to_ldisc could return without a problem by checking if tty is NULL. CPU 0 CPU 1 ----- ----- release_tty pty_write cancel_work_sync(tty) to = tty->link tty_kref_put(tty->link) tty_schedule_flip(to->port) << workqueue >> ... release_one_tty ... pty_cleanup ... kfree(tty->link->port) << workqueue >> flush_to_ldisc tty = READ_ONCE(port->itty) tty is 0x6b6b6b6b6b6b6b6b !!PANIC!! access tty->ldisc Unable to handle kernel paging request at virtual address 6b6b6b6b6b6b6b93 pgd = ffffffc0eb1c3000 [6b6b6b6b6b6b6b93] *pgd=0000000000000000, *pud=0000000000000000 ------------[ cut here ]------------ Kernel BUG at ffffff800851154c [verbose debug info unavailable] Internal error: Oops - BUG: 96000004 [#1] PREEMPT SMP CPU: 3 PID: 265 Comm: kworker/u8:9 Tainted: G W 3.18.31-g0a58eeb #1 Hardware name: Qualcomm Technologies, Inc. MSM 8996pro v1.1 + PMI8996 Carbide (DT) Workqueue: events_unbound flush_to_ldisc task: ffffffc0ed610ec0 ti: ffffffc0ed624000 task.ti: ffffffc0ed624000 PC is at ldsem_down_read_trylock+0x0/0x4c LR is at tty_ldisc_ref+0x24/0x4c pc : [] lr : [] pstate: 80400145 sp : ffffffc0ed627cd0 x29: ffffffc0ed627cd0 x28: 0000000000000000 x27: ffffff8009e05000 x26: ffffffc0d382cfa0 x25: 0000000000000000 x24: ffffff800a012f08 x23: 0000000000000000 x22: ffffffc0703fbc88 x21: 6b6b6b6b6b6b6b6b x20: 6b6b6b6b6b6b6b93 x19: 0000000000000000 x18: 0000000000000001 x17: 00e80000f80d6f53 x16: 0000000000000001 x15: 0000007f7d826fff x14: 00000000000000a0 x13: 0000000000000000 x12: 0000000000000109 x11: 0000000000000000 x10: 0000000000000000 x9 : ffffffc0ed624000 x8 : ffffffc0ed611580 x7 : 0000000000000000 x6 : ffffff800a42e000 x5 : 00000000000003fc x4 : 0000000003bd1201 x3 : 0000000000000001 x2 : 0000000000000001 x1 : ffffff800851004c x0 : 6b6b6b6b6b6b6b93 Signed-off-by: Sahara Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index dc60aeea87d8..a6ca634411e1 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1476,6 +1476,8 @@ static void release_tty(struct tty_struct *tty, int idx) if (tty->link) tty->link->port->itty = NULL; tty_buffer_cancel_work(tty->port); + if (tty->link) + tty_buffer_cancel_work(tty->link->port); tty_kref_put(tty->link); tty_kref_put(tty); -- cgit From 8ca31ba8bb3441dd9928d2f92ffeee11dd2b6e63 Mon Sep 17 00:00:00 2001 From: "Guilherme G. Piccoli" Date: Fri, 22 Dec 2017 14:31:38 -0200 Subject: tty: serial: jsm: Remove unnecessary NULL checks After inspection made by Markus using Coccinelle software, he observed that we could possibly be triggering a NULL pointer dereference in 2 functions [0]. After discussion in mailing list, it was observed in fact we have two unnecessary checks for NULL pointer, and they were leading to Coccinelle warn. So, instead of reworking the code as proposed by him, we hereby remove the unnecessary checks, and also some unneeded extra lines in the code. These two unnecessary NULL checks were tracked in the call chain as never NULL, so they can be safely removed. No functional changes are intended. [0] https://lkml.org/lkml/2017/11/29/705 Suggested-by: Markus Elfring Signed-off-by: Guilherme G. Piccoli Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_neo.c | 3 --- drivers/tty/serial/jsm/jsm_tty.c | 6 ------ 2 files changed, 9 deletions(-) diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 4718560b8fdc..6fa9a54b2454 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -282,9 +282,6 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) u16 head; u16 tail; - if (!ch) - return; - /* cache head and tail of queue */ head = ch->ch_r_head & RQUEUEMASK; tail = ch->ch_r_tail & RQUEUEMASK; diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 469927d37b41..b6bd6e15e07b 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -523,9 +523,6 @@ void jsm_input(struct jsm_channel *ch) jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n"); - if (!ch) - return; - port = &ch->uart_port.state->port; tp = port->tty; @@ -648,11 +645,8 @@ static void jsm_carrier(struct jsm_channel *ch) int phys_carrier = 0; jsm_dbg(CARR, &ch->ch_bd->pci_dev, "start\n"); - if (!ch) - return; bd = ch->ch_bd; - if (!bd) return; -- cgit From e50af488dddea7754e581d69bf978356e468845c Mon Sep 17 00:00:00 2001 From: "Guilherme G. Piccoli" Date: Fri, 22 Dec 2017 14:31:39 -0200 Subject: tty: serial: jsm: Add one check against NULL pointer dereference All calls to neo_copy_data_from_uart_to_queue() are safeguarded against NULL dereference of its parameter, except the one that this patch changes. That said, let's play safe and check for NULL in this case too. Signed-off-by: Guilherme G. Piccoli Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_neo.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 6fa9a54b2454..bf0e2a4cb0ce 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -1172,6 +1172,9 @@ static irqreturn_t neo_intr(int irq, void *voidbrd) continue; ch = brd->channels[port]; + if (!ch) + continue; + neo_copy_data_from_uart_to_queue(ch); /* Call our tty layer to enforce queue flow control if needed. */ -- cgit From 6eaf0b9507b8778bf36ba245a95d50aff268502c Mon Sep 17 00:00:00 2001 From: Rafael Gago Date: Thu, 21 Dec 2017 12:55:30 +0100 Subject: tty: omap-serial: Fix initial on-boot RTS GPIO level The rs485 flag "SER_RS485_RTS_AFTER_SEND" was wrongly read from the GPIO flags. This caused the RTS pin to be high during boot. Signed-off-by: Rafael Gago Castano Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 56e683373d6d..6420ae581a80 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1602,7 +1602,6 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, struct device_node *np) { struct serial_rs485 *rs485conf = &up->port.rs485; - enum of_gpio_flags flags; int ret; rs485conf->flags = 0; @@ -1622,13 +1621,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, } /* check for tx enable gpio */ - up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags); + up->rts_gpio = of_get_named_gpio(np, "rts-gpio", 0); if (gpio_is_valid(up->rts_gpio)) { ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial"); if (ret < 0) return ret; - ret = gpio_direction_output(up->rts_gpio, - flags & SER_RS485_RTS_AFTER_SEND); + ret = rs485conf->flags & SER_RS485_RTS_AFTER_SEND ? 1 : 0; + ret = gpio_direction_output(up->rts_gpio, ret); if (ret < 0) return ret; } else if (up->rts_gpio == -EPROBE_DEFER) { -- cgit From ea3d8465ab9b3e01be329ac5195970a84bef76c5 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 3 Jan 2018 10:18:03 -0800 Subject: tty: n_gsm: Allow ADM response in addition to UA for control dlci Some devices have the control dlci stay in ADM mode instead of the UA mode. This can seen at least on droid 4 when trying to open the ts 27.010 mux port. Enabling n_gsm debug mode shows the control dlci always respond with DM to SABM instead of UA: # modprobe n_gsm debug=0xff # ldattach -d GSM0710 /dev/ttyS0 & gsmld_output: 00000000: f9 03 3f 01 1c f9 --> 0) C: SABM(P) gsmld_receive: 00000000: f9 03 1f 01 36 f9 <-- 0) C: DM(P) ... $ minicom -D /dev/gsmtty1 minicom: cannot open /dev/gsmtty1: No error information $ strace minicom -D /dev/gsmtty1 ... open("/dev/gsmtty1", O_RDWR|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = -1 EL2HLT Note that this is different issue from other n_gsm -EL2HLT issues such as timeouts when the control dlci does not respond at all. The ADM mode seems to be a quite common according to "RF Wireless World" article "GSM Issue-UE sends SABM and gets a DM response instead of UA response": This issue is most commonly observed in GSM networks where in UE sends SABM and expects network to send UA response but it ends up receiving DM response from the network. SABM stands for Set asynchronous balanced mode, UA stands for Unnumbered Acknowledge and DA stands for Disconnected Mode. An RLP entity can be in one of two modes: - Asynchronous Balanced Mode (ABM) - Asynchronous Disconnected Mode (ADM) Currently Linux kernel closes the control dlci after several retries in gsm_dlci_t1() on DM. This causes n_gsm /dev/gsmtty ports to produce error code -EL2HLT when trying to open them as the closing of control dlci has already set gsm->dead. Let's fix the issue by allowing control dlci stay in ADM mode after the retries so the /dev/gsmtty ports can be opened and used. It seems that it might take several attempts to get any response from the control dlci, so it's best to allow ADM mode only after the SABM retries are done. Note that for droid 4 additional patches are needed to mux the ttyS0 pins and to toggle RTS gpio_149 to wake up the mdm6600 modem are also needed to use n_gsm. And the mdm6600 modem needs to be powered on. Cc: linux-serial@vger.kernel.org Cc: Alan Cox Cc: Jiri Prchal Cc: Jiri Slaby Cc: Marcel Partap Cc: Michael Scott Cc: Peter Hurley Cc: Russ Gorby Cc: Sascha Hauer Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 48e791d95f76..db6728c7d1a9 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1451,6 +1451,10 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) * in which case an opening port goes back to closed and a closing port * is simply put into closed state (any further frames from the other * end will get a DM response) + * + * Some control dlci can stay in ADM mode with other dlci working just + * fine. In that case we can just keep the control dlci open after the + * DLCI_OPENING retries time out. */ static void gsm_dlci_t1(struct timer_list *t) @@ -1464,8 +1468,15 @@ static void gsm_dlci_t1(struct timer_list *t) if (dlci->retries) { gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); - } else + } else if (!dlci->addr && gsm->control == (DM | PF)) { + if (debug & 8) + pr_info("DLCI %d opening in ADM mode.\n", + dlci->addr); + gsm_dlci_open(dlci); + } else { gsm_dlci_close(dlci); + } + break; case DLCI_CLOSING: dlci->retries--; @@ -1483,8 +1494,8 @@ static void gsm_dlci_t1(struct timer_list *t) * @dlci: DLCI to open * * Commence opening a DLCI from the Linux side. We issue SABM messages - * to the modem which should then reply with a UA, at which point we - * will move into open state. Opening is done asynchronously with retry + * to the modem which should then reply with a UA or ADM, at which point + * we will move into open state. Opening is done asynchronously with retry * running off timers and the responses. */ -- cgit From 7defa77d2baca4d6eb85234f10f38ab618332e75 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 4 Jan 2018 07:42:15 +0000 Subject: serial: 8250_uniphier: fix error return code in uniphier_uart_probe() Fix to return a negative error code from the port register error handling case instead of 0, as done elsewhere in this function. Fixes: 39be40ce066d ("serial: 8250_uniphier: fix serial port index in private data") Signed-off-by: Wei Yongjun Acked-by: Masahiro Yamada Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 45ef506293ae..28d88ccf5a0c 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -250,12 +250,13 @@ static int uniphier_uart_probe(struct platform_device *pdev) up.dl_read = uniphier_serial_dl_read; up.dl_write = uniphier_serial_dl_write; - priv->line = serial8250_register_8250_port(&up); - if (priv->line < 0) { + ret = serial8250_register_8250_port(&up); + if (ret < 0) { dev_err(dev, "failed to register 8250 port\n"); clk_disable_unprepare(priv->clk); return ret; } + priv->line = ret; platform_set_drvdata(pdev, priv); -- cgit From 38b1f0fb42f772b8c9aac53593883a18ff5eb9d7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 4 Jan 2018 15:58:34 -0200 Subject: serial: imx: Only wakeup via RTSDEN bit if the system has RTS/CTS The wakeup mechanism via RTSDEN bit relies on the system using the RTS/CTS lines, so only allow such wakeup method when the system actually has RTS/CTS support. Fixes: bc85734b126f ("serial: imx: allow waking up on RTSD") Signed-off-by: Fabio Estevam Reviewed-by: Martin Kaiser Acked-by: Fugang Duan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index c2b29fd66e8a..7143da39c170 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2225,12 +2225,14 @@ static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) val &= ~UCR3_AWAKEN; writel(val, sport->port.membase + UCR3); - val = readl(sport->port.membase + UCR1); - if (on) - val |= UCR1_RTSDEN; - else - val &= ~UCR1_RTSDEN; - writel(val, sport->port.membase + UCR1); + if (sport->have_rtscts) { + val = readl(sport->port.membase + UCR1); + if (on) + val |= UCR1_RTSDEN; + else + val &= ~UCR1_RTSDEN; + writel(val, sport->port.membase + UCR1); + } } static int imx_serial_port_suspend_noirq(struct device *dev) -- cgit From b9820a31691b771db37afe2054dd3d3a680c1eed Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 27 Dec 2017 14:21:05 +0900 Subject: serial: 8250_of: fix return code when probe function fails to get reset The error pointer from devm_reset_control_get_optional_shared() is not propagated. One of the most common problem scenarios is it returns -EPROBE_DEFER when the reset controller has not probed yet. In this case, the probe of the reset consumer should be deferred. Fixes: e2860e1f62f2 ("serial: 8250_of: Add reset support") Cc: stable@vger.kernel.org # v4.13+ Signed-off-by: Masahiro Yamada Reviewed-by: Philipp Zabel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 1e67a7e4a5fd..160b8906d9b9 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -136,8 +136,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev, } info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); - if (IS_ERR(info->rst)) + if (IS_ERR(info->rst)) { + ret = PTR_ERR(info->rst); goto err_dispose; + } + ret = reset_control_deassert(info->rst); if (ret) goto err_dispose; -- cgit From 0f646b63a1b2ede7885e45cf6e986128e001f91b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 28 Dec 2017 14:07:07 +0100 Subject: serial: core: Make uart_parse_options take const char* argument The pointed string is never modified from within uart_parse_options, so it should be marked as const in the function prototype. Signed-off-by: Paul Cercueil Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 5 +++-- include/linux/serial_core.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f57969de2f1c..2148883db66d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1955,9 +1955,10 @@ EXPORT_SYMBOL_GPL(uart_parse_earlycon); * eg: 115200n8r */ void -uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) +uart_parse_options(const char *options, int *baud, int *parity, + int *bits, int *flow) { - char *s = options; + const char *s = options; *baud = simple_strtoul(s, NULL, 10); while (*s >= '0' && *s <= '9') diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index b60b225c0a59..4c310c34ddad 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -387,7 +387,7 @@ struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct console *c); int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, char **options); -void uart_parse_options(char *options, int *baud, int *parity, int *bits, +void uart_parse_options(const char *options, int *baud, int *parity, int *bits, int *flow); int uart_set_options(struct uart_port *port, struct console *co, int baud, int parity, int bits, int flow); -- cgit From aed3d7012ca79f102bf98cca808c7ff5ceb26c57 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 28 Dec 2017 14:07:08 +0100 Subject: serial: 8250_ingenic: Add support for the JZ4770 SoC The JZ4770 SoC's UART is no different from the other JZ SoCs, so this commit simply adds the ingenic,jz4770-uart compatible string. Signed-off-by: Paul Cercueil Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/ingenic,uart.txt | 8 ++++++-- drivers/tty/serial/8250/8250_ingenic.c | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/ingenic,uart.txt b/Documentation/devicetree/bindings/serial/ingenic,uart.txt index 02cb7fe59cb7..c3c6406d5cfe 100644 --- a/Documentation/devicetree/bindings/serial/ingenic,uart.txt +++ b/Documentation/devicetree/bindings/serial/ingenic,uart.txt @@ -1,8 +1,12 @@ * Ingenic SoC UART Required properties: -- compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart", - "ingenic,jz4775-uart" or "ingenic,jz4780-uart" +- compatible : One of: + - "ingenic,jz4740-uart", + - "ingenic,jz4760-uart", + - "ingenic,jz4770-uart", + - "ingenic,jz4775-uart", + - "ingenic,jz4780-uart". - reg : offset and length of the register set for the device. - interrupts : should contain uart interrupt. - clocks : phandles to the module & baud clocks. diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 6af84900870e..165b4bb3de93 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -125,6 +125,10 @@ EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", ingenic_early_console_setup); +EARLYCON_DECLARE(jz4770_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart", + ingenic_early_console_setup); + EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", ingenic_early_console_setup); @@ -319,6 +323,7 @@ static const struct ingenic_uart_config jz4780_uart_config = { static const struct of_device_id of_match[] = { { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, + { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, { /* sentinel */ } -- cgit From ea507ce3e05a462e170db4b6af1002fb0ed72916 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 28 Dec 2017 14:07:09 +0100 Subject: serial: 8250_ingenic: Parse earlycon options In the devicetree, it is possible to specify the baudrate, parity, bits, flow of the early console, by passing a configuration string like this: aliases { serial0 = &uart0; }; chosen { stdout-path = "serial0:57600n8"; }; This, for instance, will configure the early console for a baudrate of 57600 bps, no parity, and 8 bits per baud. This patches implements parsing of this configuration string in the 8250_ingenic driver, which previously just ignored it. Signed-off-by: Paul Cercueil Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_ingenic.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 165b4bb3de93..15a8c8dfa92b 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -91,14 +91,22 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev, const char *opt) { struct uart_port *port = &dev->port; - unsigned int baud, divisor; + unsigned int divisor; + int baud = 115200; if (!dev->port.membase) return -ENODEV; + if (opt) { + unsigned int parity, bits, flow; /* unused for now */ + + uart_parse_options(opt, &baud, &parity, &bits, &flow); + } + ingenic_early_console_setup_clock(dev); - baud = dev->baud ?: 115200; + if (dev->baud) + baud = dev->baud; divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); early_out(port, UART_IER, 0); -- cgit From 7d09995dcb0577b4a56aad7f2bb56f28604e8f1a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 25 Dec 2017 21:50:45 +0100 Subject: serdev: Fix serdev_uevent failure on ACPI enumerated serdev-controllers ACPI enumerated serdev-controllers do not have an ACPI companion, the ACPI companion belongs to the serdev-device child of the serdev-controller, not to the controller itself. This was causing serdev_uevent to always return -ENODEV when called on a serdev-controller leading to errors like these: kernel: serial serial0: uevent: failed to send synthetic uevent being logged. This commit modifies serdev_uevent to directly return 0 when called on an ACPI enumerated serdev-controller fixing this. Note: I do not think that setting a modalias on a devicetree enumerated serdev-controller makes sense either. So perhaps the !dev->of_node part of the check can be dropped too, but I'm not entirely sure that doing this on devicetree too is correct. Signed-off-by: Hans de Goede Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 28133dbd2808..5dc88f61f506 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -54,6 +54,11 @@ static int serdev_uevent(struct device *dev, struct kobj_uevent_env *env) int rc; /* TODO: platform modalias */ + + /* ACPI enumerated controllers do not have a modalias */ + if (!dev->of_node && dev->type == &serdev_ctrl_type) + return 0; + rc = acpi_device_uevent_modalias(dev, env); if (rc != -ENODEV) return rc; -- cgit From e397824bf0953344000101dc8994e92a98add0fe Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Fri, 22 Dec 2017 21:29:44 +0100 Subject: gpio: serial: max310x: Support open-drain configuration for GPIOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The push-pull vs. open-drain are the only supported output modes. The inputs are always unconditionally equipped with weak pull-downs. That's the only mode, so there's probably no point in exporting that. I wonder if it's worthwhile to provide a custom dbg_show method to indicate the current status of the outputs, though. This patch and [1] for i2c-gpio together make it possible to bit-bang an I2C bus over GPIOs of an UART which is connected via SPI :). Yes, this is crazy, but it's fast enough (while on a 26Mhz SPI HW bus with a dual-core 1.6GHz CPU) to drive an I2C bus at 200kHz, according to my scope. [1] https://patchwork.ozlabs.org/patch/852591/ Signed-off-by: Jan Kundrát Reviewed-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 97576ff791db..39f635812077 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1159,6 +1159,27 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, return 0; } + +static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct max310x_port *s = gpiochip_get_data(chip); + struct uart_port *port = &s->p[offset / 4].port; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + max310x_port_update(port, MAX310X_GPIOCFG_REG, + 1 << ((offset % 4) + 4), + 1 << ((offset % 4) + 4)); + return 0; + case PIN_CONFIG_DRIVE_PUSH_PULL: + max310x_port_update(port, MAX310X_GPIOCFG_REG, + 1 << ((offset % 4) + 4), 0); + return 0; + default: + return -ENOTSUPP; + } +} #endif static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, @@ -1302,6 +1323,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->gpio.get = max310x_gpio_get; s->gpio.direction_output= max310x_gpio_direction_output; s->gpio.set = max310x_gpio_set; + s->gpio.set_config = max310x_gpio_set_config; s->gpio.base = -1; s->gpio.ngpio = devtype->nr * 4; s->gpio.can_sleep = 1; -- cgit From a0075d168a19dab5e015a03ffafbd6ab8e7d0c04 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 19 Jan 2018 18:02:04 +0200 Subject: MAINTAINERS: Add myself as designated reviewer for 8250_dw It happened several times that some odd fixes either introduced regressions, or did hack the code instead of addressing a root cause. Nominate myself to be a designated reviewer for 8250_dw driver. Cc: Heikki Krogerus Cc: Lukas Wunner Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b46c9cea5ae5..8dc5eb425267 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13098,6 +13098,11 @@ S: Supported F: drivers/reset/reset-axs10x.c F: Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt +SYNOPSYS DESIGNWARE 8250 UART DRIVER +R: Andy Shevchenko +S: Maintained +F: drivers/tty/serial/8250/8250_dw.c + SYNOPSYS DESIGNWARE APB GPIO DRIVER M: Hoan Tran L: linux-gpio@vger.kernel.org -- cgit From c14b65feac9ebed649d6fe79c6b6d64d21d0287d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 19 Jan 2018 18:02:05 +0200 Subject: serial: 8250_dw: Revert "Improve clock rate setting" The commit de9e33bdfa22 ("serial: 8250_dw: Improve clock rate setting") obviously tries to cure symptoms, and not a root cause. The root cause is the non-flexible rate calculation inside the corresponding clock driver. What we need is to provide maximum UART divisor value to the clock driver to allow it do the job transparently to the caller. Since from the initial commit message I have got no clue which clock driver actually needs to be amended, I leave this exercise to the people who know better the case. Moreover, it seems [1] the fix introduced a regression. And possible even one more [2]. Taking above, revert the commit de9e33bdfa22 for now. [1]: https://www.spinics.net/lists/linux-serial/msg28872.html [2]: https://github.com/Dunedan/mbp-2016-linux/issues/29#issuecomment-357583782 Fixes: de9e33bdfa22 ("serial: 8250_dw: Improve clock rate setting") Cc: stable # 4.15 Cc: Ed Blake Cc: Heikki Krogerus Cc: Lukas Wunner Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index bda75d317d24..cd1b94a0f451 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -252,31 +252,25 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - unsigned int target_rate, min_rate, max_rate; struct dw8250_data *d = p->private_data; long rate; - int i, ret; + int ret; if (IS_ERR(d->clk) || !old) goto out; - /* Find a clk rate within +/-1.6% of an integer multiple of baudx16 */ - target_rate = baud * 16; - min_rate = target_rate - (target_rate >> 6); - max_rate = target_rate + (target_rate >> 6); - - for (i = 1; i <= UART_DIV_MAX; i++) { - rate = clk_round_rate(d->clk, i * target_rate); - if (rate >= i * min_rate && rate <= i * max_rate) - break; - } - if (i <= UART_DIV_MAX) { - clk_disable_unprepare(d->clk); + clk_disable_unprepare(d->clk); + rate = clk_round_rate(d->clk, baud * 16); + if (rate < 0) + ret = rate; + else if (rate == 0) + ret = -ENOENT; + else ret = clk_set_rate(d->clk, rate); - clk_prepare_enable(d->clk); - if (!ret) - p->uartclk = rate; - } + clk_prepare_enable(d->clk); + + if (!ret) + p->uartclk = rate; out: p->status &= ~UPSTAT_AUTOCTS; -- cgit From f8bdfe9d27350735d1cc787a5fd7c25078667496 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 14 Jan 2018 22:07:09 +0100 Subject: serial: mxs-auart: don't use GPIOF_* with gpiod_get_direction The documentation was wrong, gpiod_get_direction() returns 0/1 instead of the GPIOF_* flags. The docs were fixed with commit 94fc73094abe47 ("gpio: correct docs about return value of gpiod_get_direction"). Now, fix this user (until a better, system-wide solution is in place). This also means we can drop the deprecated use of 'linux/gpio.h'. Yay! Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mxs-auart.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 5b470406bf9d..079dc47aa142 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -40,7 +40,6 @@ #include -#include #include #include #include @@ -1597,7 +1596,7 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) for (i = 0; i < UART_GPIO_MAX; i++) { gpiod = mctrl_gpio_to_gpiod(s->gpios, i); - if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN)) + if (gpiod && (gpiod_get_direction(gpiod) == 1)) s->gpio_irq[i] = gpiod_to_irq(gpiod); else s->gpio_irq[i] = -EINVAL; -- cgit From 2460942f51f1f262e77072c9a7c963a1b047a367 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 9 Jan 2018 17:09:16 +0100 Subject: serdev: do not generate modaliases for controllers Serdev controllers are not bound to any drivers and it therefore makes no sense to generate modaliases for them. This has already been fixed separately for ACPI controllers for which uevent errors were also being logged during probe due to the missing ACPI companions (from which ACPI modaliases are generated). This patch moves the modalias handling from the bus type to the client device type. Specifically, this means that only serdev devices (a.k.a. clients or slaves) will have have MODALIAS fields in their uevent environments and corresponding modalias sysfs attributes. Also add the missing static keyword for the modalias device attribute when moving the definition. Reported-by: Hans de Goede Signed-off-by: Johan Hovold Reviewed-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 72 ++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 5dc88f61f506..c8c43834477b 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -19,6 +19,38 @@ static bool is_registered; static DEFINE_IDA(ctrl_ida); +static ssize_t modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int len; + + len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1); + if (len != -ENODEV) + return len; + + return of_device_modalias(dev, buf, PAGE_SIZE); +} +static DEVICE_ATTR_RO(modalias); + +static struct attribute *serdev_device_attrs[] = { + &dev_attr_modalias.attr, + NULL, +}; +ATTRIBUTE_GROUPS(serdev_device); + +static int serdev_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + int rc; + + /* TODO: platform modalias */ + + rc = acpi_device_uevent_modalias(dev, env); + if (rc != -ENODEV) + return rc; + + return of_device_uevent_modalias(dev, env); +} + static void serdev_device_release(struct device *dev) { struct serdev_device *serdev = to_serdev_device(dev); @@ -26,6 +58,8 @@ static void serdev_device_release(struct device *dev) } static const struct device_type serdev_device_type = { + .groups = serdev_device_groups, + .uevent = serdev_device_uevent, .release = serdev_device_release, }; @@ -49,23 +83,6 @@ static int serdev_device_match(struct device *dev, struct device_driver *drv) return of_driver_match_device(dev, drv); } -static int serdev_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - int rc; - - /* TODO: platform modalias */ - - /* ACPI enumerated controllers do not have a modalias */ - if (!dev->of_node && dev->type == &serdev_ctrl_type) - return 0; - - rc = acpi_device_uevent_modalias(dev, env); - if (rc != -ENODEV) - return rc; - - return of_device_uevent_modalias(dev, env); -} - /** * serdev_device_add() - add a device previously constructed via serdev_device_alloc() * @serdev: serdev_device to be added @@ -305,32 +322,11 @@ static int serdev_drv_remove(struct device *dev) return 0; } -static ssize_t modalias_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int len; - - len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1); - if (len != -ENODEV) - return len; - - return of_device_modalias(dev, buf, PAGE_SIZE); -} -DEVICE_ATTR_RO(modalias); - -static struct attribute *serdev_device_attrs[] = { - &dev_attr_modalias.attr, - NULL, -}; -ATTRIBUTE_GROUPS(serdev_device); - static struct bus_type serdev_bus_type = { .name = "serial", .match = serdev_device_match, .probe = serdev_drv_probe, .remove = serdev_drv_remove, - .uevent = serdev_uevent, - .dev_groups = serdev_device_groups, }; /** -- cgit From 7ee69102dbc4eea90f46a24f16961226a477dd4c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 9 Jan 2018 17:09:17 +0100 Subject: serdev: only match serdev devices Only serdev devices (a.k.a. clients or slaves) are bound to drivers so bail out early from match() in case the device is not a serdev device (i.e. if it's a serdev controller). Signed-off-by: Johan Hovold Reviewed-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index c8c43834477b..f710862f5c06 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -63,6 +63,11 @@ static const struct device_type serdev_device_type = { .release = serdev_device_release, }; +static bool is_serdev_device(const struct device *dev) +{ + return dev->type == &serdev_device_type; +} + static void serdev_ctrl_release(struct device *dev) { struct serdev_controller *ctrl = to_serdev_controller(dev); @@ -76,6 +81,9 @@ static const struct device_type serdev_ctrl_type = { static int serdev_device_match(struct device *dev, struct device_driver *drv) { + if (!is_serdev_device(dev)) + return 0; + /* TODO: platform matching */ if (acpi_driver_match_device(dev, drv)) return 1; -- cgit From 44117a1d1732c513875d5a163f10d9adbe866c08 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 11 Jan 2018 18:57:26 +0100 Subject: serial: core: mark port as initialized after successful IRQ change setserial changes the IRQ via uart_set_info(). It invokes uart_shutdown() which free the current used IRQ and clear TTY_PORT_INITIALIZED. It will then update the IRQ number and invoke uart_startup() before returning to the caller leaving TTY_PORT_INITIALIZED cleared. The next open will crash with | list_add double add: new=ffffffff839fcc98, prev=ffffffff839fcc98, next=ffffffff839fcc98. since the close from the IOCTL won't free the IRQ (and clean the list) due to the TTY_PORT_INITIALIZED check in uart_shutdown(). There is same pattern in uart_do_autoconfig() and I *think* it also needs to set TTY_PORT_INITIALIZED there. Is there a reason why uart_startup() does not set the flag by itself after the IRQ has been acquired (since it is cleared in uart_shutdown)? Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 2148883db66d..c8dde56b532b 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -974,6 +974,8 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, } } else { retval = uart_startup(tty, state, 1); + if (retval == 0) + tty_port_set_initialized(port, true); if (retval > 0) retval = 0; } -- cgit From 09df0b3464e528c6a4ca2c48d9ff6d2fd7cbd775 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Fri, 5 Jan 2018 17:46:43 +0100 Subject: serial: imx: fix endless loop during suspend Before we go into suspend mode, we enable the imx uart's interrupt for the awake bit in the UART Status Register 1. If, for some reason, the awake bit is already set before we enter suspend mode, we get an interrupt immediately when we enable interrupts for awake. The uart's clk_ipg is disabled at this point (unless there's an ongoing transfer). We end up in the interrupt handler, which usually tries to clear the awake bit. This doesn't work with the clock disabled. Therefore, we keep getting interrupts forever, resulting in an endless loop. Clear the awake bit before setting the awaken bit to signal that we want an imx interrupt when the awake bit will be set. This ensures that we're not woken up by events that happened before we started going into suspend mode. Change the clock handling so that suspend prepares and enables the clock and suspend_noirq disables it. Revert these operations in resume_noirq and resume. With these preparations in place, we can now modify awake and awaken in the suspend function when the actual imx interrupt is disabled and the required clk_ipg is active. Update the thaw and freeze functions to use the new clock handling since we share the suspend_noirq function between suspend and hibernate. Signed-off-by: Martin Kaiser Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 7143da39c170..1d7ca382bc12 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2219,8 +2219,10 @@ static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) unsigned int val; val = readl(sport->port.membase + UCR3); - if (on) + if (on) { + writel(USR1_AWAKE, sport->port.membase + USR1); val |= UCR3_AWAKEN; + } else val &= ~UCR3_AWAKEN; writel(val, sport->port.membase + UCR3); @@ -2239,11 +2241,6 @@ static int imx_serial_port_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); - int ret; - - ret = clk_enable(sport->clk_ipg); - if (ret) - return ret; serial_imx_save_context(sport); @@ -2264,8 +2261,6 @@ static int imx_serial_port_resume_noirq(struct device *dev) serial_imx_restore_context(sport); - clk_disable(sport->clk_ipg); - return 0; } @@ -2273,15 +2268,19 @@ static int imx_serial_port_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); - - /* enable wakeup from i.MX UART */ - serial_imx_enable_wakeup(sport, true); + int ret; uart_suspend_port(&imx_reg, &sport->port); disable_irq(sport->port.irq); - /* Needed to enable clock in suspend_noirq */ - return clk_prepare(sport->clk_ipg); + ret = clk_prepare_enable(sport->clk_ipg); + if (ret) + return ret; + + /* enable wakeup from i.MX UART */ + serial_imx_enable_wakeup(sport, true); + + return 0; } static int imx_serial_port_resume(struct device *dev) @@ -2295,7 +2294,7 @@ static int imx_serial_port_resume(struct device *dev) uart_resume_port(&imx_reg, &sport->port); enable_irq(sport->port.irq); - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); return 0; } @@ -2307,8 +2306,7 @@ static int imx_serial_port_freeze(struct device *dev) uart_suspend_port(&imx_reg, &sport->port); - /* Needed to enable clock in suspend_noirq */ - return clk_prepare(sport->clk_ipg); + return clk_prepare_enable(sport->clk_ipg); } static int imx_serial_port_thaw(struct device *dev) @@ -2318,7 +2316,7 @@ static int imx_serial_port_thaw(struct device *dev) uart_resume_port(&imx_reg, &sport->port); - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); return 0; } -- cgit From b027e2298bd588d6fa36ed2eda97447fb3eac078 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 23 Jan 2018 13:16:34 +0530 Subject: tty: fix data race between tty_init_dev and flush of buf There can be a race, if receive_buf call comes before tty initialization completes in n_tty_open and tty->disc_data may be NULL. CPU0 CPU1 ---- ---- 000|n_tty_receive_buf_common() n_tty_open() -001|n_tty_receive_buf2() tty_ldisc_open.isra.3() -002|tty_ldisc_receive_buf(inline) tty_ldisc_setup() Using ldisc semaphore lock in tty_init_dev till disc_data initializes completely. Signed-off-by: Gaurav Kohli Reviewed-by: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 8 +++++++- drivers/tty/tty_ldisc.c | 4 ++-- include/linux/tty.h | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index a6ca634411e1..688bd25aa6b0 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1323,6 +1323,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n", __func__, tty->driver->name); + retval = tty_ldisc_lock(tty, 5 * HZ); + if (retval) + goto err_release_lock; tty->port->itty = tty; /* @@ -1333,6 +1336,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) retval = tty_ldisc_setup(tty, tty->link); if (retval) goto err_release_tty; + tty_ldisc_unlock(tty); /* Return the tty locked so that it cannot vanish under the caller */ return tty; @@ -1345,9 +1349,11 @@ err_module_put: /* call the tty release_tty routine to clean out this slot */ err_release_tty: - tty_unlock(tty); + tty_ldisc_unlock(tty); tty_info_ratelimited(tty, "ldisc open failed (%d), clearing slot %d\n", retval, idx); +err_release_lock: + tty_unlock(tty); release_tty(tty, idx); return ERR_PTR(retval); } diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 24ec5c7e6b20..4e7946c0484b 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -337,7 +337,7 @@ static inline void __tty_ldisc_unlock(struct tty_struct *tty) ldsem_up_write(&tty->ldisc_sem); } -static int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) +int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) { int ret; @@ -348,7 +348,7 @@ static int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) return 0; } -static void tty_ldisc_unlock(struct tty_struct *tty) +void tty_ldisc_unlock(struct tty_struct *tty) { clear_bit(TTY_LDISC_HALTED, &tty->flags); __tty_ldisc_unlock(tty); diff --git a/include/linux/tty.h b/include/linux/tty.h index 7ac8ba208b1f..0a6c71e0ad01 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -405,6 +405,8 @@ extern const char *tty_name(const struct tty_struct *tty); extern struct tty_struct *tty_kopen(dev_t device); extern void tty_kclose(struct tty_struct *tty); extern int tty_dev_name_to_number(const char *name, dev_t *number); +extern int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout); +extern void tty_ldisc_unlock(struct tty_struct *tty); #else static inline void tty_kref_put(struct tty_struct *tty) { } -- cgit From c7e1b4059075c9e8eed101d7cc5da43e95eb5e18 Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Wed, 24 Jan 2018 18:19:23 -0600 Subject: tty: serial: exar: Relocate sleep wake-up handling Exar sleep wake-up handling has been done on a per-channel basis by virtue of INT0 being accessible from each channel's address space. I believe this was initially done out of necessity, but now that Exar devices have their own driver, we can do things more efficiently by registering a dedicated INT0 handler at the PCI device level. I see this change providing the following benefits: 1. If more than one port is active, eliminates the redundant bus cycles for reading INT0 on every interrupt. 2. This note associated with hooking in the per-channel handler in 8250_port.c is resolved: /* Fixme: probably not the best place for this */ Cc: Matt Schulte Signed-off-by: Aaron Sierra Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 34 ++++++++++++++++++++++++++++++---- drivers/tty/serial/8250/8250_port.c | 26 -------------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index a402878c9f30..38af306ca0e8 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -34,6 +34,7 @@ #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define UART_EXAR_INT0 0x80 #define UART_EXAR_8XMODE 0x88 /* 8X sampling rate select */ #define UART_EXAR_FCTR 0x08 /* Feature Control Register */ @@ -121,6 +122,7 @@ struct exar8250_board { struct exar8250 { unsigned int nr; struct exar8250_board *board; + void __iomem *virt; int line[0]; }; @@ -131,12 +133,9 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, const struct exar8250_board *board = priv->board; unsigned int bar = 0; - if (!pcim_iomap_table(pcidev)[bar] && !pcim_iomap(pcidev, bar, 0)) - return -ENOMEM; - port->port.iotype = UPIO_MEM; port->port.mapbase = pci_resource_start(pcidev, bar) + offset; - port->port.membase = pcim_iomap_table(pcidev)[bar] + offset; + port->port.membase = priv->virt + offset; port->port.regshift = board->reg_shift; return 0; @@ -420,6 +419,25 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) port->port.private_data = NULL; } +/* + * These Exar UARTs have an extra interrupt indicator that could fire for a + * few interrupts that are not presented/cleared through IIR. One of which is + * a wakeup interrupt when coming out of sleep. These interrupts are only + * cleared by reading global INT0 or INT1 registers as interrupts are + * associated with channel 0. The INT[3:0] registers _are_ accessible from each + * channel's address space, but for the sake of bus efficiency we register a + * dedicated handler at the PCI device level to handle them. + */ +static irqreturn_t exar_misc_handler(int irq, void *data) +{ + struct exar8250 *priv = data; + + /* Clear all PCI interrupts by reading INT0. No effect on IIR */ + ioread8(priv->virt + UART_EXAR_INT0); + + return IRQ_HANDLED; +} + static int exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) { @@ -448,6 +466,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) return -ENOMEM; priv->board = board; + priv->virt = pcim_iomap(pcidev, bar, 0); + if (!priv->virt) + return -ENOMEM; pci_set_master(pcidev); @@ -461,6 +482,11 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) uart.port.irq = pci_irq_vector(pcidev, 0); uart.port.dev = &pcidev->dev; + rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler, + IRQF_SHARED, "exar_uart", priv); + if (rc) + return rc; + for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 11434551ac0a..1328c7e70108 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -441,7 +441,6 @@ static void io_serial_out(struct uart_port *p, int offset, int value) } static int serial8250_default_handle_irq(struct uart_port *port); -static int exar_handle_irq(struct uart_port *port); static void set_io_from_upio(struct uart_port *p) { @@ -1883,26 +1882,6 @@ static int serial8250_default_handle_irq(struct uart_port *port) return ret; } -/* - * These Exar UARTs have an extra interrupt indicator that could - * fire for a few unimplemented interrupts. One of which is a - * wakeup event when coming out of sleep. Put this here just - * to be on the safe side that these interrupts don't go unhandled. - */ -static int exar_handle_irq(struct uart_port *port) -{ - unsigned int iir = serial_port_in(port, UART_IIR); - int ret = 0; - - if (((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) && - serial_port_in(port, UART_EXAR_INT0) != 0) - ret = 1; - - ret |= serial8250_handle_irq(port, iir); - - return ret; -} - /* * Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP * have a programmable TX threshold that triggers the THRE interrupt in @@ -3067,11 +3046,6 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type == PORT_UNKNOWN) serial8250_release_std_resource(up); - /* Fixme: probably not the best place for this */ - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) - port->handle_irq = exar_handle_irq; - register_dev_spec_attr_grp(up); up->fcr = uart_config[up->port.type].fcr; } -- cgit