From 0f3b577384c07cdefd5735f78f9f375c6afe810e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 29 Aug 2021 15:19:27 +0200 Subject: [PATCH 01/86] dt-bindings: serial: brcm,bcm6345-uart: convert to the json-schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps validating DTS files. Redundant generic descriptions (e.g. "The base address of the UART register bank") were dropped and periph_clk was dropped from example as not required. Reviewed-by: Rob Herring Acked-by: Florian Fainelli Signed-off-by: Rafał Miłecki Link: https://lore.kernel.org/r/20210829131927.13682-1-zajec5@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/brcm,bcm6345-uart.txt | 36 -------------- .../bindings/serial/brcm,bcm6345-uart.yaml | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 36 deletions(-) delete mode 100644 Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.txt create mode 100644 Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.yaml diff --git a/Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.txt b/Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.txt deleted file mode 100644 index 8b2b0460259a..000000000000 --- a/Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.txt +++ /dev/null @@ -1,36 +0,0 @@ -* BCM63xx UART - -Required properties: - -- compatible: "brcm,bcm6345-uart" - -- reg: The base address of the UART register bank. - -- interrupts: A single interrupt specifier. - -- clocks: Clock driving the hardware; used to figure out the baud rate - divisor. - - -Optional properties: - -- clock-names: Should be "refclk". - -Example: - - uart0: serial@14e00520 { - compatible = "brcm,bcm6345-uart"; - reg = <0x14e00520 0x18>; - interrupt-parent = <&periph_intc>; - interrupts = <2>; - clocks = <&periph_clk>; - clock-names = "refclk"; - }; - - clocks { - periph_clk: periph_clk@0 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <54000000>; - }; - }; diff --git a/Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.yaml b/Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.yaml new file mode 100644 index 000000000000..a22285c43f80 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/brcm,bcm6345-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: BCM63xx UART + +maintainers: + - Rafał Miłecki + +allOf: + - $ref: serial.yaml# + +properties: + compatible: + const: brcm,bcm6345-uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: refclk + +unevaluatedProperties: false + +required: + - reg + - interrupts + - clocks + +examples: + - | + serial@14e00520 { + compatible = "brcm,bcm6345-uart"; + reg = <0x14e00520 0x18>; + interrupt-parent = <&periph_intc>; + interrupts = <2>; + clocks = <&periph_clk>; + clock-names = "refclk"; + }; From 42c457cc9a0a1a089ee4e8b4a32717412abb8d60 Mon Sep 17 00:00:00 2001 From: Len Baker Date: Sun, 5 Sep 2021 17:57:28 +0200 Subject: [PATCH 02/86] serial: 8250_pci: Prefer struct_size over open coded arithmetic As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. So, use the struct_size() helper to do the arithmetic instead of the argument "size + size * count" in the kzalloc() function. [1] https://www.kernel.org/doc/html/v5.14/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments Reviewed-by: Andy Shevchenko Signed-off-by: Len Baker Link: https://lore.kernel.org/r/20210905155728.11147-1-len.baker@gmx.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 726912b16a55..93159557a2fb 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -3981,9 +3981,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) nr_ports = rc; } - priv = kzalloc(sizeof(struct serial_private) + - sizeof(unsigned int) * nr_ports, - GFP_KERNEL); + priv = kzalloc(struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) { priv = ERR_PTR(-ENOMEM); goto err_deinit; From 538a9909205d1dd7dce737e3fd9a8fa3165a0c02 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Wed, 11 Aug 2021 14:48:23 +0300 Subject: [PATCH 03/86] dt-bindings: serial: samsung: Add Exynos850 doc Add compatible string for Exynos850 SoC. Reviewed-by: Krzysztof Kozlowski Acked-by: Rob Herring Signed-off-by: Sam Protsenko Link: https://lore.kernel.org/r/20210811114827.27322-4-semen.protsenko@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/samsung_uart.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index f064e5b76cf1..2940afb874b3 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -26,6 +26,7 @@ properties: - samsung,s3c6400-uart - samsung,s5pv210-uart - samsung,exynos4210-uart + - samsung,exynos850-uart reg: maxItems: 1 From f77529d9b91ac484d2ec4ad733e7594731334348 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Thu, 26 Aug 2021 15:21:51 -0400 Subject: [PATCH 04/86] dt-bindings: serial: uartlite: Convert to json-schema This converts the existing documentation for the uartlite binding to json-schema. Reviewed-by: Rob Herring Signed-off-by: Sean Anderson Link: https://lore.kernel.org/r/20210826192154.3202269-2-sean.anderson@seco.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/xlnx,opb-uartlite.txt | 23 -------- .../bindings/serial/xlnx,opb-uartlite.yaml | 53 +++++++++++++++++++ 2 files changed, 53 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.txt create mode 100644 Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml diff --git a/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.txt b/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.txt deleted file mode 100644 index c37deb44dead..000000000000 --- a/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.txt +++ /dev/null @@ -1,23 +0,0 @@ -Xilinx Axi Uartlite controller Device Tree Bindings ---------------------------------------------------------- - -Required properties: -- compatible : Can be either of - "xlnx,xps-uartlite-1.00.a" - "xlnx,opb-uartlite-1.00.b" -- reg : Physical base address and size of the Axi Uartlite - registers map. -- interrupts : Should contain the UART controller interrupt. - -Optional properties: -- port-number : Set Uart port number -- clock-names : Should be "s_axi_aclk" -- clocks : Input clock specifier. Refer to common clock bindings. - -Example: -serial@800c0000 { - compatible = "xlnx,xps-uartlite-1.00.a"; - reg = <0x0 0x800c0000 0x10000>; - interrupts = <0x0 0x6e 0x1>; - port-number = <0>; -}; diff --git a/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml b/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml new file mode 100644 index 000000000000..0cc94c920b17 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/xlnx,opb-uartlite.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx Axi Uartlite + +maintainers: + - Peter Korsgaard + +properties: + compatible: + contains: + enum: + - xlnx,xps-uartlite-1.00.a + - xlnx,opb-uartlite-1.00.b + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + port-number: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Set Uart port number + + clocks: + maxItems: 1 + + clock-names: + const: s_axi_aclk + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: /schemas/serial.yaml# + +unevaluatedProperties: false + +examples: + - | + serial@800c0000 { + compatible = "xlnx,xps-uartlite-1.00.a"; + reg = <0x800c0000 0x10000>; + interrupts = <0x0 0x6e 0x1>; + port-number = <0>; + }; +... From 3de536a8c365ada3481839ffe8da533c9940ea3f Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Thu, 26 Aug 2021 15:21:52 -0400 Subject: [PATCH 05/86] dt-bindings: serial: uartlite: Add properties for synthesis-time parameters The uartlite device is a "soft" device. Many parameters, such as baud rate, data bits, and the presence of a parity bit are configured before synthesis and may not be changed (or discovered) at runtime. However, we must know what these settings are in order to properly calculate the uart timeout (and to inform the user about the actual baud of the uart). These properties are present for out-of-tree bindings generated by Xilinx's tools. However, they are also (mostly) present in in-tree bindings. I chose current-speed over xlnx,baudrate primarily because it seemed to be used by more existing bindings. Although these properties are marked as "required", note that only current-speed is required by the driver itself. Hopefully, this will allow for an easier transition. Reviewed-by: Rob Herring Signed-off-by: Sean Anderson Link: https://lore.kernel.org/r/20210826192154.3202269-3-sean.anderson@seco.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/xlnx,opb-uartlite.yaml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml b/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml index 0cc94c920b17..b8a2bfe14bed 100644 --- a/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml +++ b/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml @@ -32,13 +32,47 @@ properties: clock-names: const: s_axi_aclk + current-speed: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The fixed baud rate that the device was configured for. + + xlnx,data-bits: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [5, 6, 7, 8] + description: + The fixed number of data bits that the device was configured for. + + xlnx,use-parity: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: + Whether parity checking was enabled when the device was configured. + + xlnx,odd-parity: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: + Whether odd parity was configured. + required: - compatible - reg - interrupts + - current-speed + - xlnx,data-bits + - xlnx,use-parity allOf: - $ref: /schemas/serial.yaml# + - if: + properties: + xlnx,use-parity: + contains: + const: 1 + then: + required: + - xlnx,odd-parity unevaluatedProperties: false @@ -49,5 +83,8 @@ examples: reg = <0x800c0000 0x10000>; interrupts = <0x0 0x6e 0x1>; port-number = <0>; + current-speed = <115200>; + xlnx,data-bits = <8>; + xlnx,use-parity = <0>; }; ... From 8517b62e0a28f474aeeb05dcadf0466965595550 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Thu, 26 Aug 2021 15:21:53 -0400 Subject: [PATCH 06/86] sh: j2: Update uartlite binding with data and parity properties These properties are necessary for properly calculating the uart timeout. I inspected the J2 source code, and believe these values to be correct. Signed-off-by: Sean Anderson Link: https://lore.kernel.org/r/20210826192154.3202269-4-sean.anderson@seco.com Signed-off-by: Greg Kroah-Hartman --- arch/sh/boot/dts/j2_mimas_v2.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sh/boot/dts/j2_mimas_v2.dts b/arch/sh/boot/dts/j2_mimas_v2.dts index 9f4742fab329..fa9562f78d53 100644 --- a/arch/sh/boot/dts/j2_mimas_v2.dts +++ b/arch/sh/boot/dts/j2_mimas_v2.dts @@ -88,6 +88,8 @@ clock-frequency = <125000000>; compatible = "xlnx,xps-uartlite-1.00.a"; current-speed = <19200>; + xlnx,use-parity = <0>; + xlnx,data-bits = <8>; device_type = "serial"; interrupts = <0x12>; port-number = <0>; From ea017f5853e9a6a11cfa9bdc61ba823a1ed54ee8 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Thu, 26 Aug 2021 15:21:54 -0400 Subject: [PATCH 07/86] tty: serial: uartlite: Prevent changing fixed parameters This device does not support changing baud, parity, data bits, stop bits, or detecting breaks. Disable "changing" these settings to prevent their termios from diverging from the actual state of the uart. In order to determine the correct parameters to enforce, we read the various new devicetree parameters to discover how the uart was configured when it was synthesized. The defaults match ulite_console_setup. xlnx,use-parity, xlnx,odd-parity, and xlnx,data-bits are optional since there were in-tree users (and presumably out-of-tree users) who did not set them. Signed-off-by: Sean Anderson Link: https://lore.kernel.org/r/20210826192154.3202269-5-sean.anderson@seco.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/uartlite.c | 91 ++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index dfc1ba4e1572..d3d9566e5dbd 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -63,9 +64,18 @@ static struct uart_port *console_port; #endif +/** + * struct uartlite_data: Driver private data + * reg_ops: Functions to read/write registers + * clk: Our parent clock, if present + * baud: The baud rate configured when this device was synthesized + * cflags: The cflags for parity and data bits + */ struct uartlite_data { const struct uartlite_reg_ops *reg_ops; struct clk *clk; + unsigned int baud; + tcflag_t cflags; }; struct uartlite_reg_ops { @@ -119,6 +129,8 @@ static inline void uart_out32(u32 val, u32 offset, struct uart_port *port) static struct uart_port ulite_ports[ULITE_NR_UARTS]; +static struct uart_driver ulite_uart_driver; + /* --------------------------------------------------------------------- * Core UART driver operations */ @@ -306,7 +318,12 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned long flags; - unsigned int baud; + struct uartlite_data *pdata = port->private_data; + + /* Set termios to what the hardware supports */ + termios->c_cflag &= ~(BRKINT | CSTOPB | PARENB | PARODD | CSIZE); + termios->c_cflag |= pdata->cflags & (PARENB | PARODD | CSIZE); + tty_termios_encode_baud_rate(termios, pdata->baud, pdata->baud); spin_lock_irqsave(&port->lock, flags); @@ -329,8 +346,7 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; /* update timeout */ - baud = uart_get_baud_rate(port, termios, old, 0, 460800); - uart_update_timeout(port, termios->c_cflag, baud); + uart_update_timeout(port, termios->c_cflag, pdata->baud); spin_unlock_irqrestore(&port->lock, flags); } @@ -532,8 +548,6 @@ static int ulite_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static struct uart_driver ulite_uart_driver; - static struct console ulite_console = { .name = ULITE_NAME, .write = ulite_console_write, @@ -765,18 +779,73 @@ static int ulite_probe(struct platform_device *pdev) struct uartlite_data *pdata; int irq, ret; int id = pdev->id; -#ifdef CONFIG_OF - const __be32 *prop; - prop = of_get_property(pdev->dev.of_node, "port-number", NULL); - if (prop) - id = be32_to_cpup(prop); -#endif pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data), GFP_KERNEL); if (!pdata) return -ENOMEM; + if (IS_ENABLED(CONFIG_OF)) { + const char *prop; + struct device_node *np = pdev->dev.of_node; + u32 val = 0; + + prop = "port-number"; + ret = of_property_read_u32(np, prop, &id); + if (ret && ret != -EINVAL) +of_err: + return dev_err_probe(&pdev->dev, ret, + "could not read %s\n", prop); + + prop = "current-speed"; + ret = of_property_read_u32(np, prop, &pdata->baud); + if (ret) + goto of_err; + + prop = "xlnx,use-parity"; + ret = of_property_read_u32(np, prop, &val); + if (ret && ret != -EINVAL) + goto of_err; + + if (val) { + prop = "xlnx,odd-parity"; + ret = of_property_read_u32(np, prop, &val); + if (ret) + goto of_err; + + if (val) + pdata->cflags |= PARODD; + pdata->cflags |= PARENB; + } + + val = 8; + prop = "xlnx,data-bits"; + ret = of_property_read_u32(np, prop, &val); + if (ret && ret != -EINVAL) + goto of_err; + + switch (val) { + case 5: + pdata->cflags |= CS5; + break; + case 6: + pdata->cflags |= CS6; + break; + case 7: + pdata->cflags |= CS7; + break; + case 8: + pdata->cflags |= CS8; + break; + default: + return dev_err_probe(&pdev->dev, -EINVAL, + "bad data bits %d\n", val); + } + } else { + pdata->baud = 9600; + pdata->cflags = CS8; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; From b9e851cd4a8749febb6d68d54d00ed7fe00633c9 Mon Sep 17 00:00:00 2001 From: Zhenguo Zhao Date: Fri, 20 Aug 2021 20:17:45 +0800 Subject: [PATCH 08/86] tty: n_gsm: Add some instructions and code for requester The gsm driver can configure initiator or requester by parameter initiator,but the config code and using are different ,the doc has initiator instructions only,it should be add instructions for requester. Signed-off-by: Zhenguo Zhao Link: https://lore.kernel.org/r/1629461872-26965-1-git-send-email-zhenguo6858@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/n_gsm.rst | 71 ++++++++++++++++++++--- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/Documentation/driver-api/serial/n_gsm.rst b/Documentation/driver-api/serial/n_gsm.rst index 87dfcd54a96b..8fe723ab9c67 100644 --- a/Documentation/driver-api/serial/n_gsm.rst +++ b/Documentation/driver-api/serial/n_gsm.rst @@ -12,13 +12,16 @@ modems connected to a physical serial port. How to use it ------------- -1. initialize the modem in 0710 mux mode (usually AT+CMUX= command) through - its serial port. Depending on the modem used, you can pass more or less - parameters to this command, -2. switch the serial line to using the n_gsm line discipline by using - TIOCSETD ioctl, -3. configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl, -4. obtain base gsmtty number for the used serial port, +1. config initiator +^^^^^^^^^^^^^^^^^^^^^ + +1.1 initialize the modem in 0710 mux mode (usually AT+CMUX= command) through + its serial port. Depending on the modem used, you can pass more or less + parameters to this command. +1.2 switch the serial line to using the n_gsm line discipline by using + TIOCSETD ioctl. +1.3 configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl. +1.4 obtain base gsmtty number for the used serial port. Major parts of the initialization program : (a good starting point is util-linux-ng/sys-utils/ldattach.c):: @@ -70,14 +73,14 @@ Major parts of the initialization program : daemon(0,0); pause(); -5. use these devices as plain serial ports. +1.5 use these devices as plain serial ports. for example, it's possible: - and to use gnokii to send / receive SMS on ttygsm1 - to use ppp to establish a datalink on ttygsm2 -6. first close all virtual ports before closing the physical port. +1.6 first close all virtual ports before closing the physical port. Note that after closing the physical port the modem is still in multiplexing mode. This may prevent a successful re-opening of the port later. To avoid @@ -87,6 +90,56 @@ Major parts of the initialization program : 0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9. +2. config requester +^^^^^^^^^^^^^^^^^^^^^ + +2.1 receive string "AT+CMUX= command" through its serial port,initialize + mux mode config +2.2 switch the serial line to using the n_gsm line discipline by using + TIOCSETD ioctl. +2.3 configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl. +2.4 obtain base gsmtty number for the used serial port, + + #include + #include + #include + #include + #define DEFAULT_SPEED B115200 + #define SERIAL_PORT /dev/ttyS0 + + int ldisc = N_GSM0710; + struct gsm_config c; + struct termios configuration; + uint32_t first; + + /* open the serial port */ + fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY); + + /* configure the serial port : speed, flow control ... */ + + /* get serial data and check "AT+CMUX=command" parameter ... */ + + /* use n_gsm line discipline */ + ioctl(fd, TIOCSETD, &ldisc); + + /* get n_gsm configuration */ + ioctl(fd, GSMIOC_GETCONF, &c); + /* we are requester and need encoding 0 (basic) */ + c.initiator = 0; + c.encapsulation = 0; + /* our modem defaults to a maximum size of 127 bytes */ + c.mru = 127; + c.mtu = 127; + /* set the new configuration */ + ioctl(fd, GSMIOC_SETCONF, &c); + /* get first gsmtty device node */ + ioctl(fd, GSMIOC_GETFIRST, &first); + printf("first muxed line: /dev/gsmtty%i\n", first); + + /* and wait for ever to keep the line discipline enabled */ + daemon(0,0); + pause(); + Additional Documentation ------------------------ More practical details on the protocol and how it's supported by industrial From cd936621379d513bd768319219840b003a45e729 Mon Sep 17 00:00:00 2001 From: Zhenguo Zhao Date: Fri, 20 Aug 2021 20:17:46 +0800 Subject: [PATCH 09/86] tty: n_gsm: Modify cr bit value when config requester When n_gsm config "initiator=0",as requester,gsmld will receive dlci SABM and DISC control command frame,the CR bit value should be 1. If cr == 0,it will goto invalid,and it can't send UA response frame and open requster dlci. case SABM|PF: - if (cr == 0) + if (cr == 0) { + printk("gsm_queue invalid\n"); goto invalid; + } Example,gsmld receive dlc0 SABM command frame:f9 03 3f 01 1c f9 but gsmld goto invalid. Kernel test log: [ 101.794705] c0 gsmld_receive: 00000000: f9 03 3f 01 1c f9 [ 101.803341] c0 <-- 0) C: SABM(P) [ 101.811371] c0 gsm_queue invalid Signed-off-by: Zhenguo Zhao Link: https://lore.kernel.org/r/1629461872-26965-2-git-send-email-zhenguo6858@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 1d92d2a84889..25ba5e669fb9 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1779,7 +1779,7 @@ static void gsm_queue(struct gsm_mux *gsm) switch (gsm->control) { case SABM|PF: - if (cr == 0) + if (cr == 1) goto invalid; if (dlci == NULL) dlci = gsm_dlci_alloc(gsm, address); @@ -1793,7 +1793,7 @@ static void gsm_queue(struct gsm_mux *gsm) } break; case DISC|PF: - if (cr == 0) + if (cr == 1) goto invalid; if (dlci == NULL || dlci->state == DLCI_CLOSED) { gsm_response(gsm, address, DM); From cc0f42122a7e7a5ede9c5f2a41199128b8449eda Mon Sep 17 00:00:00 2001 From: Zhenguo Zhao Date: Fri, 20 Aug 2021 20:17:47 +0800 Subject: [PATCH 10/86] tty: n_gsm: Modify CR,PF bit when config requester When n_gsm config "initiator=0",as requester,gsmld receives dlci SABM/DISC control command frame,but send UA frame is error. Example: Gsmld receive dlc0 SABM frame "f9 03 3f 01 1c f9",now it sends UA frame "f9 01 63 01 a3 f9",CR and PF bit are 0,but it should be set 1 from requster to initiator. Kernel test log as follows: Before modify [ 271.732031] c1 gsmld_receive: 00000000: f9 03 3f 01 1c f9 [ 271.741719] c1 <-- 0) C: SABM(P) [ 271.749483] c1 gsmld_output: 00000000: f9 01 63 01 a3 f9 [ 271.758337] c1 --> 0) R: UA(F) After modify [ 261.233188] c0 gsmld_receive: 00000000: f9 03 3f 01 1c f9 [ 261.242767] c0 <-- 0) C: SABM(P) [ 261.250497] c0 gsmld_output: 00000000: f9 03 73 01 d7 f9 [ 261.259759] c0 --> 0) C: UA(P) Signed-off-by: Zhenguo Zhao Link: https://lore.kernel.org/r/1629461872-26965-3-git-send-email-zhenguo6858@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 25ba5e669fb9..3ba0391e2a5e 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -601,7 +601,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) static inline void gsm_response(struct gsm_mux *gsm, int addr, int control) { - gsm_send(gsm, addr, 0, control); + gsm_send(gsm, addr, 1, control); } /** @@ -1786,9 +1786,9 @@ static void gsm_queue(struct gsm_mux *gsm) if (dlci == NULL) return; if (dlci->dead) - gsm_response(gsm, address, DM); + gsm_response(gsm, address, DM|PF); else { - gsm_response(gsm, address, UA); + gsm_response(gsm, address, UA|PF); gsm_dlci_open(dlci); } break; @@ -1796,11 +1796,11 @@ static void gsm_queue(struct gsm_mux *gsm) if (cr == 1) goto invalid; if (dlci == NULL || dlci->state == DLCI_CLOSED) { - gsm_response(gsm, address, DM); + gsm_response(gsm, address, DM|PF); return; } /* Real close complete */ - gsm_response(gsm, address, UA); + gsm_response(gsm, address, UA|PF); gsm_dlci_close(dlci); break; case UA: From f999c3b35735d9e9b33a7be7b071f8ad75237f68 Mon Sep 17 00:00:00 2001 From: Zhenguo Zhao Date: Fri, 20 Aug 2021 20:17:48 +0800 Subject: [PATCH 11/86] tty: n_gsm: Modify CR,PF bit printk info when config requester When n_gsm config "initiator=0",as requester,gsmld receives dlci SABM/DISC control command frame,UA frame printk info is error. Example: Gsmld send UA frame "f9 03 73 01 d7 f9",but CR,PF bit printk info looks like error. Kernel test log as follows: Before modify [ 78.837626] c0 gsmld_receive: 00000000: f9 03 3f 01 1c f9 [ 78.846356] c0 <-- 0) C: SABM(P) [ 78.854021] c0 gsmld_output: 00000000: f9 03 73 01 d7 f9 [ 78.862574] c0 --> 0) C: UA(P) After modify [ 261.233188] c0 gsmld_receive: 00000000: f9 03 3f 01 1c f9 [ 261.242767] c0 <-- 0) C: SABM(P) [ 261.250497] c0 gsmld_output: 00000000: f9 03 73 01 d7 f9 [ 261.259759] c0 --> 0) R: UA(F) Signed-off-by: Zhenguo Zhao Link: https://lore.kernel.org/r/1629461872-26965-4-git-send-email-zhenguo6858@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 3ba0391e2a5e..563b685de88c 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -587,6 +587,10 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) return; } gsmld_output(gsm, cbuf, len); + if (!gsm->initiator) { + cr = cr & gsm->initiator; + control = control & ~PF; + } gsm_print_packet("-->", addr, cr, control, NULL, 0); } From 509067bbd2644ed8f59b84b5db95a985633004ba Mon Sep 17 00:00:00 2001 From: Zhenguo Zhao Date: Fri, 20 Aug 2021 20:17:49 +0800 Subject: [PATCH 12/86] tty: n_gsm: Delete gsm_disconnect when config requester When n_gsm config "initiator=0",when gsmld config ,as requester ,it doesn't need to send CLD frame data or SABM frame. Example,when tty dev receive "AT+CMUX=0",it will change ldisc n_tty to n_gsm,during config requester,gsmld output "7e 01 ef c3 aa 7e", initiator maybe not want to receive the frame data. [ 154.666457] c1 Q> 0) R: UIH(F) [ 154.669514] c1 C3 [ 154.671519] c1 gsmld_output: 00000000: 7e 01 ef c3 aa 7e [ 155.014874] c1 Q> 0) R: UIH(F) [ 155.018000] c1 C3 [ 155.020046] c1 gsmld_output: 00000000: 7e 01 ef c3 aa 7e [ 155.364425] c1 Q> 0) R: UIH(F) [ 155.367546] c1 C3 [ 155.369597] c1 gsmld_output: 00000000: 7e 01 ef c3 aa 7e Signed-off-by: Zhenguo Zhao Link: https://lore.kernel.org/r/1629461872-26965-5-git-send-email-zhenguo6858@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 563b685de88c..fd980a68c7ea 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2304,7 +2304,7 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c) * configuration */ - if (need_close || need_restart) { + if (gsm->initiator && (need_close || need_restart)) { int ret; ret = gsm_disconnect(gsm); From cbff2b32516881bef30bbebf413d1b49495bab1d Mon Sep 17 00:00:00 2001 From: Zhenguo Zhao Date: Fri, 20 Aug 2021 20:17:50 +0800 Subject: [PATCH 13/86] tty: n_gsm: Delete gsmtty open SABM frame when config requester When n_gsm config "initiator=0",as requester ,it doesn't need to send SABM frame data during gsmtty open. Example,when gsmtty open,it will send SABM frame.for initiator,it maybe not want to receive the frame. [ 88.410426] c1 gsmld_output: 00000000: f9 07 3f 01 de f9 [ 88.420839] c1 --> 1) R: SABM(F) Signed-off-by: Zhenguo Zhao Link: https://lore.kernel.org/r/1629461872-26965-6-git-send-email-zhenguo6858@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index fd980a68c7ea..daf38ce5abd6 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3004,6 +3004,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) { struct gsm_dlci *dlci = tty->driver_data; struct tty_port *port = &dlci->port; + struct gsm_mux *gsm = dlci->gsm; port->count++; tty_port_tty_set(port, tty); @@ -3013,7 +3014,8 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) a DM straight back. This is ok as that will have caused a hangup */ tty_port_set_initialized(port, 1); /* Start sending off SABM messages */ - gsm_dlci_begin_open(dlci); + if (gsm->initiator) + gsm_dlci_begin_open(dlci); /* And wait for virtual carrier */ return tty_port_block_til_ready(port, tty, filp); } From 5b87686e3203808cd6442dc3c686b9c90b435bce Mon Sep 17 00:00:00 2001 From: Zhenguo Zhao Date: Fri, 20 Aug 2021 20:17:51 +0800 Subject: [PATCH 14/86] tty: n_gsm: Modify gsmtty driver register method when config requester As requester,because n_gsm has no uevent report for application,the application can't know dlci connect or disconnect. The application will control every dlcl dev by uevent,when application receive gsmtty0 dev remove uevent,it will close mux function,and change to normal mode. Example: Before modify: gsmld receive DLC0 DISC,no event report to application gsmld receive DLC1 SABM,no event report to application gsmld receive DLC1 DISC,no event report to application After modify: Receive DLC0 DISC,report "/devices/virtual/tty/gsmtty0" remove uevent Receive DLC1 SABM,report "/devices/virtual/tty/gsmtty1" add uevent Receive DLC1 DISC,report "/devices/virtual/tty/gsmtty1" remove uevent Signed-off-by: Zhenguo Zhao Link: https://lore.kernel.org/r/1629461872-26965-7-git-send-email-zhenguo6858@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index daf38ce5abd6..db55f3fb0cdb 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1433,6 +1433,8 @@ static void gsm_dlci_close(struct gsm_dlci *dlci) kfifo_reset(&dlci->fifo); } else dlci->gsm->dead = true; + /* Unregister gsmtty driver,report gsmtty dev remove uevent for user */ + tty_unregister_device(gsm_tty_driver, dlci->addr); wake_up(&dlci->gsm->event); /* A DLCI 0 close is a MUX termination so we need to kick that back to userspace somehow */ @@ -1454,6 +1456,8 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) dlci->state = DLCI_OPEN; if (debug & 8) pr_debug("DLCI %d goes open.\n", dlci->addr); + /* Register gsmtty driver,report gsmtty dev add uevent for user */ + tty_register_device(gsm_tty_driver, dlci->addr, NULL); wake_up(&dlci->gsm->event); } @@ -2388,17 +2392,19 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) else { /* Don't register device 0 - this is the control channel and not a usable tty interface */ - base = mux_num_to_base(gsm); /* Base for this MUX */ - for (i = 1; i < NUM_DLCI; i++) { - struct device *dev; + if (gsm->initiator) { + base = mux_num_to_base(gsm); /* Base for this MUX */ + for (i = 1; i < NUM_DLCI; i++) { + struct device *dev; - dev = tty_register_device(gsm_tty_driver, + dev = tty_register_device(gsm_tty_driver, base + i, NULL); - if (IS_ERR(dev)) { - for (i--; i >= 1; i--) - tty_unregister_device(gsm_tty_driver, - base + i); - return PTR_ERR(dev); + if (IS_ERR(dev)) { + for (i--; i >= 1; i--) + tty_unregister_device(gsm_tty_driver, + base + i); + return PTR_ERR(dev); + } } } } @@ -2420,8 +2426,10 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) int i; WARN_ON(tty != gsm->tty); - for (i = 1; i < NUM_DLCI; i++) - tty_unregister_device(gsm_tty_driver, base + i); + if (gsm->initiator) { + for (i = 1; i < NUM_DLCI; i++) + tty_unregister_device(gsm_tty_driver, base + i); + } gsm_cleanup_mux(gsm); tty_kref_put(gsm->tty); gsm->tty = NULL; From 0b91b5332368f2fb0c3e5cfebc6aff9e167acd8b Mon Sep 17 00:00:00 2001 From: Zhenguo Zhao Date: Fri, 20 Aug 2021 20:17:52 +0800 Subject: [PATCH 15/86] tty: n_gsm: Save dlci address open status when config requester When n_gsm config "initiator=0",as requester ,receive SABM frame,n_gsm register gsmtty dev,and save dlci open address status,if receive DLC0 DISC or CLD frame,it can unregister the gsmtty dev by saving dlci address. Signed-off-by: Zhenguo Zhao Link: https://lore.kernel.org/r/1629461872-26965-8-git-send-email-zhenguo6858@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 57 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index db55f3fb0cdb..157b51ce9cc0 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -271,6 +271,10 @@ static DEFINE_SPINLOCK(gsm_mux_lock); static struct tty_driver *gsm_tty_driver; +/* Save dlci open address */ +static int addr_open[256] = { 0 }; +/* Save dlci open count */ +static int addr_cnt; /* * This section of the driver logic implements the GSM encodings * both the basic and the 'advanced'. Reliable transport is not @@ -1181,6 +1185,7 @@ static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen) } static void gsm_dlci_begin_close(struct gsm_dlci *dlci); +static void gsm_dlci_close(struct gsm_dlci *dlci); /** * gsm_control_message - DLCI 0 control processing @@ -1199,15 +1204,28 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, { u8 buf[1]; unsigned long flags; + struct gsm_dlci *dlci; + int i; + int address; switch (command) { case CMD_CLD: { - struct gsm_dlci *dlci = gsm->dlci[0]; + if (addr_cnt > 0) { + for (i = 0; i < addr_cnt; i++) { + address = addr_open[i]; + dlci = gsm->dlci[address]; + gsm_dlci_close(dlci); + addr_open[i] = 0; + } + } /* Modem wishes to close down */ + dlci = gsm->dlci[0]; if (dlci) { dlci->dead = true; gsm->dead = true; - gsm_dlci_begin_close(dlci); + gsm_dlci_close(dlci); + addr_cnt = 0; + gsm_response(gsm, 0, UA|PF); } } break; @@ -1756,6 +1774,7 @@ static void gsm_queue(struct gsm_mux *gsm) struct gsm_dlci *dlci; u8 cr; int address; + int i, j, k, address_tmp; /* We have to sneak a look at the packet body to do the FCS. A somewhat layering violation in the spec */ @@ -1798,6 +1817,11 @@ static void gsm_queue(struct gsm_mux *gsm) else { gsm_response(gsm, address, UA|PF); gsm_dlci_open(dlci); + /* Save dlci open address */ + if (address) { + addr_open[addr_cnt] = address; + addr_cnt++; + } } break; case DISC|PF: @@ -1808,8 +1832,33 @@ static void gsm_queue(struct gsm_mux *gsm) return; } /* Real close complete */ - gsm_response(gsm, address, UA|PF); - gsm_dlci_close(dlci); + if (!address) { + if (addr_cnt > 0) { + for (i = 0; i < addr_cnt; i++) { + address = addr_open[i]; + dlci = gsm->dlci[address]; + gsm_dlci_close(dlci); + addr_open[i] = 0; + } + } + dlci = gsm->dlci[0]; + gsm_dlci_close(dlci); + addr_cnt = 0; + gsm_response(gsm, 0, UA|PF); + } else { + gsm_response(gsm, address, UA|PF); + gsm_dlci_close(dlci); + /* clear dlci address */ + for (j = 0; j < addr_cnt; j++) { + address_tmp = addr_open[j]; + if (address_tmp == address) { + for (k = j; k < addr_cnt; k++) + addr_open[k] = addr_open[k+1]; + addr_cnt--; + break; + } + } + } break; case UA: case UA|PF: From b55c8aa6b1abfc0fb0beede48627ac4d13b5ddc7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Sep 2021 11:08:23 +0200 Subject: [PATCH 16/86] tty: moxa: merge moxa.h into moxa.c There is no need for existence of a separate header for Moxa's Intellio cards. Merge it into moxa.c to clean up the tty dir a bit. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210914090823.17206-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/moxa.c | 302 +++++++++++++++++++++++++++++++++++++++++++- drivers/tty/moxa.h | 307 --------------------------------------------- 2 files changed, 301 insertions(+), 308 deletions(-) delete mode 100644 drivers/tty/moxa.h diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index bf17e90858b8..e37683e25055 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -45,7 +45,307 @@ #include #include -#include "moxa.h" +#define MOXA 0x400 +#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */ +#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */ +#define MOXA_GETDATACOUNT (MOXA + 23) +#define MOXA_GET_IOQUEUE (MOXA + 27) +#define MOXA_FLUSH_QUEUE (MOXA + 28) +#define MOXA_GETMSTATUS (MOXA + 65) + +/* + * System Configuration + */ + +#define Magic_code 0x404 + +/* + * for C218 BIOS initialization + */ +#define C218_ConfBase 0x800 +#define C218_status (C218_ConfBase + 0) /* BIOS running status */ +#define C218_diag (C218_ConfBase + 2) /* diagnostic status */ +#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */ +#define C218DLoad_len (C218_ConfBase + 6) /* WORD */ +#define C218check_sum (C218_ConfBase + 8) /* BYTE */ +#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */ +#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */ +#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */ +#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */ +#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */ + +#define C218_LoadBuf 0x0F00 +#define C218_KeyCode 0x218 +#define CP204J_KeyCode 0x204 + +/* + * for C320 BIOS initialization + */ +#define C320_ConfBase 0x800 +#define C320_LoadBuf 0x0f00 +#define STS_init 0x05 /* for C320_status */ + +#define C320_status C320_ConfBase + 0 /* BIOS running status */ +#define C320_diag C320_ConfBase + 2 /* diagnostic status */ +#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */ +#define C320DLoad_len C320_ConfBase + 6 /* WORD */ +#define C320check_sum C320_ConfBase + 8 /* WORD */ +#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */ +#define C320bapi_len C320_ConfBase + 0x0c /* WORD */ +#define C320UART_no C320_ConfBase + 0x0e /* WORD */ + +#define C320_KeyCode 0x320 + +#define FixPage_addr 0x0000 /* starting addr of static page */ +#define DynPage_addr 0x2000 /* starting addr of dynamic page */ +#define C218_start 0x3000 /* starting addr of C218 BIOS prg */ +#define Control_reg 0x1ff0 /* select page and reset control */ +#define HW_reset 0x80 + +/* + * Function Codes + */ +#define FC_CardReset 0x80 +#define FC_ChannelReset 1 /* C320 firmware not supported */ +#define FC_EnableCH 2 +#define FC_DisableCH 3 +#define FC_SetParam 4 +#define FC_SetMode 5 +#define FC_SetRate 6 +#define FC_LineControl 7 +#define FC_LineStatus 8 +#define FC_XmitControl 9 +#define FC_FlushQueue 10 +#define FC_SendBreak 11 +#define FC_StopBreak 12 +#define FC_LoopbackON 13 +#define FC_LoopbackOFF 14 +#define FC_ClrIrqTable 15 +#define FC_SendXon 16 +#define FC_SetTermIrq 17 /* C320 firmware not supported */ +#define FC_SetCntIrq 18 /* C320 firmware not supported */ +#define FC_SetBreakIrq 19 +#define FC_SetLineIrq 20 +#define FC_SetFlowCtl 21 +#define FC_GenIrq 22 +#define FC_InCD180 23 +#define FC_OutCD180 24 +#define FC_InUARTreg 23 +#define FC_OutUARTreg 24 +#define FC_SetXonXoff 25 +#define FC_OutCD180CCR 26 +#define FC_ExtIQueue 27 +#define FC_ExtOQueue 28 +#define FC_ClrLineIrq 29 +#define FC_HWFlowCtl 30 +#define FC_GetClockRate 35 +#define FC_SetBaud 36 +#define FC_SetDataMode 41 +#define FC_GetCCSR 43 +#define FC_GetDataError 45 +#define FC_RxControl 50 +#define FC_ImmSend 51 +#define FC_SetXonState 52 +#define FC_SetXoffState 53 +#define FC_SetRxFIFOTrig 54 +#define FC_SetTxFIFOCnt 55 +#define FC_UnixRate 56 +#define FC_UnixResetTimer 57 + +#define RxFIFOTrig1 0 +#define RxFIFOTrig4 1 +#define RxFIFOTrig8 2 +#define RxFIFOTrig14 3 + +/* + * Dual-Ported RAM + */ +#define DRAM_global 0 +#define INT_data (DRAM_global + 0) +#define Config_base (DRAM_global + 0x108) + +#define IRQindex (INT_data + 0) +#define IRQpending (INT_data + 4) +#define IRQtable (INT_data + 8) + +/* + * Interrupt Status + */ +#define IntrRx 0x01 /* receiver data O.K. */ +#define IntrTx 0x02 /* transmit buffer empty */ +#define IntrFunc 0x04 /* function complete */ +#define IntrBreak 0x08 /* received break */ +#define IntrLine 0x10 /* line status change + for transmitter */ +#define IntrIntr 0x20 /* received INTR code */ +#define IntrQuit 0x40 /* received QUIT code */ +#define IntrEOF 0x80 /* received EOF code */ + +#define IntrRxTrigger 0x100 /* rx data count reach trigger value */ +#define IntrTxTrigger 0x200 /* tx data count below trigger value */ + +#define Magic_no (Config_base + 0) +#define Card_model_no (Config_base + 2) +#define Total_ports (Config_base + 4) +#define Module_cnt (Config_base + 8) +#define Module_no (Config_base + 10) +#define Timer_10ms (Config_base + 14) +#define Disable_IRQ (Config_base + 20) +#define TMS320_PORT1 (Config_base + 22) +#define TMS320_PORT2 (Config_base + 24) +#define TMS320_CLOCK (Config_base + 26) + +/* + * DATA BUFFER in DRAM + */ +#define Extern_table 0x400 /* Base address of the external table + (24 words * 64) total 3K bytes + (24 words * 128) total 6K bytes */ +#define Extern_size 0x60 /* 96 bytes */ +#define RXrptr 0x00 /* read pointer for RX buffer */ +#define RXwptr 0x02 /* write pointer for RX buffer */ +#define TXrptr 0x04 /* read pointer for TX buffer */ +#define TXwptr 0x06 /* write pointer for TX buffer */ +#define HostStat 0x08 /* IRQ flag and general flag */ +#define FlagStat 0x0A +#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */ + /* x x x x | | | | */ + /* | | | + CTS flow */ + /* | | +--- RTS flow */ + /* | +------ TX Xon/Xoff */ + /* +--------- RX Xon/Xoff */ +#define Break_cnt 0x0E /* received break count */ +#define CD180TXirq 0x10 /* if non-0: enable TX irq */ +#define RX_mask 0x12 +#define TX_mask 0x14 +#define Ofs_rxb 0x16 +#define Ofs_txb 0x18 +#define Page_rxb 0x1A +#define Page_txb 0x1C +#define EndPage_rxb 0x1E +#define EndPage_txb 0x20 +#define Data_error 0x22 +#define RxTrigger 0x28 +#define TxTrigger 0x2a + +#define rRXwptr 0x34 +#define Low_water 0x36 + +#define FuncCode 0x40 +#define FuncArg 0x42 +#define FuncArg1 0x44 + +#define C218rx_size 0x2000 /* 8K bytes */ +#define C218tx_size 0x8000 /* 32K bytes */ + +#define C218rx_mask (C218rx_size - 1) +#define C218tx_mask (C218tx_size - 1) + +#define C320p8rx_size 0x2000 +#define C320p8tx_size 0x8000 +#define C320p8rx_mask (C320p8rx_size - 1) +#define C320p8tx_mask (C320p8tx_size - 1) + +#define C320p16rx_size 0x2000 +#define C320p16tx_size 0x4000 +#define C320p16rx_mask (C320p16rx_size - 1) +#define C320p16tx_mask (C320p16tx_size - 1) + +#define C320p24rx_size 0x2000 +#define C320p24tx_size 0x2000 +#define C320p24rx_mask (C320p24rx_size - 1) +#define C320p24tx_mask (C320p24tx_size - 1) + +#define C320p32rx_size 0x1000 +#define C320p32tx_size 0x1000 +#define C320p32rx_mask (C320p32rx_size - 1) +#define C320p32tx_mask (C320p32tx_size - 1) + +#define Page_size 0x2000U +#define Page_mask (Page_size - 1) +#define C218rx_spage 3 +#define C218tx_spage 4 +#define C218rx_pageno 1 +#define C218tx_pageno 4 +#define C218buf_pageno 5 + +#define C320p8rx_spage 3 +#define C320p8tx_spage 4 +#define C320p8rx_pgno 1 +#define C320p8tx_pgno 4 +#define C320p8buf_pgno 5 + +#define C320p16rx_spage 3 +#define C320p16tx_spage 4 +#define C320p16rx_pgno 1 +#define C320p16tx_pgno 2 +#define C320p16buf_pgno 3 + +#define C320p24rx_spage 3 +#define C320p24tx_spage 4 +#define C320p24rx_pgno 1 +#define C320p24tx_pgno 1 +#define C320p24buf_pgno 2 + +#define C320p32rx_spage 3 +#define C320p32tx_ofs C320p32rx_size +#define C320p32tx_spage 3 +#define C320p32buf_pgno 1 + +/* + * Host Status + */ +#define WakeupRx 0x01 +#define WakeupTx 0x02 +#define WakeupBreak 0x08 +#define WakeupLine 0x10 +#define WakeupIntr 0x20 +#define WakeupQuit 0x40 +#define WakeupEOF 0x80 /* used in VTIME control */ +#define WakeupRxTrigger 0x100 +#define WakeupTxTrigger 0x200 +/* + * Flag status + */ +#define Rx_over 0x01 +#define Xoff_state 0x02 +#define Tx_flowOff 0x04 +#define Tx_enable 0x08 +#define CTS_state 0x10 +#define DSR_state 0x20 +#define DCD_state 0x80 +/* + * FlowControl + */ +#define CTS_FlowCtl 1 +#define RTS_FlowCtl 2 +#define Tx_FlowCtl 4 +#define Rx_FlowCtl 8 +#define IXM_IXANY 0x10 + +#define LowWater 128 + +#define DTR_ON 1 +#define RTS_ON 2 +#define CTS_ON 1 +#define DSR_ON 2 +#define DCD_ON 8 + +/* mode definition */ +#define MX_CS8 0x03 +#define MX_CS7 0x02 +#define MX_CS6 0x01 +#define MX_CS5 0x00 + +#define MX_STOP1 0x00 +#define MX_STOP15 0x04 +#define MX_STOP2 0x08 + +#define MX_PARNONE 0x00 +#define MX_PAREVEN 0x40 +#define MX_PARODD 0xC0 +#define MX_PARMARK 0xA0 +#define MX_PARSPACE 0x20 #define MOXA_VERSION "6.0k" diff --git a/drivers/tty/moxa.h b/drivers/tty/moxa.h deleted file mode 100644 index f0a4381b6861..000000000000 --- a/drivers/tty/moxa.h +++ /dev/null @@ -1,307 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef MOXA_H_FILE -#define MOXA_H_FILE - -#define MOXA 0x400 -#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */ -#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */ -#define MOXA_GETDATACOUNT (MOXA + 23) -#define MOXA_GET_IOQUEUE (MOXA + 27) -#define MOXA_FLUSH_QUEUE (MOXA + 28) -#define MOXA_GETMSTATUS (MOXA + 65) - -/* - * System Configuration - */ - -#define Magic_code 0x404 - -/* - * for C218 BIOS initialization - */ -#define C218_ConfBase 0x800 -#define C218_status (C218_ConfBase + 0) /* BIOS running status */ -#define C218_diag (C218_ConfBase + 2) /* diagnostic status */ -#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */ -#define C218DLoad_len (C218_ConfBase + 6) /* WORD */ -#define C218check_sum (C218_ConfBase + 8) /* BYTE */ -#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */ -#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */ -#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */ -#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */ -#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */ - -#define C218_LoadBuf 0x0F00 -#define C218_KeyCode 0x218 -#define CP204J_KeyCode 0x204 - -/* - * for C320 BIOS initialization - */ -#define C320_ConfBase 0x800 -#define C320_LoadBuf 0x0f00 -#define STS_init 0x05 /* for C320_status */ - -#define C320_status C320_ConfBase + 0 /* BIOS running status */ -#define C320_diag C320_ConfBase + 2 /* diagnostic status */ -#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */ -#define C320DLoad_len C320_ConfBase + 6 /* WORD */ -#define C320check_sum C320_ConfBase + 8 /* WORD */ -#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */ -#define C320bapi_len C320_ConfBase + 0x0c /* WORD */ -#define C320UART_no C320_ConfBase + 0x0e /* WORD */ - -#define C320_KeyCode 0x320 - -#define FixPage_addr 0x0000 /* starting addr of static page */ -#define DynPage_addr 0x2000 /* starting addr of dynamic page */ -#define C218_start 0x3000 /* starting addr of C218 BIOS prg */ -#define Control_reg 0x1ff0 /* select page and reset control */ -#define HW_reset 0x80 - -/* - * Function Codes - */ -#define FC_CardReset 0x80 -#define FC_ChannelReset 1 /* C320 firmware not supported */ -#define FC_EnableCH 2 -#define FC_DisableCH 3 -#define FC_SetParam 4 -#define FC_SetMode 5 -#define FC_SetRate 6 -#define FC_LineControl 7 -#define FC_LineStatus 8 -#define FC_XmitControl 9 -#define FC_FlushQueue 10 -#define FC_SendBreak 11 -#define FC_StopBreak 12 -#define FC_LoopbackON 13 -#define FC_LoopbackOFF 14 -#define FC_ClrIrqTable 15 -#define FC_SendXon 16 -#define FC_SetTermIrq 17 /* C320 firmware not supported */ -#define FC_SetCntIrq 18 /* C320 firmware not supported */ -#define FC_SetBreakIrq 19 -#define FC_SetLineIrq 20 -#define FC_SetFlowCtl 21 -#define FC_GenIrq 22 -#define FC_InCD180 23 -#define FC_OutCD180 24 -#define FC_InUARTreg 23 -#define FC_OutUARTreg 24 -#define FC_SetXonXoff 25 -#define FC_OutCD180CCR 26 -#define FC_ExtIQueue 27 -#define FC_ExtOQueue 28 -#define FC_ClrLineIrq 29 -#define FC_HWFlowCtl 30 -#define FC_GetClockRate 35 -#define FC_SetBaud 36 -#define FC_SetDataMode 41 -#define FC_GetCCSR 43 -#define FC_GetDataError 45 -#define FC_RxControl 50 -#define FC_ImmSend 51 -#define FC_SetXonState 52 -#define FC_SetXoffState 53 -#define FC_SetRxFIFOTrig 54 -#define FC_SetTxFIFOCnt 55 -#define FC_UnixRate 56 -#define FC_UnixResetTimer 57 - -#define RxFIFOTrig1 0 -#define RxFIFOTrig4 1 -#define RxFIFOTrig8 2 -#define RxFIFOTrig14 3 - -/* - * Dual-Ported RAM - */ -#define DRAM_global 0 -#define INT_data (DRAM_global + 0) -#define Config_base (DRAM_global + 0x108) - -#define IRQindex (INT_data + 0) -#define IRQpending (INT_data + 4) -#define IRQtable (INT_data + 8) - -/* - * Interrupt Status - */ -#define IntrRx 0x01 /* receiver data O.K. */ -#define IntrTx 0x02 /* transmit buffer empty */ -#define IntrFunc 0x04 /* function complete */ -#define IntrBreak 0x08 /* received break */ -#define IntrLine 0x10 /* line status change - for transmitter */ -#define IntrIntr 0x20 /* received INTR code */ -#define IntrQuit 0x40 /* received QUIT code */ -#define IntrEOF 0x80 /* received EOF code */ - -#define IntrRxTrigger 0x100 /* rx data count reach trigger value */ -#define IntrTxTrigger 0x200 /* tx data count below trigger value */ - -#define Magic_no (Config_base + 0) -#define Card_model_no (Config_base + 2) -#define Total_ports (Config_base + 4) -#define Module_cnt (Config_base + 8) -#define Module_no (Config_base + 10) -#define Timer_10ms (Config_base + 14) -#define Disable_IRQ (Config_base + 20) -#define TMS320_PORT1 (Config_base + 22) -#define TMS320_PORT2 (Config_base + 24) -#define TMS320_CLOCK (Config_base + 26) - -/* - * DATA BUFFER in DRAM - */ -#define Extern_table 0x400 /* Base address of the external table - (24 words * 64) total 3K bytes - (24 words * 128) total 6K bytes */ -#define Extern_size 0x60 /* 96 bytes */ -#define RXrptr 0x00 /* read pointer for RX buffer */ -#define RXwptr 0x02 /* write pointer for RX buffer */ -#define TXrptr 0x04 /* read pointer for TX buffer */ -#define TXwptr 0x06 /* write pointer for TX buffer */ -#define HostStat 0x08 /* IRQ flag and general flag */ -#define FlagStat 0x0A -#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */ - /* x x x x | | | | */ - /* | | | + CTS flow */ - /* | | +--- RTS flow */ - /* | +------ TX Xon/Xoff */ - /* +--------- RX Xon/Xoff */ -#define Break_cnt 0x0E /* received break count */ -#define CD180TXirq 0x10 /* if non-0: enable TX irq */ -#define RX_mask 0x12 -#define TX_mask 0x14 -#define Ofs_rxb 0x16 -#define Ofs_txb 0x18 -#define Page_rxb 0x1A -#define Page_txb 0x1C -#define EndPage_rxb 0x1E -#define EndPage_txb 0x20 -#define Data_error 0x22 -#define RxTrigger 0x28 -#define TxTrigger 0x2a - -#define rRXwptr 0x34 -#define Low_water 0x36 - -#define FuncCode 0x40 -#define FuncArg 0x42 -#define FuncArg1 0x44 - -#define C218rx_size 0x2000 /* 8K bytes */ -#define C218tx_size 0x8000 /* 32K bytes */ - -#define C218rx_mask (C218rx_size - 1) -#define C218tx_mask (C218tx_size - 1) - -#define C320p8rx_size 0x2000 -#define C320p8tx_size 0x8000 -#define C320p8rx_mask (C320p8rx_size - 1) -#define C320p8tx_mask (C320p8tx_size - 1) - -#define C320p16rx_size 0x2000 -#define C320p16tx_size 0x4000 -#define C320p16rx_mask (C320p16rx_size - 1) -#define C320p16tx_mask (C320p16tx_size - 1) - -#define C320p24rx_size 0x2000 -#define C320p24tx_size 0x2000 -#define C320p24rx_mask (C320p24rx_size - 1) -#define C320p24tx_mask (C320p24tx_size - 1) - -#define C320p32rx_size 0x1000 -#define C320p32tx_size 0x1000 -#define C320p32rx_mask (C320p32rx_size - 1) -#define C320p32tx_mask (C320p32tx_size - 1) - -#define Page_size 0x2000U -#define Page_mask (Page_size - 1) -#define C218rx_spage 3 -#define C218tx_spage 4 -#define C218rx_pageno 1 -#define C218tx_pageno 4 -#define C218buf_pageno 5 - -#define C320p8rx_spage 3 -#define C320p8tx_spage 4 -#define C320p8rx_pgno 1 -#define C320p8tx_pgno 4 -#define C320p8buf_pgno 5 - -#define C320p16rx_spage 3 -#define C320p16tx_spage 4 -#define C320p16rx_pgno 1 -#define C320p16tx_pgno 2 -#define C320p16buf_pgno 3 - -#define C320p24rx_spage 3 -#define C320p24tx_spage 4 -#define C320p24rx_pgno 1 -#define C320p24tx_pgno 1 -#define C320p24buf_pgno 2 - -#define C320p32rx_spage 3 -#define C320p32tx_ofs C320p32rx_size -#define C320p32tx_spage 3 -#define C320p32buf_pgno 1 - -/* - * Host Status - */ -#define WakeupRx 0x01 -#define WakeupTx 0x02 -#define WakeupBreak 0x08 -#define WakeupLine 0x10 -#define WakeupIntr 0x20 -#define WakeupQuit 0x40 -#define WakeupEOF 0x80 /* used in VTIME control */ -#define WakeupRxTrigger 0x100 -#define WakeupTxTrigger 0x200 -/* - * Flag status - */ -#define Rx_over 0x01 -#define Xoff_state 0x02 -#define Tx_flowOff 0x04 -#define Tx_enable 0x08 -#define CTS_state 0x10 -#define DSR_state 0x20 -#define DCD_state 0x80 -/* - * FlowControl - */ -#define CTS_FlowCtl 1 -#define RTS_FlowCtl 2 -#define Tx_FlowCtl 4 -#define Rx_FlowCtl 8 -#define IXM_IXANY 0x10 - -#define LowWater 128 - -#define DTR_ON 1 -#define RTS_ON 2 -#define CTS_ON 1 -#define DSR_ON 2 -#define DCD_ON 8 - -/* mode definition */ -#define MX_CS8 0x03 -#define MX_CS7 0x02 -#define MX_CS6 0x01 -#define MX_CS5 0x00 - -#define MX_STOP1 0x00 -#define MX_STOP15 0x04 -#define MX_STOP2 0x08 - -#define MX_PARNONE 0x00 -#define MX_PAREVEN 0x40 -#define MX_PARODD 0xC0 -#define MX_PARMARK 0xA0 -#define MX_PARSPACE 0x20 - -#endif From 28f5cb3715006bc8c4be25170b513d8c81590379 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 15 Sep 2021 14:58:34 +0200 Subject: [PATCH 17/86] serial: 8250_fsl: Move fsl8250_data to ACPI section The fsl8250_data structure is only used by ACPI support. Hence move its definition to the driver's ACPI section. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/e406730a5eab880448d6bb55fbce492d281034ef.1631710623.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fsl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index fc65a2293ce9..9c01c531349d 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -23,10 +23,6 @@ #include "8250.h" -struct fsl8250_data { - int line; -}; - int fsl8250_handle_irq(struct uart_port *port) { unsigned char lsr, orig_lsr; @@ -90,6 +86,10 @@ int fsl8250_handle_irq(struct uart_port *port) EXPORT_SYMBOL_GPL(fsl8250_handle_irq); #ifdef CONFIG_ACPI +struct fsl8250_data { + int line; +}; + static int fsl8250_acpi_probe(struct platform_device *pdev) { struct fsl8250_data *data; From 5c7dcc4fd040dae6dc3d4f736f8ba1b0cb178bba Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 19:08:59 +0200 Subject: [PATCH 18/86] serial: 8250: remove duplicated BRI0A49 and BDP3336 entries BRI0A49 and BDP3336 are already on the list. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210916170859.138813-1-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pnp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index 98e5ee4d0d08..1974bbadc975 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -56,10 +56,6 @@ static const struct pnp_device_id pnp_dev_table[] = { { "BRI1400", 0 }, /* Boca 33.6 Kbps Internal FD34FSVD */ { "BRI3400", 0 }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { "BRI0A49", 0 }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { "BDP3336", 0 }, /* Computer Peripherals Inc */ /* EuroViVa CommCenter-33.6 SP PnP */ { "CPI4050", 0 }, From 2a7458ed0672010d05d2f92d9918fade44913f11 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 15 Sep 2021 14:49:22 +0200 Subject: [PATCH 19/86] serial: 8250: SERIAL_8250_EM should depend on ARCH_RENESAS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Emma Mobile integrated serial port hardware is only present on Emma Mobile SoCs. Hence add a dependency on ARCH_RENESAS, to prevent asking the user about this driver when configuring a kernel without Renesas ARM32 SoC support. Reviewed-by: Niklas Söderlund Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/7b5a4bbf2f47b2c4c127817e8b1524a650795d97.1631710085.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 71ae16de0f90..808268edd2e8 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -376,7 +376,7 @@ config SERIAL_8250_DW config SERIAL_8250_EM tristate "Support for Emma Mobile integrated serial port" depends on SERIAL_8250 && HAVE_CLK - depends on ARM || COMPILE_TEST + depends on (ARM && ARCH_RENESAS) || COMPILE_TEST help Selecting this option will add support for the integrated serial port hardware found on the Emma Mobile line of processors. From 4586c5fc4590662be906cfb06deabdfffcaec293 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Sep 2021 11:11:19 +0200 Subject: [PATCH 20/86] tty: unexport tty_ldisc_release Initially, tty_ldisc_release() was exported for speakup (spk_tty) while in staging. Later, the call to this function was removed as it was bogus anyway. Remove the export now. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210914091134.17426-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 756a4bfa6a69..3e4e0b20b4bb 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -812,7 +812,6 @@ void tty_ldisc_release(struct tty_struct *tty) tty_ldisc_debug(tty, "released\n"); } -EXPORT_SYMBOL_GPL(tty_ldisc_release); /** * tty_ldisc_init - ldisc setup for new tty From b468e688240b58ece498c430c377bb81b78a41f1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Sep 2021 11:11:20 +0200 Subject: [PATCH 21/86] tty: remove flags from struct tty_ldisc_ops The last user was apparently removed by commit a352def21a64 (tty: Ldisc revamp) in 2008. So remove the field completely, the only setter (n_tty_inherit_ops) and also its only possible value (LDISC_FLAG_DEFINED). Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210914091134.17426-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 1 - include/linux/tty_ldisc.h | 3 --- 2 files changed, 4 deletions(-) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 0ec93f1a61f5..797af5d46cbe 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2450,7 +2450,6 @@ void n_tty_inherit_ops(struct tty_ldisc_ops *ops) { *ops = n_tty_ops; ops->owner = NULL; - ops->flags = 0; } EXPORT_SYMBOL_GPL(n_tty_inherit_ops); diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index b1d812e902aa..1f37184eee63 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -180,7 +180,6 @@ extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, struct tty_ldisc_ops { char *name; int num; - int flags; /* * The following routines are called from above. @@ -220,8 +219,6 @@ struct tty_ldisc { struct tty_struct *tty; }; -#define LDISC_FLAG_DEFINED 0x00000001 - #define MODULE_ALIAS_LDISC(ldisc) \ MODULE_ALIAS("tty-ldisc-" __stringify(ldisc)) From 7894193436b65f304ba790abe2532a7a3bbeb7c8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Sep 2021 11:11:21 +0200 Subject: [PATCH 22/86] tty: remove extern from functions in tty headers After the recent headers cleanup, some function declarations still have extern before them. It is superfluous (for function declarations), so remove extern from those which still have it. This unifies them with the rest of the files. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210914091134.17426-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 139 ++++++++++++++++++------------------- include/linux/tty_driver.h | 8 +-- include/linux/tty_flip.h | 20 +++--- include/linux/tty_ldisc.h | 22 +++--- 4 files changed, 94 insertions(+), 95 deletions(-) diff --git a/include/linux/tty.h b/include/linux/tty.h index 168e57e40bbb..15453b0c4081 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -252,20 +252,20 @@ static inline bool tty_throttled(struct tty_struct *tty) } #ifdef CONFIG_TTY -extern void tty_kref_put(struct tty_struct *tty); -extern struct pid *tty_get_pgrp(struct tty_struct *tty); -extern void tty_vhangup_self(void); -extern void disassociate_ctty(int priv); -extern dev_t tty_devnum(struct tty_struct *tty); -extern void proc_clear_tty(struct task_struct *p); -extern struct tty_struct *get_current_tty(void); +void tty_kref_put(struct tty_struct *tty); +struct pid *tty_get_pgrp(struct tty_struct *tty); +void tty_vhangup_self(void); +void disassociate_ctty(int priv); +dev_t tty_devnum(struct tty_struct *tty); +void proc_clear_tty(struct task_struct *p); +struct tty_struct *get_current_tty(void); /* tty_io.c */ -extern int __init tty_init(void); -extern const char *tty_name(const struct tty_struct *tty); -extern struct tty_struct *tty_kopen_exclusive(dev_t device); -extern struct tty_struct *tty_kopen_shared(dev_t device); -extern void tty_kclose(struct tty_struct *tty); -extern int tty_dev_name_to_number(const char *name, dev_t *number); +int __init tty_init(void); +const char *tty_name(const struct tty_struct *tty); +struct tty_struct *tty_kopen_exclusive(dev_t device); +struct tty_struct *tty_kopen_shared(dev_t device); +void tty_kclose(struct tty_struct *tty); +int tty_dev_name_to_number(const char *name, dev_t *number); #else static inline void tty_kref_put(struct tty_struct *tty) { } @@ -296,7 +296,7 @@ static inline int tty_dev_name_to_number(const char *name, dev_t *number) extern struct ktermios tty_std_termios; -extern int vcs_init(void); +int vcs_init(void); extern struct class *tty_class; @@ -316,34 +316,34 @@ static inline struct tty_struct *tty_kref_get(struct tty_struct *tty) return tty; } -extern const char *tty_driver_name(const struct tty_struct *tty); -extern void tty_wait_until_sent(struct tty_struct *tty, long timeout); -extern void stop_tty(struct tty_struct *tty); -extern void start_tty(struct tty_struct *tty); -extern void tty_write_message(struct tty_struct *tty, char *msg); -extern int tty_send_xchar(struct tty_struct *tty, char ch); -extern int tty_put_char(struct tty_struct *tty, unsigned char c); -extern unsigned int tty_chars_in_buffer(struct tty_struct *tty); -extern unsigned int tty_write_room(struct tty_struct *tty); -extern void tty_driver_flush_buffer(struct tty_struct *tty); -extern void tty_unthrottle(struct tty_struct *tty); -extern int tty_throttle_safe(struct tty_struct *tty); -extern int tty_unthrottle_safe(struct tty_struct *tty); -extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws); -extern int tty_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); -extern int is_current_pgrp_orphaned(void); -extern void tty_hangup(struct tty_struct *tty); -extern void tty_vhangup(struct tty_struct *tty); -extern int tty_hung_up_p(struct file *filp); -extern void do_SAK(struct tty_struct *tty); -extern void __do_SAK(struct tty_struct *tty); -extern void no_tty(void); -extern speed_t tty_termios_baud_rate(struct ktermios *termios); -extern void tty_termios_encode_baud_rate(struct ktermios *termios, - speed_t ibaud, speed_t obaud); -extern void tty_encode_baud_rate(struct tty_struct *tty, - speed_t ibaud, speed_t obaud); +const char *tty_driver_name(const struct tty_struct *tty); +void tty_wait_until_sent(struct tty_struct *tty, long timeout); +void stop_tty(struct tty_struct *tty); +void start_tty(struct tty_struct *tty); +void tty_write_message(struct tty_struct *tty, char *msg); +int tty_send_xchar(struct tty_struct *tty, char ch); +int tty_put_char(struct tty_struct *tty, unsigned char c); +unsigned int tty_chars_in_buffer(struct tty_struct *tty); +unsigned int tty_write_room(struct tty_struct *tty); +void tty_driver_flush_buffer(struct tty_struct *tty); +void tty_unthrottle(struct tty_struct *tty); +int tty_throttle_safe(struct tty_struct *tty); +int tty_unthrottle_safe(struct tty_struct *tty); +int tty_do_resize(struct tty_struct *tty, struct winsize *ws); +int tty_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount); +int is_current_pgrp_orphaned(void); +void tty_hangup(struct tty_struct *tty); +void tty_vhangup(struct tty_struct *tty); +int tty_hung_up_p(struct file *filp); +void do_SAK(struct tty_struct *tty); +void __do_SAK(struct tty_struct *tty); +void no_tty(void); +speed_t tty_termios_baud_rate(struct ktermios *termios); +void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, + speed_t obaud); +void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, + speed_t obaud); /** * tty_get_baud_rate - get tty bit rates @@ -363,37 +363,37 @@ static inline speed_t tty_get_baud_rate(struct tty_struct *tty) unsigned char tty_get_char_size(unsigned int cflag); unsigned char tty_get_frame_size(unsigned int cflag); -extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old); -extern int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b); -extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); +void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old); +int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b); +int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); -extern void tty_wakeup(struct tty_struct *tty); +void tty_wakeup(struct tty_struct *tty); -extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file, +int tty_mode_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg); -extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); -extern void tty_release_struct(struct tty_struct *tty, int idx); -extern void tty_init_termios(struct tty_struct *tty); -extern void tty_save_termios(struct tty_struct *tty); -extern int tty_standard_install(struct tty_driver *driver, +int tty_perform_flush(struct tty_struct *tty, unsigned long arg); +struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); +void tty_release_struct(struct tty_struct *tty, int idx); +void tty_init_termios(struct tty_struct *tty); +void tty_save_termios(struct tty_struct *tty); +int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty); extern struct mutex tty_mutex; /* n_tty.c */ -extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops); +void n_tty_inherit_ops(struct tty_ldisc_ops *ops); #ifdef CONFIG_TTY -extern void __init n_tty_init(void); +void __init n_tty_init(void); #else static inline void n_tty_init(void) { } #endif /* tty_audit.c */ #ifdef CONFIG_AUDIT -extern void tty_audit_exit(void); -extern void tty_audit_fork(struct signal_struct *sig); -extern int tty_audit_push(void); +void tty_audit_exit(void); +void tty_audit_fork(struct signal_struct *sig); +int tty_audit_push(void); #else static inline void tty_audit_exit(void) { @@ -408,24 +408,23 @@ static inline int tty_audit_push(void) #endif /* tty_ioctl.c */ -extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); +int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); /* vt.c */ -extern int vt_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); +int vt_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -extern long vt_compat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); +long vt_compat_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg); /* tty_mutex.c */ /* functions for preparation of BKL removal */ -extern void tty_lock(struct tty_struct *tty); -extern int tty_lock_interruptible(struct tty_struct *tty); -extern void tty_unlock(struct tty_struct *tty); -extern void tty_lock_slave(struct tty_struct *tty); -extern void tty_unlock_slave(struct tty_struct *tty); -extern void tty_set_lock_subclass(struct tty_struct *tty); +void tty_lock(struct tty_struct *tty); +int tty_lock_interruptible(struct tty_struct *tty); +void tty_unlock(struct tty_struct *tty); +void tty_lock_slave(struct tty_struct *tty); +void tty_unlock_slave(struct tty_struct *tty); +void tty_set_lock_subclass(struct tty_struct *tty); #endif diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index c20431d8def8..29e1cf178afb 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -327,11 +327,11 @@ struct tty_driver { extern struct list_head tty_drivers; -extern struct tty_driver *__tty_alloc_driver(unsigned int lines, - struct module *owner, unsigned long flags); -extern struct tty_driver *tty_find_polling_driver(char *name, int *line); +struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, + unsigned long flags); +struct tty_driver *tty_find_polling_driver(char *name, int *line); -extern void tty_driver_kref_put(struct tty_driver *driver); +void tty_driver_kref_put(struct tty_driver *driver); /* Use TTY_DRIVER_* flags below */ #define tty_alloc_driver(lines, flags) \ diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index 32284992b31a..9916acb5de49 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -7,16 +7,16 @@ struct tty_ldisc; -extern int tty_buffer_set_limit(struct tty_port *port, int limit); -extern unsigned int tty_buffer_space_avail(struct tty_port *port); -extern int tty_buffer_request_room(struct tty_port *port, size_t size); -extern int tty_insert_flip_string_flags(struct tty_port *port, +int tty_buffer_set_limit(struct tty_port *port, int limit); +unsigned int tty_buffer_space_avail(struct tty_port *port); +int tty_buffer_request_room(struct tty_port *port, size_t size); +int tty_insert_flip_string_flags(struct tty_port *port, const unsigned char *chars, const char *flags, size_t size); -extern int tty_insert_flip_string_fixed_flag(struct tty_port *port, +int tty_insert_flip_string_fixed_flag(struct tty_port *port, const unsigned char *chars, char flag, size_t size); -extern int tty_prepare_flip_string(struct tty_port *port, - unsigned char **chars, size_t size); -extern void tty_flip_buffer_push(struct tty_port *port); +int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, + size_t size); +void tty_flip_buffer_push(struct tty_port *port); void tty_schedule_flip(struct tty_port *port); int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag); @@ -45,7 +45,7 @@ static inline int tty_insert_flip_string(struct tty_port *port, int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, const char *f, int count); -extern void tty_buffer_lock_exclusive(struct tty_port *port); -extern void tty_buffer_unlock_exclusive(struct tty_port *port); +void tty_buffer_lock_exclusive(struct tty_port *port); +void tty_buffer_unlock_exclusive(struct tty_port *port); #endif /* _LINUX_TTY_FLIP_H */ diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 1f37184eee63..4d1c128afbfa 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -146,7 +146,7 @@ struct ld_semaphore { #endif }; -extern void __init_ldsem(struct ld_semaphore *sem, const char *name, +void __init_ldsem(struct ld_semaphore *sem, const char *name, struct lock_class_key *key); #define init_ldsem(sem) \ @@ -157,18 +157,18 @@ do { \ } while (0) -extern int ldsem_down_read(struct ld_semaphore *sem, long timeout); -extern int ldsem_down_read_trylock(struct ld_semaphore *sem); -extern int ldsem_down_write(struct ld_semaphore *sem, long timeout); -extern int ldsem_down_write_trylock(struct ld_semaphore *sem); -extern void ldsem_up_read(struct ld_semaphore *sem); -extern void ldsem_up_write(struct ld_semaphore *sem); +int ldsem_down_read(struct ld_semaphore *sem, long timeout); +int ldsem_down_read_trylock(struct ld_semaphore *sem); +int ldsem_down_write(struct ld_semaphore *sem, long timeout); +int ldsem_down_write_trylock(struct ld_semaphore *sem); +void ldsem_up_read(struct ld_semaphore *sem); +void ldsem_up_write(struct ld_semaphore *sem); #ifdef CONFIG_DEBUG_LOCK_ALLOC -extern int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass, - long timeout); -extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, - long timeout); +int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass, + long timeout); +int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, + long timeout); #else # define ldsem_down_read_nested(sem, subclass, timeout) \ ldsem_down_read(sem, timeout) From 28f194da4a2c4d431552025a4386edaffab181bd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Sep 2021 11:11:22 +0200 Subject: [PATCH 23/86] tty: make tty_ldisc_ops::hangup return void The documentation says that the return value of tty_ldisc_ops::hangup hook is ignored. And it really is, so there is no point for its return type to be int. Switch it to void and all the hooks too. Cc: Dmitry Torokhov Cc: Wolfgang Grandegger Cc: Marc Kleine-Budde Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Paul Mackerras Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Peter Ujfalusi Acked-by: Dmitry Torokhov Acked-by: Mark Brown Acked-by: Marc Kleine-Budde Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210914091134.17426-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/tty.rst | 2 +- drivers/input/serio/serport.c | 3 +-- drivers/net/can/slcan.c | 3 +-- drivers/net/ppp/ppp_async.c | 3 +-- drivers/net/ppp/ppp_synctty.c | 3 +-- drivers/net/slip/slip.c | 3 +-- include/linux/tty_ldisc.h | 2 +- sound/soc/codecs/cx20442.c | 3 +-- sound/soc/ti/ams-delta.c | 3 +-- 9 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Documentation/driver-api/serial/tty.rst b/Documentation/driver-api/serial/tty.rst index dd972caacf3e..4b709f392713 100644 --- a/Documentation/driver-api/serial/tty.rst +++ b/Documentation/driver-api/serial/tty.rst @@ -58,7 +58,7 @@ close() This is called on a terminal when the line hangup() Called when the tty line is hung up. The line discipline should cease I/O to the tty. No further calls into the ldisc code will occur. - The return value is ignored. Can sleep. + Can sleep. read() (optional) A process requests reading data from the line. Multiple read calls may occur in parallel diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 7fbbe00e3553..17eb8f2aa48d 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -244,7 +244,7 @@ static int serport_ldisc_compat_ioctl(struct tty_struct *tty, } #endif -static int serport_ldisc_hangup(struct tty_struct *tty) +static void serport_ldisc_hangup(struct tty_struct *tty) { struct serport *serport = (struct serport *) tty->disc_data; unsigned long flags; @@ -254,7 +254,6 @@ static int serport_ldisc_hangup(struct tty_struct *tty) spin_unlock_irqrestore(&serport->lock, flags); wake_up_interruptible(&serport->wait); - return 0; } static void serport_ldisc_write_wakeup(struct tty_struct * tty) diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index d42ec7d1bc14..012da4b8abe0 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -664,10 +664,9 @@ static void slcan_close(struct tty_struct *tty) /* This will complete via sl_free_netdev */ } -static int slcan_hangup(struct tty_struct *tty) +static void slcan_hangup(struct tty_struct *tty) { slcan_close(tty); - return 0; } /* Perform I/O control on an active SLCAN channel. */ diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 29a93d6bfe37..78ec1bcebc4f 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -247,10 +247,9 @@ ppp_asynctty_close(struct tty_struct *tty) * Wait for I/O to driver to complete and unregister PPP channel. * This is already done by the close routine, so just call that. */ -static int ppp_asynctty_hangup(struct tty_struct *tty) +static void ppp_asynctty_hangup(struct tty_struct *tty) { ppp_asynctty_close(tty); - return 0; } /* diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index af3e048695b6..c249db7c466a 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -245,10 +245,9 @@ ppp_sync_close(struct tty_struct *tty) * Wait for I/O to driver to complete and unregister PPP channel. * This is already done by the close routine, so just call that. */ -static int ppp_sync_hangup(struct tty_struct *tty) +static void ppp_sync_hangup(struct tty_struct *tty) { ppp_sync_close(tty); - return 0; } /* diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 5435b5689ce6..8be9d0c351b5 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -907,10 +907,9 @@ static void slip_close(struct tty_struct *tty) /* This will complete via sl_free_netdev */ } -static int slip_hangup(struct tty_struct *tty) +static void slip_hangup(struct tty_struct *tty) { slip_close(tty); - return 0; } /************************************************************************ * STANDARD SLIP ENCAPSULATION * diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 4d1c128afbfa..b85d84fb5f49 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -199,7 +199,7 @@ struct tty_ldisc_ops { void (*set_termios)(struct tty_struct *tty, struct ktermios *old); __poll_t (*poll)(struct tty_struct *, struct file *, struct poll_table_struct *); - int (*hangup)(struct tty_struct *tty); + void (*hangup)(struct tty_struct *tty); /* * The following routines are called from below. diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 13258f3ca9aa..1af0bf5f1e2f 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -252,10 +252,9 @@ static void v253_close(struct tty_struct *tty) } /* Line discipline .hangup() */ -static int v253_hangup(struct tty_struct *tty) +static void v253_hangup(struct tty_struct *tty) { v253_close(tty); - return 0; } /* Line discipline .receive_buf() */ diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index ecd24d412a9b..b1a32545babd 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -330,10 +330,9 @@ static void cx81801_close(struct tty_struct *tty) } /* Line discipline .hangup() */ -static int cx81801_hangup(struct tty_struct *tty) +static void cx81801_hangup(struct tty_struct *tty) { cx81801_close(tty); - return 0; } /* Line discipline .receive_buf() */ From dcc223e8b9bf3f987bcd3c327a6737022b39e35b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Sep 2021 11:11:23 +0200 Subject: [PATCH 24/86] tty: remove file from tty_mode_ioctl The only user of 'file' parameter in tty_mode_ioctl is a BUG_ON check. Provided it never crashed for anyone, it's an overkill to pass the parameter to tty_mode_ioctl only for this check. If we wanted to check 'file' there, we should handle it in more graceful way anyway. Not by a BUG == crash. Cc: Wolfgang Grandegger Cc: Marc Kleine-Budde Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Andreas Koensgen Cc: Paul Mackerras Acked-by: Marc Kleine-Budde Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210914091134.17426-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/slcan.c | 2 +- drivers/net/hamradio/6pack.c | 2 +- drivers/net/ppp/ppp_async.c | 2 +- drivers/net/ppp/ppp_synctty.c | 2 +- drivers/net/slip/slip.c | 2 +- drivers/tty/tty_ioctl.c | 8 ++------ include/linux/tty.h | 3 +-- 7 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 012da4b8abe0..9a4ebda30510 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -691,7 +691,7 @@ static int slcan_ioctl(struct tty_struct *tty, struct file *file, return -EINVAL; default: - return tty_mode_ioctl(tty, file, cmd, arg); + return tty_mode_ioctl(tty, cmd, arg); } } diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 8fe8887d506a..05404f7a3204 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -732,7 +732,7 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, break; } default: - err = tty_mode_ioctl(tty, file, cmd, arg); + err = tty_mode_ioctl(tty, cmd, arg); } sp_put(sp); diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 78ec1bcebc4f..6492523fc234 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -322,7 +322,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, default: /* Try the various mode ioctls */ - err = tty_mode_ioctl(tty, file, cmd, arg); + err = tty_mode_ioctl(tty, cmd, arg); } ap_put(ap); diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index c249db7c466a..ebbfea0e1140 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -314,7 +314,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, break; default: - err = tty_mode_ioctl(tty, file, cmd, arg); + err = tty_mode_ioctl(tty, cmd, arg); break; } diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 8be9d0c351b5..9f3b4c1aa5ce 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -1173,7 +1173,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, /* VSV changes end */ #endif default: - return tty_mode_ioctl(tty, file, cmd, arg); + return tty_mode_ioctl(tty, cmd, arg); } } diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 507a25d692bb..99a29d72d294 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -675,7 +675,6 @@ static int tty_change_softcar(struct tty_struct *tty, int arg) /** * tty_mode_ioctl - mode related ioctls * @tty: tty for the ioctl - * @file: file pointer for the tty * @cmd: command * @arg: ioctl argument * @@ -684,16 +683,13 @@ static int tty_change_softcar(struct tty_struct *tty, int arg) * consistent mode setting. */ -int tty_mode_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct tty_struct *real_tty; void __user *p = (void __user *)arg; int ret = 0; struct ktermios kterm; - BUG_ON(file == NULL); - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) real_tty = tty->link; @@ -904,7 +900,7 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, return __tty_perform_flush(tty, arg); default: /* Try the mode commands */ - return tty_mode_ioctl(tty, file, cmd, arg); + return tty_mode_ioctl(tty, cmd, arg); } } EXPORT_SYMBOL(n_tty_ioctl_helper); diff --git a/include/linux/tty.h b/include/linux/tty.h index 15453b0c4081..5e73f577c2b4 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -369,8 +369,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); void tty_wakeup(struct tty_struct *tty); -int tty_mode_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); +int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); int tty_perform_flush(struct tty_struct *tty, unsigned long arg); struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); void tty_release_struct(struct tty_struct *tty, int idx); From 7c783601a3bc22a54cce0fb650259a983c8cafba Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Sep 2021 11:11:24 +0200 Subject: [PATCH 25/86] tty: remove file from n_tty_ioctl_helper After the previous patch, there are no users of 'file' in n_tty_ioctl_helper. So remove it also from there. Cc: Marcel Holtmann Cc: Johan Hedberg Cc: Luiz Augusto von Dentz Cc: Paul Mackerras Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Krzysztof Kozlowski Acked-by: Krzysztof Kozlowski Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210914091134.17426-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_ldisc.c | 2 +- drivers/net/ppp/ppp_async.c | 2 +- drivers/net/ppp/ppp_synctty.c | 2 +- drivers/tty/n_gsm.c | 2 +- drivers/tty/n_hdlc.c | 2 +- drivers/tty/n_tty.c | 2 +- drivers/tty/tty_ioctl.c | 4 ++-- include/linux/tty.h | 4 ++-- net/nfc/nci/uart.c | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 5ed2cfa7da1d..824d1c7e3e53 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -790,7 +790,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, break; default: - err = n_tty_ioctl_helper(tty, file, cmd, arg); + err = n_tty_ioctl_helper(tty, cmd, arg); break; } diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 6492523fc234..f4429b93a9c8 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -310,7 +310,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, /* flush our buffers and the serial port's buffer */ if (arg == TCIOFLUSH || arg == TCOFLUSH) ppp_async_flush_output(ap); - err = n_tty_ioctl_helper(tty, file, cmd, arg); + err = n_tty_ioctl_helper(tty, cmd, arg); break; case FIONREAD: diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index ebbfea0e1140..b3a71b409a80 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -303,7 +303,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, /* flush our buffers and the serial port's buffer */ if (arg == TCIOFLUSH || arg == TCOFLUSH) ppp_sync_flush_output(ap); - err = n_tty_ioctl_helper(tty, file, cmd, arg); + err = n_tty_ioctl_helper(tty, cmd, arg); break; case FIONREAD: diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 157b51ce9cc0..c98a04595084 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2712,7 +2712,7 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file, base = mux_num_to_base(gsm); return put_user(base + 1, (__u32 __user *)arg); default: - return n_tty_ioctl_helper(tty, file, cmd, arg); + return n_tty_ioctl_helper(tty, cmd, arg); } } diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 580a37b3fe1b..7e0884ecc74f 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -630,7 +630,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, fallthrough; /* to default */ default: - error = n_tty_ioctl_helper(tty, file, cmd, arg); + error = n_tty_ioctl_helper(tty, cmd, arg); break; } return error; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 797af5d46cbe..5be6d02dc690 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2418,7 +2418,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, up_write(&tty->termios_rwsem); return put_user(retval, (unsigned int __user *) arg); default: - return n_tty_ioctl_helper(tty, file, cmd, arg); + return n_tty_ioctl_helper(tty, cmd, arg); } } diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 99a29d72d294..63181925ec1a 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -854,8 +854,8 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) } EXPORT_SYMBOL_GPL(tty_perform_flush); -int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +int n_tty_ioctl_helper(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { int retval; diff --git a/include/linux/tty.h b/include/linux/tty.h index 5e73f577c2b4..5dbd7c5afac7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -407,8 +407,8 @@ static inline int tty_audit_push(void) #endif /* tty_ioctl.c */ -int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); +int n_tty_ioctl_helper(struct tty_struct *tty, unsigned int cmd, + unsigned long arg); /* vt.c */ diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 502e7a3f8948..9bdd9a7d187e 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -349,7 +349,7 @@ static int nci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, return -EBUSY; break; default: - err = n_tty_ioctl_helper(tty, file, cmd, arg); + err = n_tty_ioctl_helper(tty, cmd, arg); break; } From e01f9125e7c7f4af45758618b853d1542cd2d1f1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Sep 2021 15:30:40 +0200 Subject: [PATCH 26/86] tty: serial: samsung: describe driver in KConfig Describe better which driver applies to which SoC, to make configuring kernel for Samsung SoC easier. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210924133040.111706-1-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 131a6a587acd..6ff94cfcd9db 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -239,10 +239,11 @@ config SERIAL_SAMSUNG depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || COMPILE_TEST select SERIAL_CORE help - Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, - providing /dev/ttySAC0, 1 and 2 (note, some machines may not - provide all of these ports, depending on how the serial port - pins are configured. + Support for the on-chip UARTs on the Samsung + S3C24xx/S3C64xx/S5Pv210/Exynos and Apple M1 SoCs, providing + /dev/ttySAC0, 1 and 2 (note, some machines may not provide all of + these ports, depending on how the serial port pins are configured. + Choose Y/M here only if you build for such SoC. config SERIAL_SAMSUNG_UARTS_4 bool From 46292622ad73792b44bd9744d269793b209c7630 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Oct 2021 13:43:43 +0300 Subject: [PATCH 27/86] tty: n_gsm: clean up indenting in gsm_queue() These two lines need to be indented one more tab. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20211004104343.GF25015@kili Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c98a04595084..182d5914dfb9 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1854,8 +1854,8 @@ static void gsm_queue(struct gsm_mux *gsm) if (address_tmp == address) { for (k = j; k < addr_cnt; k++) addr_open[k] = addr_open[k+1]; - addr_cnt--; - break; + addr_cnt--; + break; } } } From 9136c68346d096697935b9840782f7051d5796c5 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 30 Sep 2021 09:06:24 +0300 Subject: [PATCH 28/86] tty: n_gsm: Don't ignore write return value in gsmld_output() We currently have gsmld_output() ignore the return value from device write. This means we will lose packets if device write returns 0 or an error. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20210930060624.46523-1-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 182d5914dfb9..0b96b14bbfe1 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -695,7 +695,7 @@ static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci) print_hex_dump_bytes("gsm_data_kick: ", DUMP_PREFIX_OFFSET, gsm->txframe, len); - if (gsmld_output(gsm, gsm->txframe, len) < 0) + if (gsmld_output(gsm, gsm->txframe, len) <= 0) break; /* FIXME: Can eliminate one SOF in many more cases */ gsm->tx_bytes -= msg->len; @@ -2415,8 +2415,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len) if (debug & 4) print_hex_dump_bytes("gsmld_output: ", DUMP_PREFIX_OFFSET, data, len); - gsm->tty->ops->write(gsm->tty, data, len); - return len; + return gsm->tty->ops->write(gsm->tty, data, len); } /** From 3fdfa165d79bdbdac1fdd6b4f3eebd78bf8bc8fc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 22 Sep 2021 09:59:32 +0200 Subject: [PATCH 29/86] mxser: restore baud rate if its setting fails If a user tries to set a too high rate, it fails due to check in mxser_set_baud(). But the high rate remains set in termios, so the user might think everything went smooth. Restore the baud rate from the old_termios if this happens, so that user knows nothing was changed in fact. It used to behave the correct way many years ago, but somehow the restoration vanished with commit 1c45607ad3eb (Char: mxser, remove it) -- the commit removed mxser's older clone. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210922075938.31390-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 1216f3985e18..b9cc41782ce1 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -559,14 +559,20 @@ static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info, * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void mxser_change_speed(struct tty_struct *tty) +static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_termios) { struct mxser_port *info = tty->driver_data; unsigned cflag, cval, fcr; cflag = tty->termios.c_cflag; - mxser_set_baud(tty, tty_get_baud_rate(tty)); + if (mxser_set_baud(tty, tty_get_baud_rate(tty))) { + /* Use previous rate on a failure */ + if (old_termios) { + speed_t baud = tty_termios_baud_rate(old_termios); + tty_encode_baud_rate(tty, baud, baud); + } + } /* byte size and parity */ switch (cflag & CSIZE) { @@ -791,7 +797,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) /* * and set the speed of the serial port */ - mxser_change_speed(tty); + mxser_change_speed(tty, NULL); spin_unlock_irqrestore(&info->slock, flags); return 0; @@ -1119,7 +1125,7 @@ static int mxser_set_serial_info(struct tty_struct *tty, if (tty_port_initialized(port)) { if (old_speed != (port->flags & ASYNC_SPD_MASK)) { spin_lock_irqsave(&info->slock, sl_flags); - mxser_change_speed(tty); + mxser_change_speed(tty, NULL); spin_unlock_irqrestore(&info->slock, sl_flags); } } else { @@ -1425,7 +1431,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi unsigned long flags; spin_lock_irqsave(&info->slock, flags); - mxser_change_speed(tty); + mxser_change_speed(tty, old_termios); spin_unlock_irqrestore(&info->slock, flags); if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { From 7d5006d59da3595272ce524f0d8b507397d265ae Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 22 Sep 2021 09:59:33 +0200 Subject: [PATCH 30/86] mxser: simplify condition in mxser_receive_chars_new mxser_receive_chars_old() is used whenever MOXA_MUST_LSR_RERR is set in status no matter the HW ID (the last 'if'). So there is no need for another check of MOXA_MUST_LSR_RERR _with_ hwid == MOXA_MUST_MU860_HWID (the third 'if'). Hence remove this subcase. That allows us to check status on a single line with both UART_LSR_BRK_ERROR_BITS (from the second 'if') and MOXA_MUST_LSR_RERR (the last 'if'). Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210922075938.31390-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index b9cc41782ce1..f907de56e08b 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1550,11 +1550,7 @@ static bool mxser_receive_chars_new(struct tty_struct *tty, if (hwid == MOXA_OTHER_UART) return false; - if (status & UART_LSR_BRK_ERROR_BITS) - return false; - if (hwid == MOXA_MUST_MU860_HWID && (status & MOXA_MUST_LSR_RERR)) - return false; - if (status & MOXA_MUST_LSR_RERR) + if (status & (UART_LSR_BRK_ERROR_BITS | MOXA_MUST_LSR_RERR)) return false; gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER); From 19236287d8d5752b3d072bb8bd18b533ef085d15 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 22 Sep 2021 09:59:34 +0200 Subject: [PATCH 31/86] mxser: make mxser_port::ldisc_stop_rx a bool It's used only as a yes-no variable, so make it a bool and switch the set values appropriately. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210922075938.31390-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index f907de56e08b..309acf3f1ec3 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -250,7 +250,7 @@ struct mxser_port { u8 IER; /* Interrupt Enable Register */ u8 MCR; /* Modem control register */ - unsigned char ldisc_stop_rx; + bool ldisc_stop_rx; struct async_icount icount; /* kernel counters for 4 input interrupts */ unsigned int timeout; @@ -1341,7 +1341,7 @@ static void mxser_stoprx(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - info->ldisc_stop_rx = 1; + info->ldisc_stop_rx = true; if (I_IXOFF(tty)) { if (info->board->must_hwid) { info->IER &= ~MOXA_MUST_RECV_ISR; @@ -1374,7 +1374,7 @@ static void mxser_unthrottle(struct tty_struct *tty) struct mxser_port *info = tty->driver_data; /* startrx */ - info->ldisc_stop_rx = 0; + info->ldisc_stop_rx = false; if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; @@ -1849,7 +1849,7 @@ static void mxser_initbrd(struct mxser_board *brd, bool high_baud) tty_port_init(&info->port); info->port.ops = &mxser_port_ops; info->board = brd; - info->ldisc_stop_rx = 0; + info->ldisc_stop_rx = false; /* Enhance mode enabled here */ if (brd->must_hwid != MOXA_OTHER_UART) From bf1434c1b72451c4e02cdbf6984fdafcec194762 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 22 Sep 2021 09:59:35 +0200 Subject: [PATCH 32/86] mxser: simplify FCR computation in mxser_change_speed() Provided FIFO is always enabled for MUST chips, move its FCR setting out of PORT_8250/PORT_16450 special case in mxser_change_speed(). Now, we can pre-set fcr to zero and invert the condition of the 'if'. This makes the code more readable (no functional change intended). Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210922075938.31390-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 47 +++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 309acf3f1ec3..c194a96bb14e 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -600,33 +600,26 @@ static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_term if (cflag & CMSPAR) cval |= UART_LCR_SPAR; - if ((info->type == PORT_8250) || (info->type == PORT_16450)) { - if (info->board->must_hwid) { - fcr = UART_FCR_ENABLE_FIFO; - fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; - mxser_set_must_fifo_value(info); - } else - fcr = 0; - } else { - fcr = UART_FCR_ENABLE_FIFO; - if (info->board->must_hwid) { - fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; - mxser_set_must_fifo_value(info); - } else { - switch (info->rx_high_water) { - case 1: - fcr |= UART_FCR_TRIGGER_1; - break; - case 4: - fcr |= UART_FCR_TRIGGER_4; - break; - case 8: - fcr |= UART_FCR_TRIGGER_8; - break; - default: - fcr |= UART_FCR_TRIGGER_14; - break; - } + fcr = 0; + if (info->board->must_hwid) { + fcr |= UART_FCR_ENABLE_FIFO | + MOXA_MUST_FCR_GDA_MODE_ENABLE; + mxser_set_must_fifo_value(info); + } else if (info->type != PORT_8250 && info->type != PORT_16450) { + fcr |= UART_FCR_ENABLE_FIFO; + switch (info->rx_high_water) { + case 1: + fcr |= UART_FCR_TRIGGER_1; + break; + case 4: + fcr |= UART_FCR_TRIGGER_4; + break; + case 8: + fcr |= UART_FCR_TRIGGER_8; + break; + default: + fcr |= UART_FCR_TRIGGER_14; + break; } } From ee7e5e66f2d4fa3cc05382d6f739c644a666010c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 22 Sep 2021 09:59:36 +0200 Subject: [PATCH 33/86] mxser: move FIFO clearing to mxser_disable_and_clear_FIFO() This code is used on two places, make a helper for disabling and clearing FIFOs. And demangle the too complicated 'if' by using a local variable. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210922075938.31390-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index c194a96bb14e..6913a1caa6f0 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -706,6 +706,16 @@ static void mxser_check_modem_status(struct tty_struct *tty, mxser_handle_cts(tty, port, status); } +static void mxser_disable_and_clear_FIFO(struct mxser_port *info) +{ + u8 fcr = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT; + + if (info->board->must_hwid) + fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; + + outb(fcr, info->ioaddr + UART_FCR); +} + static int mxser_activate(struct tty_port *port, struct tty_struct *tty) { struct mxser_port *info = container_of(port, struct mxser_port, port); @@ -730,13 +740,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) * Clear the FIFO buffers and disable them * (they will be reenabled in mxser_change_speed()) */ - if (info->board->must_hwid) - outb((UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT | - MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR); - else - outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), - info->ioaddr + UART_FCR); + mxser_disable_and_clear_FIFO(info); /* * At this point there's no way the LSR could still be 0xFF; @@ -824,13 +828,7 @@ static void mxser_shutdown_port(struct tty_port *port) outb(0x00, info->ioaddr + UART_IER); /* clear Rx/Tx FIFO's */ - if (info->board->must_hwid) - outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | - MOXA_MUST_FCR_GDA_MODE_ENABLE, - info->ioaddr + UART_FCR); - else - outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, - info->ioaddr + UART_FCR); + mxser_disable_and_clear_FIFO(info); /* read data port to reset things */ (void) inb(info->ioaddr + UART_RX); From 215fa41c2dfb4cf36d5b39dea9417bfadc9e770e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 22 Sep 2021 09:59:37 +0200 Subject: [PATCH 34/86] mxser: don't read from UART_FCR The UART_FCR register is write-only. When reading it, one gets contents of (read-only) UART_IIR instead as they are shared. This mistake was performed in mxser_flush_buffer() to clear FIFOs. Actually FCR handling throughout the driver is completely broken. On many places, it respects neither mu860 settings, nor FIFO (16450 vs 16550) setting. This patch doesn't help to fix this, it actually does the same. We will introduce a mxser_port::FCR in the next patch to fix this issue. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210922075938.31390-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 6913a1caa6f0..4ce21cdb1ea5 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -859,17 +859,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) static void mxser_flush_buffer(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - char fcr; unsigned long flags; spin_lock_irqsave(&info->slock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - fcr = inb(info->ioaddr + UART_FCR); - outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), + outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, info->ioaddr + UART_FCR); - outb(fcr, info->ioaddr + UART_FCR); spin_unlock_irqrestore(&info->slock, flags); From d249e662c3e4a9d2caebf74487cf283cb6df2f77 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 22 Sep 2021 09:59:38 +0200 Subject: [PATCH 35/86] mxser: store FCR state in mxser_port::FCR We force the FCR contents on many places in the code instead of writing what was actually set in mxser_change_speed() (by ->activate() or ->set_serial_info()). So introduce mxser_port::FCR to hold the proper contents and bitwise-OR the value to what needs to be set on all those locations. That is, clearing RX and/or TX FIFOs. Those flags are self-clearing, so no need to set them to mxser_port::FCR. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210922075938.31390-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 4ce21cdb1ea5..93a95a135a71 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -249,6 +249,7 @@ struct mxser_port { unsigned char x_char; /* xon/xoff character */ u8 IER; /* Interrupt Enable Register */ u8 MCR; /* Modem control register */ + u8 FCR; /* FIFO control register */ bool ldisc_stop_rx; @@ -562,7 +563,7 @@ static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info, static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_termios) { struct mxser_port *info = tty->driver_data; - unsigned cflag, cval, fcr; + unsigned cflag, cval; cflag = tty->termios.c_cflag; @@ -600,25 +601,25 @@ static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_term if (cflag & CMSPAR) cval |= UART_LCR_SPAR; - fcr = 0; + info->FCR = 0; if (info->board->must_hwid) { - fcr |= UART_FCR_ENABLE_FIFO | + info->FCR |= UART_FCR_ENABLE_FIFO | MOXA_MUST_FCR_GDA_MODE_ENABLE; mxser_set_must_fifo_value(info); } else if (info->type != PORT_8250 && info->type != PORT_16450) { - fcr |= UART_FCR_ENABLE_FIFO; + info->FCR |= UART_FCR_ENABLE_FIFO; switch (info->rx_high_water) { case 1: - fcr |= UART_FCR_TRIGGER_1; + info->FCR |= UART_FCR_TRIGGER_1; break; case 4: - fcr |= UART_FCR_TRIGGER_4; + info->FCR |= UART_FCR_TRIGGER_4; break; case 8: - fcr |= UART_FCR_TRIGGER_8; + info->FCR |= UART_FCR_TRIGGER_8; break; default: - fcr |= UART_FCR_TRIGGER_14; + info->FCR |= UART_FCR_TRIGGER_14; break; } } @@ -679,7 +680,7 @@ static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_term } - outb(fcr, info->ioaddr + UART_FCR); /* set fcr */ + outb(info->FCR, info->ioaddr + UART_FCR); outb(cval, info->ioaddr + UART_LCR); } @@ -865,7 +866,7 @@ static void mxser_flush_buffer(struct tty_struct *tty) spin_lock_irqsave(&info->slock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, info->ioaddr + UART_FCR); spin_unlock_irqrestore(&info->slock, flags); @@ -1572,8 +1573,7 @@ static u8 mxser_receive_chars_old(struct tty_struct *tty, ch = inb(port->ioaddr + UART_RX); if (hwid && (status & UART_LSR_OE)) - outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | - MOXA_MUST_FCR_GDA_MODE_ENABLE, + outb(port->FCR | UART_FCR_CLEAR_RCVR, port->ioaddr + UART_FCR); status &= port->read_status_mask; if (status & port->ignore_status_mask) { @@ -1685,8 +1685,7 @@ static bool mxser_port_isr(struct mxser_port *port) tty = tty_port_tty_get(&port->port); if (!tty || port->closing || !tty_port_initialized(&port->port)) { status = inb(port->ioaddr + UART_LSR); - outb(MOXA_MUST_FCR_GDA_MODE_ENABLE | UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + outb(port->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, port->ioaddr + UART_FCR); inb(port->ioaddr + UART_MSR); From 63dfaadfac62434356bce13dba8c6cbbe75e3e04 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Tue, 28 Sep 2021 17:52:28 +0800 Subject: [PATCH 36/86] dt-bindings: serial: Add a new compatible string for UMS512 The UMS512 also uses the same serial device with SC9836. Signed-off-by: Chunyan Zhang Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210928095229.233572-3-zhang.lyra@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/sprd-uart.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.yaml b/Documentation/devicetree/bindings/serial/sprd-uart.yaml index 09f6283f3cae..a444bebd2c1a 100644 --- a/Documentation/devicetree/bindings/serial/sprd-uart.yaml +++ b/Documentation/devicetree/bindings/serial/sprd-uart.yaml @@ -19,6 +19,7 @@ properties: - enum: - sprd,sc9860-uart - sprd,sc9863a-uart + - sprd,ums512-uart - const: sprd,sc9836-uart - const: sprd,sc9836-uart From 27e8c8b483a8c33bd770b8cf619d43c7a68ddbaa Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 25 Sep 2021 23:47:26 +0100 Subject: [PATCH 37/86] serial: sifive: set pointer to NULL rather than 0. Clean up the assignment of sifive_serial_console_ports[ssp->port.line], this is a pointer to a struct sifive_serial_port so the assignment should be a NULL rather than a integer 0. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210925224726.183360-1-colin.king@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sifive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 0ac0371f943b..b79900d0e91a 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -887,7 +887,7 @@ static void __ssp_add_console_port(struct sifive_serial_port *ssp) static void __ssp_remove_console_port(struct sifive_serial_port *ssp) { - sifive_serial_console_ports[ssp->port.line] = 0; + sifive_serial_console_ports[ssp->port.line] = NULL; } #define SIFIVE_SERIAL_CONSOLE (&sifive_serial_console) From 4545b069aa2cd3287bf9399c02bdb3c829b75b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 27 Sep 2021 15:35:16 +0200 Subject: [PATCH 38/86] tty: baudrate: Explicit usage of B0 for encoding input baudrate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function tty_termios_input_baud_rate() checks IBSHIFT & CBAUD against B0 constant to determinate if input speed equals to output speed. So do same B0 check also in tty_termios_encode_baud_rate() function to make these two functions compatible. Currently macro B0 is defined to 0 so there is no functional change. This change just make code more explicit to show that Bnnn constants are stored in CBAUD. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20210927133516.8671-1-pali@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_baudrate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index 426b1252781a..d903e111dbcb 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -154,7 +154,7 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, termios->c_ospeed = obaud; #ifdef IBSHIFT - if ((termios->c_cflag >> IBSHIFT) & CBAUD) + if (((termios->c_cflag >> IBSHIFT) & CBAUD) != B0) ibinput = 1; /* An input speed was specified */ #endif #ifdef BOTHER From 027b57170bf8bb6999a28e4a5f3d78bf1db0f90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 2 Oct 2021 15:09:00 +0200 Subject: [PATCH 39/86] serial: core: Fix initializing and restoring termios speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit edc6afc54968 ("tty: switch to ktermios and new framework") termios speed is no longer stored only in c_cflag member but also in new additional c_ispeed and c_ospeed members. If BOTHER flag is set in c_cflag then termios speed is stored only in these new members. Therefore to correctly restore termios speed it is required to store also ispeed and ospeed members, not only cflag member. In case only cflag member with BOTHER flag is restored then functions tty_termios_baud_rate() and tty_termios_input_baud_rate() returns baudrate stored in c_ospeed / c_ispeed member, which is zero as it was not restored too. If reported baudrate is invalid (e.g. zero) then serial core functions report fallback baudrate value 9600. So it means that in this case original baudrate is lost and kernel changes it to value 9600. Simple reproducer of this issue is to boot kernel with following command line argument: "console=ttyXXX,86400" (where ttyXXX is the device name). For speed 86400 there is no Bnnn constant and therefore kernel has to represent this speed via BOTHER c_cflag. Which means that speed is stored only in c_ospeed and c_ispeed members, not in c_cflag anymore. If bootloader correctly configures serial device to speed 86400 then kernel prints boot log to early console at speed speed 86400 without any issue. But after kernel starts initializing real console device ttyXXX then speed is changed to fallback value 9600 because information about speed was lost. This patch fixes above issue by storing and restoring also ispeed and ospeed members, which are required for BOTHER flag. Fixes: edc6afc54968 ("[PATCH] tty: switch to ktermios and new framework") Cc: stable@vger.kernel.org Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20211002130900.9518-1-pali@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 16 ++++++++++++++-- include/linux/console.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0e2e35ab64c7..1e738f265eea 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -222,7 +222,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (retval == 0) { if (uart_console(uport) && uport->cons->cflag) { tty->termios.c_cflag = uport->cons->cflag; + tty->termios.c_ispeed = uport->cons->ispeed; + tty->termios.c_ospeed = uport->cons->ospeed; uport->cons->cflag = 0; + uport->cons->ispeed = 0; + uport->cons->ospeed = 0; } /* * Initialise the hardware port settings. @@ -290,8 +294,11 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Turn off DTR and RTS early. */ - if (uport && uart_console(uport) && tty) + if (uport && uart_console(uport) && tty) { uport->cons->cflag = tty->termios.c_cflag; + uport->cons->ispeed = tty->termios.c_ispeed; + uport->cons->ospeed = tty->termios.c_ospeed; + } if (!tty || C_HUPCL(tty)) uart_port_dtr_rts(uport, 0); @@ -2094,8 +2101,11 @@ uart_set_options(struct uart_port *port, struct console *co, * Allow the setting of the UART parameters with a NULL console * too: */ - if (co) + if (co) { co->cflag = termios.c_cflag; + co->ispeed = termios.c_ispeed; + co->ospeed = termios.c_ospeed; + } return 0; } @@ -2229,6 +2239,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) */ memset(&termios, 0, sizeof(struct ktermios)); termios.c_cflag = uport->cons->cflag; + termios.c_ispeed = uport->cons->ispeed; + termios.c_ospeed = uport->cons->ospeed; /* * If that's unset, use the tty termios setting. diff --git a/include/linux/console.h b/include/linux/console.h index 20874db50bc8..a97f277cfdfa 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -149,6 +149,8 @@ struct console { short flags; short index; int cflag; + uint ispeed; + uint ospeed; void *data; struct console *next; }; From 32262e2e429cdb31f9e957e997d53458762931b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 27 Sep 2021 11:37:04 +0200 Subject: [PATCH 40/86] serial: 8250: Fix reporting real baudrate value in c_ospeed field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In most cases it is not possible to set exact baudrate value to hardware. So fix reporting real baudrate value which was set to hardware via c_ospeed termios field. It can be retrieved by ioctl(TCGETS2) from userspace. Real baudrate value is calculated from chosen hardware divisor and base clock. It is implemented in a new function serial8250_compute_baud_rate() which is inverse of serial8250_get_divisor() function. With this change is fixed also UART timeout value (it is updated via uart_update_timeout() function), which is calculated from the now fixed baudrate value too. Cc: stable@vger.kernel.org Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20210927093704.19768-1-pali@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 66374704747e..dc6900b2daa8 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2584,6 +2584,19 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, return serial8250_do_get_divisor(port, baud, frac); } +static unsigned int serial8250_compute_baud_rate(struct uart_port *port, + unsigned int quot) +{ + if ((port->flags & UPF_MAGIC_MULTIPLIER) && quot == 0x8001) + return port->uartclk / 4; + else if ((port->flags & UPF_MAGIC_MULTIPLIER) && quot == 0x8002) + return port->uartclk / 8; + else if (port->type == PORT_NPCM) + return DIV_ROUND_CLOSEST(port->uartclk - 2 * (quot + 2), 16 * (quot + 2)); + else + return DIV_ROUND_CLOSEST(port->uartclk, 16 * quot); +} + static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, tcflag_t c_cflag) { @@ -2714,11 +2727,14 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) baud = serial8250_get_baud_rate(port, termios, NULL); quot = serial8250_get_divisor(port, baud, &frac); + baud = serial8250_compute_baud_rate(port, quot); serial8250_rpm_get(up); spin_lock_irqsave(&port->lock, flags); uart_update_timeout(port, termios->c_cflag, baud); + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); serial8250_set_divisor(port, baud, quot, frac); serial_port_out(port, UART_LCR, up->lcr); @@ -2750,6 +2766,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, baud = serial8250_get_baud_rate(port, termios, old); quot = serial8250_get_divisor(port, baud, &frac); + baud = serial8250_compute_baud_rate(port, quot); /* * Ok, we're now changing the port state. Do it with From d02b006b29de14968ba4afa998bede0d55469e29 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 7 Oct 2021 15:31:46 +0200 Subject: [PATCH 41/86] Revert "serial: 8250: Fix reporting real baudrate value in c_ospeed field" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 32262e2e429cdb31f9e957e997d53458762931b7. The commit in question claims to determine the inverse of serial8250_get_divisor() but failed to notice that some drivers override the default implementation using a get_divisor() callback. This means that the computed line-speed values can be completely wrong and results in regular TCSETS requests failing (the incorrect values would also be passed to any overridden set_divisor() callback). Similarly, it also failed to honour the old (deprecated) ASYNC_SPD_FLAGS and would break applications relying on those when re-encoding the actual line speed. There are also at least two quirks, UART_BUG_QUOT and an OMAP1510 workaround, which were happily ignored and that are now broken. Finally, even if the offending commit were to be implemented correctly, this is a new feature and not something which should be backported to stable. Cc: Pali Rohár Fixes: 32262e2e429c ("serial: 8250: Fix reporting real baudrate value in c_ospeed field") Cc: stable Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20211007133146.28949-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index dc6900b2daa8..66374704747e 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2584,19 +2584,6 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, return serial8250_do_get_divisor(port, baud, frac); } -static unsigned int serial8250_compute_baud_rate(struct uart_port *port, - unsigned int quot) -{ - if ((port->flags & UPF_MAGIC_MULTIPLIER) && quot == 0x8001) - return port->uartclk / 4; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && quot == 0x8002) - return port->uartclk / 8; - else if (port->type == PORT_NPCM) - return DIV_ROUND_CLOSEST(port->uartclk - 2 * (quot + 2), 16 * (quot + 2)); - else - return DIV_ROUND_CLOSEST(port->uartclk, 16 * quot); -} - static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, tcflag_t c_cflag) { @@ -2727,14 +2714,11 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) baud = serial8250_get_baud_rate(port, termios, NULL); quot = serial8250_get_divisor(port, baud, &frac); - baud = serial8250_compute_baud_rate(port, quot); serial8250_rpm_get(up); spin_lock_irqsave(&port->lock, flags); uart_update_timeout(port, termios->c_cflag, baud); - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); serial8250_set_divisor(port, baud, quot, frac); serial_port_out(port, UART_LCR, up->lcr); @@ -2766,7 +2750,6 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, baud = serial8250_get_baud_rate(port, termios, old); quot = serial8250_get_divisor(port, baud, &frac); - baud = serial8250_compute_baud_rate(port, quot); /* * Ok, we're now changing the port state. Do it with From 3aee752cd0b880b052b2757278227d09673a2abd Mon Sep 17 00:00:00 2001 From: Oskari Pirhonen Date: Sat, 25 Sep 2021 23:42:48 -0500 Subject: [PATCH 42/86] tty/sysrq: More intuitive Shift handling Make Alt-SysRq-Shift- behave like Alt-Shift-SysRq-. Acked-by: Pavel Machek Signed-off-by: Oskari Pirhonen Link: https://lore.kernel.org/r/YU/6SCmUr9qGkqBu@dj3ntoo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/sysrq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index c911196ac893..4d3dbe62daf8 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -843,6 +843,8 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq, sysrq->shift = KEY_RESERVED; else if (value != 2) sysrq->shift = code; + if (sysrq->active) + sysrq->shift_use = sysrq->shift; break; case KEY_SYSRQ: From 4c9883e1f4ddc53ff66eeb124a96530435dee22b Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Fri, 1 Oct 2021 23:17:31 +0200 Subject: [PATCH 43/86] dt-bindings: serial: 8250_omap: allow serdev subnodes additionalProperties: false ignores the pattern matching for serdev objects in serial.yaml, causing error messages when serdev subnodes like bluetooth or gnss devices are defined. Using unevaluatedProperties instead is the correct way if arbitrary children nodes can appear. Acked-by: Rob Herring Signed-off-by: Andreas Kemnade Link: https://lore.kernel.org/r/20211001211731.2923066-1-andreas@kemnade.info Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/8250_omap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/8250_omap.yaml b/Documentation/devicetree/bindings/serial/8250_omap.yaml index 70ca61688bb9..7b34ec8fa90e 100644 --- a/Documentation/devicetree/bindings/serial/8250_omap.yaml +++ b/Documentation/devicetree/bindings/serial/8250_omap.yaml @@ -86,7 +86,7 @@ required: - reg - interrupts -additionalProperties: false +unevaluatedProperties: false if: properties: From aec079f8875220c2c0657ba22e10099910295e20 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 7 Oct 2021 14:20:14 +0300 Subject: [PATCH 44/86] tty: serial: atmel: use macros instead of hardcoded values Use UART_PM_STATE_ON, UART_PM_STATE_OFF instead of hardcoded values. Reviewed-by: Nicolas Ferre Acked-by: Richard Genoud Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20211007112014.2332019-1-claudiu.beznea@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 249ea35088d2..2c99a47a2535 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2084,7 +2084,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); switch (state) { - case 0: + case UART_PM_STATE_ON: /* * Enable the peripheral clock for this serial port. * This is called on uart_open() or a resume event. @@ -2094,7 +2094,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, /* re-enable interrupts if we disabled some on suspend */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr); break; - case 3: + case UART_PM_STATE_OFF: /* Back up the interrupt mask and disable all interrupts */ atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR); atmel_uart_writel(port, ATMEL_US_IDR, -1); From b84d0001512aec42bd3357bf66ab13ade1c633cf Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Tue, 5 Oct 2021 12:58:00 +0300 Subject: [PATCH 45/86] tty: serial: samsung: Improve naming for common macro Having "_USI" suffix in EXYNOS_COMMON_SERIAL_DRV_DATA_USI() macro is confusing. Rename it to just EXYNOS_COMMON_SERIAL_DRV_DATA() and provide USI registers availability for all Exynos variants instead. While at it, also convert .has_usi field type to bool, so its usage is more obvious. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sam Protsenko Link: https://lore.kernel.org/r/20211005095800.2165-1-semen.protsenko@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index e2f49863e9c2..ca084c10d0bb 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -65,7 +65,7 @@ enum s3c24xx_port_type { struct s3c24xx_uart_info { char *name; enum s3c24xx_port_type type; - unsigned int has_usi; + bool has_usi; unsigned int port_type; unsigned int fifosize; unsigned long rx_fifomask; @@ -2780,7 +2780,7 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #endif #if defined(CONFIG_ARCH_EXYNOS) -#define EXYNOS_COMMON_SERIAL_DRV_DATA_USI(_has_usi) \ +#define EXYNOS_COMMON_SERIAL_DRV_DATA(_has_usi) \ .info = &(struct s3c24xx_uart_info) { \ .name = "Samsung Exynos UART", \ .type = TYPE_S3C6400, \ @@ -2804,21 +2804,18 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .has_fracval = 1, \ } \ -#define EXYNOS_COMMON_SERIAL_DRV_DATA \ - EXYNOS_COMMON_SERIAL_DRV_DATA_USI(0) - static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA, + EXYNOS_COMMON_SERIAL_DRV_DATA(false), .fifosize = { 256, 64, 16, 16 }, }; static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA, + EXYNOS_COMMON_SERIAL_DRV_DATA(false), .fifosize = { 64, 256, 16, 256 }, }; static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA_USI(1), + EXYNOS_COMMON_SERIAL_DRV_DATA(true), .fifosize = { 256, 64, 64, 64 }, }; From ebabb77a2a115b6c5e68f7364b598310b5f61fb2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Oct 2021 16:45:16 +0300 Subject: [PATCH 46/86] serial: 8250_dw: Drop wrong use of ACPI_PTR() ACPI_PTR() is more harmful than helpful. For example, in this case if CONFIG_ACPI=n, the ID table left unused which is not what we want. Instead of adding ifdeffery here and there, drop ACPI_PTR(). Fixes: 6a7320c4669f ("serial: 8250_dw: Add ACPI 5.0 support") Reported-by: Daniel Palmer Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211005134516.23218-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a3a0154da567..49559731bbcf 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -726,7 +726,7 @@ static struct platform_driver dw8250_platform_driver = { .name = "dw-apb-uart", .pm = &dw8250_pm_ops, .of_match_table = dw8250_of_match, - .acpi_match_table = ACPI_PTR(dw8250_acpi_match), + .acpi_match_table = dw8250_acpi_match, }, .probe = dw8250_probe, .remove = dw8250_remove, From 0946efc2255feed04803b811bbcbccbaba4e5a91 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Oct 2021 16:45:28 +0300 Subject: [PATCH 47/86] serial: 8250_dw: Re-use temporary variable for of_node In couple of places we may re-use temporary variable instead of dereferencing it. No functional changes intended. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211005134529.23256-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 49559731bbcf..cc91cb0ce08f 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -393,8 +393,9 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param) static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) { - if (p->dev->of_node) { - struct device_node *np = p->dev->of_node; + struct device_node *np = p->dev->of_node; + + if (np) { int id; /* get index of serial line, if found in DT aliases */ @@ -411,11 +412,13 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) data->skip_autocfg = true; } #endif - if (of_device_is_big_endian(p->dev->of_node)) { + + if (of_device_is_big_endian(np)) { p->iotype = UPIO_MEM32BE; p->serial_in = dw8250_serial_in32be; p->serial_out = dw8250_serial_out32be; } + if (of_device_is_compatible(np, "marvell,armada-38x-uart")) p->serial_out = dw8250_serial_out38x; From 0eb9da9cf20184bdc16729e690ba38e0a2922d81 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Oct 2021 16:45:29 +0300 Subject: [PATCH 48/86] serial: 8250_dw: Fix the trivial typo in the comment Fix the trivial typo in the comment: Premilinary --> Preliminary. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211005134529.23256-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index cc91cb0ce08f..b7d6c0674a8f 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -338,7 +338,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, rate = clk_round_rate(d->clk, newrate); if (rate > 0) { /* - * Premilinary set the uartclk to the new clock rate so the + * Preliminary set the uartclk to the new clock rate so the * clock update event handler caused by the clk_set_rate() * calling wouldn't actually update the UART divisor since * we about to do this anyway. From 7c4fc082f50431cc0814b47595ec9f9cca285993 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Oct 2021 16:30:25 +0300 Subject: [PATCH 49/86] serial: 8250_lpss: Extract dw8250_do_set_termios() for common use Some of the code currently used in dw8250_set_termios(), byt_set_termios() may be reused by other methods in the future. Extract it to a common helper function. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211005133026.21488-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 6 +----- drivers/tty/serial/8250/8250_dwlib.c | 10 ++++++++++ drivers/tty/serial/8250/8250_dwlib.h | 1 + drivers/tty/serial/8250/8250_lpss.c | 6 +----- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index b7d6c0674a8f..5a2ff843ec5d 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -350,11 +350,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, } clk_prepare_enable(d->clk); - p->status &= ~UPSTAT_AUTOCTS; - if (termios->c_cflag & CRTSCTS) - p->status |= UPSTAT_AUTOCTS; - - serial8250_do_set_termios(p, termios, old); + dw8250_do_set_termios(p, termios, old); } static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios) diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index 6d6a78eead3e..622d3b0d89e7 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -77,6 +77,16 @@ static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, serial8250_do_set_divisor(p, baud, quot, quot_frac); } +void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) +{ + p->status &= ~UPSTAT_AUTOCTS; + if (termios->c_cflag & CRTSCTS) + p->status |= UPSTAT_AUTOCTS; + + serial8250_do_set_termios(p, termios, old); +} +EXPORT_SYMBOL_GPL(dw8250_do_set_termios); + void dw8250_setup_port(struct uart_port *p) { struct uart_8250_port *up = up_to_u8250p(p); diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h index 9a12953832d3..83d528e5cc21 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -16,4 +16,5 @@ struct dw8250_port_data { u8 dlf_size; }; +void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old); void dw8250_setup_port(struct uart_port *p); diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 848d81e3838c..398d2c4a40e3 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -100,11 +100,7 @@ static void byt_set_termios(struct uart_port *p, struct ktermios *termios, reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; writel(reg, p->membase + BYT_PRV_CLK); - p->status &= ~UPSTAT_AUTOCTS; - if (termios->c_cflag & CRTSCTS) - p->status |= UPSTAT_AUTOCTS; - - serial8250_do_set_termios(p, termios, old); + dw8250_do_set_termios(p, termios, old); } static unsigned int byt_get_mctrl(struct uart_port *port) From 2cb3315107b5b3312b0f434efdb3ad354274e2a5 Mon Sep 17 00:00:00 2001 From: Aman Kumar Date: Tue, 5 Oct 2021 16:30:26 +0300 Subject: [PATCH 50/86] serial: 8250_lpss: Enable PSE UART Auto Flow Control Add a call to the custom ->set_termios() which has implementation about changing the state of RTS and CTS. Reviewed-by: Jiri Slaby Signed-off-by: Aman Kumar Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211005133026.21488-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpss.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 398d2c4a40e3..d3bafec7619d 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -164,6 +164,9 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) * matching with the registered General Purpose DMA controllers. */ up->dma = dma; + + port->set_termios = dw8250_do_set_termios; + return 0; } From 70b4d23226c85a30affd612a05c5898a724bcd62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 12 Oct 2021 17:39:42 +0200 Subject: [PATCH 51/86] serial: max310x: Make max310x_remove() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now max310x_remove() returns zero unconditionally. Make it return void instead which makes it easier to see in the callers that there is no error to handle. Also the return value of spi remove callbacks is ignored anyway. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20211012153945.2651412-18-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3df0788ddeb0..dde0824b2fa5 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1426,7 +1426,7 @@ out_clk: return ret; } -static int max310x_remove(struct device *dev) +static void max310x_remove(struct device *dev) { struct max310x_port *s = dev_get_drvdata(dev); int i; @@ -1441,8 +1441,6 @@ static int max310x_remove(struct device *dev) } clk_disable_unprepare(s->clk); - - return 0; } static const struct of_device_id __maybe_unused max310x_dt_ids[] = { @@ -1491,7 +1489,8 @@ static int max310x_spi_probe(struct spi_device *spi) static int max310x_spi_remove(struct spi_device *spi) { - return max310x_remove(&spi->dev); + max310x_remove(&spi->dev); + return 0; } static const struct spi_device_id max310x_id_table[] = { From 9b29075c1a4595b1d4c41668be4c72553ff60b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 12 Oct 2021 17:39:43 +0200 Subject: [PATCH 52/86] serial: sc16is7xx: Make sc16is7xx_remove() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now sc16is7xx_remove() returns zero unconditionally. Make it return void instead which makes it easier to see in the callers that there is no error to handle. Also the return value of spi remove callbacks is ignored anyway. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20211012153945.2651412-19-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index acbb615dd28f..64e7e6c8145f 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1365,7 +1365,7 @@ out_clk: return ret; } -static int sc16is7xx_remove(struct device *dev) +static void sc16is7xx_remove(struct device *dev) { struct sc16is7xx_port *s = dev_get_drvdata(dev); int i; @@ -1385,8 +1385,6 @@ static int sc16is7xx_remove(struct device *dev) kthread_stop(s->kworker_task); clk_disable_unprepare(s->clk); - - return 0; } static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { @@ -1444,7 +1442,9 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) static int sc16is7xx_spi_remove(struct spi_device *spi) { - return sc16is7xx_remove(&spi->dev); + sc16is7xx_remove(&spi->dev); + + return 0; } static const struct spi_device_id sc16is7xx_spi_id_table[] = { @@ -1497,7 +1497,9 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c, static int sc16is7xx_i2c_remove(struct i2c_client *client) { - return sc16is7xx_remove(&client->dev); + sc16is7xx_remove(&client->dev); + + return 0; } static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { From 5f0ac3a1dae17ec0af6b845376247d7cc948ea3d Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Sat, 9 Oct 2021 01:43:12 +0200 Subject: [PATCH 53/86] dt-bindings: serial: uartlite: drop $ref for -bits property Fixes warning: Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml: properties:xlnx,data-bits: {'const': '$ref'} is not allowed for '$ref' hint: Standard unit suffix properties don't need a type $ref from schema $id: http://devicetree.org/meta-schemas/core.yaml# Acked-by: Rob Herring Signed-off-by: David Heidelberg Link: https://lore.kernel.org/r/20211008234312.61688-1-david@ixit.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml b/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml index b8a2bfe14bed..f7617b88c7c3 100644 --- a/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml +++ b/Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.yaml @@ -38,7 +38,6 @@ properties: The fixed baud rate that the device was configured for. xlnx,data-bits: - $ref: /schemas/types.yaml#/definitions/uint32 enum: [5, 6, 7, 8] description: The fixed number of data bits that the device was configured for. From 3968ddcf05fb4b9409cd1859feb06a5b0550a1c1 Mon Sep 17 00:00:00 2001 From: Guanghui Feng Date: Mon, 11 Oct 2021 22:08:24 +0800 Subject: [PATCH 54/86] tty: tty_buffer: Fix the softlockup issue in flush_to_ldisc When running ltp testcase(ltp/testcases/kernel/pty/pty04.c) with arm64, there is a soft lockup, which look like this one: Workqueue: events_unbound flush_to_ldisc Call trace: dump_backtrace+0x0/0x1ec show_stack+0x24/0x30 dump_stack+0xd0/0x128 panic+0x15c/0x374 watchdog_timer_fn+0x2b8/0x304 __run_hrtimer+0x88/0x2c0 __hrtimer_run_queues+0xa4/0x120 hrtimer_interrupt+0xfc/0x270 arch_timer_handler_phys+0x40/0x50 handle_percpu_devid_irq+0x94/0x220 __handle_domain_irq+0x88/0xf0 gic_handle_irq+0x84/0xfc el1_irq+0xc8/0x180 slip_unesc+0x80/0x214 [slip] tty_ldisc_receive_buf+0x64/0x80 tty_port_default_receive_buf+0x50/0x90 flush_to_ldisc+0xbc/0x110 process_one_work+0x1d4/0x4b0 worker_thread+0x180/0x430 kthread+0x11c/0x120 In the testcase pty04, The first process call the write syscall to send data to the pty master. At the same time, the workqueue will do the flush_to_ldisc to pop data in a loop until there is no more data left. When the sender and workqueue running in different core, the sender sends data fastly in full time which will result in workqueue doing work in loop for a long time and occuring softlockup in flush_to_ldisc with kernel configured without preempt. So I add need_resched check and cond_resched in the flush_to_ldisc loop to avoid it. Signed-off-by: Guanghui Feng Link: https://lore.kernel.org/r/1633961304-24759-1-git-send-email-guanghuifeng@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 635d0af229b7..6c7e65b1d9a1 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -544,6 +544,9 @@ static void flush_to_ldisc(struct work_struct *work) if (!count) break; head->read += count; + + if (need_resched()) + cond_resched(); } mutex_unlock(&buf->lock); From 6d0d1b5a1b4870911beb89544ec1a9751c42fec7 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 20 Oct 2021 21:26:42 +0200 Subject: [PATCH 55/86] serial: imx: fix detach/attach of serial console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the device used as a serial console gets detached/attached at runtime, register_console() will try to call imx_uart_setup_console(), but this is not possible since it is marked as __init. For instance # cat /sys/devices/virtual/tty/console/active tty1 ttymxc0 # echo -n N > /sys/devices/virtual/tty/console/subsystem/ttymxc0/console # echo -n Y > /sys/devices/virtual/tty/console/subsystem/ttymxc0/console [ 73.166649] 8<--- cut here --- [ 73.167005] Unable to handle kernel paging request at virtual address c154d928 [ 73.167601] pgd = 55433e84 [ 73.167875] [c154d928] *pgd=8141941e(bad) [ 73.168304] Internal error: Oops: 8000000d [#1] SMP ARM [ 73.168429] Modules linked in: [ 73.168522] CPU: 0 PID: 536 Comm: sh Not tainted 5.15.0-rc6-00056-g3968ddcf05fb #3 [ 73.168675] Hardware name: Freescale i.MX6 Ultralite (Device Tree) [ 73.168791] PC is at imx_uart_console_setup+0x0/0x238 [ 73.168927] LR is at try_enable_new_console+0x98/0x124 [ 73.169056] pc : [] lr : [] psr: a0000013 [ 73.169178] sp : c2ef5e70 ip : 00000000 fp : 00000000 [ 73.169281] r10: 00000000 r9 : c02cf970 r8 : 00000000 [ 73.169389] r7 : 00000001 r6 : 00000001 r5 : c1760164 r4 : c1e0fb08 [ 73.169512] r3 : c154d928 r2 : 00000000 r1 : efffcbd1 r0 : c1760164 [ 73.169641] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 73.169782] Control: 10c5387d Table: 8345406a DAC: 00000051 [ 73.169895] Register r0 information: non-slab/vmalloc memory [ 73.170032] Register r1 information: non-slab/vmalloc memory [ 73.170158] Register r2 information: NULL pointer [ 73.170273] Register r3 information: non-slab/vmalloc memory [ 73.170397] Register r4 information: non-slab/vmalloc memory [ 73.170521] Register r5 information: non-slab/vmalloc memory [ 73.170647] Register r6 information: non-paged memory [ 73.170771] Register r7 information: non-paged memory [ 73.170892] Register r8 information: NULL pointer [ 73.171009] Register r9 information: non-slab/vmalloc memory [ 73.171142] Register r10 information: NULL pointer [ 73.171259] Register r11 information: NULL pointer [ 73.171375] Register r12 information: NULL pointer [ 73.171494] Process sh (pid: 536, stack limit = 0xcd1ba82f) [ 73.171621] Stack: (0xc2ef5e70 to 0xc2ef6000) [ 73.171731] 5e60: ???????? ???????? ???????? ???????? [ 73.171899] 5e80: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.172059] 5ea0: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.172217] 5ec0: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.172377] 5ee0: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.172537] 5f00: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.172698] 5f20: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.172856] 5f40: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.173016] 5f60: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.173177] 5f80: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.173336] 5fa0: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.173496] 5fc0: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.173654] 5fe0: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.173826] [] (try_enable_new_console) from [] (register_console+0x10c/0x2ec) [ 73.174053] [] (register_console) from [] (console_store+0x14c/0x168) [ 73.174262] [] (console_store) from [] (kernfs_fop_write_iter+0x110/0x1cc) [ 73.174470] [] (kernfs_fop_write_iter) from [] (vfs_write+0x31c/0x548) [ 73.174679] [] (vfs_write) from [] (ksys_write+0x60/0xec) [ 73.174863] [] (ksys_write) from [] (ret_fast_syscall+0x0/0x1c) [ 73.175052] Exception stack(0xc2ef5fa8 to 0xc2ef5ff0) [ 73.175167] 5fa0: ???????? ???????? ???????? ???????? ???????? ???????? [ 73.175327] 5fc0: ???????? ???????? ???????? ???????? ???????? ???????? ???????? ???????? [ 73.175486] 5fe0: ???????? ???????? ???????? ???????? [ 73.175608] Code: 00000000 00000000 00000000 00000000 (00000000) [ 73.175744] ---[ end trace 9b75121265109bf1 ]--- A similar issue could be triggered by unbinding/binding the serial console device [*]. Drop __init so that imx_uart_setup_console() can be safely called at runtime. [*] https://lore.kernel.org/all/20181114174940.7865-3-stefan@agner.ch/ Fixes: a3cb39d258ef ("serial: core: Allow detach and attach serial device for console") Reviewed-by: Andy Shevchenko Acked-by: Uwe Kleine-König Signed-off-by: Stefan Agner Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20211020192643.476895-2-francesco.dolcini@toradex.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 8b121cd869e9..51a9f9423b1a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2017,7 +2017,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. */ -static void __init +static void imx_uart_console_get_options(struct imx_port *sport, int *baud, int *parity, int *bits) { @@ -2076,7 +2076,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud, } } -static int __init +static int imx_uart_console_setup(struct console *co, char *options) { struct imx_port *sport; From 9768a37cec37b03f745ce90f8c3d378e0aa223ae Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Wed, 20 Oct 2021 21:26:43 +0200 Subject: [PATCH 56/86] serial: imx: disable console clocks on unregister During console setup imx_uart_console_setup() enables clocks, but they are never disabled when the console is unregistered, this leads to clk_prepare_enable() being called multiple times without a matching clk_disable_unprepare() in case of console unregister. Ensure that clock enable/disable are balanced adding clk_disable_unprepare() in the console exit callback. Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20211020192643.476895-3-francesco.dolcini@toradex.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 51a9f9423b1a..90f82e6c54e4 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2124,12 +2124,24 @@ error_console: return retval; } +static int +imx_uart_console_exit(struct console *co) +{ + struct imx_port *sport = imx_uart_ports[co->index]; + + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); + + return 0; +} + static struct uart_driver imx_uart_uart_driver; static struct console imx_uart_console = { .name = DEV_NAME, .write = imx_uart_console_write, .device = uart_console_device, .setup = imx_uart_console_setup, + .exit = imx_uart_console_exit, .flags = CON_PRINTBUFFER, .index = -1, .data = &imx_uart_uart_driver, From 30480f65b575631ea5ac8172174f492bd1342ab5 Mon Sep 17 00:00:00 2001 From: Xianting Tian Date: Fri, 15 Oct 2021 10:46:56 +0800 Subject: [PATCH 57/86] tty: hvc: use correct dma alignment size Use L1_CACHE_BYTES as the dma alignment size, use 'sizeof(long)' as dma alignment is wrong. Signed-off-by: Xianting Tian Signed-off-by: Shile Zhang Link: https://lore.kernel.org/r/20211015024658.1353987-2-xianting.tian@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 7b30d5a05e2f..4802cfaa107f 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -49,7 +49,7 @@ #define N_OUTBUF 16 #define N_INBUF 16 -#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) +#define __ALIGNED__ __attribute__((__aligned__(L1_CACHE_BYTES))) static struct tty_driver *hvc_driver; static struct task_struct *hvc_task; From 0986d7bc5598f5df30e3db777d00e73890c97627 Mon Sep 17 00:00:00 2001 From: Xianting Tian Date: Fri, 15 Oct 2021 10:46:57 +0800 Subject: [PATCH 58/86] tty: hvc: pass DMA capable memory to put_chars() As well known, hvc backend can register its opertions to hvc backend. the operations contain put_chars(), get_chars() and so on. Some hvc backend may do dma in its operations. eg, put_chars() of virtio-console. But in the code of hvc framework, it may pass DMA incapable memory to put_chars() under a specific configuration, which is explained in commit c4baad5029(virtio-console: avoid DMA from stack): 1, c[] is on stack, hvc_console_print(): char c[N_OUTBUF] __ALIGNED__; cons_ops[index]->put_chars(vtermnos[index], c, i); 2, ch is on stack, static void hvc_poll_put_char(,,char ch) { struct tty_struct *tty = driver->ttys[0]; struct hvc_struct *hp = tty->driver_data; int n; do { n = hp->ops->put_chars(hp->vtermno, &ch, 1); } while (n <= 0); } Commit c4baad5029 is just the fix to avoid DMA from stack memory, which is passed to virtio-console by hvc framework in above code. But I think the fix is aggressive, it directly uses kmemdup() to alloc new buffer from kmalloc area and do memcpy no matter the memory is in kmalloc area or not. But most importantly, it should better be fixed in the hvc framework, by changing it to never pass stack memory to the put_chars() function in the first place. Otherwise, we still face the same issue if a new hvc backend using dma added in the furture. In this patch, add 'char cons_outbuf[]' as part of 'struct hvc_struct', so hp->cons_outbuf is no longer the stack memory, we can use it in above cases safely. We also add lock to protect cons_outbuf instead of using the global lock of hvc. Introduce another array(cons_hvcs[]) for hvc pointers next to the cons_ops[] and vtermnos[] arrays. With the array, we can easily find hvc's cons_outbuf and its lock. With the patch, we can revert the fix c4baad5029. Signed-off-by: Xianting Tian Signed-off-by: Shile Zhang Link: https://lore.kernel.org/r/20211015024658.1353987-3-xianting.tian@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 36 ++++++++++++++++++++--------------- drivers/tty/hvc/hvc_console.h | 21 +++++++++++++++++++- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 4802cfaa107f..5bdb3df022ce 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -41,16 +41,6 @@ */ #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ -/* - * These sizes are most efficient for vio, because they are the - * native transfer size. We could make them selectable in the - * future to better deal with backends that want other buffer sizes. - */ -#define N_OUTBUF 16 -#define N_INBUF 16 - -#define __ALIGNED__ __attribute__((__aligned__(L1_CACHE_BYTES))) - static struct tty_driver *hvc_driver; static struct task_struct *hvc_task; @@ -142,6 +132,7 @@ static int hvc_flush(struct hvc_struct *hp) static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; +static struct hvc_struct *cons_hvcs[MAX_NR_HVC_CONSOLES]; /* * Console APIs, NOT TTY. These APIs are available immediately when @@ -151,9 +142,11 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = static void hvc_console_print(struct console *co, const char *b, unsigned count) { - char c[N_OUTBUF] __ALIGNED__; + char *c; unsigned i = 0, n = 0; int r, donecr = 0, index = co->index; + unsigned long flags; + struct hvc_struct *hp; /* Console access attempt outside of acceptable console range. */ if (index >= MAX_NR_HVC_CONSOLES) @@ -163,6 +156,13 @@ static void hvc_console_print(struct console *co, const char *b, if (vtermnos[index] == -1) return; + hp = cons_hvcs[index]; + if (!hp) + return; + + c = hp->cons_outbuf; + + spin_lock_irqsave(&hp->cons_outbuf_lock, flags); while (count > 0 || i > 0) { if (count > 0 && i < sizeof(c)) { if (b[n] == '\n' && !donecr) { @@ -191,6 +191,7 @@ static void hvc_console_print(struct console *co, const char *b, } } } + spin_unlock_irqrestore(&hp->cons_outbuf_lock, flags); hvc_console_flush(cons_ops[index], vtermnos[index]); } @@ -878,9 +879,13 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch) struct tty_struct *tty = driver->ttys[0]; struct hvc_struct *hp = tty->driver_data; int n; + unsigned long flags; do { - n = hp->ops->put_chars(hp->vtermno, &ch, 1); + spin_lock_irqsave(&hp->cons_outbuf_lock, flags); + hp->cons_outbuf[0] = ch; + n = hp->ops->put_chars(hp->vtermno, &hp->cons_outbuf[0], 1); + spin_unlock_irqrestore(&hp->cons_outbuf_lock, flags); } while (n <= 0); } #endif @@ -922,8 +927,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, return ERR_PTR(err); } - hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, - GFP_KERNEL); + hp = kzalloc(struct_size(hp, outbuf, outbuf_size), GFP_KERNEL); if (!hp) return ERR_PTR(-ENOMEM); @@ -931,13 +935,13 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, hp->data = data; hp->ops = ops; hp->outbuf_size = outbuf_size; - hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; tty_port_init(&hp->port); hp->port.ops = &hvc_port_ops; INIT_WORK(&hp->tty_resize, hvc_set_winsz); spin_lock_init(&hp->lock); + spin_lock_init(&hp->cons_outbuf_lock); mutex_lock(&hvc_structs_mutex); /* @@ -964,6 +968,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, if (i < MAX_NR_HVC_CONSOLES) { cons_ops[i] = ops; vtermnos[i] = vtermno; + cons_hvcs[i] = hp; } list_add_tail(&(hp->next), &hvc_structs); @@ -988,6 +993,7 @@ int hvc_remove(struct hvc_struct *hp) if (hp->index < MAX_NR_HVC_CONSOLES) { vtermnos[hp->index] = -1; cons_ops[hp->index] = NULL; + cons_hvcs[hp->index] = NULL; } /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index 18d005814e4b..2c32ab67b68d 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -32,12 +32,21 @@ */ #define HVC_ALLOC_TTY_ADAPTERS 8 +/* + * These sizes are most efficient for vio, because they are the + * native transfer size. We could make them selectable in the + * future to better deal with backends that want other buffer sizes. + */ +#define N_OUTBUF 16 +#define N_INBUF 16 + +#define __ALIGNED__ __attribute__((__aligned__(L1_CACHE_BYTES))) + struct hvc_struct { struct tty_port port; spinlock_t lock; int index; int do_wakeup; - char *outbuf; int outbuf_size; int n_outbuf; uint32_t vtermno; @@ -48,6 +57,16 @@ struct hvc_struct { struct work_struct tty_resize; struct list_head next; unsigned long flags; + + /* + * the buf and its lock are used in hvc console api for putting chars, + * and also used in hvc_poll_put_char() for putting single char. + */ + spinlock_t cons_outbuf_lock; + char cons_outbuf[N_OUTBUF] __ALIGNED__; + + /* the buf is used for putting chars to tty */ + char outbuf[] __ALIGNED__; }; /* implemented by a low level driver */ From 9db81eca10ba2d84177fa076704db3a5d76863c3 Mon Sep 17 00:00:00 2001 From: Xianting Tian Date: Fri, 15 Oct 2021 10:46:58 +0800 Subject: [PATCH 59/86] virtio-console: remove unnecessary kmemdup() This revert commit c4baad5029 ("virtio-console: avoid DMA from stack") hvc framework will never pass stack memory to the put_chars() function, So the calling of kmemdup() is unnecessary, we can remove it. Signed-off-by: Xianting Tian Reviewed-by: Shile Zhang Link: https://lore.kernel.org/r/20211015024658.1353987-4-xianting.tian@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 7eaf303a7a86..4ed3ffb1d479 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1117,8 +1117,6 @@ static int put_chars(u32 vtermno, const char *buf, int count) { struct port *port; struct scatterlist sg[1]; - void *data; - int ret; if (unlikely(early_put_chars)) return early_put_chars(vtermno, buf, count); @@ -1127,14 +1125,8 @@ static int put_chars(u32 vtermno, const char *buf, int count) if (!port) return -EPIPE; - data = kmemdup(buf, count, GFP_ATOMIC); - if (!data) - return -ENOMEM; - - sg_init_one(sg, data, count); - ret = __send_to_port(port, sg, 1, count, data, false); - kfree(data); - return ret; + sg_init_one(sg, buf, count); + return __send_to_port(port, sg, 1, count, (void *)buf, false); } /* From cc58d0a3f0a4755b9c808e065d9227c6e984e7db Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Wed, 20 Oct 2021 17:03:30 +0200 Subject: [PATCH 60/86] serial: stm32: re-introduce an irq flag condition in usart_receive_chars Re-introduce an irq flag condition in usart_receive_chars. This condition has been deleted by commit 75f4e830fa9c ("serial: do not restore interrupt state in sysrq helper"). This code was present to handle threaded case, and has been removed because it is no more needed in this case. Nevertheless an irq safe lock is still needed in some cases, when DMA should be stopped to receive errors or breaks in PIO mode. This patch is a precursor to the complete rework or stm32 serial driver DMA implementation. Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20211020150332.10214-2-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 8f032e77b954..848e063db2ae 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -209,19 +209,22 @@ static unsigned long stm32_usart_get_char(struct uart_port *port, u32 *sr, return c; } -static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) +static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) { struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - unsigned long c; + unsigned long c, flags; u32 sr; char flag; - spin_lock(&port->lock); + if (irqflag) + spin_lock_irqsave(&port->lock, flags); + else + spin_lock(&port->lock); while (stm32_usart_pending_rx(port, &sr, &stm32_port->last_res, - threaded)) { + irqflag)) { sr |= USART_SR_DUMMY_RX; flag = TTY_NORMAL; @@ -275,7 +278,10 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) uart_insert_char(port, sr, USART_SR_ORE, c, flag); } - uart_unlock_and_check_sysrq(port); + if (irqflag) + uart_unlock_and_check_sysrq_irqrestore(port, irqflag); + else + uart_unlock_and_check_sysrq(port); tty_flip_buffer_push(tport); } @@ -496,10 +502,9 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; - struct stm32_port *stm32_port = to_stm32_port(port); - if (stm32_port->rx_ch) - stm32_usart_receive_chars(port, true); + /* Receiver timeout irq for DMA RX */ + stm32_usart_receive_chars(port, false); return IRQ_HANDLED; } From 33bb2f6ac3088936b7aad3cab6f439f91af0223c Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Wed, 20 Oct 2021 17:03:31 +0200 Subject: [PATCH 61/86] serial: stm32: rework RX over DMA This patch reworks RX support over DMA to improve reliability: - change dma buffer cyclic configuration by using 2 periods. DMA buffer data are handled by a flip-flop between the 2 periods in order to avoid risk of data loss/corruption - change the size of dma buffer to 4096 to limit overruns - add rx errors management (breaks, parity, framing and overrun). When an error occurs on the uart line, the dma request line is masked at HW level. The SW must 1st clear DMAR (dma request line enable), to handle the error, then re-enable DMAR to recover. So, any correct data is taken from the DMA buffer, before handling the error itself. Then errors are handled from RDR/ISR/FIFO (e.g. in PIO mode). Last, DMA reception is resumed. - add a condition on DMA request line in DMA RX routines in order to switch to PIO mode when no DMA request line is disabled, even if the DMA channel is still enabled. When the UART is wakeup source and is configured to use DMA for RX, any incoming data that wakes up the system isn't correctly received. At data reception, the irq_handler handles the WUF irq, and then the data reception over DMA. As the DMA transfer has been terminated at suspend, and will be restored by resume callback (which has no yet been called by system), the data can't be received. The wake-up data has to be handled in PIO mode while suspend callback has not been called. Signed-off-by: Valentin Caron Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20211020150332.10214-3-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 208 +++++++++++++++++++++++-------- drivers/tty/serial/stm32-usart.h | 12 +- 2 files changed, 166 insertions(+), 54 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 848e063db2ae..cfdda35499e6 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -165,66 +165,60 @@ static int stm32_usart_init_rs485(struct uart_port *port, return uart_get_rs485_mode(port); } -static int stm32_usart_pending_rx(struct uart_port *port, u32 *sr, - int *last_res, bool threaded) +static bool stm32_usart_rx_dma_enabled(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - enum dma_status status; - struct dma_tx_state state; - *sr = readl_relaxed(port->membase + ofs->isr); + if (!stm32_port->rx_ch) + return false; - if (threaded && stm32_port->rx_ch) { - status = dmaengine_tx_status(stm32_port->rx_ch, - stm32_port->rx_ch->cookie, - &state); - if (status == DMA_IN_PROGRESS && (*last_res != state.residue)) - return 1; - else - return 0; - } else if (*sr & USART_SR_RXNE) { - return 1; - } - return 0; + return !!(readl_relaxed(port->membase + ofs->cr3) & USART_CR3_DMAR); } -static unsigned long stm32_usart_get_char(struct uart_port *port, u32 *sr, - int *last_res) +/* Return true when data is pending (in pio mode), and false when no data is pending. */ +static bool stm32_usart_pending_rx_pio(struct uart_port *port, u32 *sr) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + *sr = readl_relaxed(port->membase + ofs->isr); + /* Get pending characters in RDR or FIFO */ + if (*sr & USART_SR_RXNE) { + /* Get all pending characters from the RDR or the FIFO when using interrupts */ + if (!stm32_usart_rx_dma_enabled(port)) + return true; + + /* Handle only RX data errors when using DMA */ + if (*sr & USART_SR_ERR_MASK) + return true; + } + + return false; +} + +static unsigned long stm32_usart_get_char_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; - if (stm32_port->rx_ch) { - c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; - if ((*last_res) == 0) - *last_res = RX_BUF_L; - } else { - c = readl_relaxed(port->membase + ofs->rdr); - /* apply RDR data mask */ - c &= stm32_port->rdr_mask; - } + c = readl_relaxed(port->membase + ofs->rdr); + /* Apply RDR data mask */ + c &= stm32_port->rdr_mask; return c; } -static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) +static void stm32_usart_receive_chars_pio(struct uart_port *port) { - struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - unsigned long c, flags; + unsigned long c; u32 sr; char flag; - if (irqflag) - spin_lock_irqsave(&port->lock, flags); - else - spin_lock(&port->lock); - - while (stm32_usart_pending_rx(port, &sr, &stm32_port->last_res, - irqflag)) { + while (stm32_usart_pending_rx_pio(port, &sr)) { sr |= USART_SR_DUMMY_RX; flag = TTY_NORMAL; @@ -243,7 +237,7 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) writel_relaxed(sr & USART_SR_ERR_MASK, port->membase + ofs->icr); - c = stm32_usart_get_char(port, &sr, &stm32_port->last_res); + c = stm32_usart_get_char_pio(port); port->icount.rx++; if (sr & USART_SR_ERR_MASK) { if (sr & USART_SR_ORE) { @@ -277,6 +271,94 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) continue; uart_insert_char(port, sr, USART_SR_ORE, c, flag); } +} + +static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma_size) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct tty_port *ttyport = &stm32_port->port.state->port; + unsigned char *dma_start; + int dma_count, i; + + dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res); + + /* + * Apply rdr_mask on buffer in order to mask parity bit. + * This loop is useless in cs8 mode because DMA copies only + * 8 bits and already ignores parity bit. + */ + if (!(stm32_port->rdr_mask == (BIT(8) - 1))) + for (i = 0; i < dma_size; i++) + *(dma_start + i) &= stm32_port->rdr_mask; + + dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size); + port->icount.rx += dma_count; + if (dma_count != dma_size) + port->icount.buf_overrun++; + stm32_port->last_res -= dma_count; + if (stm32_port->last_res == 0) + stm32_port->last_res = RX_BUF_L; +} + +static void stm32_usart_receive_chars_dma(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int dma_size; + + /* DMA buffer is configured in cyclic mode and handles the rollback of the buffer. */ + if (stm32_port->rx_dma_state.residue > stm32_port->last_res) { + /* Conditional first part: from last_res to end of DMA buffer */ + dma_size = stm32_port->last_res; + stm32_usart_push_buffer_dma(port, dma_size); + } + + dma_size = stm32_port->last_res - stm32_port->rx_dma_state.residue; + stm32_usart_push_buffer_dma(port, dma_size); +} + +static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) +{ + struct tty_port *tport = &port->state->port; + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + enum dma_status rx_dma_status; + unsigned long flags; + u32 sr; + + if (irqflag) + spin_lock_irqsave(&port->lock, flags); + else + spin_lock(&port->lock); + + if (stm32_usart_rx_dma_enabled(port)) { + rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + &stm32_port->rx_dma_state); + if (rx_dma_status == DMA_IN_PROGRESS) { + /* Empty DMA buffer */ + stm32_usart_receive_chars_dma(port); + sr = readl_relaxed(port->membase + ofs->isr); + if (sr & USART_SR_ERR_MASK) { + /* Disable DMA request line */ + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + + /* Switch to PIO mode to handle the errors */ + stm32_usart_receive_chars_pio(port); + + /* Switch back to DMA mode */ + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + } + } else { + /* Disable RX DMA */ + dmaengine_terminate_async(stm32_port->rx_ch); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + /* Fall back to interrupt mode */ + dev_dbg(port->dev, "DMA error, fallback to irq mode\n"); + stm32_usart_receive_chars_pio(port); + } + } else { + stm32_usart_receive_chars_pio(port); + } if (irqflag) uart_unlock_and_check_sysrq_irqrestore(port, irqflag); @@ -318,6 +400,13 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port) stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE); } +static void stm32_usart_rx_dma_complete(void *arg) +{ + struct uart_port *port = arg; + + stm32_usart_receive_chars(port, true); +} + static void stm32_usart_tx_interrupt_disable(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); @@ -484,7 +573,12 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) pm_wakeup_event(tport->tty->dev, 0); } - if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) + /* + * rx errors in dma mode has to be handled ASAP to avoid overrun as the DMA request + * line has been masked by HW and rx data are stacking in FIFO. + */ + if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || + ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) stm32_usart_receive_chars(port, false); if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { @@ -493,7 +587,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) spin_unlock(&port->lock); } - if (stm32_port->rx_ch) + if (stm32_usart_rx_dma_enabled(port)) return IRQ_WAKE_THREAD; else return IRQ_HANDLED; @@ -815,9 +909,11 @@ static void stm32_usart_set_termios(struct uart_port *port, stm32_port->cr1_irq = USART_CR1_RTOIE; writel_relaxed(bits, port->membase + ofs->rtor); cr2 |= USART_CR2_RTOEN; - /* Not using dma, enable fifo threshold irq */ - if (!stm32_port->rx_ch) - stm32_port->cr3_irq = USART_CR3_RXFTIE; + /* + * Enable fifo threshold irq in two cases, either when there is no DMA, or when + * wake up over usart, from low power until the DMA gets re-enabled by resume. + */ + stm32_port->cr3_irq = USART_CR3_RXFTIE; } cr1 |= stm32_port->cr1_irq; @@ -880,8 +976,16 @@ static void stm32_usart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= USART_SR_DUMMY_RX; - if (stm32_port->rx_ch) + if (stm32_port->rx_ch) { + /* + * Setup DMA to collect only valid data and enable error irqs. + * This also enables break reception when using DMA. + */ + cr1 |= USART_CR1_PEIE; + cr3 |= USART_CR3_EIE; cr3 |= USART_CR3_DMAR; + cr3 |= USART_CR3_DDRE; + } if (rs485conf->flags & SER_RS485_ENABLED) { stm32_usart_config_reg_rs485(&cr1, &cr3, @@ -1210,9 +1314,9 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, return -ENODEV; } - /* No callback as dma buffer is drained on usart interrupt */ - desc->callback = NULL; - desc->callback_param = NULL; + /* Set DMA callback */ + desc->callback = stm32_usart_rx_dma_complete; + desc->callback_param = port; /* Push current DMA transaction in the pending queue */ ret = dma_submit_error(dmaengine_submit(desc)); @@ -1377,6 +1481,7 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; int err; + u32 cr3; pm_runtime_get_sync(&pdev->dev); err = uart_remove_one_port(&stm32_usart_driver, port); @@ -1387,7 +1492,12 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_PEIE); + cr3 = readl_relaxed(port->membase + ofs->cr3); + cr3 &= ~USART_CR3_EIE; + cr3 &= ~USART_CR3_DMAR; + cr3 &= ~USART_CR3_DDRE; + writel_relaxed(cr3, port->membase + ofs->cr3); if (stm32_port->tx_ch) { dmaengine_terminate_async(stm32_port->tx_ch); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 07ac291328cd..53bcd032fce7 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -109,7 +109,7 @@ struct stm32_usart_info stm32h7_info = { /* USART_SR (F4) / USART_ISR (F7) */ #define USART_SR_PE BIT(0) #define USART_SR_FE BIT(1) -#define USART_SR_NF BIT(2) +#define USART_SR_NE BIT(2) /* F7 (NF for F4) */ #define USART_SR_ORE BIT(3) #define USART_SR_IDLE BIT(4) #define USART_SR_RXNE BIT(5) @@ -126,7 +126,8 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ -#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE) +#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_NE | USART_SR_FE |\ + USART_SR_PE) /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) @@ -246,9 +247,9 @@ struct stm32_usart_info stm32h7_info = { #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 -#define RX_BUF_L 200 /* dma rx buffer length */ -#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ -#define TX_BUF_L 200 /* dma tx buffer length */ +#define RX_BUF_L 4096 /* dma rx buffer length */ +#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ +#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ struct stm32_port { struct uart_port port; @@ -272,6 +273,7 @@ struct stm32_port { bool wakeup_src; int rdr_mask; /* receive data register mask */ struct mctrl_gpios *gpios; /* modem control gpios */ + struct dma_tx_state rx_dma_state; }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; From d1ec8a2eabe969b333031e8fb36fe7fc61a5f0ac Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Wed, 20 Oct 2021 17:03:32 +0200 Subject: [PATCH 62/86] serial: stm32: update throttle and unthrottle ops for dma mode Disable DMA request line (if enabled) to switch in PIO mode in throttle ops, so the RX data gets queues into the FIFO. The hardware flow control is triggered when the RX FIFO is full. Switch back to DMA mode (re-enable DMA request line) in unthrottle ops. Hardware flow control is stopped when FIFO is not full anymore. Signed-off-by: Valentin Caron Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20211020150332.10214-4-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 37 ++++++++++++++++++++++++++++---- drivers/tty/serial/stm32-usart.h | 1 + 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index cfdda35499e6..7fd192e1e15d 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -577,9 +577,12 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) * rx errors in dma mode has to be handled ASAP to avoid overrun as the DMA request * line has been masked by HW and rx data are stacking in FIFO. */ - if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || - ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) - stm32_usart_receive_chars(port, false); + if (!stm32_port->throttled) { + if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || + ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) { + stm32_usart_receive_chars(port, false); + } + } if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { spin_lock(&port->lock); @@ -596,9 +599,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct stm32_port *stm32_port = to_stm32_port(port); /* Receiver timeout irq for DMA RX */ - stm32_usart_receive_chars(port, false); + if (!stm32_port->throttled) + stm32_usart_receive_chars(port, false); return IRQ_HANDLED; } @@ -711,10 +716,19 @@ static void stm32_usart_throttle(struct uart_port *port) unsigned long flags; spin_lock_irqsave(&port->lock, flags); + + /* + * Disable DMA request line if enabled, so the RX data gets queued into the FIFO. + * Hardware flow control is triggered when RX FIFO is full. + */ + if (stm32_usart_rx_dma_enabled(port)) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_port->throttled = true; spin_unlock_irqrestore(&port->lock, flags); } @@ -730,6 +744,14 @@ static void stm32_usart_unthrottle(struct uart_port *port) if (stm32_port->cr3_irq) stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + /* + * Switch back to DMA mode (re-enable DMA request line). + * Hardware flow control is stopped when FIFO is not full any more. + */ + if (stm32_port->rx_ch) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + + stm32_port->throttled = false; spin_unlock_irqrestore(&port->lock, flags); } @@ -775,6 +797,13 @@ static int stm32_usart_startup(struct uart_port *port) if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); + /* + * DMA request line not re-enabled at resume when port is throttled. + * It will be re-enabled by unthrottle ops. + */ + if (!stm32_port->throttled) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + /* RX enabling */ val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); stm32_usart_set_bits(port, ofs->cr1, val); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 53bcd032fce7..e23916bfbb60 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -265,6 +265,7 @@ struct stm32_port { u32 cr3_irq; /* USART_CR3_RXFTIE */ int last_res; bool tx_dma_busy; /* dma tx busy */ + bool throttled; /* port throttled */ bool hw_flow_control; bool swap; /* swap RX & TX pins */ bool fifoen; From 211cde4f5817dc88ef7f8f2fa286e57fbf14c8ee Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 15 Oct 2021 13:14:20 +0200 Subject: [PATCH 63/86] serial: 8250: fix racy uartclk update Commit 868f3ee6e452 ("serial: 8250: Add 8250 port clock update method") added a hack to support SoCs where the UART reference clock can change behind the back of the driver but failed to add the proper locking. First, make sure to take a reference to the tty struct to avoid dereferencing a NULL pointer if the clock change races with a hangup. Second, the termios semaphore must be held during the update to prevent a racing termios change. Fixes: 868f3ee6e452 ("serial: 8250: Add 8250 port clock update method") Fixes: c8dff3aa8241 ("serial: 8250: Skip uninitialized TTY port baud rate update") Cc: stable@vger.kernel.org # 5.9 Cc: Serge Semin Tested-by: Serge Semin Reviewed-by: Serge Semin Acked-by: Andy Shevchenko Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20211015111422.1027-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 66374704747e..e4dd82fd7c2a 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2696,21 +2696,32 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) { struct uart_8250_port *up = up_to_u8250p(port); + struct tty_port *tport = &port->state->port; unsigned int baud, quot, frac = 0; struct ktermios *termios; + struct tty_struct *tty; unsigned long flags; - mutex_lock(&port->state->port.mutex); + tty = tty_port_tty_get(tport); + if (!tty) { + mutex_lock(&tport->mutex); + port->uartclk = uartclk; + mutex_unlock(&tport->mutex); + return; + } + + down_write(&tty->termios_rwsem); + mutex_lock(&tport->mutex); if (port->uartclk == uartclk) goto out_lock; port->uartclk = uartclk; - if (!tty_port_initialized(&port->state->port)) + if (!tty_port_initialized(tport)) goto out_lock; - termios = &port->state->port.tty->termios; + termios = &tty->termios; baud = serial8250_get_baud_rate(port, termios, NULL); quot = serial8250_get_divisor(port, baud, &frac); @@ -2727,7 +2738,9 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) serial8250_rpm_put(up); out_lock: - mutex_unlock(&port->state->port.mutex); + mutex_unlock(&tport->mutex); + up_write(&tty->termios_rwsem); + tty_kref_put(tty); } EXPORT_SYMBOL_GPL(serial8250_update_uartclk); From d2248ca8d6ba867fd9b2317af730ba73284d0989 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 15 Oct 2021 13:14:21 +0200 Subject: [PATCH 64/86] serial: 8250: rename unlock labels Rename a couple of oddly named labels that are used to unlock before returning after what they do (rather than after the context they are used in) to improve readability. Tested-by: Serge Semin Reviewed-by: Andy Shevchenko Reviewed-by: Serge Semin Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20211015111422.1027-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index e4dd82fd7c2a..5775cbff8f6e 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1338,7 +1338,7 @@ static void autoconfig(struct uart_8250_port *up) up->tx_loadsz = uart_config[port->type].tx_loadsz; if (port->type == PORT_UNKNOWN) - goto out_lock; + goto out_unlock; /* * Reset the UART. @@ -1355,7 +1355,7 @@ static void autoconfig(struct uart_8250_port *up) else serial_out(up, UART_IER, 0); -out_lock: +out_unlock: spin_unlock_irqrestore(&port->lock, flags); /* @@ -2714,12 +2714,12 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) mutex_lock(&tport->mutex); if (port->uartclk == uartclk) - goto out_lock; + goto out_unlock; port->uartclk = uartclk; if (!tty_port_initialized(tport)) - goto out_lock; + goto out_unlock; termios = &tty->termios; @@ -2737,7 +2737,7 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) spin_unlock_irqrestore(&port->lock, flags); serial8250_rpm_put(up); -out_lock: +out_unlock: mutex_unlock(&tport->mutex); up_write(&tty->termios_rwsem); tty_kref_put(tty); From 74365bc138ab03bdac205047aac02f8db0a479fa Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 15 Oct 2021 13:14:22 +0200 Subject: [PATCH 65/86] serial: 8250_dw: drop bogus uartclk optimisation The driver was updating the port uartclk before setting the new rate in an attempt to avoid having the clock notifier redundantly update the divisors. The set_termios() callback is however called under the termios semaphore and tty-port mutex so the worker scheduled by the clock notifier will block in serial8250_update_uartclk() until the uartclk and divisors have been updated anyway. Drop the unnecessary swaps and incorrect comment and simply update the uartclk field if the clock-rate change was successful. Tested-by: Serge Semin Reviewed-by: Serge Semin Acked-by: Andy Shevchenko Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20211015111422.1027-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5a2ff843ec5d..53f57c3b9f42 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -338,15 +338,12 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, rate = clk_round_rate(d->clk, newrate); if (rate > 0) { /* - * Preliminary set the uartclk to the new clock rate so the - * clock update event handler caused by the clk_set_rate() - * calling wouldn't actually update the UART divisor since - * we about to do this anyway. + * Note that any clock-notifer worker will block in + * serial8250_update_uartclk() until we are done. */ - swap(p->uartclk, rate); ret = clk_set_rate(d->clk, newrate); - if (ret) - swap(p->uartclk, rate); + if (!ret) + p->uartclk = rate; } clk_prepare_enable(d->clk); From e279317e9aeb11d8670e0a5acb10d50566eea9c9 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Fri, 15 Oct 2021 11:47:00 +0200 Subject: [PATCH 66/86] rpmsg: core: add API to get MTU Return the rpmsg buffer MTU for sending message, so rpmsg users can split a long message in several sub rpmsg buffers. Reviewed-by: Mathieu Poirier Reviewed-by: Bjorn Andersson Acked-by: Suman Anna Signed-off-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20211015094701.5732-2-arnaud.pouliquen@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/rpmsg/rpmsg_core.c | 21 +++++++++++++++++++++ drivers/rpmsg/rpmsg_internal.h | 2 ++ drivers/rpmsg/virtio_rpmsg_bus.c | 10 ++++++++++ include/linux/rpmsg.h | 10 ++++++++++ 4 files changed, 43 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 9151836190ce..d3eb60059ef1 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -327,6 +327,27 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, } EXPORT_SYMBOL(rpmsg_trysend_offchannel); +/** + * rpmsg_get_mtu() - get maximum transmission buffer size for sending message. + * @ept: the rpmsg endpoint + * + * This function returns maximum buffer size available for a single outgoing message. + * + * Return: the maximum transmission size on success and an appropriate error + * value on failure. + */ + +ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->get_mtu) + return -ENOTSUPP; + + return ept->ops->get_mtu(ept); +} +EXPORT_SYMBOL(rpmsg_get_mtu); + /* * match a rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index a76c344253bf..b1245d3ed7c6 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -53,6 +53,7 @@ struct rpmsg_device_ops { * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel: see @rpmsg_trysend_offchannel(), optional * @poll: see @rpmsg_poll(), optional + * @get_mtu: see @rpmsg_get_mtu(), optional * * Indirection table for the operations that a rpmsg backend should implement. * In addition to @destroy_ept, the backend must at least implement @send and @@ -72,6 +73,7 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + ssize_t (*get_mtu)(struct rpmsg_endpoint *ept); }; struct device *rpmsg_find_device(struct device *parent, diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 8e49a3bacfc7..05fd06fc67e9 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -149,6 +149,7 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst); static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, void *data, int len); +static ssize_t virtio_rpmsg_get_mtu(struct rpmsg_endpoint *ept); static struct rpmsg_device *__rpmsg_create_channel(struct virtproc_info *vrp, struct rpmsg_channel_info *chinfo); @@ -160,6 +161,7 @@ static const struct rpmsg_endpoint_ops virtio_endpoint_ops = { .trysend = virtio_rpmsg_trysend, .trysendto = virtio_rpmsg_trysendto, .trysend_offchannel = virtio_rpmsg_trysend_offchannel, + .get_mtu = virtio_rpmsg_get_mtu, }; /** @@ -696,6 +698,14 @@ static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); } +static ssize_t virtio_rpmsg_get_mtu(struct rpmsg_endpoint *ept) +{ + struct rpmsg_device *rpdev = ept->rpdev; + struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev); + + return vch->vrp->buf_size - sizeof(struct rpmsg_hdr); +} + static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, struct rpmsg_hdr *msg, unsigned int len) { diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index d97dcd049f18..990b80fb49ad 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -186,6 +186,8 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); +ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept); + #else static inline int rpmsg_register_device(struct rpmsg_device *rpdev) @@ -296,6 +298,14 @@ static inline __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, return 0; } +static inline ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + #endif /* IS_ENABLED(CONFIG_RPMSG) */ /* use a macro to avoid include chaining to get THIS_MODULE */ From 7c0408d805797178f075f33d0f705a1c6ef76c82 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Fri, 15 Oct 2021 11:47:01 +0200 Subject: [PATCH 67/86] tty: add rpmsg driver This driver exposes a standard TTY interface on top of the rpmsg framework through a rpmsg service. This driver supports multi-instances, offering a /dev/ttyRPMSGx entry per rpmsg endpoint. Reviewed-by: Mathieu Poirier Signed-off-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20211015094701.5732-3-arnaud.pouliquen@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/Kconfig | 12 ++ drivers/tty/Makefile | 1 + drivers/tty/rpmsg_tty.c | 274 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/tty/rpmsg_tty.c diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 23cc988c68a4..cc30ff93e2e4 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -368,6 +368,18 @@ config VCC source "drivers/tty/hvc/Kconfig" +config RPMSG_TTY + tristate "RPMSG tty driver" + depends on RPMSG + help + Say y here to export rpmsg endpoints as tty devices, usually found + in /dev/ttyRPMSGx. + This makes it possible for user-space programs to send and receive + rpmsg messages as a standard tty protocol. + + To compile this driver as a module, choose M here: the module will be + called rpmsg_tty. + endif # TTY source "drivers/tty/serdev/Kconfig" diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index a2bd75fbaaa4..07aca5184a55 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -26,5 +26,6 @@ obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o obj-$(CONFIG_VCC) += vcc.o +obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o obj-y += ipwireless/ diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c new file mode 100644 index 000000000000..813076341ffd --- /dev/null +++ b/drivers/tty/rpmsg_tty.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 STMicroelectronics - All Rights Reserved + * + * The rpmsg tty driver implements serial communication on the RPMsg bus to makes + * possible for user-space programs to send and receive rpmsg messages as a standard + * tty protocol. + * + * The remote processor can instantiate a new tty by requesting a "rpmsg-tty" RPMsg service. + * The "rpmsg-tty" service is directly used for data exchange. No flow control is implemented yet. + */ + +#include +#include +#include +#include +#include + +#define MAX_TTY_RPMSG 32 + +static DEFINE_IDR(tty_idr); /* tty instance id */ +static DEFINE_MUTEX(idr_lock); /* protects tty_idr */ + +static struct tty_driver *rpmsg_tty_driver; + +struct rpmsg_tty_port { + struct tty_port port; /* TTY port data */ + int id; /* TTY rpmsg index */ + struct rpmsg_device *rpdev; /* rpmsg device */ +}; + +static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 src) +{ + struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); + int copied; + + if (!len) + return -EINVAL; + copied = tty_insert_flip_string(&cport->port, data, len); + if (copied != len) + dev_err_ratelimited(&rpdev->dev, "Trunc buffer: available space is %d\n", copied); + tty_flip_buffer_push(&cport->port); + + return 0; +} + +static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct rpmsg_tty_port *cport = idr_find(&tty_idr, tty->index); + + tty->driver_data = cport; + + return tty_port_install(&cport->port, driver, tty); +} + +static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp) +{ + return tty_port_open(tty->port, tty, filp); +} + +static void rpmsg_tty_close(struct tty_struct *tty, struct file *filp) +{ + return tty_port_close(tty->port, tty, filp); +} + +static int rpmsg_tty_write(struct tty_struct *tty, const u8 *buf, int len) +{ + struct rpmsg_tty_port *cport = tty->driver_data; + struct rpmsg_device *rpdev; + int msg_max_size, msg_size; + int ret; + + rpdev = cport->rpdev; + + msg_max_size = rpmsg_get_mtu(rpdev->ept); + if (msg_max_size < 0) + return msg_max_size; + + msg_size = min(len, msg_max_size); + + /* + * Use rpmsg_trysend instead of rpmsg_send to send the message so the caller is not + * hung until a rpmsg buffer is available. In such case rpmsg_trysend returns -ENOMEM. + */ + ret = rpmsg_trysend(rpdev->ept, (void *)buf, msg_size); + if (ret) { + dev_dbg_ratelimited(&rpdev->dev, "rpmsg_send failed: %d\n", ret); + return ret; + } + + return msg_size; +} + +static unsigned int rpmsg_tty_write_room(struct tty_struct *tty) +{ + struct rpmsg_tty_port *cport = tty->driver_data; + int size; + + size = rpmsg_get_mtu(cport->rpdev->ept); + if (size < 0) + return 0; + + return size; +} + +static const struct tty_operations rpmsg_tty_ops = { + .install = rpmsg_tty_install, + .open = rpmsg_tty_open, + .close = rpmsg_tty_close, + .write = rpmsg_tty_write, + .write_room = rpmsg_tty_write_room, +}; + +static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void) +{ + struct rpmsg_tty_port *cport; + int err; + + cport = kzalloc(sizeof(*cport), GFP_KERNEL); + if (!cport) + return ERR_PTR(-ENOMEM); + + mutex_lock(&idr_lock); + cport->id = idr_alloc(&tty_idr, cport, 0, MAX_TTY_RPMSG, GFP_KERNEL); + mutex_unlock(&idr_lock); + + if (cport->id < 0) { + err = cport->id; + kfree(cport); + return ERR_PTR(err); + } + + return cport; +} + +static void rpmsg_tty_release_cport(struct rpmsg_tty_port *cport) +{ + mutex_lock(&idr_lock); + idr_remove(&tty_idr, cport->id); + mutex_unlock(&idr_lock); + + kfree(cport); +} + +static const struct tty_port_operations rpmsg_tty_port_ops = { }; + +static int rpmsg_tty_probe(struct rpmsg_device *rpdev) +{ + struct rpmsg_tty_port *cport; + struct device *dev = &rpdev->dev; + struct device *tty_dev; + int ret; + + cport = rpmsg_tty_alloc_cport(); + if (IS_ERR(cport)) { + dev_err(dev, "Failed to alloc tty port\n"); + return PTR_ERR(cport); + } + + tty_port_init(&cport->port); + cport->port.ops = &rpmsg_tty_port_ops; + + tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver, + cport->id, dev); + if (IS_ERR(tty_dev)) { + dev_err(dev, "Failed to register tty port\n"); + ret = PTR_ERR(tty_dev); + goto err_destroy; + } + + cport->rpdev = rpdev; + + dev_set_drvdata(dev, cport); + + dev_dbg(dev, "New channel: 0x%x -> 0x%x : ttyRPMSG%d\n", + rpdev->src, rpdev->dst, cport->id); + + return 0; + +err_destroy: + tty_port_destroy(&cport->port); + rpmsg_tty_release_cport(cport); + + return ret; +} + +static void rpmsg_tty_remove(struct rpmsg_device *rpdev) +{ + struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); + + dev_dbg(&rpdev->dev, "Removing rpmsg tty device %d\n", cport->id); + + /* User hang up to release the tty */ + if (tty_port_initialized(&cport->port)) + tty_port_tty_hangup(&cport->port, false); + + tty_unregister_device(rpmsg_tty_driver, cport->id); + + tty_port_destroy(&cport->port); + rpmsg_tty_release_cport(cport); +} + +static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = { + { .name = "rpmsg-tty" }, + { }, +}; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_tty_id_table); + +static struct rpmsg_driver rpmsg_tty_rpmsg_drv = { + .drv.name = KBUILD_MODNAME, + .id_table = rpmsg_driver_tty_id_table, + .probe = rpmsg_tty_probe, + .callback = rpmsg_tty_cb, + .remove = rpmsg_tty_remove, +}; + +static int __init rpmsg_tty_init(void) +{ + int err; + + rpmsg_tty_driver = tty_alloc_driver(MAX_TTY_RPMSG, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(rpmsg_tty_driver)) + return PTR_ERR(rpmsg_tty_driver); + + rpmsg_tty_driver->driver_name = "rpmsg_tty"; + rpmsg_tty_driver->name = "ttyRPMSG"; + rpmsg_tty_driver->major = 0; + rpmsg_tty_driver->type = TTY_DRIVER_TYPE_CONSOLE; + + /* Disable unused mode by default */ + rpmsg_tty_driver->init_termios = tty_std_termios; + rpmsg_tty_driver->init_termios.c_lflag &= ~(ECHO | ICANON); + rpmsg_tty_driver->init_termios.c_oflag &= ~(OPOST | ONLCR); + + tty_set_operations(rpmsg_tty_driver, &rpmsg_tty_ops); + + err = tty_register_driver(rpmsg_tty_driver); + if (err < 0) { + pr_err("Couldn't install rpmsg tty driver: err %d\n", err); + goto error_put; + } + + err = register_rpmsg_driver(&rpmsg_tty_rpmsg_drv); + if (err < 0) { + pr_err("Couldn't register rpmsg tty driver: err %d\n", err); + goto error_unregister; + } + + return 0; + +error_unregister: + tty_unregister_driver(rpmsg_tty_driver); + +error_put: + tty_driver_kref_put(rpmsg_tty_driver); + + return err; +} + +static void __exit rpmsg_tty_exit(void) +{ + unregister_rpmsg_driver(&rpmsg_tty_rpmsg_drv); + tty_unregister_driver(rpmsg_tty_driver); + tty_driver_kref_put(rpmsg_tty_driver); + idr_destroy(&tty_idr); +} + +module_init(rpmsg_tty_init); +module_exit(rpmsg_tty_exit); + +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_DESCRIPTION("remote processor messaging tty driver"); +MODULE_LICENSE("GPL v2"); From 35b4f17231923e2f64521bdf7a2793ce2c3c74a6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Oct 2021 16:51:45 +0300 Subject: [PATCH 68/86] serial: 8250_pci: Refactor the loop in pci_ite887x_init() The loop can be refactored by using ARRAY_SIZE() instead of NULL terminator. This reduces code base and makes it easier to read and understand. Signed-off-by: Andy Shevchenko Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/20211022135147.70965-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 93159557a2fb..8a2f42507c18 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -897,18 +897,16 @@ static int pci_netmos_init(struct pci_dev *dev) /* enable IO_Space bit */ #define ITE_887x_POSIO_ENABLE (1 << 31) +/* inta_addr are the configuration addresses of the ITE */ +static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, 0x200, 0x280 }; static int pci_ite887x_init(struct pci_dev *dev) { - /* inta_addr are the configuration addresses of the ITE */ - static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, - 0x200, 0x280, 0 }; int ret, i, type; struct resource *iobase = NULL; u32 miscr, uartbar, ioport; /* search for the base-ioport */ - i = 0; - while (inta_addr[i] && iobase == NULL) { + for (i = 0; i < ARRAY_SIZE(inta_addr); i++) { iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, "ite887x"); if (iobase != NULL) { @@ -925,12 +923,10 @@ static int pci_ite887x_init(struct pci_dev *dev) break; } release_region(iobase->start, ITE_887x_IOSIZE); - iobase = NULL; } - i++; } - if (!inta_addr[i]) { + if (i == ARRAY_SIZE(inta_addr)) { dev_err(&dev->dev, "ite887x: could not find iobase\n"); return -ENODEV; } From 0187f884e272708a5e5cde12d25ab706b1f42049 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Oct 2021 16:51:46 +0300 Subject: [PATCH 69/86] serial: 8250_pci: Get rid of redundant 'else' keyword The 'else' keyword is not needed when previous conditional branch returns to the upper layer. Get rid of redundant 'else' keyword in such cases. Signed-off-by: Andy Shevchenko Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/20211022135147.70965-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 8a2f42507c18..463b2c71da6f 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -515,7 +515,7 @@ static int pci_siig_init(struct pci_dev *dev) if (type == 0x1000) return pci_siig10x_init(dev); - else if (type == 0x2000) + if (type == 0x2000) return pci_siig20x_init(dev); moan_device("Unknown SIIG card", dev); @@ -792,9 +792,9 @@ static int pci_netmos_9900_setup(struct serial_private *priv, bar = 3 * idx; return setup_port(priv, port, bar, 0, board->reg_shift); - } else { - return pci_default_setup(priv, board, port, idx); } + + return pci_default_setup(priv, board, port, idx); } /* the 99xx series comes with a range of device IDs and a variety From 1177384179416c7136e1348f07609e0da1ae6b91 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Oct 2021 16:51:47 +0300 Subject: [PATCH 70/86] serial: 8250_pci: Replace dev_*() by pci_*() macros PCI subsystem provides convenient shortcut macros for message printing. Use those macros instead of dev_*(). Signed-off-by: Andy Shevchenko Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/20211022135147.70965-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 52 +++++++++++++----------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 463b2c71da6f..aea12263a1ff 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -75,13 +75,12 @@ static int pci_default_setup(struct serial_private*, static void moan_device(const char *str, struct pci_dev *dev) { - dev_err(&dev->dev, - "%s: %s\n" + pci_err(dev, "%s\n" "Please send the output of lspci -vv, this\n" "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" "manufacturer and name of serial board or\n" "modem board to .\n", - pci_name(dev), str, dev->vendor, dev->device, + str, dev->vendor, dev->device, dev->subsystem_vendor, dev->subsystem_device); } @@ -238,7 +237,7 @@ static int pci_inteli960ni_init(struct pci_dev *dev) /* is firmware started? */ pci_read_config_dword(dev, 0x44, &oldval); if (oldval == 0x00001000L) { /* RESET value */ - dev_dbg(&dev->dev, "Local i960 firmware missing\n"); + pci_dbg(dev, "Local i960 firmware missing\n"); return -ENODEV; } return 0; @@ -588,9 +587,8 @@ static int pci_timedia_probe(struct pci_dev *dev) * (0,2,3,5,6: serial only -- 7,8,9: serial + parallel) */ if ((dev->subsystem_device & 0x00f0) >= 0x70) { - dev_info(&dev->dev, - "ignoring Timedia subdevice %04x for parport_serial\n", - dev->subsystem_device); + pci_info(dev, "ignoring Timedia subdevice %04x for parport_serial\n", + dev->subsystem_device); return -ENODEV; } @@ -827,8 +825,7 @@ static int pci_netmos_9900_numports(struct pci_dev *dev) if (sub_serports > 0) return sub_serports; - dev_err(&dev->dev, - "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); + pci_err(dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); return 0; } @@ -927,7 +924,7 @@ static int pci_ite887x_init(struct pci_dev *dev) } if (i == ARRAY_SIZE(inta_addr)) { - dev_err(&dev->dev, "ite887x: could not find iobase\n"); + pci_err(dev, "could not find iobase\n"); return -ENODEV; } @@ -1022,9 +1019,7 @@ static int pci_endrun_init(struct pci_dev *dev) /* EndRun device */ if (deviceID == 0x07000200) { number_uarts = ioread8(p + 4); - dev_dbg(&dev->dev, - "%d ports detected on EndRun PCI Express device\n", - number_uarts); + pci_dbg(dev, "%d ports detected on EndRun PCI Express device\n", number_uarts); } pci_iounmap(dev, p); return number_uarts; @@ -1054,9 +1049,7 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) /* Tornado device */ if (deviceID == 0x07000200) { number_uarts = ioread8(p + 4); - dev_dbg(&dev->dev, - "%d ports detected on Oxford PCI Express device\n", - number_uarts); + pci_dbg(dev, "%d ports detected on Oxford PCI Express device\n", number_uarts); } pci_iounmap(dev, p); return number_uarts; @@ -1116,15 +1109,15 @@ static struct quatech_feature quatech_cards[] = { { 0, } }; -static int pci_quatech_amcc(u16 devid) +static int pci_quatech_amcc(struct pci_dev *dev) { struct quatech_feature *qf = &quatech_cards[0]; while (qf->devid) { - if (qf->devid == devid) + if (qf->devid == dev->device) return qf->amcc; qf++; } - pr_err("quatech: unknown port type '0x%04X'.\n", devid); + pci_err(dev, "unknown port type '0x%04X'.\n", dev->device); return 0; }; @@ -1287,7 +1280,7 @@ static int pci_quatech_rs422(struct uart_8250_port *port) static int pci_quatech_init(struct pci_dev *dev) { - if (pci_quatech_amcc(dev->device)) { + if (pci_quatech_amcc(dev)) { unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; @@ -1311,7 +1304,7 @@ static int pci_quatech_setup(struct serial_private *priv, port->port.uartclk = pci_quatech_clock(port); /* For now just warn about RS422 */ if (pci_quatech_rs422(port)) - pr_warn("quatech: software control of RS422 features not currently supported.\n"); + pci_warn(priv->dev, "software control of RS422 features not currently supported.\n"); return pci_default_setup(priv, board, port, idx); } @@ -1521,7 +1514,7 @@ static int pci_fintek_setup(struct serial_private *priv, /* Get the io address from configuration space */ pci_read_config_word(pdev, config_base + 4, &iobase); - dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); + pci_dbg(pdev, "idx=%d iobase=0x%x", idx, iobase); port->port.iotype = UPIO_PORT; port->port.iobase = iobase; @@ -1685,7 +1678,7 @@ static int skip_tx_en_setup(struct serial_private *priv, struct uart_8250_port *port, int idx) { port->port.quirks |= UPQ_NO_TXEN_TEST; - dev_dbg(&priv->dev->dev, + pci_dbg(priv->dev, "serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", priv->dev->vendor, priv->dev->device, priv->dev->subsystem_vendor, priv->dev->subsystem_device); @@ -3994,12 +3987,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) uart.port.irq = 0; } else { if (pci_match_id(pci_use_msi, dev)) { - dev_dbg(&dev->dev, "Using MSI(-X) interrupts\n"); + pci_dbg(dev, "Using MSI(-X) interrupts\n"); pci_set_master(dev); uart.port.flags &= ~UPF_SHARE_IRQ; rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); } else { - dev_dbg(&dev->dev, "Using legacy interrupts\n"); + pci_dbg(dev, "Using legacy interrupts\n"); rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); } if (rc < 0) { @@ -4017,12 +4010,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) if (quirk->setup(priv, board, &uart, i)) break; - dev_dbg(&dev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + pci_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n", uart.port.iobase, uart.port.irq, uart.port.iotype); priv->line[i] = serial8250_register_8250_port(&uart); if (priv->line[i] < 0) { - dev_err(&dev->dev, + pci_err(dev, "Couldn't register serial port %lx, irq %d, type %d, error %d\n", uart.port.iobase, uart.port.irq, uart.port.iotype, priv->line[i]); @@ -4118,8 +4111,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) } if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { - dev_err(&dev->dev, "invalid driver_data: %ld\n", - ent->driver_data); + pci_err(dev, "invalid driver_data: %ld\n", ent->driver_data); return -EINVAL; } @@ -4202,7 +4194,7 @@ static int pciserial_resume_one(struct device *dev) err = pci_enable_device(pdev); /* FIXME: We cannot simply error out here */ if (err) - dev_err(dev, "Unable to re-enable ports, trying to continue.\n"); + pci_err(pdev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; From 45965252a29afc8ef6f58938077fe30f86081bf0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 26 Oct 2021 08:45:53 +0200 Subject: [PATCH 71/86] Revert "virtio-console: remove unnecessary kmemdup()" This reverts commit 9db81eca10ba2d84177fa076704db3a5d76863c3. A dependant patch on this one needs to be reverted, so this one also needs to be reverted at this point in time. Link: https://lore.kernel.org/r/208f7a41-a9fa-630c-cb44-c37c503f3a72@kernel.org Reported-by: Jiri Slaby Cc: Xianting Tian Cc: Shile Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 4ed3ffb1d479..7eaf303a7a86 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1117,6 +1117,8 @@ static int put_chars(u32 vtermno, const char *buf, int count) { struct port *port; struct scatterlist sg[1]; + void *data; + int ret; if (unlikely(early_put_chars)) return early_put_chars(vtermno, buf, count); @@ -1125,8 +1127,14 @@ static int put_chars(u32 vtermno, const char *buf, int count) if (!port) return -EPIPE; - sg_init_one(sg, buf, count); - return __send_to_port(port, sg, 1, count, (void *)buf, false); + data = kmemdup(buf, count, GFP_ATOMIC); + if (!data) + return -ENOMEM; + + sg_init_one(sg, data, count); + ret = __send_to_port(port, sg, 1, count, data, false); + kfree(data); + return ret; } /* From 60f41e8484926c2a82fe6fe0585edfccaf1208f5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 26 Oct 2021 08:48:09 +0200 Subject: [PATCH 72/86] Revert "tty: hvc: pass DMA capable memory to put_chars()" This reverts commit 0986d7bc5598f5df30e3db777d00e73890c97627. It still has some issues and needs to be dropped at this point in time. Link: https://lore.kernel.org/r/208f7a41-a9fa-630c-cb44-c37c503f3a72@kernel.org Reported-by: Jiri Slaby Cc: Xianting Tian Cc: Shile Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 36 +++++++++++++++-------------------- drivers/tty/hvc/hvc_console.h | 21 +------------------- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 5bdb3df022ce..4802cfaa107f 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -41,6 +41,16 @@ */ #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ +/* + * These sizes are most efficient for vio, because they are the + * native transfer size. We could make them selectable in the + * future to better deal with backends that want other buffer sizes. + */ +#define N_OUTBUF 16 +#define N_INBUF 16 + +#define __ALIGNED__ __attribute__((__aligned__(L1_CACHE_BYTES))) + static struct tty_driver *hvc_driver; static struct task_struct *hvc_task; @@ -132,7 +142,6 @@ static int hvc_flush(struct hvc_struct *hp) static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; -static struct hvc_struct *cons_hvcs[MAX_NR_HVC_CONSOLES]; /* * Console APIs, NOT TTY. These APIs are available immediately when @@ -142,11 +151,9 @@ static struct hvc_struct *cons_hvcs[MAX_NR_HVC_CONSOLES]; static void hvc_console_print(struct console *co, const char *b, unsigned count) { - char *c; + char c[N_OUTBUF] __ALIGNED__; unsigned i = 0, n = 0; int r, donecr = 0, index = co->index; - unsigned long flags; - struct hvc_struct *hp; /* Console access attempt outside of acceptable console range. */ if (index >= MAX_NR_HVC_CONSOLES) @@ -156,13 +163,6 @@ static void hvc_console_print(struct console *co, const char *b, if (vtermnos[index] == -1) return; - hp = cons_hvcs[index]; - if (!hp) - return; - - c = hp->cons_outbuf; - - spin_lock_irqsave(&hp->cons_outbuf_lock, flags); while (count > 0 || i > 0) { if (count > 0 && i < sizeof(c)) { if (b[n] == '\n' && !donecr) { @@ -191,7 +191,6 @@ static void hvc_console_print(struct console *co, const char *b, } } } - spin_unlock_irqrestore(&hp->cons_outbuf_lock, flags); hvc_console_flush(cons_ops[index], vtermnos[index]); } @@ -879,13 +878,9 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch) struct tty_struct *tty = driver->ttys[0]; struct hvc_struct *hp = tty->driver_data; int n; - unsigned long flags; do { - spin_lock_irqsave(&hp->cons_outbuf_lock, flags); - hp->cons_outbuf[0] = ch; - n = hp->ops->put_chars(hp->vtermno, &hp->cons_outbuf[0], 1); - spin_unlock_irqrestore(&hp->cons_outbuf_lock, flags); + n = hp->ops->put_chars(hp->vtermno, &ch, 1); } while (n <= 0); } #endif @@ -927,7 +922,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, return ERR_PTR(err); } - hp = kzalloc(struct_size(hp, outbuf, outbuf_size), GFP_KERNEL); + hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, + GFP_KERNEL); if (!hp) return ERR_PTR(-ENOMEM); @@ -935,13 +931,13 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, hp->data = data; hp->ops = ops; hp->outbuf_size = outbuf_size; + hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; tty_port_init(&hp->port); hp->port.ops = &hvc_port_ops; INIT_WORK(&hp->tty_resize, hvc_set_winsz); spin_lock_init(&hp->lock); - spin_lock_init(&hp->cons_outbuf_lock); mutex_lock(&hvc_structs_mutex); /* @@ -968,7 +964,6 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, if (i < MAX_NR_HVC_CONSOLES) { cons_ops[i] = ops; vtermnos[i] = vtermno; - cons_hvcs[i] = hp; } list_add_tail(&(hp->next), &hvc_structs); @@ -993,7 +988,6 @@ int hvc_remove(struct hvc_struct *hp) if (hp->index < MAX_NR_HVC_CONSOLES) { vtermnos[hp->index] = -1; cons_ops[hp->index] = NULL; - cons_hvcs[hp->index] = NULL; } /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index 2c32ab67b68d..18d005814e4b 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -32,21 +32,12 @@ */ #define HVC_ALLOC_TTY_ADAPTERS 8 -/* - * These sizes are most efficient for vio, because they are the - * native transfer size. We could make them selectable in the - * future to better deal with backends that want other buffer sizes. - */ -#define N_OUTBUF 16 -#define N_INBUF 16 - -#define __ALIGNED__ __attribute__((__aligned__(L1_CACHE_BYTES))) - struct hvc_struct { struct tty_port port; spinlock_t lock; int index; int do_wakeup; + char *outbuf; int outbuf_size; int n_outbuf; uint32_t vtermno; @@ -57,16 +48,6 @@ struct hvc_struct { struct work_struct tty_resize; struct list_head next; unsigned long flags; - - /* - * the buf and its lock are used in hvc console api for putting chars, - * and also used in hvc_poll_put_char() for putting single char. - */ - spinlock_t cons_outbuf_lock; - char cons_outbuf[N_OUTBUF] __ALIGNED__; - - /* the buf is used for putting chars to tty */ - char outbuf[] __ALIGNED__; }; /* implemented by a low level driver */ From 159f1f9e46dd09bffee3674d300b02856221e794 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 26 Oct 2021 10:04:26 +0200 Subject: [PATCH 73/86] serial: sunzilog: Mark sunzilog_putchar() __maybe_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONSOLE_POLL=n, CONFIG_SERIAL_SUNZILOG_CONSOLE=n, and CONFIG_SERIO=m: drivers/tty/serial/sunzilog.c:1128:13: error: ‘sunzilog_putchar’ defined but not used [-Werror=unused-function] 1128 | static void sunzilog_putchar(struct uart_port *port, int ch) | ^~~~~~~~~~~~~~~~ Fix this by marking sunzilog_putchar() __maybe_unused. Acked-by: Arnd Bergmann Acked-by: David S. Miller Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211026080426.2444756-1-geert@linux-m68k.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sunzilog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 1a54e3e52ed6..b714b00d2dad 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1125,7 +1125,7 @@ static void sunzilog_free_tables(void) #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ -static void sunzilog_putchar(struct uart_port *port, int ch) +static void __maybe_unused sunzilog_putchar(struct uart_port *port, int ch) { struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); int loops = ZS_PUT_CHAR_MAX_DELAY; From 88b20f84f0fe47409342669caf3e58a3fc64c316 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 26 Oct 2021 13:27:41 +0300 Subject: [PATCH 74/86] serial: xilinx_uartps: Fix race condition causing stuck TX xilinx_uartps .start_tx() clears TXEMPTY when enabling TXEMPTY to avoid any previous TXEVENT event asserting the UART interrupt. This clear operation is done immediately after filling the TX FIFO. However, if the bytes inserted by cdns_uart_handle_tx() are consumed by the UART before the TXEMPTY is cleared, the clear operation eats the new TXEMPTY event as well, causing cdns_uart_isr() to never receive the TXEMPTY event. If there are bytes still queued in circbuf, TX will get stuck as they will never get transferred to FIFO (unless new bytes are queued to circbuf in which case .start_tx() is called again). While the racy missed TXEMPTY occurs fairly often with short data sequences (e.g. write 1 byte), in those cases circbuf is usually empty so no action on TXEMPTY would have been needed anyway. On the other hand, longer data sequences make the race much more unlikely as UART takes longer to consume the TX FIFO. Therefore it is rare for this race to cause visible issues in general. Fix the race by clearing the TXEMPTY bit in ISR *before* filling the FIFO. The TXEMPTY bit in ISR will only get asserted at the exact moment the TX FIFO *becomes* empty, so clearing the bit before filling FIFO does not cause an extra immediate assertion even if the FIFO is initially empty. This is hard to reproduce directly on a normal system, but inserting e.g. udelay(200) after cdns_uart_handle_tx(port), setting 4000000 baud, and then running "dd if=/dev/zero bs=128 of=/dev/ttyPS0 count=50" reliably reproduces the issue on my ZynqMP test system unless this fix is applied. Fixes: 85baf542d54e ("tty: xuartps: support 64 byte FIFO size") Signed-off-by: Anssi Hannula Link: https://lore.kernel.org/r/20211026102741.2910441-1-anssi.hannula@bitwise.fi Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 962e522ccc45..d5e243908d9f 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -601,9 +601,10 @@ static void cdns_uart_start_tx(struct uart_port *port) if (uart_circ_empty(&port->state->xmit)) return; + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); + cdns_uart_handle_tx(port); - writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER); } From 4290242776a603d1acc9ae944e7396057d7aec66 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Oct 2021 16:34:51 +0300 Subject: [PATCH 75/86] serial: 8250_pci: Replace custom pci_match_id() implementation Replace pci_quatech_amcc() with generic pci_match_id(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211026133452.61657-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 72 +++++++++++++----------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index aea12263a1ff..1c2eb44e9c33 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1063,13 +1063,6 @@ static int pci_asix_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } -/* Quatech devices have their own extra interface features */ - -struct quatech_feature { - u16 devid; - bool amcc; -}; - #define QPCR_TEST_FOR1 0x3F #define QPCR_TEST_GET1 0x00 #define QPCR_TEST_FOR2 0x40 @@ -1085,42 +1078,30 @@ struct quatech_feature { #define QOPR_CLOCK_X8 0x0003 #define QOPR_CLOCK_RATE_MASK 0x0003 - -static struct quatech_feature quatech_cards[] = { - { PCI_DEVICE_ID_QUATECH_QSC100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC100E, 0 }, - { PCI_DEVICE_ID_QUATECH_DSC200, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC200E, 0 }, - { PCI_DEVICE_ID_QUATECH_ESC100D, 1 }, - { PCI_DEVICE_ID_QUATECH_ESC100M, 1 }, - { PCI_DEVICE_ID_QUATECH_QSCP100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSCP100, 1 }, - { PCI_DEVICE_ID_QUATECH_QSCP200, 1 }, - { PCI_DEVICE_ID_QUATECH_DSCP200, 1 }, - { PCI_DEVICE_ID_QUATECH_ESCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_QSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_DSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_SSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_QSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_DSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_SSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 }, +/* Quatech devices have their own extra interface features */ +static struct pci_device_id quatech_cards[] = { + { PCI_DEVICE_DATA(QUATECH, QSC100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC100E, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSC200, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC200E, 0) }, + { PCI_DEVICE_DATA(QUATECH, ESC100D, 1) }, + { PCI_DEVICE_DATA(QUATECH, ESC100M, 1) }, + { PCI_DEVICE_DATA(QUATECH, QSCP100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSCP100, 1) }, + { PCI_DEVICE_DATA(QUATECH, QSCP200, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSCP200, 1) }, + { PCI_DEVICE_DATA(QUATECH, ESCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, QSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, SSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, QSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, SSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, SPPXP_100, 0) }, { 0, } }; -static int pci_quatech_amcc(struct pci_dev *dev) -{ - struct quatech_feature *qf = &quatech_cards[0]; - while (qf->devid) { - if (qf->devid == dev->device) - return qf->amcc; - qf++; - } - pci_err(dev, "unknown port type '0x%04X'.\n", dev->device); - return 0; -}; - static int pci_quatech_rqopr(struct uart_8250_port *port) { unsigned long base = port->port.iobase; @@ -1280,7 +1261,16 @@ static int pci_quatech_rs422(struct uart_8250_port *port) static int pci_quatech_init(struct pci_dev *dev) { - if (pci_quatech_amcc(dev)) { + const struct pci_device_id *match; + bool amcc = false; + + match = pci_match_id(quatech_cards, dev); + if (match) + amcc = match->driver_data; + else + pci_err(dev, "unknown port type '0x%04X'.\n", dev->device); + + if (amcc) { unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; From 175003d7f9d15d4d5172f48d51e926acac676ad6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Oct 2021 16:34:52 +0300 Subject: [PATCH 76/86] serial: 8250_pci: Remove empty stub pci_quatech_exit() The ->exit() callback is checked for presence anyway, no need to have an empty stub. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211026133452.61657-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 1c2eb44e9c33..5d43de143f33 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1298,10 +1298,6 @@ static int pci_quatech_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } -static void pci_quatech_exit(struct pci_dev *dev) -{ -} - static int pci_default_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -2176,7 +2172,6 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .subdevice = PCI_ANY_ID, .init = pci_quatech_init, .setup = pci_quatech_setup, - .exit = pci_quatech_exit, }, /* * Panacom From e0abc903deea0148955af1e7ccabf3e980af7815 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Mon, 25 Oct 2021 15:42:27 +0200 Subject: [PATCH 77/86] serial: stm32: rework RX dma initialization and release The RX DMA channel is kept active forever (from the probe). That prevents going to low power mode when it is used. This change moves the DMA configuration and enabling procedures to startup routine to allow transition to low power mode. The DMA disabling procedure is implemented in stop_rx routine as this ops has to stop characters reception, and DMA transation in shutdown. Clean useless dma_async_tx_descriptor initialization to NULL value. Signed-off-by: Valentin Caron Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20211025134229.8456-2-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 69 +++++++++++++++++++------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 7fd192e1e15d..ee3495c0abbb 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -761,6 +761,10 @@ static void stm32_usart_stop_rx(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + /* Disable DMA request line. */ + if (stm32_port->rx_ch) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); @@ -777,6 +781,7 @@ static int stm32_usart_startup(struct uart_port *port) const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; const struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; + struct dma_async_tx_descriptor *desc; u32 val; int ret; @@ -797,6 +802,33 @@ static int stm32_usart_startup(struct uart_port *port) if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); + if (stm32_port->rx_ch) { + stm32_port->last_res = RX_BUF_L; + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, + stm32_port->rx_dma_buf, + RX_BUF_L, RX_BUF_P, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "rx dma prep cyclic failed\n"); + ret = -ENODEV; + goto err; + } + + desc->callback = stm32_usart_rx_dma_complete; + desc->callback_param = port; + + /* Push current DMA transaction in the pending queue */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dmaengine_terminate_sync(stm32_port->rx_ch); + goto err; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32_port->rx_ch); + } /* * DMA request line not re-enabled at resume when port is throttled. * It will be re-enabled by unthrottle ops. @@ -809,6 +841,11 @@ static int stm32_usart_startup(struct uart_port *port) stm32_usart_set_bits(port, ofs->cr1, val); return 0; + +err: + free_irq(port->irq, port); + + return ret; } static void stm32_usart_shutdown(struct uart_port *port) @@ -836,6 +873,10 @@ static void stm32_usart_shutdown(struct uart_port *port) if (ret) dev_err(port->dev, "Transmission is not complete\n"); + /* Disable RX DMA. */ + if (stm32_port->rx_ch) + dmaengine_terminate_async(stm32_port->rx_ch); + /* flush RX & TX FIFO */ if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, @@ -1304,7 +1345,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, struct uart_port *port = &stm32port->port; struct device *dev = &pdev->dev; struct dma_slave_config config; - struct dma_async_tx_descriptor *desc = NULL; int ret; /* @@ -1332,32 +1372,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, return ret; } - /* Prepare a DMA cyclic transaction */ - desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, - stm32port->rx_dma_buf, - RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { - dev_err(dev, "rx dma prep cyclic failed\n"); - stm32_usart_of_dma_rx_remove(stm32port, pdev); - return -ENODEV; - } - - /* Set DMA callback */ - desc->callback = stm32_usart_rx_dma_complete; - desc->callback_param = port; - - /* Push current DMA transaction in the pending queue */ - ret = dma_submit_error(dmaengine_submit(desc)); - if (ret) { - dmaengine_terminate_sync(stm32port->rx_ch); - stm32_usart_of_dma_rx_remove(stm32port, pdev); - return ret; - } - - /* Issue pending DMA requests */ - dma_async_issue_pending(stm32port->rx_ch); - return 0; } @@ -1535,7 +1549,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) } if (stm32_port->rx_ch) { - dmaengine_terminate_async(stm32_port->rx_ch); stm32_usart_of_dma_rx_remove(stm32_port, pdev); dma_release_channel(stm32_port->rx_ch); } From 6eeb348c8482862a788a2903e3fc45e76d4ea6b5 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Mon, 25 Oct 2021 15:42:28 +0200 Subject: [PATCH 78/86] serial: stm32: terminate / restart DMA transfer at suspend / resume DMA prevents the system to suspend when an UART RX wake-up source is using DMA. DMA can't suspend while DMA channels are still active. Terminate DMA transfer at suspend, and restart a new DMA transfer at resume. Create stm32_usart_start_rx_dma_cyclic function to factorize dma RX initialization. Move RX DMA code related to wakeup into stm32_usart_serial_en_wakeup() routine to ease further improvements on wakeup from low power modes. Don't enable/disable wakeup on uninitialized port. There may be data residue in the RX FIFO while suspending. Flush it at suspend time. Receiver timeout interrupt won't trigger later in low power mode, so call stm32_usart_receive_chars() in case there's data to handle. Signed-off-by: Valentin Caron Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20211025134229.8456-3-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 127 ++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 43 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index ee3495c0abbb..4b5b0748790c 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -775,13 +775,54 @@ static void stm32_usart_break_ctl(struct uart_port *port, int break_state) { } +static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct dma_async_tx_descriptor *desc; + int ret; + + stm32_port->last_res = RX_BUF_L; + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, + stm32_port->rx_dma_buf, + RX_BUF_L, RX_BUF_P, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "rx dma prep cyclic failed\n"); + return -ENODEV; + } + + desc->callback = stm32_usart_rx_dma_complete; + desc->callback_param = port; + + /* Push current DMA transaction in the pending queue */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dmaengine_terminate_sync(stm32_port->rx_ch); + return ret; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32_port->rx_ch); + + /* + * DMA request line not re-enabled at resume when port is throttled. + * It will be re-enabled by unthrottle ops. + */ + if (!stm32_port->throttled) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + + return 0; +} + static int stm32_usart_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; const struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; - struct dma_async_tx_descriptor *desc; u32 val; int ret; @@ -803,49 +844,18 @@ static int stm32_usart_startup(struct uart_port *port) writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); if (stm32_port->rx_ch) { - stm32_port->last_res = RX_BUF_L; - /* Prepare a DMA cyclic transaction */ - desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, - stm32_port->rx_dma_buf, - RX_BUF_L, RX_BUF_P, - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { - dev_err(port->dev, "rx dma prep cyclic failed\n"); - ret = -ENODEV; - goto err; - } - - desc->callback = stm32_usart_rx_dma_complete; - desc->callback_param = port; - - /* Push current DMA transaction in the pending queue */ - ret = dma_submit_error(dmaengine_submit(desc)); + ret = stm32_usart_start_rx_dma_cyclic(port); if (ret) { - dmaengine_terminate_sync(stm32_port->rx_ch); - goto err; + free_irq(port->irq, port); + return ret; } - - /* Issue pending DMA requests */ - dma_async_issue_pending(stm32_port->rx_ch); } - /* - * DMA request line not re-enabled at resume when port is throttled. - * It will be re-enabled by unthrottle ops. - */ - if (!stm32_port->throttled) - stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); /* RX enabling */ val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); stm32_usart_set_bits(port, ofs->cr1, val); return 0; - -err: - free_irq(port->irq, port); - - return ret; } static void stm32_usart_shutdown(struct uart_port *port) @@ -1661,14 +1671,16 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; -static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, - bool enable) +static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, + bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct tty_port *tport = &port->state->port; + int ret; - if (!stm32_port->wakeup_src) - return; + if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) + return 0; /* * Enable low-power wake-up and wake-up irq if argument is set to @@ -1677,20 +1689,45 @@ static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, if (enable) { stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + + /* + * When DMA is used for reception, it must be disabled before + * entering low-power mode and re-enabled when exiting from + * low-power mode. + */ + if (stm32_port->rx_ch) { + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + dmaengine_terminate_sync(stm32_port->rx_ch); + } + + /* Poll data from RX FIFO if any */ + stm32_usart_receive_chars(port, false); } else { + if (stm32_port->rx_ch) { + ret = stm32_usart_start_rx_dma_cyclic(port); + if (ret) + return ret; + } + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } + + return 0; } static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; uart_suspend_port(&stm32_usart_driver, port); - if (device_may_wakeup(dev) || device_wakeup_path(dev)) - stm32_usart_serial_en_wakeup(port, true); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, true); + if (ret) + return ret; + } /* * When "no_console_suspend" is enabled, keep the pinctrl default state @@ -1711,11 +1748,15 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) static int __maybe_unused stm32_usart_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; pinctrl_pm_select_default_state(dev); - if (device_may_wakeup(dev) || device_wakeup_path(dev)) - stm32_usart_serial_en_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, false); + if (ret) + return ret; + } return uart_resume_port(&stm32_usart_driver, port); } From 6333a485062172e1c118b44585d90c1d835aec52 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Mon, 25 Oct 2021 15:42:29 +0200 Subject: [PATCH 79/86] serial: stm32: push DMA RX data before suspending Data may be stored in DMA RX buffer, when suspending. The data needs to be pushed to the upper layer. We can't rely on the timeout IRQ (RTOR) that can't be triggered into low power state. So safely clear DMA request (DMAR), force the DMA reception routines to push RX buffer content, before disabling RX DMA. This way, handover to pio mode is safe. Only call tty_flip_buffer_push() when there is RX data to handle. Move the locking outside of stm32_usart_receive_chars() to prevent a race condition, when disabling DMA request upon suspend / pm_runtime_suspend. Data may be received under IRQ and pushed before stm32_usart_receive_chars() has pushed older data from DMA rx_buf upon suspend. The sequence in suspend routine needs proper locking to avoid this. Signed-off-by: Fabrice Gasnier Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20211025134229.8456-4-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 80 +++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 4b5b0748790c..3244e7f6818c 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -210,11 +210,12 @@ static unsigned long stm32_usart_get_char_pio(struct uart_port *port) return c; } -static void stm32_usart_receive_chars_pio(struct uart_port *port) +static unsigned int stm32_usart_receive_chars_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; + unsigned int size = 0; u32 sr; char flag; @@ -239,6 +240,7 @@ static void stm32_usart_receive_chars_pio(struct uart_port *port) c = stm32_usart_get_char_pio(port); port->icount.rx++; + size++; if (sr & USART_SR_ERR_MASK) { if (sr & USART_SR_ORE) { port->icount.overrun++; @@ -271,6 +273,8 @@ static void stm32_usart_receive_chars_pio(struct uart_port *port) continue; uart_insert_char(port, sr, USART_SR_ORE, c, flag); } + + return size; } static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma_size) @@ -300,50 +304,48 @@ static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma stm32_port->last_res = RX_BUF_L; } -static void stm32_usart_receive_chars_dma(struct uart_port *port) +static unsigned int stm32_usart_receive_chars_dma(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - unsigned int dma_size; + unsigned int dma_size, size = 0; /* DMA buffer is configured in cyclic mode and handles the rollback of the buffer. */ if (stm32_port->rx_dma_state.residue > stm32_port->last_res) { /* Conditional first part: from last_res to end of DMA buffer */ dma_size = stm32_port->last_res; stm32_usart_push_buffer_dma(port, dma_size); + size = dma_size; } dma_size = stm32_port->last_res - stm32_port->rx_dma_state.residue; stm32_usart_push_buffer_dma(port, dma_size); + size += dma_size; + + return size; } -static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) +static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force_dma_flush) { - struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; enum dma_status rx_dma_status; - unsigned long flags; u32 sr; + unsigned int size = 0; - if (irqflag) - spin_lock_irqsave(&port->lock, flags); - else - spin_lock(&port->lock); - - if (stm32_usart_rx_dma_enabled(port)) { + if (stm32_usart_rx_dma_enabled(port) || force_dma_flush) { rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, stm32_port->rx_ch->cookie, &stm32_port->rx_dma_state); if (rx_dma_status == DMA_IN_PROGRESS) { /* Empty DMA buffer */ - stm32_usart_receive_chars_dma(port); + size = stm32_usart_receive_chars_dma(port); sr = readl_relaxed(port->membase + ofs->isr); if (sr & USART_SR_ERR_MASK) { /* Disable DMA request line */ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); /* Switch to PIO mode to handle the errors */ - stm32_usart_receive_chars_pio(port); + size += stm32_usart_receive_chars_pio(port); /* Switch back to DMA mode */ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); @@ -354,18 +356,13 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); /* Fall back to interrupt mode */ dev_dbg(port->dev, "DMA error, fallback to irq mode\n"); - stm32_usart_receive_chars_pio(port); + size = stm32_usart_receive_chars_pio(port); } } else { - stm32_usart_receive_chars_pio(port); + size = stm32_usart_receive_chars_pio(port); } - if (irqflag) - uart_unlock_and_check_sysrq_irqrestore(port, irqflag); - else - uart_unlock_and_check_sysrq(port); - - tty_flip_buffer_push(tport); + return size; } static void stm32_usart_tx_dma_complete(void *arg) @@ -403,8 +400,15 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port) static void stm32_usart_rx_dma_complete(void *arg) { struct uart_port *port = arg; + struct tty_port *tport = &port->state->port; + unsigned int size; + unsigned long flags; - stm32_usart_receive_chars(port, true); + spin_lock_irqsave(&port->lock, flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); } static void stm32_usart_tx_interrupt_disable(struct uart_port *port) @@ -557,6 +561,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; + unsigned int size; sr = readl_relaxed(port->membase + ofs->isr); @@ -580,7 +585,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) if (!stm32_port->throttled) { if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) { - stm32_usart_receive_chars(port, false); + spin_lock(&port->lock); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq(port); + if (size) + tty_flip_buffer_push(tport); } } @@ -599,11 +608,19 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int size; + unsigned long flags; /* Receiver timeout irq for DMA RX */ - if (!stm32_port->throttled) - stm32_usart_receive_chars(port, false); + if (!stm32_port->throttled) { + spin_lock_irqsave(&port->lock, flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); + } return IRQ_HANDLED; } @@ -1678,6 +1695,8 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct tty_port *tport = &port->state->port; int ret; + unsigned int size; + unsigned long flags; if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) return 0; @@ -1696,8 +1715,15 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, * low-power mode. */ if (stm32_port->rx_ch) { + spin_lock_irqsave(&port->lock, flags); + /* Avoid race with RX IRQ when DMAR is cleared */ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); - dmaengine_terminate_sync(stm32_port->rx_ch); + /* Poll data from DMA RX buffer if any */ + size = stm32_usart_receive_chars(port, true); + dmaengine_terminate_async(stm32_port->rx_ch); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); } /* Poll data from RX FIFO if any */ From 0572da285d694e945303e74b7f9084b41e02ecbd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Oct 2021 16:51:44 +0300 Subject: [PATCH 80/86] tty: rpmsg: Assign returned id to a local variable Instead of putting garbage in the data structure, assign allocated id or an error code to a temporary variable. This makes code cleaner. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211025135148.53944-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/rpmsg_tty.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c index 813076341ffd..8c17ddbf371d 100644 --- a/drivers/tty/rpmsg_tty.c +++ b/drivers/tty/rpmsg_tty.c @@ -121,15 +121,16 @@ static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void) return ERR_PTR(-ENOMEM); mutex_lock(&idr_lock); - cport->id = idr_alloc(&tty_idr, cport, 0, MAX_TTY_RPMSG, GFP_KERNEL); + err = idr_alloc(&tty_idr, cport, 0, MAX_TTY_RPMSG, GFP_KERNEL); mutex_unlock(&idr_lock); - if (cport->id < 0) { - err = cport->id; + if (err < 0) { kfree(cport); return ERR_PTR(err); } + cport->id = err; + return cport; } From 408a507996e4c2ba943bc9b28be8bbb8424410b1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Oct 2021 16:51:45 +0300 Subject: [PATCH 81/86] tty: rpmsg: Unify variable used to keep an error code In some ret is used, in the other err. Let's unify it across the driver. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211025135148.53944-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/rpmsg_tty.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c index 8c17ddbf371d..fc5d33dc4cb8 100644 --- a/drivers/tty/rpmsg_tty.c +++ b/drivers/tty/rpmsg_tty.c @@ -114,22 +114,22 @@ static const struct tty_operations rpmsg_tty_ops = { static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void) { struct rpmsg_tty_port *cport; - int err; + int ret; cport = kzalloc(sizeof(*cport), GFP_KERNEL); if (!cport) return ERR_PTR(-ENOMEM); mutex_lock(&idr_lock); - err = idr_alloc(&tty_idr, cport, 0, MAX_TTY_RPMSG, GFP_KERNEL); + ret = idr_alloc(&tty_idr, cport, 0, MAX_TTY_RPMSG, GFP_KERNEL); mutex_unlock(&idr_lock); - if (err < 0) { + if (ret < 0) { kfree(cport); - return ERR_PTR(err); + return ERR_PTR(ret); } - cport->id = err; + cport->id = ret; return cport; } @@ -217,7 +217,7 @@ static struct rpmsg_driver rpmsg_tty_rpmsg_drv = { static int __init rpmsg_tty_init(void) { - int err; + int ret; rpmsg_tty_driver = tty_alloc_driver(MAX_TTY_RPMSG, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); @@ -236,15 +236,15 @@ static int __init rpmsg_tty_init(void) tty_set_operations(rpmsg_tty_driver, &rpmsg_tty_ops); - err = tty_register_driver(rpmsg_tty_driver); - if (err < 0) { - pr_err("Couldn't install rpmsg tty driver: err %d\n", err); + ret = tty_register_driver(rpmsg_tty_driver); + if (ret < 0) { + pr_err("Couldn't install rpmsg tty driver: %d\n", ret); goto error_put; } - err = register_rpmsg_driver(&rpmsg_tty_rpmsg_drv); - if (err < 0) { - pr_err("Couldn't register rpmsg tty driver: err %d\n", err); + ret = register_rpmsg_driver(&rpmsg_tty_rpmsg_drv); + if (ret < 0) { + pr_err("Couldn't register rpmsg tty driver: %d\n", ret); goto error_unregister; } @@ -256,7 +256,7 @@ error_unregister: error_put: tty_driver_kref_put(rpmsg_tty_driver); - return err; + return ret; } static void __exit rpmsg_tty_exit(void) From 8673ef7bd96dd75ed308cb71d48a292eaa1b72fa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Oct 2021 16:51:46 +0300 Subject: [PATCH 82/86] tty: rpmsg: Use dev_err_probe() in ->probe() It's fine to use dev_err_probe() in ->probe() even if we know it won't be deferred. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211025135148.53944-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/rpmsg_tty.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c index fc5d33dc4cb8..d172dd331bc9 100644 --- a/drivers/tty/rpmsg_tty.c +++ b/drivers/tty/rpmsg_tty.c @@ -153,10 +153,8 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev) int ret; cport = rpmsg_tty_alloc_cport(); - if (IS_ERR(cport)) { - dev_err(dev, "Failed to alloc tty port\n"); - return PTR_ERR(cport); - } + if (IS_ERR(cport)) + return dev_err_probe(dev, PTR_ERR(cport), "Failed to alloc tty port\n"); tty_port_init(&cport->port); cport->port.ops = &rpmsg_tty_port_ops; @@ -164,9 +162,8 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev) tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver, cport->id, dev); if (IS_ERR(tty_dev)) { - dev_err(dev, "Failed to register tty port\n"); - ret = PTR_ERR(tty_dev); - goto err_destroy; + ret = dev_err_probe(dev, PTR_ERR(tty_dev), "Failed to register tty port\n"); + goto err_destroy; } cport->rpdev = rpdev; From 88af70be4a5b936aa440bb9e22e6c57304067db6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Oct 2021 16:51:47 +0300 Subject: [PATCH 83/86] tty: rpmsg: Add pr_fmt() to prefix messages Make all messages to be prefixed in a unified way. Add pr_fmt() to achieve this. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211025135148.53944-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/rpmsg_tty.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c index d172dd331bc9..4bee6c5bbb53 100644 --- a/drivers/tty/rpmsg_tty.c +++ b/drivers/tty/rpmsg_tty.c @@ -10,6 +10,8 @@ * The "rpmsg-tty" service is directly used for data exchange. No flow control is implemented yet. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -235,13 +237,13 @@ static int __init rpmsg_tty_init(void) ret = tty_register_driver(rpmsg_tty_driver); if (ret < 0) { - pr_err("Couldn't install rpmsg tty driver: %d\n", ret); + pr_err("Couldn't install driver: %d\n", ret); goto error_put; } ret = register_rpmsg_driver(&rpmsg_tty_rpmsg_drv); if (ret < 0) { - pr_err("Couldn't register rpmsg tty driver: %d\n", ret); + pr_err("Couldn't register driver: %d\n", ret); goto error_unregister; } From 73a3d4f41886e6bd27f8b09c6235539a586e5131 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Oct 2021 16:51:48 +0300 Subject: [PATCH 84/86] tty: rpmsg: Define tty name via constant string literal Driver uses already twice the same string literal. Define it in one place, so every user will have this name consistent. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211025135148.53944-5-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/rpmsg_tty.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c index 4bee6c5bbb53..dae2a4e44f38 100644 --- a/drivers/tty/rpmsg_tty.c +++ b/drivers/tty/rpmsg_tty.c @@ -18,6 +18,7 @@ #include #include +#define RPMSG_TTY_NAME "ttyRPMSG" #define MAX_TTY_RPMSG 32 static DEFINE_IDR(tty_idr); /* tty instance id */ @@ -172,7 +173,7 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev) dev_set_drvdata(dev, cport); - dev_dbg(dev, "New channel: 0x%x -> 0x%x : ttyRPMSG%d\n", + dev_dbg(dev, "New channel: 0x%x -> 0x%x: " RPMSG_TTY_NAME "%d\n", rpdev->src, rpdev->dst, cport->id); return 0; @@ -224,7 +225,7 @@ static int __init rpmsg_tty_init(void) return PTR_ERR(rpmsg_tty_driver); rpmsg_tty_driver->driver_name = "rpmsg_tty"; - rpmsg_tty_driver->name = "ttyRPMSG"; + rpmsg_tty_driver->name = RPMSG_TTY_NAME; rpmsg_tty_driver->major = 0; rpmsg_tty_driver->type = TTY_DRIVER_TYPE_CONSOLE; From d142585bceb3218ad432ed0fcd5be9d6e3cd9052 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 27 Oct 2021 09:53:26 +0200 Subject: [PATCH 85/86] serial: cpm_uart: Protect udbg definitions by CONFIG_SERIAL_CPM_CONSOLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_CONSOLE_POLL=y, and CONFIG_SERIAL_CPM=m (hence CONFIG_SERIAL_CPM_CONSOLE=n): drivers/tty/serial/cpm_uart/cpm_uart_core.c:1109:12: warning: ‘udbg_cpm_getc’ defined but not used [-Wunused-function] 1109 | static int udbg_cpm_getc(void) | ^~~~~~~~~~~~~ drivers/tty/serial/cpm_uart/cpm_uart_core.c:1095:13: warning: ‘udbg_cpm_putc’ defined but not used [-Wunused-function] 1095 | static void udbg_cpm_putc(char c) | ^~~~~~~~~~~~~ Fix this by making the udbg definitions depend on CONFIG_SERIAL_CPM_CONSOLE, in addition to CONFIG_CONSOLE_POLL. Fixes: a60526097f42eb98 ("tty: serial: cpm_uart: Add udbg support for enabling xmon") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211027075326.3270785-1-geert@linux-m68k.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/cpm_uart/cpm_uart_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index c719aa2b1832..d6d3db9c3b1f 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1090,6 +1090,7 @@ static void cpm_put_poll_char(struct uart_port *port, cpm_uart_early_write(pinfo, ch, 1, false); } +#ifdef CONFIG_SERIAL_CPM_CONSOLE static struct uart_port *udbg_port; static void udbg_cpm_putc(char c) @@ -1114,6 +1115,7 @@ static int udbg_cpm_getc(void) cpu_relax(); return c; } +#endif /* CONFIG_SERIAL_CPM_CONSOLE */ #endif /* CONFIG_CONSOLE_POLL */ From cc8d7b4aea79df7cb45b74f9bc5b8a8bd2ed4c07 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 27 Oct 2021 13:21:24 +0300 Subject: [PATCH 86/86] tty: Fix extra "not" in TTY_DRIVER_REAL_RAW description TTY_DRIVER_REAL_RAW flag (which is always set for e.g. serial ports) documentation says that driver must always set special character handling flags in certain conditions. However, as the following sentence makes clear, what is actually intended is the opposite. Fix that by removing the unintended double negation. Acked-by: Johan Hovold Signed-off-by: Anssi Hannula Link: https://lore.kernel.org/r/20211027102124.3049414-1-anssi.hannula@bitwise.fi Signed-off-by: Greg Kroah-Hartman --- include/linux/tty_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 29e1cf178afb..795b94ccdeb6 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -360,7 +360,7 @@ static inline void tty_set_operations(struct tty_driver *driver, * Used for PTY's, in particular. * * TTY_DRIVER_REAL_RAW --- if set, indicates that the driver will - * guarantee never not to set any special character handling + * guarantee never to set any special character handling * flags if ((IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR || * !INPCK)). That is, if there is no reason for the driver to * send notifications of parity and break characters up to the