From 8e217b078138b6dadcef3080a5450ecd6767d09f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 24 Jan 2020 18:11:32 +0200 Subject: kgdboc: Use for_each_console() helper Replace open coded single-linked list iteration loop with for_each_console() helper in use. Signed-off-by: Andy Shevchenko Acked-by: Daniel Thompson Link: https://lore.kernel.org/r/20200124161132.65519-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/kgdboc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index c7d51b51898f..c9f94fa82be4 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -169,15 +169,13 @@ static int configure_kgdboc(void) if (!p) goto noconfig; - cons = console_drivers; - while (cons) { + for_each_console(cons) { int idx; if (cons->device && cons->device(cons, &idx) == p && idx == tty_line) { kgdboc_io_ops.is_console = 1; break; } - cons = cons->next; } kgdb_tty_driver = p; -- cgit From a287885f1e378bff5f58cee6d0fd16b886c4863b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 30 Jan 2020 12:58:43 +0100 Subject: n_tty: check printk arguments for n_tty_trace When N_TTY_TRACE is undefined (the default), define n_tty_trace to use no_printk. That way, arguments are still checked during compilation. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200130115843.7452-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index f9c584244f72..640fdd1e4c1d 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -84,7 +84,7 @@ #ifdef N_TTY_TRACE # define n_tty_trace(f, args...) trace_printk(f, ##args) #else -# define n_tty_trace(f, args...) +# define n_tty_trace(f, args...) no_printk(f, ##args) #endif struct n_tty_data { -- cgit From c6825c6395b7dbcb5421d89ac8d5631be815ca36 Mon Sep 17 00:00:00 2001 From: Jeff Brasen Date: Wed, 29 Jan 2020 13:28:17 +0000 Subject: serial: 8250_tegra: Create Tegra specific 8250 driver To support booting NVIDIA Tegra platforms with either Device-Tree or ACPI, create a Tegra specific 8250 serial driver that supports both firmware types. Another benefit from doing this, is that the Tegra specific codec in the generic Open Firmware 8250 driver can now be removed. Signed-off-by: Jeff Brasen Signed-off-by: Jon Hunter Link: https://lore.kernel.org/r/20200129132817.26343-1-jonathanh@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 28 ----- drivers/tty/serial/8250/8250_tegra.c | 198 +++++++++++++++++++++++++++++++++++ drivers/tty/serial/8250/Kconfig | 9 ++ drivers/tty/serial/8250/Makefile | 1 + 4 files changed, 208 insertions(+), 28 deletions(-) create mode 100644 drivers/tty/serial/8250/8250_tegra.c (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 531ad67395e0..5e45cf8dbc6e 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -26,28 +25,6 @@ struct of_serial_info { int line; }; -#ifdef CONFIG_ARCH_TEGRA -static void tegra_serial_handle_break(struct uart_port *p) -{ - unsigned int status, tmout = 10000; - - do { - status = p->serial_in(p, UART_LSR); - if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) - status = p->serial_in(p, UART_RX); - else - break; - if (--tmout == 0) - break; - udelay(1); - } while (1); -} -#else -static inline void tegra_serial_handle_break(struct uart_port *port) -{ -} -#endif - static int of_8250_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) { @@ -211,10 +188,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->rs485_config = of_8250_rs485_config; switch (type) { - case PORT_TEGRA: - port->handle_break = tegra_serial_handle_break; - break; - case PORT_RT2880: port->iotype = UPIO_AU; break; @@ -359,7 +332,6 @@ static const struct of_device_id of_platform_serial_table[] = { { .compatible = "ns16550", .data = (void *)PORT_16550, }, { .compatible = "ns16750", .data = (void *)PORT_16750, }, { .compatible = "ns16850", .data = (void *)PORT_16850, }, - { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, { .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, }, { .compatible = "intel,xscale-uart", .data = (void *)PORT_XSCALE, }, diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c new file mode 100644 index 000000000000..c0ffad1572c6 --- /dev/null +++ b/drivers/tty/serial/8250/8250_tegra.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Serial Port driver for Tegra devices + * + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "8250.h" + +struct tegra_uart { + struct clk *clk; + struct reset_control *rst; + int line; +}; + +static void tegra_uart_handle_break(struct uart_port *p) +{ + unsigned int status, tmout = 10000; + + do { + status = p->serial_in(p, UART_LSR); + if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) + status = p->serial_in(p, UART_RX); + else + break; + if (--tmout == 0) + break; + udelay(1); + } while (1); +} + +static int tegra_uart_probe(struct platform_device *pdev) +{ + struct uart_8250_port port8250; + struct tegra_uart *uart; + struct uart_port *port; + struct resource *res; + int ret; + + uart = devm_kzalloc(&pdev->dev, sizeof(*uart), GFP_KERNEL); + if (!uart) + return -ENOMEM; + + memset(&port8250, 0, sizeof(port8250)); + + port = &port8250.port; + spin_lock_init(&port->lock); + + port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | + UPF_FIXED_TYPE; + port->iotype = UPIO_MEM32; + port->regshift = 2; + port->type = PORT_TEGRA; + port->irqflags |= IRQF_SHARED; + port->dev = &pdev->dev; + port->handle_break = tegra_uart_handle_break; + + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (ret >= 0) + port->line = ret; + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + + port->irq = ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + port->membase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!port->membase) + return -ENOMEM; + + port->mapbase = res->start; + port->mapsize = resource_size(res); + + uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); + if (IS_ERR(uart->rst)) + return PTR_ERR(uart->rst); + + if (device_property_read_u32(&pdev->dev, "clock-frequency", + &port->uartclk)) { + uart->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(uart->clk)) { + dev_err(&pdev->dev, "failed to get clock!\n"); + return -ENODEV; + } + + ret = clk_prepare_enable(uart->clk); + if (ret < 0) + return ret; + + port->uartclk = clk_get_rate(uart->clk); + } + + ret = reset_control_deassert(uart->rst); + if (ret) + goto err_clkdisable; + + ret = serial8250_register_8250_port(&port8250); + if (ret < 0) + goto err_clkdisable; + + platform_set_drvdata(pdev, uart); + uart->line = ret; + + return 0; + +err_clkdisable: + clk_disable_unprepare(uart->clk); + + return ret; +} + +static int tegra_uart_remove(struct platform_device *pdev) +{ + struct tegra_uart *uart = platform_get_drvdata(pdev); + + serial8250_unregister_port(uart->line); + reset_control_assert(uart->rst); + clk_disable_unprepare(uart->clk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tegra_uart_suspend(struct device *dev) +{ + struct tegra_uart *uart = dev_get_drvdata(dev); + struct uart_8250_port *port8250 = serial8250_get_port(uart->line); + struct uart_port *port = &port8250->port; + + serial8250_suspend_port(uart->line); + + if (!uart_console(port) || console_suspend_enabled) + clk_disable_unprepare(uart->clk); + + return 0; +} + +static int tegra_uart_resume(struct device *dev) +{ + struct tegra_uart *uart = dev_get_drvdata(dev); + struct uart_8250_port *port8250 = serial8250_get_port(uart->line); + struct uart_port *port = &port8250->port; + + if (!uart_console(port) || console_suspend_enabled) + clk_prepare_enable(uart->clk); + + serial8250_resume_port(uart->line); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(tegra_uart_pm_ops, tegra_uart_suspend, + tegra_uart_resume); + +static const struct of_device_id tegra_uart_of_match[] = { + { .compatible = "nvidia,tegra20-uart", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_uart_of_match); + +static const struct acpi_device_id tegra_uart_acpi_match[] = { + { "NVDA0100", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, tegra_uart_acpi_match); + +static struct platform_driver tegra_uart_driver = { + .driver = { + .name = "tegra-uart", + .pm = &tegra_uart_pm_ops, + .of_match_table = tegra_uart_of_match, + .acpi_match_table = ACPI_PTR(tegra_uart_acpi_match), + }, + .probe = tegra_uart_probe, + .remove = tegra_uart_remove, +}; + +module_platform_driver(tegra_uart_driver); + +MODULE_AUTHOR("Jeff Brasen "); +MODULE_DESCRIPTION("NVIDIA Tegra 8250 Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index f16824bbb573..af0688156dd0 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -500,6 +500,15 @@ config SERIAL_8250_PXA applicable to both devicetree and legacy boards, and early console is part of its support. +config SERIAL_8250_TEGRA + tristate "8250 support for Tegra serial ports" + default SERIAL_8250 + depends on SERIAL_8250 + depends on ARCH_TEGRA || COMPILE_TEST + help + Select this option if you have machine with an NVIDIA Tegra SoC and + wish to enable 8250 serial driver for the Tegra serial interfaces. + config SERIAL_OF_PLATFORM tristate "Devicetree based probing for 8250 ports" depends on SERIAL_8250 && OF diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 51a6079d3f1f..a8bfb654d490 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o +obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt -- cgit From 57b76faf1d7860f070a1ee2d0b7eccd9f37ecc55 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Sun, 26 Jan 2020 13:33:14 +0100 Subject: serial: 8250_early: Add earlycon for BCM2835 aux uart Define the OF early console for BCM2835 aux UART, which can be enabled by passing "earlycon" on the boot command line. This UART is found on BCM283x and BCM27xx SoCs, a.k.a. Raspberry Pi in its variants. Signed-off-by: Matthias Brugger Link: https://lore.kernel.org/r/20200126123314.3558-1-matthias.bgg@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm2835aux.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index e70e3cc30050..5cc03bf24f85 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -137,6 +137,24 @@ static struct platform_driver bcm2835aux_serial_driver = { }; module_platform_driver(bcm2835aux_serial_driver); +#ifdef CONFIG_SERIAL_8250_CONSOLE + +static int __init early_bcm2835aux_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->port.iotype = UPIO_MEM32; + device->port.regshift = 2; + + return early_serial8250_setup(device, NULL); +} + +OF_EARLYCON_DECLARE(bcm2835aux, "brcm,bcm2835-aux-uart", + early_bcm2835aux_setup); +#endif + MODULE_DESCRIPTION("BCM2835 auxiliar UART driver"); MODULE_AUTHOR("Martin Sperl "); MODULE_LICENSE("GPL v2"); -- cgit From 00d963abcb92e9e3192036f83f5c3f964b19141a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 12 Feb 2020 13:37:00 -0600 Subject: tty/serial: 8250_exar: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertenly introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20200212193700.GA29715@embeddedor Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 91e9b070d36d..65898ef90801 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -127,7 +127,7 @@ struct exar8250 { unsigned int nr; struct exar8250_board *board; void __iomem *virt; - int line[0]; + int line[]; }; static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old) -- cgit From 2f202d03a5785ffaf894f9503193a3767ff88d88 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 12 Feb 2020 13:35:23 -0600 Subject: tty: n_gsm: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertenly introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20200212193523.GA28826@embeddedor Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index f1c90fa2978e..5f8c30f0538e 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -97,7 +97,7 @@ struct gsm_msg { u8 ctrl; /* Control byte + flags */ unsigned int len; /* Length of data block (can be zero) */ unsigned char *data; /* Points into buffer but not at the start */ - unsigned char buffer[0]; + unsigned char buffer[]; }; /* -- cgit From 4a37c0fcf5d403e7d9f5309ea970ea3c9074b5d8 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 12 Feb 2020 18:46:11 -0600 Subject: serial: sc16is7xx: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20200213004611.GA8748@embeddedor.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 7d3ae31cc720..06e8071d5601 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -329,7 +329,7 @@ struct sc16is7xx_port { struct task_struct *kworker_task; struct kthread_work irq_work; struct mutex efr_lock; - struct sc16is7xx_one p[0]; + struct sc16is7xx_one p[]; }; static unsigned long sc16is7xx_lines; -- cgit From 02042a4cf472a1362e39da72a1d992d59a58a0ab Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 12 Feb 2020 18:44:26 -0600 Subject: serial: 8250_pci: Replace zero-length array with flexible-array member The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20200213004426.GA7886@embeddedor.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 939685fed396..0804469ff052 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -53,7 +53,7 @@ struct serial_private { unsigned int nr; struct pci_serial_quirk *quirk; const struct pciserial_board *board; - int line[0]; + int line[]; }; static const struct pci_device_id pci_use_msi[] = { -- cgit From 7a49955af1441dd58d27c1ab59205d83ec42907f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 14 Feb 2020 13:43:32 +0200 Subject: serial: core: Introduce uart_console_enabled() helper Introduce uart_console_enabled() helper which checks port to be console and console is registered in the list. Note, this helper will be used in the future as well. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200214114339.53897-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 76e506ee335c..d956da0b6d9c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1908,6 +1908,11 @@ static int uart_proc_show(struct seq_file *m, void *v) } #endif +static inline bool uart_console_enabled(struct uart_port *port) +{ + return uart_console(port) && (port->cons->flags & CON_ENABLED); +} + #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) /** * uart_console_write - write a console message to a serial port @@ -2066,7 +2071,7 @@ uart_set_options(struct uart_port *port, struct console *co, * If this port is a console, then the spinlock is already * initialised. */ - if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) { + if (!uart_console_enabled(port)) { spin_lock_init(&port->lock); lockdep_set_class(&port->lock, &port_lock_key); } @@ -2828,7 +2833,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) * If this port is a console, then the spinlock is already * initialised. */ - if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { + if (!uart_console_enabled(uport)) { spin_lock_init(&uport->lock); lockdep_set_class(&uport->lock, &port_lock_key); } -- cgit From d2403cadc1ee93b9ccf3766e1bc60e7e4d48387b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 14 Feb 2020 13:43:33 +0200 Subject: serial: core: Consolidate spin lock initialization code We have two times duplicated excerpt where we initialize spin lock for UART port. Consolidate it under uart_port_spin_lock_init() helper. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200214114339.53897-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index d956da0b6d9c..bb2287048108 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1913,6 +1913,19 @@ static inline bool uart_console_enabled(struct uart_port *port) return uart_console(port) && (port->cons->flags & CON_ENABLED); } +/* + * Ensure that the serial console lock is initialised early. + * If this port is a console, then the spinlock is already initialised. + */ +static inline void uart_port_spin_lock_init(struct uart_port *port) +{ + if (uart_console_enabled(port)) + return; + + spin_lock_init(&port->lock); + lockdep_set_class(&port->lock, &port_lock_key); +} + #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) /** * uart_console_write - write a console message to a serial port @@ -2065,16 +2078,7 @@ uart_set_options(struct uart_port *port, struct console *co, struct ktermios termios; static struct ktermios dummy; - /* - * Ensure that the serial console lock is initialised - * early. - * If this port is a console, then the spinlock is already - * initialised. - */ - if (!uart_console_enabled(port)) { - spin_lock_init(&port->lock); - lockdep_set_class(&port->lock, &port_lock_key); - } + uart_port_spin_lock_init(port); memset(&termios, 0, sizeof(struct ktermios)); @@ -2829,14 +2833,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) goto out; } - /* - * If this port is a console, then the spinlock is already - * initialised. - */ - if (!uart_console_enabled(uport)) { - spin_lock_init(&uport->lock); - lockdep_set_class(&uport->lock, &port_lock_key); - } + uart_port_spin_lock_init(uport); + if (uport->cons && uport->dev) of_console_check(uport->dev->of_node, uport->cons->name, uport->line); -- cgit From 643f7d95fe236d739aaba3b63f0627b20471d4da Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 14 Feb 2020 13:43:34 +0200 Subject: serial: core: use octal permissions on module param Symbolic permissions 'S_IRUSR | S_IRGRP' are not preferred. Use octal permissions '0440'. This also makes code shorter. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200214114339.53897-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index bb2287048108..7564bbd3061c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2749,19 +2749,19 @@ static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); } -static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL); -static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL); -static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL); -static DEVICE_ATTR(irq, S_IRUSR | S_IRGRP, uart_get_attr_irq, NULL); -static DEVICE_ATTR(flags, S_IRUSR | S_IRGRP, uart_get_attr_flags, NULL); -static DEVICE_ATTR(xmit_fifo_size, S_IRUSR | S_IRGRP, uart_get_attr_xmit_fifo_size, NULL); -static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL); -static DEVICE_ATTR(close_delay, S_IRUSR | S_IRGRP, uart_get_attr_close_delay, NULL); -static DEVICE_ATTR(closing_wait, S_IRUSR | S_IRGRP, uart_get_attr_closing_wait, NULL); -static DEVICE_ATTR(custom_divisor, S_IRUSR | S_IRGRP, uart_get_attr_custom_divisor, NULL); -static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL); -static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL); -static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL); +static DEVICE_ATTR(type, 0440, uart_get_attr_type, NULL); +static DEVICE_ATTR(line, 0440, uart_get_attr_line, NULL); +static DEVICE_ATTR(port, 0440, uart_get_attr_port, NULL); +static DEVICE_ATTR(irq, 0440, uart_get_attr_irq, NULL); +static DEVICE_ATTR(flags, 0440, uart_get_attr_flags, NULL); +static DEVICE_ATTR(xmit_fifo_size, 0440, uart_get_attr_xmit_fifo_size, NULL); +static DEVICE_ATTR(uartclk, 0440, uart_get_attr_uartclk, NULL); +static DEVICE_ATTR(close_delay, 0440, uart_get_attr_close_delay, NULL); +static DEVICE_ATTR(closing_wait, 0440, uart_get_attr_closing_wait, NULL); +static DEVICE_ATTR(custom_divisor, 0440, uart_get_attr_custom_divisor, NULL); +static DEVICE_ATTR(io_type, 0440, uart_get_attr_io_type, NULL); +static DEVICE_ATTR(iomem_base, 0440, uart_get_attr_iomem_base, NULL); +static DEVICE_ATTR(iomem_reg_shift, 0440, uart_get_attr_iomem_reg_shift, NULL); static struct attribute *tty_dev_attrs[] = { &dev_attr_type.attr, -- cgit From 143c02c88d6d3fd725257c3941bf37ee78258741 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 Feb 2020 13:40:11 +0200 Subject: serial: core: Switch to use DEVICE_ATTR_RO() Move device attributes to DEVICE_ATTR_RO() as that would make things a lot more "obvious" what is happening here. Suggested-by: Greg Kroah-Hartman Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200217114016.49856-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 57 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 29 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 7564bbd3061c..5444293fe2e8 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2614,7 +2614,7 @@ struct tty_driver *uart_console_device(struct console *co, int *index) } EXPORT_SYMBOL_GPL(uart_console_device); -static ssize_t uart_get_attr_uartclk(struct device *dev, +static ssize_t uartclk_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2624,7 +2624,7 @@ static ssize_t uart_get_attr_uartclk(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16); } -static ssize_t uart_get_attr_type(struct device *dev, +static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2633,7 +2633,8 @@ static ssize_t uart_get_attr_type(struct device *dev, uart_get_info(port, &tmp); return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type); } -static ssize_t uart_get_attr_line(struct device *dev, + +static ssize_t line_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2643,7 +2644,7 @@ static ssize_t uart_get_attr_line(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line); } -static ssize_t uart_get_attr_port(struct device *dev, +static ssize_t port_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2657,7 +2658,7 @@ static ssize_t uart_get_attr_port(struct device *dev, return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr); } -static ssize_t uart_get_attr_irq(struct device *dev, +static ssize_t irq_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2667,7 +2668,7 @@ static ssize_t uart_get_attr_irq(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq); } -static ssize_t uart_get_attr_flags(struct device *dev, +static ssize_t flags_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2677,7 +2678,7 @@ static ssize_t uart_get_attr_flags(struct device *dev, return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags); } -static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev, +static ssize_t xmit_fifo_size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2687,8 +2688,7 @@ static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size); } - -static ssize_t uart_get_attr_close_delay(struct device *dev, +static ssize_t close_delay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2698,8 +2698,7 @@ static ssize_t uart_get_attr_close_delay(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay); } - -static ssize_t uart_get_attr_closing_wait(struct device *dev, +static ssize_t closing_wait_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2709,7 +2708,7 @@ static ssize_t uart_get_attr_closing_wait(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait); } -static ssize_t uart_get_attr_custom_divisor(struct device *dev, +static ssize_t custom_divisor_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2719,7 +2718,7 @@ static ssize_t uart_get_attr_custom_divisor(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor); } -static ssize_t uart_get_attr_io_type(struct device *dev, +static ssize_t io_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2729,7 +2728,7 @@ static ssize_t uart_get_attr_io_type(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type); } -static ssize_t uart_get_attr_iomem_base(struct device *dev, +static ssize_t iomem_base_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2739,7 +2738,7 @@ static ssize_t uart_get_attr_iomem_base(struct device *dev, return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base); } -static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev, +static ssize_t iomem_reg_shift_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2749,28 +2748,28 @@ static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); } -static DEVICE_ATTR(type, 0440, uart_get_attr_type, NULL); -static DEVICE_ATTR(line, 0440, uart_get_attr_line, NULL); -static DEVICE_ATTR(port, 0440, uart_get_attr_port, NULL); -static DEVICE_ATTR(irq, 0440, uart_get_attr_irq, NULL); -static DEVICE_ATTR(flags, 0440, uart_get_attr_flags, NULL); -static DEVICE_ATTR(xmit_fifo_size, 0440, uart_get_attr_xmit_fifo_size, NULL); -static DEVICE_ATTR(uartclk, 0440, uart_get_attr_uartclk, NULL); -static DEVICE_ATTR(close_delay, 0440, uart_get_attr_close_delay, NULL); -static DEVICE_ATTR(closing_wait, 0440, uart_get_attr_closing_wait, NULL); -static DEVICE_ATTR(custom_divisor, 0440, uart_get_attr_custom_divisor, NULL); -static DEVICE_ATTR(io_type, 0440, uart_get_attr_io_type, NULL); -static DEVICE_ATTR(iomem_base, 0440, uart_get_attr_iomem_base, NULL); -static DEVICE_ATTR(iomem_reg_shift, 0440, uart_get_attr_iomem_reg_shift, NULL); +static DEVICE_ATTR_RO(uartclk); +static DEVICE_ATTR_RO(type); +static DEVICE_ATTR_RO(line); +static DEVICE_ATTR_RO(port); +static DEVICE_ATTR_RO(irq); +static DEVICE_ATTR_RO(flags); +static DEVICE_ATTR_RO(xmit_fifo_size); +static DEVICE_ATTR_RO(close_delay); +static DEVICE_ATTR_RO(closing_wait); +static DEVICE_ATTR_RO(custom_divisor); +static DEVICE_ATTR_RO(io_type); +static DEVICE_ATTR_RO(iomem_base); +static DEVICE_ATTR_RO(iomem_reg_shift); static struct attribute *tty_dev_attrs[] = { + &dev_attr_uartclk.attr, &dev_attr_type.attr, &dev_attr_line.attr, &dev_attr_port.attr, &dev_attr_irq.attr, &dev_attr_flags.attr, &dev_attr_xmit_fifo_size.attr, - &dev_attr_uartclk.attr, &dev_attr_close_delay.attr, &dev_attr_closing_wait.attr, &dev_attr_custom_divisor.attr, -- cgit From 8c6b6ffac367a0d09b6898d26b997728f7c6dd7f Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 19 Feb 2020 09:01:30 +0100 Subject: serial: 8250_pxa: avoid autodetecting the port type If we're unlucky enough that this drivers binds to a mrvl,mmp-uart device on a MMP3, the port type gets detected as 16550A instead of XScale, and it won't work. Other drivers that may bind to the same hardware are 8250_of and, god forbid, serial_pxa. Force the port type, we know it's a PORT_XSCALE. Signed-off-by: Lubomir Rintel Link: https://lore.kernel.org/r/20200219080130.4334-1-lkundrak@v3.sk Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c index c47188860e32..11612d174716 100644 --- a/drivers/tty/serial/8250/8250_pxa.c +++ b/drivers/tty/serial/8250/8250_pxa.c @@ -123,7 +123,7 @@ static int serial_pxa_probe(struct platform_device *pdev) uart.port.regshift = 2; uart.port.irq = irqres->start; uart.port.fifosize = 64; - uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST; + uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE; uart.port.dev = &pdev->dev; uart.port.uartclk = clk_get_rate(data->clk); uart.port.pm = serial_pxa_pm; -- cgit From 9ff2f0f7f24723afa72ac212f3138a8ebbe84fdd Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 16 Feb 2020 11:27:42 +0100 Subject: tty: serial: Kconfig: Fix a typo 'exsisting' has an extra 's' Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20200216102742.19298-1-christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 52eaac21ff9f..7172f1c5fa6d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1111,7 +1111,7 @@ config SERIAL_SC16IS7XX_SPI help Enable SC16IS7xx driver on SPI bus, If required say y, and say n to spi if not required, - This is additional support to exsisting driver. + This is additional support to existing driver. You must select at least one bus for the driver to be built. config SERIAL_TIMBERDALE -- cgit From 47eff47cc27598c4befe9af4516b7e30e6c1564b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 14 Feb 2020 15:14:06 +0100 Subject: tty: serial: efm32: fix spelling mistake "reserverd" -> "reserved" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a spelling mistake in a comment. Signed-off-by: Alexandre Belloni Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20200214141406.20792-1-alexandre.belloni@bootlin.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/efm32-uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 2ac87128d7fd..f12f29cf4f31 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -200,7 +200,7 @@ static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port) /* * This is a reserved bit and I only saw it read as 0. But to be * sure not to be confused too much by new devices adhere to the - * warning in the reference manual that reserverd bits might + * warning in the reference manual that reserved bits might * read as 1 in the future. */ rxdata &= ~SW_UARTn_RXDATAX_BERR; -- cgit From 567a0e17f75f412adf8a6bff59de5cebcee87450 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 Feb 2020 13:40:13 +0200 Subject: serial: 8250_port: Switch to use DEVICE_ATTR_RW() Move device attributes to DEVICE_ATTR_RW() as that would make things a lot more "obvious" what is happening here. Suggested-by: Greg Kroah-Hartman Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200217114016.49856-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 430e3467aff7..df2b2f6463c5 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2876,7 +2876,7 @@ static int do_serial8250_get_rxtrig(struct tty_port *port) return rxtrig_bytes; } -static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev, +static ssize_t rx_trig_bytes_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tty_port *port = dev_get_drvdata(dev); @@ -2922,7 +2922,7 @@ static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes) return ret; } -static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev, +static ssize_t rx_trig_bytes_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tty_port *port = dev_get_drvdata(dev); @@ -2943,18 +2943,16 @@ static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev, return count; } -static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP, - serial8250_get_attr_rx_trig_bytes, - serial8250_set_attr_rx_trig_bytes); +static DEVICE_ATTR_RW(rx_trig_bytes); static struct attribute *serial8250_dev_attrs[] = { &dev_attr_rx_trig_bytes.attr, - NULL, - }; + NULL +}; static struct attribute_group serial8250_dev_attr_group = { .attrs = serial8250_dev_attrs, - }; +}; static void register_dev_spec_attr_grp(struct uart_8250_port *up) { -- cgit From 21680a6dcb011151398aa7bf0e7f4b148fa0bc79 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 Feb 2020 13:40:14 +0200 Subject: serial: 8250_port: Use dev_*() instead of pr_*() Convert pr_*() calls to dev_*() ones. We have a port, we should use it. Suggested-by: Greg Kroah-Hartman Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200217114016.49856-5-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index df2b2f6463c5..602cd94a5635 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1318,8 +1318,8 @@ out_lock: fintek_8250_probe(up); if (up->capabilities != old_capabilities) { - pr_warn("%s: detected caps %08x should be %08x\n", - port->name, old_capabilities, up->capabilities); + dev_warn(port->dev, "detected caps %08x should be %08x\n", + old_capabilities, up->capabilities); } out: DEBUG_AUTOCONF("iir=%d ", scratch); @@ -1683,7 +1683,7 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) lsr &= port->read_status_mask; if (lsr & UART_LSR_BI) { - pr_debug("%s: handling break\n", __func__); + dev_dbg(port->dev, "handling break\n"); flag = TTY_BREAK; } else if (lsr & UART_LSR_PE) flag = TTY_PARITY; @@ -2134,7 +2134,7 @@ int serial8250_do_startup(struct uart_port *port) */ if (!(port->flags & UPF_BUGGY_UART) && (serial_port_in(port, UART_LSR) == 0xff)) { - pr_info_ratelimited("%s: LSR safety check engaged!\n", port->name); + dev_info_ratelimited(port->dev, "LSR safety check engaged!\n"); retval = -ENODEV; goto out; } @@ -2166,8 +2166,7 @@ int serial8250_do_startup(struct uart_port *port) (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) { /* Bounds checking of TX threshold (valid 0 to fifosize-2) */ if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) { - pr_err("%s TX FIFO Threshold errors, skipping\n", - port->name); + dev_err(port->dev, "TX FIFO Threshold errors, skipping\n"); } else { serial_port_out(port, UART_ALTR_AFR, UART_ALTR_EN_TXFIFO_LW); @@ -2264,8 +2263,7 @@ int serial8250_do_startup(struct uart_port *port) if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { if (!(up->bugs & UART_BUG_TXEN)) { up->bugs |= UART_BUG_TXEN; - pr_debug("%s - enabling bad tx status workarounds\n", - port->name); + dev_dbg(port->dev, "enabling bad tx status workarounds\n"); } } else { up->bugs &= ~UART_BUG_TXEN; @@ -2292,8 +2290,7 @@ dont_test_tx_en: if (up->dma) { retval = serial8250_request_dma(up); if (retval) { - pr_warn_ratelimited("%s - failed to request DMA\n", - port->name); + dev_warn_ratelimited(port->dev, "failed to request DMA\n"); up->dma = NULL; } } -- cgit From 036bca1fcce80fcf90bcfbff6ab3534ad575eb46 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:40 +0100 Subject: n_gsm: drop unneeded gsm_dlci->fifo field gsm_dlci->fifo always points to gsm_dlci->_fifo. So drop the pointer and rename _fifo to fifo. And update all the users (add & to them). Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 5f8c30f0538e..828c0c7babdd 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -129,8 +129,7 @@ struct gsm_dlci { int retries; /* Uplink tty if active */ struct tty_port port; /* The tty bound to this DLCI if there is one */ - struct kfifo *fifo; /* Queue fifo for the DLCI */ - struct kfifo _fifo; /* For new fifo API porting only */ + struct kfifo fifo; /* Queue fifo for the DLCI */ int adaption; /* Adaption layer in use */ int prev_adaption; u32 modem_rx; /* Our incoming virtual modem lines */ @@ -796,7 +795,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci) total_size = 0; while (1) { - len = kfifo_len(dlci->fifo); + len = kfifo_len(&dlci->fifo); if (len == 0) return total_size; @@ -820,7 +819,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci) *dp++ = gsm_encode_modem(dlci); break; } - WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len); + WARN_ON(kfifo_out_locked(&dlci->fifo, dp , len, &dlci->lock) != len); __gsm_data_queue(dlci, msg); total_size += size; } @@ -1424,7 +1423,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci) dlci->state = DLCI_CLOSED; if (dlci->addr != 0) { tty_port_tty_hangup(&dlci->port, false); - kfifo_reset(dlci->fifo); + kfifo_reset(&dlci->fifo); } else dlci->gsm->dead = 1; wake_up(&dlci->gsm->event); @@ -1645,8 +1644,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) return NULL; spin_lock_init(&dlci->lock); mutex_init(&dlci->mutex); - dlci->fifo = &dlci->_fifo; - if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) { + if (kfifo_alloc(&dlci->fifo, 4096, GFP_KERNEL) < 0) { kfree(dlci); return NULL; } @@ -1681,7 +1679,7 @@ static void gsm_dlci_free(struct tty_port *port) del_timer_sync(&dlci->t1); dlci->gsm->dlci[dlci->addr] = NULL; - kfifo_free(dlci->fifo); + kfifo_free(&dlci->fifo); while ((dlci->skb = skb_dequeue(&dlci->skb_list))) dev_kfree_skb(dlci->skb); kfree(dlci); @@ -3030,7 +3028,7 @@ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf, if (dlci->state == DLCI_CLOSED) return -EINVAL; /* Stuff the bytes into the fifo queue */ - sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock); + sent = kfifo_in_locked(&dlci->fifo, buf, len, &dlci->lock); /* Need to kick the channel */ gsm_dlci_data_kick(dlci); return sent; @@ -3041,7 +3039,7 @@ static int gsmtty_write_room(struct tty_struct *tty) struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) return -EINVAL; - return TX_SIZE - kfifo_len(dlci->fifo); + return TX_SIZE - kfifo_len(&dlci->fifo); } static int gsmtty_chars_in_buffer(struct tty_struct *tty) @@ -3049,7 +3047,7 @@ static int gsmtty_chars_in_buffer(struct tty_struct *tty) struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) return -EINVAL; - return kfifo_len(dlci->fifo); + return kfifo_len(&dlci->fifo); } static void gsmtty_flush_buffer(struct tty_struct *tty) @@ -3061,7 +3059,7 @@ static void gsmtty_flush_buffer(struct tty_struct *tty) then the data being transmitted can't simply be junked once it has first hit the stack. Until then we can just blow it away */ - kfifo_reset(dlci->fifo); + kfifo_reset(&dlci->fifo); /* Need to unhook this DLCI from the transmit queue logic */ } -- cgit From 72ae8cc192a312aa6a3cd643434a8992ea878737 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:41 +0100 Subject: n_gsm: introduce enum gsm_dlci_state gsm_dlci->state is clearly an enumeration. So introduce one and use it -- compiler now checks if valid values are assigned to the field. Note that a compiler warns about unhandled cases in switch. Add default cases with a pr_debug (which is not printed by default). Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 828c0c7babdd..1d0a140027ff 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -100,6 +100,13 @@ struct gsm_msg { unsigned char buffer[]; }; +enum gsm_dlci_state { + DLCI_CLOSED, + DLCI_OPENING, /* Sending SABM not seen UA */ + DLCI_OPEN, /* SABM/UA complete */ + DLCI_CLOSING, /* Sending DISC not seen UA/DM */ +}; + /* * Each active data link has a gsm_dlci structure associated which ties * the link layer to an optional tty (if the tty side is open). To avoid @@ -113,11 +120,7 @@ struct gsm_msg { struct gsm_dlci { struct gsm_mux *gsm; int addr; - int state; -#define DLCI_CLOSED 0 -#define DLCI_OPENING 1 /* Sending SABM not seen UA */ -#define DLCI_OPEN 2 /* SABM/UA complete */ -#define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */ + enum gsm_dlci_state state; struct mutex mutex; /* Link layer */ @@ -1495,6 +1498,9 @@ static void gsm_dlci_t1(struct timer_list *t) } else gsm_dlci_close(dlci); break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, dlci->state); + break; } } @@ -1808,6 +1814,10 @@ static void gsm_queue(struct gsm_mux *gsm) case DLCI_OPENING: gsm_dlci_open(dlci); break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, + dlci->state); + break; } break; case DM: /* DM can be valid unsolicited */ -- cgit From e1785996f4c659f24e93aea6632cb565e5924bf5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:42 +0100 Subject: n_gsm: introduce enum gsm_dlci_mode gsm_dlci->mode is clearly an enumeration. So introduce one and use it -- compiler now checks if valid values are assigned to the field. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 1d0a140027ff..7fee5a580f21 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -107,6 +107,11 @@ enum gsm_dlci_state { DLCI_CLOSING, /* Sending DISC not seen UA/DM */ }; +enum gsm_dlci_mode { + DLCI_MODE_ABM, /* Normal Asynchronous Balanced Mode */ + DLCI_MODE_ADM, /* Asynchronous Disconnected Mode */ +}; + /* * Each active data link has a gsm_dlci structure associated which ties * the link layer to an optional tty (if the tty side is open). To avoid @@ -124,9 +129,7 @@ struct gsm_dlci { struct mutex mutex; /* Link layer */ - int mode; -#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */ -#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */ + enum gsm_dlci_mode mode; spinlock_t lock; /* Protects the internal state */ struct timer_list t1; /* Retransmit timer for SABM and UA */ int retries; -- cgit From 329aa6e6e12f2667eb59baf2030a38047ce0a1cd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:43 +0100 Subject: n_gsm: introduce enum gsm_mux_state gsm_mux->state is clearly an enumeration. So introduce one and use it -- compiler now checks if valid values are assigned to the field. Note that a compiler warns about unhandled cases in switch. Add default cases with a pr_debug (which is not printed by default). The values of the states are preserved thanks to the nature of enum. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 7fee5a580f21..82e3d88c1f3f 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -173,6 +173,20 @@ struct gsm_control { int error; /* Error if any */ }; +enum gsm_mux_state { + GSM_SEARCH, + GSM_START, + GSM_ADDRESS, + GSM_CONTROL, + GSM_LEN, + GSM_DATA, + GSM_FCS, + GSM_OVERRUN, + GSM_LEN0, + GSM_LEN1, + GSM_SSOF, +}; + /* * Each GSM mux we have is represented by this structure. If we are * operating as an ldisc then we use this structure as our ldisc @@ -197,18 +211,7 @@ struct gsm_mux { /* Framing Layer */ unsigned char *buf; - int state; -#define GSM_SEARCH 0 -#define GSM_START 1 -#define GSM_ADDRESS 2 -#define GSM_CONTROL 3 -#define GSM_LEN 4 -#define GSM_DATA 5 -#define GSM_FCS 6 -#define GSM_OVERRUN 7 -#define GSM_LEN0 8 -#define GSM_LEN1 9 -#define GSM_SSOF 10 + enum gsm_mux_state state; unsigned int len; unsigned int address; unsigned int count; @@ -1934,6 +1937,9 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) break; } break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, gsm->state); + break; } } @@ -2008,6 +2014,9 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) break; case GSM_OVERRUN: /* Over-long - eg a dropped SOF */ break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, gsm->state); + break; } } -- cgit From edd05a735a391df1a8eeee05a5ba1c02ce41b369 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:44 +0100 Subject: n_gsm: add missing __user annotations sparse warns about incorrect types: n_gsm.c:2638:35: warning: incorrect type in argument 1 (different address spaces) n_gsm.c:2638:35: expected void [noderef] *to n_gsm.c:2638:35: got void * The ioctl handler casts its `arg' to (void *) without __user. Add that. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 82e3d88c1f3f..d866884c105b 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2638,11 +2638,11 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case GSMIOC_GETCONF: gsm_copy_config_values(gsm, &c); - if (copy_to_user((void *)arg, &c, sizeof(c))) + if (copy_to_user((void __user *)arg, &c, sizeof(c))) return -EFAULT; return 0; case GSMIOC_SETCONF: - if (copy_from_user(&c, (void *)arg, sizeof(c))) + if (copy_from_user(&c, (void __user *)arg, sizeof(c))) return -EFAULT; return gsm_config(gsm, &c); case GSMIOC_GETFIRST: -- cgit From d8ca4ecf8dbd22728ce9f36cd76cc7702f76f297 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:45 +0100 Subject: n_gsm: add missing \n to prints Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index d866884c105b..8afe635a04fd 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2789,7 +2789,7 @@ static void gsm_destroy_network(struct gsm_dlci *dlci) { struct gsm_mux_net *mux_net; - pr_debug("destroy network interface"); + pr_debug("destroy network interface\n"); if (!dlci->net) return; mux_net = netdev_priv(dlci->net); @@ -2818,7 +2818,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) if (nc->adaption != 3 && nc->adaption != 4) return -EPROTONOSUPPORT; - pr_debug("create network interface"); + pr_debug("create network interface\n"); netname = "gsm%d"; if (nc->if_name[0] != '\0') @@ -2826,7 +2826,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) net = alloc_netdev(sizeof(struct gsm_mux_net), netname, NET_NAME_UNKNOWN, gsm_mux_net_init); if (!net) { - pr_err("alloc_netdev failed"); + pr_err("alloc_netdev failed\n"); return -ENOMEM; } net->mtu = dlci->gsm->mtu; @@ -2844,7 +2844,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) dlci->data = gsm_mux_rx_netchar; dlci->net = net; - pr_debug("register netdev"); + pr_debug("register netdev\n"); retval = register_netdev(net); if (retval) { pr_err("network register fail %d\n", retval); -- cgit From 5677fcf376d5d129510f995efd8e77ef31ddf7d2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:46 +0100 Subject: n_gsm: switch dead to bool Both gsm_dlci->dead and gsm_mux->dead are used as bools, so treat them as such. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 8afe635a04fd..24ce46e4fb45 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -140,7 +140,7 @@ struct gsm_dlci { int prev_adaption; u32 modem_rx; /* Our incoming virtual modem lines */ u32 modem_tx; /* Our outgoing modem lines */ - int dead; /* Refuse re-open */ + bool dead; /* Refuse re-open */ /* Flow control */ int throttled; /* Private copy of throttle state */ int constipated; /* Throttle status for outgoing */ @@ -232,7 +232,7 @@ struct gsm_mux { unsigned int mru; unsigned int mtu; int initiator; /* Did we initiate connection */ - int dead; /* Has the mux been shut down */ + bool dead; /* Has the mux been shut down */ struct gsm_dlci *dlci[NUM_DLCI]; int constipated; /* Asked by remote to shut up */ @@ -1207,8 +1207,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, struct gsm_dlci *dlci = gsm->dlci[0]; /* Modem wishes to close down */ if (dlci) { - dlci->dead = 1; - gsm->dead = 1; + dlci->dead = true; + gsm->dead = true; gsm_dlci_begin_close(dlci); } } @@ -1434,7 +1434,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci) tty_port_tty_hangup(&dlci->port, false); kfifo_reset(&dlci->fifo); } else - dlci->gsm->dead = 1; + dlci->gsm->dead = true; wake_up(&dlci->gsm->event); /* A DLCI 0 close is a MUX termination so we need to kick that back to userspace somehow */ @@ -2081,7 +2081,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm) struct gsm_dlci *dlci = gsm->dlci[0]; struct gsm_msg *txq, *ntxq; - gsm->dead = 1; + gsm->dead = true; spin_lock(&gsm_mux_lock); for (i = 0; i < MAX_MUX; i++) { @@ -2098,7 +2098,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm) del_timer_sync(&gsm->t2_timer); /* Now we are sure T2 has stopped */ if (dlci) - dlci->dead = 1; + dlci->dead = true; /* Free up any link layer users */ mutex_lock(&gsm->mutex); @@ -2152,7 +2152,7 @@ static int gsm_activate_mux(struct gsm_mux *gsm) dlci = gsm_dlci_alloc(gsm, 0); if (dlci == NULL) return -ENOMEM; - gsm->dead = 0; /* Tty opens are now permissible */ + gsm->dead = false; /* Tty opens are now permissible */ return 0; } @@ -2236,7 +2236,7 @@ static struct gsm_mux *gsm_alloc_mux(void) gsm->encoding = 1; gsm->mru = 64; /* Default to encoding 1 so these should be 64 */ gsm->mtu = 64; - gsm->dead = 1; /* Avoid early tty opens */ + gsm->dead = true; /* Avoid early tty opens */ return gsm; } -- cgit From e9360b9a0d4cfac97d31d3958ef6d0614cd405a0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:47 +0100 Subject: n_gsm: switch throttled to bool gsm_dlci->throttled is used as a bool, so treat it as such. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 24ce46e4fb45..6bd51d309c32 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -142,7 +142,7 @@ struct gsm_dlci { u32 modem_tx; /* Our outgoing modem lines */ bool dead; /* Refuse re-open */ /* Flow control */ - int throttled; /* Private copy of throttle state */ + bool throttled; /* Private copy of throttle state */ int constipated; /* Throttle status for outgoing */ /* Packetised I/O */ struct sk_buff *skb; /* Frame being sent */ @@ -3172,7 +3172,7 @@ static void gsmtty_throttle(struct tty_struct *tty) return; if (C_CRTSCTS(tty)) dlci->modem_tx &= ~TIOCM_DTR; - dlci->throttled = 1; + dlci->throttled = true; /* Send an MSC with DTR cleared */ gsmtty_modem_update(dlci, 0); } @@ -3184,7 +3184,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty) return; if (C_CRTSCTS(tty)) dlci->modem_tx |= TIOCM_DTR; - dlci->throttled = 0; + dlci->throttled = false; /* Send an MSC with DTR set */ gsmtty_modem_update(dlci, 0); } -- cgit From 7a9ed9c069f149048ca34c9c0cc0050933bc78f4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:48 +0100 Subject: n_gsm: switch constipated to bool Both gsm_dlci->constipated and gsm_mux->constipated are used as bools, so treat them as such. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-9-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 6bd51d309c32..e0283bb24bb5 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -143,7 +143,7 @@ struct gsm_dlci { bool dead; /* Refuse re-open */ /* Flow control */ bool throttled; /* Private copy of throttle state */ - int constipated; /* Throttle status for outgoing */ + bool constipated; /* Throttle status for outgoing */ /* Packetised I/O */ struct sk_buff *skb; /* Frame being sent */ struct sk_buff_head skb_list; /* Queued frames */ @@ -234,7 +234,7 @@ struct gsm_mux { int initiator; /* Did we initiate connection */ bool dead; /* Has the mux been shut down */ struct gsm_dlci *dlci[NUM_DLCI]; - int constipated; /* Asked by remote to shut up */ + bool constipated; /* Asked by remote to shut up */ spinlock_t tx_lock; unsigned int tx_bytes; /* TX data outstanding */ @@ -1042,9 +1042,9 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, fc = (modem & MDM_FC) || !(modem & MDM_RTR); if (fc && !dlci->constipated) { /* Need to throttle our output on this device */ - dlci->constipated = 1; + dlci->constipated = true; } else if (!fc && dlci->constipated) { - dlci->constipated = 0; + dlci->constipated = false; gsm_dlci_data_kick(dlci); } @@ -1219,7 +1219,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, break; case CMD_FCON: /* Modem can accept data again */ - gsm->constipated = 0; + gsm->constipated = false; gsm_control_reply(gsm, CMD_FCON, NULL, 0); /* Kick the link in case it is idling */ spin_lock_irqsave(&gsm->tx_lock, flags); @@ -1228,7 +1228,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, break; case CMD_FCOFF: /* Modem wants us to STFU */ - gsm->constipated = 1; + gsm->constipated = true; gsm_control_reply(gsm, CMD_FCOFF, NULL, 0); break; case CMD_MSC: -- cgit From c50704bdef9b22551328a25ccacd61c1df700a57 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:49:49 +0100 Subject: n_gsm: switch escape to bool gsm_mux->escape is used as a bool, so treat it as such. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084949.28074-10-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index e0283bb24bb5..d77ed82a4840 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -215,7 +215,7 @@ struct gsm_mux { unsigned int len; unsigned int address; unsigned int count; - int escape; + bool escape; int encoding; u8 control; u8 fcs; @@ -1976,7 +1976,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) } if (c == GSM1_ESCAPE) { - gsm->escape = 1; + gsm->escape = true; return; } @@ -1986,7 +1986,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) if (gsm->escape) { c ^= GSM1_ESCAPE_BITS; - gsm->escape = 0; + gsm->escape = false; } switch (gsm->state) { case GSM_START: /* First byte after SOF */ -- cgit From 175b558d0efb8b4f33aa7bd2c1b5389b912d3019 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 20 Feb 2020 11:26:27 +0100 Subject: tty: serial: samsung_tty: build it for any platform There is no need to tie this driver to only a specific SoC, or compile test, so remove that dependancy from the Kconfig rules. Cc: linux-kernel@vger.kernel.org Cc: linux-serial@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: Jiri Slaby Cc: Shinbeom Choi Cc: HYUN-KI KOO Cc: Hyunki Koo Cc: Donghoon Yu Cc: Kukjin Kim Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200220102628.3371996-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 7172f1c5fa6d..ce1fece86b30 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -237,7 +237,6 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" - depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, -- cgit From 3b3845bb6c78760e97f2d50cce5b527a0fc27ff3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 20 Feb 2020 11:26:28 +0100 Subject: tty: serial: samsung_tty: remove SERIAL_SAMSUNG_DEBUG Since a05025d0ce72 ("tty: serial: samsung_tty: use standard debugging macros") this configuration option is not used at all, so remove it from the Kconfig file. Cc: linux-kernel@vger.kernel.org Cc: linux-serial@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: Jiri Slaby Cc: Shinbeom Choi Cc: HYUN-KI KOO Cc: Hyunki Koo Cc: Donghoon Yu Cc: Kukjin Kim Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200220102628.3371996-2-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index ce1fece86b30..880b96201530 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -259,15 +259,6 @@ config SERIAL_SAMSUNG_UARTS help Select the number of available UART ports for the Samsung S3C serial driver - -config SERIAL_SAMSUNG_DEBUG - bool "Samsung SoC serial debug" - depends on SERIAL_SAMSUNG && DEBUG_LL - help - Add support for debugging the serial driver. Since this is - generally being used as a console, we use our own output - routines that go via the low-level debug printascii() - function. config SERIAL_SAMSUNG_CONSOLE bool "Support for console on Samsung SoC serial port" -- cgit From 66c3bdf11d9d753d8c4c024ca4cd35e7f7fc2eca Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:40:55 +0100 Subject: n_hdlc: remove tracing debug prints We can trace functions using ftrace, so there is no need for this additional prints. Remove them. We keep only those which print some additional info, not only function name & "entry"/"exit". Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 27b506bf03ce..9e115ecf920d 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -232,10 +232,7 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc) { struct tty_struct *tty = n_hdlc2tty (n_hdlc); struct n_hdlc_buf *buf; - - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__); - + /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ wake_up_interruptible (&tty->read_wait); wake_up_interruptible (&tty->write_wait); @@ -287,9 +284,6 @@ static void n_hdlc_tty_close(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__); - if (n_hdlc != NULL) { if (n_hdlc->magic != HDLC_MAGIC) { printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n"); @@ -309,10 +303,6 @@ static void n_hdlc_tty_close(struct tty_struct *tty) n_hdlc_release (n_hdlc); } } - - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__); - } /* end of n_hdlc_tty_close() */ /** @@ -353,10 +343,7 @@ static int n_hdlc_tty_open (struct tty_struct *tty) /* flush receive data from driver */ tty_driver_flush_buffer(tty); - - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__); - + return 0; } /* end of n_tty_hdlc_open() */ @@ -376,8 +363,6 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) unsigned long flags; struct n_hdlc_buf *tbuf; - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__); check_again: spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); @@ -447,10 +432,6 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) if (n_hdlc->woke_up) goto check_again; - - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__); - } /* end of n_hdlc_send_frames() */ /** @@ -463,9 +444,6 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__); - if (!n_hdlc) return; @@ -564,9 +542,6 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, struct n_hdlc_buf *rbuf; DECLARE_WAITQUEUE(wait, current); - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); - /* Validate the pointers */ if (!n_hdlc) return -EIO; @@ -802,9 +777,6 @@ static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, struct n_hdlc *n_hdlc = tty2n_hdlc (tty); __poll_t mask = 0; - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__); - if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) { /* queue current process into any wait queue that */ /* may awaken in the future (read and write) */ -- cgit From 683efabc66225ace701f726316ad0ba2ccd924fb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:40:56 +0100 Subject: n_hdlc: remove unused macros VERSION and bset are unused. Remove them. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 9e115ecf920d..881da4d440c8 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -87,9 +87,6 @@ #include #include -#undef VERSION -#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch)) - #include #include #include @@ -186,8 +183,6 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp, char *fp, int count); static void n_hdlc_tty_wakeup(struct tty_struct *tty); -#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f))) - #define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data)) #define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty) -- cgit From f3c2e27750ea42b3cec96e5264d95c2a2b793156 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:40:57 +0100 Subject: n_hdlc: convert debuglevel use to pr_debug With pr_debug we have a fine-grained control about debugging prints. So convert the use of global debuglevel variable and tests to a commonly used pr_debug. And drop debuglevel completely. This also implicitly adds a loglevel to the messages (KERN_DEBUG) as it was missing on most of them. And also use __func__ instead of function names explicitly typed. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 79 +++++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 48 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 881da4d440c8..e37dab2528a1 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -160,10 +160,6 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list); static struct n_hdlc *n_hdlc_alloc (void); -/* debug level can be set by insmod for debugging purposes */ -#define DEBUG_LEVEL_INFO 1 -static int debuglevel; - /* max frame size for memory allocations */ static int maxframe = 4096; @@ -310,11 +306,9 @@ static int n_hdlc_tty_open (struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n", - __FILE__,__LINE__, - tty->name); - + pr_debug("%s(%d)%s() called (device=%s)\n", + __FILE__, __LINE__, __func__, tty->name); + /* There should not be an existing table for this slot. */ if (n_hdlc) { printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" ); @@ -372,10 +366,9 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); while (tbuf) { - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)sending frame %p, count=%d\n", - __FILE__,__LINE__,tbuf,tbuf->count); - + pr_debug("%s(%d)sending frame %p, count=%d\n", + __FILE__, __LINE__, tbuf, tbuf->count); + /* Send the next block of data to device */ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); actual = tty->ops->write(tty, tbuf->buf, tbuf->count); @@ -391,10 +384,9 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) actual = tbuf->count; if (actual == tbuf->count) { - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)frame %p completed\n", - __FILE__,__LINE__,tbuf); - + pr_debug("%s(%d)frame %p completed\n", + __FILE__, __LINE__, tbuf); + /* free current transmit buffer */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf); @@ -404,9 +396,8 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) /* get next pending transmit buffer */ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); } else { - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)frame %p pending\n", - __FILE__,__LINE__,tbuf); + pr_debug("%s(%d)frame %p pending\n", + __FILE__, __LINE__, tbuf); /* * the buffer was not accepted by driver, @@ -467,10 +458,9 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); register struct n_hdlc_buf *buf; - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_receive() called count=%d\n", - __FILE__,__LINE__, count); - + pr_debug("%s(%d)%s() called count=%d\n", + __FILE__, __LINE__, __func__, count); + /* This can happen if stuff comes in on the backup tty */ if (!n_hdlc || tty != n_hdlc->tty) return; @@ -483,9 +473,8 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, } if ( count>maxframe ) { - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d) rx count>maxframesize, data discarded\n", - __FILE__,__LINE__); + pr_debug("%s(%d) rx count>maxframesize, data discarded\n", + __FILE__, __LINE__); return; } @@ -500,9 +489,8 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, } if (!buf) { - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d) no more rx buffers, data discarded\n", - __FILE__,__LINE__); + pr_debug("%s(%d) no more rx buffers, data discarded\n", + __FILE__, __LINE__); return; } @@ -619,10 +607,9 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, DECLARE_WAITQUEUE(wait, current); struct n_hdlc_buf *tbuf; - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_write() called count=%zd\n", - __FILE__,__LINE__,count); - + pr_debug("%s(%d)%s() called count=%zd\n", __FILE__, __LINE__, __func__, + count); + /* Verify pointers */ if (!n_hdlc) return -EIO; @@ -632,11 +619,8 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, /* verify frame size */ if (count > maxframe ) { - if (debuglevel & DEBUG_LEVEL_INFO) - printk (KERN_WARNING - "n_hdlc_tty_write: truncating user packet " - "from %lu to %d\n", (unsigned long) count, - maxframe ); + pr_debug("%s: truncating user packet from %zu to %d\n", + __func__, count, maxframe); count = maxframe; } @@ -704,10 +688,8 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned long flags; struct n_hdlc_buf *buf = NULL; - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_ioctl() called %d\n", - __FILE__,__LINE__,cmd); - + pr_debug("%s(%d)%s() called %d\n", __FILE__, __LINE__, __func__, cmd); + /* Verify the status of the device */ if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC) return -EBADF; @@ -822,8 +804,9 @@ static struct n_hdlc *n_hdlc_alloc(void) buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL); if (buf) n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf); - else if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i); + else + pr_debug("%s(%d)%s(), kmalloc() failed for rx buffer %d\n", + __FILE__, __LINE__, __func__, i); } /* allocate free tx buffer list */ @@ -831,8 +814,9 @@ static struct n_hdlc *n_hdlc_alloc(void) buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL); if (buf) n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf); - else if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i); + else + pr_debug("%s(%d)%s(), kmalloc() failed for tx buffer %d\n", + __FILE__, __LINE__, __func__, i); } /* Initialize the control block */ @@ -960,6 +944,5 @@ module_exit(n_hdlc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com"); -module_param(debuglevel, int, 0); module_param(maxframe, int, 0); MODULE_ALIAS_LDISC(N_HDLC); -- cgit From aebe5fc3b5685e1d9b86cc8314a8e8f3c6f3284e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:40:58 +0100 Subject: n_hdlc: put init/exit strings directly to prints These strings were put aside from prints to save some bytes after module load or when built-in -- they were freed after module load (__init ones) or when the driver is selected as built-in (__exit ones). The savings are negligible, but the code readability is worse by the order of magnitude. So put the strings where they belong. Note that it also used to make little sense putting const data in .data (the __exit case). While at it, switch to pr_info, pr_err, not using the KERN_INFO and _ERR directly. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index e37dab2528a1..b651b5ba64ee 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -889,13 +889,6 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list) return buf; } /* end of n_hdlc_buf_get() */ -static const char hdlc_banner[] __initconst = - KERN_INFO "HDLC line discipline maxframe=%u\n"; -static const char hdlc_register_ok[] __initconst = - KERN_INFO "N_HDLC line discipline registered.\n"; -static const char hdlc_register_fail[] __initconst = - KERN_ERR "error registering line discipline: %d\n"; - static int __init n_hdlc_init(void) { int status; @@ -906,37 +899,28 @@ static int __init n_hdlc_init(void) else if (maxframe > 65535) maxframe = 65535; - printk(hdlc_banner, maxframe); + pr_info("HDLC line discipline maxframe=%d\n", maxframe); status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc); if (!status) - printk(hdlc_register_ok); + pr_info("N_HDLC line discipline registered.\n"); else - printk(hdlc_register_fail, status); + pr_err("error registering line discipline: %d\n", status); return status; } /* end of init_module() */ -#ifdef CONFIG_SPARC -#undef __exitdata -#define __exitdata -#endif - -static const char hdlc_unregister_ok[] __exitdata = - KERN_INFO "N_HDLC: line discipline unregistered\n"; -static const char hdlc_unregister_fail[] __exitdata = - KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n"; - static void __exit n_hdlc_exit(void) { /* Release tty registration of line discipline */ int status = tty_unregister_ldisc(N_HDLC); if (status) - printk(hdlc_unregister_fail, status); + pr_err("N_HDLC: can't unregister line discipline (err = %d)\n", + status); else - printk(hdlc_unregister_ok); + pr_info("N_HDLC: line discipline unregistered\n"); } module_init(n_hdlc_init); -- cgit From cda3756ca5c4308c4cb1110209f27b49a680409a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:40:59 +0100 Subject: n_hdlc: cleanup messages during registration 1) n_hdlc prints two lines during registration. Squeeze it into one. 2) prefix the error message with "N_HDLC: ", so that it's clear which ldisc failed to register. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index b651b5ba64ee..87f22e57e4f6 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -899,13 +899,13 @@ static int __init n_hdlc_init(void) else if (maxframe > 65535) maxframe = 65535; - pr_info("HDLC line discipline maxframe=%d\n", maxframe); - status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc); if (!status) - pr_info("N_HDLC line discipline registered.\n"); + pr_info("N_HDLC line discipline registered with maxframe=%d\n", + maxframe); else - pr_err("error registering line discipline: %d\n", status); + pr_err("N_HDLC: error registering line discipline: %d\n", + status); return status; -- cgit From c549725ff85ab2dee1b8453a92ab437150ece800 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:00 +0100 Subject: n_hdlc: use clamp() for maxframe It is easier to read. And use MAX_HDLC_FRAME_SIZE instead of magic constant. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 87f22e57e4f6..a713a98fea2e 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -894,10 +894,7 @@ static int __init n_hdlc_init(void) int status; /* range check maxframe arg */ - if (maxframe < 4096) - maxframe = 4096; - else if (maxframe > 65535) - maxframe = 65535; + maxframe = clamp(maxframe, 4096, MAX_HDLC_FRAME_SIZE); status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc); if (!status) -- cgit From 30fafd92c272d238efe781a5daeaa4af2824067a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:01 +0100 Subject: n_hdlc: simplify freeing of buffer list n_hdlc_release contains four loops to free each buffer list. Create a helper (n_hdlc_free_buf_list) and call it for every list instead. It makes n_hdlc_release more readable. We are switching from "for (;;)" to "do {} while (buf)" which avoids the "if (buf)" completely -- kfree is a nop for NULL pointers. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 45 ++++++++++++++------------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index a713a98fea2e..07ba42badd7a 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -215,6 +215,16 @@ static struct tty_ldisc_ops n_hdlc_ldisc = { .flush_buffer = flush_rx_queue, }; +static void n_hdlc_free_buf_list(struct n_hdlc_buf_list *list) +{ + struct n_hdlc_buf *buf; + + do { + buf = n_hdlc_buf_get(list); + kfree(buf); + } while (buf); +} + /** * n_hdlc_release - release an n_hdlc per device line discipline info structure * @n_hdlc - per device line discipline info structure @@ -222,7 +232,6 @@ static struct tty_ldisc_ops n_hdlc_ldisc = { static void n_hdlc_release(struct n_hdlc *n_hdlc) { struct tty_struct *tty = n_hdlc2tty (n_hdlc); - struct n_hdlc_buf *buf; /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ wake_up_interruptible (&tty->read_wait); @@ -231,37 +240,11 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc) if (tty->disc_data == n_hdlc) tty->disc_data = NULL; /* Break the tty->n_hdlc link */ - /* Release transmit and receive buffers */ - for(;;) { - buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); - if (buf) { - kfree(buf); - } else - break; - } - for(;;) { - buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); - if (buf) { - kfree(buf); - } else - break; - } - for(;;) { - buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); - if (buf) { - kfree(buf); - } else - break; - } - for(;;) { - buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); - if (buf) { - kfree(buf); - } else - break; - } + n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list); + n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list); + n_hdlc_free_buf_list(&n_hdlc->rx_buf_list); + n_hdlc_free_buf_list(&n_hdlc->tx_buf_list); kfree(n_hdlc); - } /* end of n_hdlc_release() */ /** -- cgit From 5f2895143d5e18641bcbdea70029d17cd5650201 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:02 +0100 Subject: n_hdlc: invert conditions in n_hdlc_tty_close and n_hdlc_tty_poll This makes the functions return immediatelly on invalid state. And we can push the indent of the later code one level left. Pass "-w" to "git show" to see we are changing only the conditions (and whitespace). Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 72 +++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 34 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 07ba42badd7a..e40561caa450 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -258,24 +258,25 @@ static void n_hdlc_tty_close(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); - if (n_hdlc != NULL) { - if (n_hdlc->magic != HDLC_MAGIC) { - printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n"); - return; - } + if (!n_hdlc) + return; + + if (n_hdlc->magic != HDLC_MAGIC) { + printk(KERN_WARNING "n_hdlc: trying to close unopened tty!\n"); + return; + } #if defined(TTY_NO_WRITE_SPLIT) - clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags); + clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags); #endif - tty->disc_data = NULL; - if (tty == n_hdlc->backup_tty) - n_hdlc->backup_tty = NULL; - if (tty != n_hdlc->tty) - return; - if (n_hdlc->backup_tty) { - n_hdlc->tty = n_hdlc->backup_tty; - } else { - n_hdlc_release (n_hdlc); - } + tty->disc_data = NULL; + if (tty == n_hdlc->backup_tty) + n_hdlc->backup_tty = NULL; + if (tty != n_hdlc->tty) + return; + if (n_hdlc->backup_tty) { + n_hdlc->tty = n_hdlc->backup_tty; + } else { + n_hdlc_release (n_hdlc); } } /* end of n_hdlc_tty_close() */ @@ -737,24 +738,27 @@ static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, struct n_hdlc *n_hdlc = tty2n_hdlc (tty); __poll_t mask = 0; - if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) { - /* queue current process into any wait queue that */ - /* may awaken in the future (read and write) */ - - poll_wait(filp, &tty->read_wait, wait); - poll_wait(filp, &tty->write_wait, wait); - - /* set bits for operations that won't block */ - if (!list_empty(&n_hdlc->rx_buf_list.list)) - mask |= EPOLLIN | EPOLLRDNORM; /* readable */ - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) - mask |= EPOLLHUP; - if (tty_hung_up_p(filp)) - mask |= EPOLLHUP; - if (!tty_is_writelocked(tty) && - !list_empty(&n_hdlc->tx_free_buf_list.list)) - mask |= EPOLLOUT | EPOLLWRNORM; /* writable */ - } + if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) + return 0; + + /* + * queue the current process into any wait queue that may awaken in the + * future (read and write) + */ + poll_wait(filp, &tty->read_wait, wait); + poll_wait(filp, &tty->write_wait, wait); + + /* set bits for operations that won't block */ + if (!list_empty(&n_hdlc->rx_buf_list.list)) + mask |= EPOLLIN | EPOLLRDNORM; /* readable */ + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + mask |= EPOLLHUP; + if (tty_hung_up_p(filp)) + mask |= EPOLLHUP; + if (!tty_is_writelocked(tty) && + !list_empty(&n_hdlc->tx_free_buf_list.list)) + mask |= EPOLLOUT | EPOLLWRNORM; /* writable */ + return mask; } /* end of n_hdlc_tty_poll() */ -- cgit From a1274b26ac2780ea21ef69507421b43d0f5a8a4a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:03 +0100 Subject: n_hdlc: remove unused flags They are only set to 0 and never read. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-9-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index e40561caa450..d0e538ba51ea 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -124,7 +124,6 @@ struct n_hdlc_buf_list { /** * struct n_hdlc - per device instance data structure * @magic - magic value for structure - * @flags - miscellaneous control flags * @tty - ptr to TTY structure * @backup_tty - TTY to use if tty gets closed * @tbusy - reentrancy flag for tx wakeup code @@ -136,7 +135,6 @@ struct n_hdlc_buf_list { */ struct n_hdlc { int magic; - __u32 flags; struct tty_struct *tty; struct tty_struct *backup_tty; int tbusy; @@ -808,8 +806,7 @@ static struct n_hdlc *n_hdlc_alloc(void) /* Initialize the control block */ n_hdlc->magic = HDLC_MAGIC; - n_hdlc->flags = 0; - + return n_hdlc; } /* end of n_hdlc_alloc() */ -- cgit From 4040c828607975fbdc4c557a85bde115c524e857 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:04 +0100 Subject: n_hdlc: remove unused backup_tty It's only set to NULL and never properly used. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-10-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index d0e538ba51ea..ae6b9a45ae81 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -125,7 +125,6 @@ struct n_hdlc_buf_list { * struct n_hdlc - per device instance data structure * @magic - magic value for structure * @tty - ptr to TTY structure - * @backup_tty - TTY to use if tty gets closed * @tbusy - reentrancy flag for tx wakeup code * @woke_up - FIXME: describe this field * @tx_buf_list - list of pending transmit frame buffers @@ -136,7 +135,6 @@ struct n_hdlc_buf_list { struct n_hdlc { int magic; struct tty_struct *tty; - struct tty_struct *backup_tty; int tbusy; int woke_up; struct n_hdlc_buf_list tx_buf_list; @@ -267,15 +265,9 @@ static void n_hdlc_tty_close(struct tty_struct *tty) clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags); #endif tty->disc_data = NULL; - if (tty == n_hdlc->backup_tty) - n_hdlc->backup_tty = NULL; if (tty != n_hdlc->tty) return; - if (n_hdlc->backup_tty) { - n_hdlc->tty = n_hdlc->backup_tty; - } else { - n_hdlc_release (n_hdlc); - } + n_hdlc_release (n_hdlc); } /* end of n_hdlc_tty_close() */ /** -- cgit From 75011682e7c57b085adb49e8305647ccfadbcf6a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:05 +0100 Subject: n_hdlc: expand tty2n_hdlc macro It's simple tty->disc_data, but it obfuscates code. So expand it to all locations and drop it. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-11-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index ae6b9a45ae81..67162611af58 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -175,12 +175,11 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp, char *fp, int count); static void n_hdlc_tty_wakeup(struct tty_struct *tty); -#define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data)) #define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty) static void flush_rx_queue(struct tty_struct *tty) { - struct n_hdlc *n_hdlc = tty2n_hdlc(tty); + struct n_hdlc *n_hdlc = tty->disc_data; struct n_hdlc_buf *buf; while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list))) @@ -189,7 +188,7 @@ static void flush_rx_queue(struct tty_struct *tty) static void flush_tx_queue(struct tty_struct *tty) { - struct n_hdlc *n_hdlc = tty2n_hdlc(tty); + struct n_hdlc *n_hdlc = tty->disc_data; struct n_hdlc_buf *buf; while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list))) @@ -252,7 +251,7 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc) */ static void n_hdlc_tty_close(struct tty_struct *tty) { - struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + struct n_hdlc *n_hdlc = tty->disc_data; if (!n_hdlc) return; @@ -278,7 +277,7 @@ static void n_hdlc_tty_close(struct tty_struct *tty) */ static int n_hdlc_tty_open (struct tty_struct *tty) { - struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + struct n_hdlc *n_hdlc = tty->disc_data; pr_debug("%s(%d)%s() called (device=%s)\n", __FILE__, __LINE__, __func__, tty->name); @@ -402,7 +401,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) */ static void n_hdlc_tty_wakeup(struct tty_struct *tty) { - struct n_hdlc *n_hdlc = tty2n_hdlc(tty); + struct n_hdlc *n_hdlc = tty->disc_data; if (!n_hdlc) return; @@ -429,7 +428,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count) { - register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + register struct n_hdlc *n_hdlc = tty->disc_data; register struct n_hdlc_buf *buf; pr_debug("%s(%d)%s() called count=%d\n", @@ -494,7 +493,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, __u8 __user *buf, size_t nr) { - struct n_hdlc *n_hdlc = tty2n_hdlc(tty); + struct n_hdlc *n_hdlc = tty->disc_data; int ret = 0; struct n_hdlc_buf *rbuf; DECLARE_WAITQUEUE(wait, current); @@ -576,7 +575,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) { - struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + struct n_hdlc *n_hdlc = tty->disc_data; int error = 0; DECLARE_WAITQUEUE(wait, current); struct n_hdlc_buf *tbuf; @@ -613,7 +612,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, } schedule(); - n_hdlc = tty2n_hdlc (tty); + n_hdlc = tty->disc_data; if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) { printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc); @@ -656,7 +655,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + struct n_hdlc *n_hdlc = tty->disc_data; int error = 0; int count; unsigned long flags; @@ -725,7 +724,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) { - struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + struct n_hdlc *n_hdlc = tty->disc_data; __poll_t mask = 0; if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) -- cgit From 43e784eca86a38a957db4022b3e40efbb663b091 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:06 +0100 Subject: n_hdlc: inline n_hdlc_release Put the body of n_hdlc_release into the only caller. It can be seen, that the "if" is superfluous now -- the same happens few lines above in n_hdlc_tty_close already. So drop it. Drop also n_hdlc2tty macro as this was the only user. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-12-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 67162611af58..39a58febd896 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -175,8 +175,6 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp, char *fp, int count); static void n_hdlc_tty_wakeup(struct tty_struct *tty); -#define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty) - static void flush_rx_queue(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty->disc_data; @@ -220,28 +218,6 @@ static void n_hdlc_free_buf_list(struct n_hdlc_buf_list *list) } while (buf); } -/** - * n_hdlc_release - release an n_hdlc per device line discipline info structure - * @n_hdlc - per device line discipline info structure - */ -static void n_hdlc_release(struct n_hdlc *n_hdlc) -{ - struct tty_struct *tty = n_hdlc2tty (n_hdlc); - - /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ - wake_up_interruptible (&tty->read_wait); - wake_up_interruptible (&tty->write_wait); - - if (tty->disc_data == n_hdlc) - tty->disc_data = NULL; /* Break the tty->n_hdlc link */ - - n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list); - n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list); - n_hdlc_free_buf_list(&n_hdlc->rx_buf_list); - n_hdlc_free_buf_list(&n_hdlc->tx_buf_list); - kfree(n_hdlc); -} /* end of n_hdlc_release() */ - /** * n_hdlc_tty_close - line discipline close * @tty - pointer to tty info structure @@ -266,7 +242,16 @@ static void n_hdlc_tty_close(struct tty_struct *tty) tty->disc_data = NULL; if (tty != n_hdlc->tty) return; - n_hdlc_release (n_hdlc); + + /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ + wake_up_interruptible(&tty->read_wait); + wake_up_interruptible(&tty->write_wait); + + n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list); + n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list); + n_hdlc_free_buf_list(&n_hdlc->rx_buf_list); + n_hdlc_free_buf_list(&n_hdlc->tx_buf_list); + kfree(n_hdlc); } /* end of n_hdlc_tty_close() */ /** -- cgit From df6de639d42cce92f56b4a0583896f590fe046b8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:07 +0100 Subject: n_hdlc: remove cached tty It's not needed, as now it's clear, that it's always the same as the one passed from the tty layer. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-13-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 39a58febd896..2ac702974b57 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -124,7 +124,6 @@ struct n_hdlc_buf_list { /** * struct n_hdlc - per device instance data structure * @magic - magic value for structure - * @tty - ptr to TTY structure * @tbusy - reentrancy flag for tx wakeup code * @woke_up - FIXME: describe this field * @tx_buf_list - list of pending transmit frame buffers @@ -134,7 +133,6 @@ struct n_hdlc_buf_list { */ struct n_hdlc { int magic; - struct tty_struct *tty; int tbusy; int woke_up; struct n_hdlc_buf_list tx_buf_list; @@ -240,8 +238,6 @@ static void n_hdlc_tty_close(struct tty_struct *tty) clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags); #endif tty->disc_data = NULL; - if (tty != n_hdlc->tty) - return; /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ wake_up_interruptible(&tty->read_wait); @@ -280,7 +276,6 @@ static int n_hdlc_tty_open (struct tty_struct *tty) } tty->disc_data = n_hdlc; - n_hdlc->tty = tty; tty->receive_room = 65536; #if defined(TTY_NO_WRITE_SPLIT) @@ -391,11 +386,6 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) if (!n_hdlc) return; - if (tty != n_hdlc->tty) { - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - return; - } - n_hdlc_send_frames (n_hdlc, tty); } /* end of n_hdlc_tty_wakeup() */ @@ -420,7 +410,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, __FILE__, __LINE__, __func__, count); /* This can happen if stuff comes in on the backup tty */ - if (!n_hdlc || tty != n_hdlc->tty) + if (!n_hdlc) return; /* verify line is using HDLC discipline */ @@ -461,8 +451,8 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&tty->read_wait); - if (n_hdlc->tty->fasync != NULL) - kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN); + if (tty->fasync != NULL) + kill_fasync(&tty->fasync, SIGIO, POLL_IN); } /* end of n_hdlc_tty_receive() */ @@ -598,8 +588,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, schedule(); n_hdlc = tty->disc_data; - if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || - tty != n_hdlc->tty) { + if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC) { printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc); error = -EIO; break; @@ -712,7 +701,7 @@ static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, struct n_hdlc *n_hdlc = tty->disc_data; __poll_t mask = 0; - if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) + if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC) return 0; /* -- cgit From 844cc5f9e530da7502b0de69f0268b1fb0dd7ce3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:08 +0100 Subject: n_hdlc: remove checking of n_hdlc We got rid of backup_tty recently. Also, the tty layer ensures not to call other ldisc hooks after ldisc close. That means, all those tests are superfluous now so remove them. Note that we remove the magic check in write after schedule too. The tty cannot change during schedule. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-14-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 2ac702974b57..2709d18364eb 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -227,9 +227,6 @@ static void n_hdlc_tty_close(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty->disc_data; - if (!n_hdlc) - return; - if (n_hdlc->magic != HDLC_MAGIC) { printk(KERN_WARNING "n_hdlc: trying to close unopened tty!\n"); return; @@ -383,11 +380,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty->disc_data; - if (!n_hdlc) - return; - n_hdlc_send_frames (n_hdlc, tty); - } /* end of n_hdlc_tty_wakeup() */ /** @@ -409,10 +402,6 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, pr_debug("%s(%d)%s() called count=%d\n", __FILE__, __LINE__, __func__, count); - /* This can happen if stuff comes in on the backup tty */ - if (!n_hdlc) - return; - /* verify line is using HDLC discipline */ if (n_hdlc->magic != HDLC_MAGIC) { printk("%s(%d) line not using HDLC discipline\n", @@ -473,10 +462,6 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, struct n_hdlc_buf *rbuf; DECLARE_WAITQUEUE(wait, current); - /* Validate the pointers */ - if (!n_hdlc) - return -EIO; - /* verify user access to buffer */ if (!access_ok(buf, nr)) { printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user " @@ -558,10 +543,6 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, pr_debug("%s(%d)%s() called count=%zd\n", __FILE__, __LINE__, __func__, count); - /* Verify pointers */ - if (!n_hdlc) - return -EIO; - if (n_hdlc->magic != HDLC_MAGIC) return -EIO; @@ -586,14 +567,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, break; } schedule(); - - n_hdlc = tty->disc_data; - if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC) { - printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc); - error = -EIO; - break; - } - + if (signal_pending(current)) { error = -EINTR; break; @@ -638,7 +612,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, pr_debug("%s(%d)%s() called %d\n", __FILE__, __LINE__, __func__, cmd); /* Verify the status of the device */ - if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC) + if (n_hdlc->magic != HDLC_MAGIC) return -EBADF; switch (cmd) { @@ -701,7 +675,7 @@ static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, struct n_hdlc *n_hdlc = tty->disc_data; __poll_t mask = 0; - if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC) + if (n_hdlc->magic != HDLC_MAGIC) return 0; /* -- cgit From 740708abbba281480f2986418c8acf2b540f0e98 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:09 +0100 Subject: n_hdlc: add helper for buffers allocation Given both rx and tx allocations do the same, add a new helper (n_hdlc_alloc_buf) and use it for both of them. This cleans up n_hdlc_alloc slightly. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-15-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 2709d18364eb..4276931fd071 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -699,6 +699,23 @@ static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, return mask; } /* end of n_hdlc_tty_poll() */ +static void n_hdlc_alloc_buf(struct n_hdlc_buf_list *list, unsigned int count, + const char *name) +{ + struct n_hdlc_buf *buf; + unsigned int i; + + for (i = 0; i < count; i++) { + buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL); + if (!buf) { + pr_debug("%s(%d)%s(), kmalloc() failed for %s buffer %u\n", + __FILE__, __LINE__, __func__, name, i); + return; + } + n_hdlc_buf_put(list, buf); + } +} + /** * n_hdlc_alloc - allocate an n_hdlc instance data structure * @@ -706,8 +723,6 @@ static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, */ static struct n_hdlc *n_hdlc_alloc(void) { - struct n_hdlc_buf *buf; - int i; struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL); if (!n_hdlc) @@ -723,26 +738,9 @@ static struct n_hdlc *n_hdlc_alloc(void) INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list); INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list); - /* allocate free rx buffer list */ - for(i=0;irx_free_buf_list,buf); - else - pr_debug("%s(%d)%s(), kmalloc() failed for rx buffer %d\n", - __FILE__, __LINE__, __func__, i); - } - - /* allocate free tx buffer list */ - for(i=0;itx_free_buf_list,buf); - else - pr_debug("%s(%d)%s(), kmalloc() failed for tx buffer %d\n", - __FILE__, __LINE__, __func__, i); - } - + n_hdlc_alloc_buf(&n_hdlc->rx_free_buf_list, DEFAULT_RX_BUF_COUNT, "rx"); + n_hdlc_alloc_buf(&n_hdlc->tx_free_buf_list, DEFAULT_TX_BUF_COUNT, "tx"); + /* Initialize the control block */ n_hdlc->magic = HDLC_MAGIC; -- cgit From edee649f9d278e322ff107ce8d2539522b76a388 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:10 +0100 Subject: n_hdlc: move tty_ldisc_ops to the bottom This makes forward declarations unnecessary. So drop them. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-16-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 46 +++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 4276931fd071..615abe582cac 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -157,22 +157,6 @@ static struct n_hdlc *n_hdlc_alloc (void); /* max frame size for memory allocations */ static int maxframe = 4096; -/* TTY callbacks */ - -static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, - __u8 __user *buf, size_t nr); -static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr); -static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); -static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, - poll_table *wait); -static int n_hdlc_tty_open(struct tty_struct *tty); -static void n_hdlc_tty_close(struct tty_struct *tty); -static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp, - char *fp, int count); -static void n_hdlc_tty_wakeup(struct tty_struct *tty); - static void flush_rx_queue(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty->disc_data; @@ -191,21 +175,6 @@ static void flush_tx_queue(struct tty_struct *tty) n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf); } -static struct tty_ldisc_ops n_hdlc_ldisc = { - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "hdlc", - .open = n_hdlc_tty_open, - .close = n_hdlc_tty_close, - .read = n_hdlc_tty_read, - .write = n_hdlc_tty_write, - .ioctl = n_hdlc_tty_ioctl, - .poll = n_hdlc_tty_poll, - .receive_buf = n_hdlc_tty_receive, - .write_wakeup = n_hdlc_tty_wakeup, - .flush_buffer = flush_rx_queue, -}; - static void n_hdlc_free_buf_list(struct n_hdlc_buf_list *list) { struct n_hdlc_buf *buf; @@ -810,6 +779,21 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list) return buf; } /* end of n_hdlc_buf_get() */ +static struct tty_ldisc_ops n_hdlc_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "hdlc", + .open = n_hdlc_tty_open, + .close = n_hdlc_tty_close, + .read = n_hdlc_tty_read, + .write = n_hdlc_tty_write, + .ioctl = n_hdlc_tty_ioctl, + .poll = n_hdlc_tty_poll, + .receive_buf = n_hdlc_tty_receive, + .write_wakeup = n_hdlc_tty_wakeup, + .flush_buffer = flush_rx_queue, +}; + static int __init n_hdlc_init(void) { int status; -- cgit From 0f2382981442504d6b92fc300312646aaa5fd6b3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:11 +0100 Subject: n_hdlc: switch tbusy and woke_up to bools They are in fact bools, so save some bytes (8B on x86_64). Also describe @woke_up as we know what it is. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-17-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 615abe582cac..c4fe09124185 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -125,7 +125,7 @@ struct n_hdlc_buf_list { * struct n_hdlc - per device instance data structure * @magic - magic value for structure * @tbusy - reentrancy flag for tx wakeup code - * @woke_up - FIXME: describe this field + * @woke_up - tx wakeup needs to be run again as it was called while @tbusy * @tx_buf_list - list of pending transmit frame buffers * @rx_buf_list - list of received frame buffers * @tx_free_buf_list - list unused transmit frame buffers @@ -133,8 +133,8 @@ struct n_hdlc_buf_list { */ struct n_hdlc { int magic; - int tbusy; - int woke_up; + bool tbusy; + bool woke_up; struct n_hdlc_buf_list tx_buf_list; struct n_hdlc_buf_list rx_buf_list; struct n_hdlc_buf_list tx_free_buf_list; @@ -275,12 +275,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->tbusy) { - n_hdlc->woke_up = 1; - spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); + n_hdlc->woke_up = true; + spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); return; } - n_hdlc->tbusy = 1; - n_hdlc->woke_up = 0; + n_hdlc->tbusy = true; + n_hdlc->woke_up = false; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); @@ -332,7 +332,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) /* Clear the re-entry flag */ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); - n_hdlc->tbusy = 0; + n_hdlc->tbusy = false; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->woke_up) -- cgit From b9c010dfe85e2e91bbf2b625b680f340346ad443 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:12 +0100 Subject: n_hdlc: remove unneeded ifdef TTY_NO_WRITE_SPLIT is (always) defined in linux/tty.h, so no need to check for it. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-18-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index c4fe09124185..cf8485beaccd 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -244,10 +244,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty) tty->disc_data = n_hdlc; tty->receive_room = 65536; -#if defined(TTY_NO_WRITE_SPLIT) /* change tty_io write() to not split large writes into 8K chunks */ set_bit(TTY_NO_WRITE_SPLIT,&tty->flags); -#endif /* flush receive data from driver */ tty_driver_flush_buffer(tty); -- cgit From d86b05cb0e20a52a7e7bbfbcf116d3c792481b57 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:13 +0100 Subject: n_hdlc: use __func__ and pr_ print helpers * we mark the message in n_hdlc_tty_receive as error * we use __func__ instead of explicit function name * we switch the remaining prints to pr_* helpers Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-19-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index cf8485beaccd..048e5a155bea 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -197,7 +197,7 @@ static void n_hdlc_tty_close(struct tty_struct *tty) struct n_hdlc *n_hdlc = tty->disc_data; if (n_hdlc->magic != HDLC_MAGIC) { - printk(KERN_WARNING "n_hdlc: trying to close unopened tty!\n"); + pr_warn("n_hdlc: trying to close unopened tty!\n"); return; } #if defined(TTY_NO_WRITE_SPLIT) @@ -231,13 +231,13 @@ static int n_hdlc_tty_open (struct tty_struct *tty) /* There should not be an existing table for this slot. */ if (n_hdlc) { - printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" ); + pr_err("%s: tty already associated!\n", __func__); return -EEXIST; } n_hdlc = n_hdlc_alloc(); if (!n_hdlc) { - printk (KERN_ERR "n_hdlc_alloc failed\n"); + pr_err("%s: n_hdlc_alloc failed\n", __func__); return -ENFILE; } @@ -371,8 +371,8 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, /* verify line is using HDLC discipline */ if (n_hdlc->magic != HDLC_MAGIC) { - printk("%s(%d) line not using HDLC discipline\n", - __FILE__,__LINE__); + pr_err("%s(%d) line not using HDLC discipline\n", + __FILE__, __LINE__); return; } @@ -431,8 +431,8 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, /* verify user access to buffer */ if (!access_ok(buf, nr)) { - printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user " - "buffer\n", __FILE__, __LINE__); + pr_warn("%s(%d) %s() can't verify user buffer\n", + __FILE__, __LINE__, __func__); return -EFAULT; } -- cgit From 43741e9bc0fb42d01e0eabad7fcfee66a9f0e21a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:14 +0100 Subject: n_hdlc: remove useless whitespace at line wraps Do s@[ \t]\+$@@ s@ \+\t@\t@ on the file as there are many spaces at the begininning of lines and many spaces/tabs at EOLs. And vim screamed. git show -w is supposed to show no difference here. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-20-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 74 ++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 048e5a155bea..ee27573b0624 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -18,7 +18,7 @@ * All HDLC data is frame oriented which means: * * 1. tty write calls represent one complete transmit frame of data - * The device driver should accept the complete frame or none of + * The device driver should accept the complete frame or none of * the frame (busy) in the write method. Each write call should have * a byte count in the range of 2-65535 bytes (2 is min HDLC frame * with 1 addr byte and 1 ctrl byte). The max byte count of 65535 @@ -39,7 +39,7 @@ * tty read calls. * * 3. tty read calls returns an entire frame of data or nothing. - * + * * 4. all send and receive data is considered raw. No processing * or translation is performed by the line discipline, regardless * of the tty flags @@ -104,7 +104,7 @@ /* * Buffers for individual HDLC frames */ -#define MAX_HDLC_FRAME_SIZE 65535 +#define MAX_HDLC_FRAME_SIZE 65535 #define DEFAULT_RX_BUF_COUNT 10 #define MAX_RX_BUF_COUNT 60 #define DEFAULT_TX_BUF_COUNT 3 @@ -234,24 +234,24 @@ static int n_hdlc_tty_open (struct tty_struct *tty) pr_err("%s: tty already associated!\n", __func__); return -EEXIST; } - + n_hdlc = n_hdlc_alloc(); if (!n_hdlc) { pr_err("%s: n_hdlc_alloc failed\n", __func__); return -ENFILE; } - + tty->disc_data = n_hdlc; tty->receive_room = 65536; - + /* change tty_io write() to not split large writes into 8K chunks */ set_bit(TTY_NO_WRITE_SPLIT,&tty->flags); - + /* flush receive data from driver */ tty_driver_flush_buffer(tty); return 0; - + } /* end of n_tty_hdlc_open() */ /** @@ -269,9 +269,9 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) unsigned long flags; struct n_hdlc_buf *tbuf; - check_again: - - spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); +check_again: + + spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->tbusy) { n_hdlc->woke_up = true; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); @@ -299,7 +299,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) /* pretending it was accepted by driver */ if (actual < 0) actual = tbuf->count; - + if (actual == tbuf->count) { pr_debug("%s(%d)frame %p completed\n", __FILE__, __LINE__, tbuf); @@ -309,7 +309,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) /* wait up sleeping writers */ wake_up_interruptible(&tty->write_wait); - + /* get next pending transmit buffer */ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); } else { @@ -324,17 +324,17 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) break; } } - + if (!tbuf) clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - + /* Clear the re-entry flag */ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); n_hdlc->tbusy = false; - spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); - - if (n_hdlc->woke_up) - goto check_again; + spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); + + if (n_hdlc->woke_up) + goto check_again; } /* end of n_hdlc_send_frames() */ /** @@ -375,14 +375,14 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, __FILE__, __LINE__); return; } - + if ( count>maxframe ) { pr_debug("%s(%d) rx count>maxframesize, data discarded\n", __FILE__, __LINE__); return; } - /* get a free HDLC buffer */ + /* get a free HDLC buffer */ buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (!buf) { /* no buffers in free list, attempt to allocate another rx buffer */ @@ -391,20 +391,20 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, buf = kmalloc(struct_size(buf, buf, maxframe), GFP_ATOMIC); } - + if (!buf) { pr_debug("%s(%d) no more rx buffers, data discarded\n", __FILE__, __LINE__); return; } - + /* copy received data to HDLC buffer */ memcpy(buf->buf,data,count); buf->count=count; /* add HDLC buffer to list of received frames */ n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf); - + /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&tty->read_wait); if (tty->fasync != NULL) @@ -418,7 +418,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, * @file - pointer to open file object * @buf - pointer to returned data buffer * @nr - size of returned data buffer - * + * * Returns the number of bytes returned or error code. */ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, @@ -468,7 +468,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf); break; } - + /* no data */ if (tty_io_nonblock(tty, file)) { ret = -EAGAIN; @@ -487,7 +487,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, __set_current_state(TASK_RUNNING); return ret; - + } /* end of n_hdlc_tty_read() */ /** @@ -496,7 +496,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, * @file - pointer to file object data * @data - pointer to transmit data (one frame) * @count - size of transmit frame in bytes - * + * * Returns the number of bytes written (or error code). */ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, @@ -519,12 +519,12 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, __func__, count, maxframe); count = maxframe; } - + add_wait_queue(&tty->write_wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - + tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); if (tbuf) break; @@ -544,7 +544,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, __set_current_state(TASK_RUNNING); remove_wait_queue(&tty->write_wait, &wait); - if (!error) { + if (!error) { /* Retrieve the user's buffer */ memcpy(tbuf->buf, data, count); @@ -555,7 +555,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, } return error; - + } /* end of n_hdlc_tty_write() */ /** @@ -623,7 +623,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, break; } return error; - + } /* end of n_hdlc_tty_ioctl() */ /** @@ -631,7 +631,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, * @tty - pointer to tty instance data * @filp - pointer to open file object for device * @poll_table - wait queue for operations - * + * * Determine which operations (read/write) will not block and return info * to caller. * Returns a bit mask containing info on which ops will not block. @@ -712,7 +712,7 @@ static struct n_hdlc *n_hdlc_alloc(void) n_hdlc->magic = HDLC_MAGIC; return n_hdlc; - + } /* end of n_hdlc_alloc() */ /** @@ -754,7 +754,7 @@ static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list, /** * n_hdlc_buf_get - remove and return an HDLC buffer from list * @buf_list - pointer to HDLC buffer list - * + * * Remove and return an HDLC buffer from the head of the specified HDLC buffer * list. * Returns a pointer to HDLC buffer if available, otherwise %NULL. @@ -808,7 +808,7 @@ static int __init n_hdlc_init(void) status); return status; - + } /* end of init_module() */ static void __exit n_hdlc_exit(void) -- cgit From 2bfb2b753bc6c3e80f5b87f850c6388300f69689 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:15 +0100 Subject: n_hdlc: remove spaces between function name and ( Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-21-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index ee27573b0624..d52bcfa7f8e4 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -152,7 +152,7 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list); /* Local functions */ -static struct n_hdlc *n_hdlc_alloc (void); +static struct n_hdlc *n_hdlc_alloc(void); /* max frame size for memory allocations */ static int maxframe = 4096; @@ -222,7 +222,7 @@ static void n_hdlc_tty_close(struct tty_struct *tty) * * Returns 0 if success, otherwise error code */ -static int n_hdlc_tty_open (struct tty_struct *tty) +static int n_hdlc_tty_open(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty->disc_data; @@ -347,7 +347,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty->disc_data; - n_hdlc_send_frames (n_hdlc, tty); + n_hdlc_send_frames(n_hdlc, tty); } /* end of n_hdlc_tty_wakeup() */ /** @@ -406,7 +406,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf); /* wake up any blocked reads and perform async signalling */ - wake_up_interruptible (&tty->read_wait); + wake_up_interruptible(&tty->read_wait); if (tty->fasync != NULL) kill_fasync(&tty->fasync, SIGIO, POLL_IN); -- cgit From 8d79bb5c4b972e463787cf16586c4eda0979cde7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:16 +0100 Subject: n_hdlc: add missing spaces after commas Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-22-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index d52bcfa7f8e4..7ae4347a946f 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -201,7 +201,7 @@ static void n_hdlc_tty_close(struct tty_struct *tty) return; } #if defined(TTY_NO_WRITE_SPLIT) - clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags); + clear_bit(TTY_NO_WRITE_SPLIT, &tty->flags); #endif tty->disc_data = NULL; @@ -245,7 +245,7 @@ static int n_hdlc_tty_open(struct tty_struct *tty) tty->receive_room = 65536; /* change tty_io write() to not split large writes into 8K chunks */ - set_bit(TTY_NO_WRITE_SPLIT,&tty->flags); + set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); /* flush receive data from driver */ tty_driver_flush_buffer(tty); @@ -399,7 +399,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, } /* copy received data to HDLC buffer */ - memcpy(buf->buf,data,count); + memcpy(buf->buf, data, count); buf->count=count; /* add HDLC buffer to list of received frames */ @@ -550,8 +550,8 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, /* Send the data */ tbuf->count = error = count; - n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); - n_hdlc_send_frames(n_hdlc,tty); + n_hdlc_buf_put(&n_hdlc->tx_buf_list, tbuf); + n_hdlc_send_frames(n_hdlc, tty); } return error; @@ -586,14 +586,14 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, case FIONREAD: /* report count of read data available */ /* in next available frame (if any) */ - spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags); + spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock, flags); buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list, struct n_hdlc_buf, list_item); if (buf) count = buf->count; else count = 0; - spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags); + spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock, flags); error = put_user(count, (int __user *)arg); break; @@ -601,12 +601,12 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, /* get the pending tx byte count in the driver */ count = tty_chars_in_buffer(tty); /* add size of next output frame in queue */ - spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags); + spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list, struct n_hdlc_buf, list_item); if (buf) count += buf->count; - spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags); + spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); error = put_user(count, (int __user *)arg); break; -- cgit From 1283c72135f012808bfcc67c8a5752e876519339 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:17 +0100 Subject: n_hdlc: fix whitespace around binary operators Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-23-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 7ae4347a946f..b74a8ecc65b5 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -376,7 +376,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, return; } - if ( count>maxframe ) { + if (count > maxframe) { pr_debug("%s(%d) rx count>maxframesize, data discarded\n", __FILE__, __LINE__); return; @@ -400,7 +400,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, /* copy received data to HDLC buffer */ memcpy(buf->buf, data, count); - buf->count=count; + buf->count = count; /* add HDLC buffer to list of received frames */ n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf); @@ -514,7 +514,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, return -EIO; /* verify frame size */ - if (count > maxframe ) { + if (count > maxframe) { pr_debug("%s: truncating user packet from %zu to %d\n", __func__, count, maxframe); count = maxframe; -- cgit From 80967ff2d15fb91f5046118d1de3ef32a151e30a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 09:41:18 +0100 Subject: n_hdlc: wrap a comment properly Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219084118.26491-24-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index b74a8ecc65b5..cd1319d26c45 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -385,8 +385,10 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, /* get a free HDLC buffer */ buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (!buf) { - /* no buffers in free list, attempt to allocate another rx buffer */ - /* unless the maximum count has been reached */ + /* + * no buffers in free list, attempt to allocate another rx + * buffer unless the maximum count has been reached + */ if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT) buf = kmalloc(struct_size(buf, buf, maxframe), GFP_ATOMIC); -- cgit From dce05aa6eec977f1472abed95ccd71276b9a3864 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 08:39:43 +0100 Subject: vt: selection, introduce vc_is_sel Avoid global variables (namely sel_cons) by introducing vc_is_sel. It checks whether the parameter is the current selection console. This will help putting sel_cons to a struct later. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219073951.16151-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 5 +++++ drivers/tty/vt/vt.c | 7 ++++--- drivers/tty/vt/vt_ioctl.c | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 78732feaf65b..f3ec0037a0e3 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -84,6 +84,11 @@ void clear_selection(void) } EXPORT_SYMBOL_GPL(clear_selection); +bool vc_is_sel(struct vc_data *vc) +{ + return vc == sel_cons; +} + /* * User settable table: what characters are to be considered alphabetic? * 128 bits. Locked by the console lock. diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 35d21cdb60d0..a2bbff602999 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -890,8 +890,9 @@ static void hide_softcursor(struct vc_data *vc) static void hide_cursor(struct vc_data *vc) { - if (vc == sel_cons) + if (vc_is_sel(vc)) clear_selection(); + vc->vc_sw->con_cursor(vc, CM_ERASE); hide_softcursor(vc); } @@ -901,7 +902,7 @@ static void set_cursor(struct vc_data *vc) if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS) return; if (vc->vc_deccm) { - if (vc == sel_cons) + if (vc_is_sel(vc)) clear_selection(); add_softcursor(vc); if ((vc->vc_cursor_type & 0x0f) != 1) @@ -1196,7 +1197,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, } } - if (vc == sel_cons) + if (vc_is_sel(vc)) clear_selection(); old_rows = vc->vc_rows; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 8b0ed139592f..dc8c5a34f8eb 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -43,7 +43,7 @@ char vt_dont_switch; extern struct tty_driver *console_driver; #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) -#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons) +#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_is_sel(vc_cons[i].d)) /* * Console (vt and kd) routines, as defined by USL SVR4 manual, and by -- cgit From e587e8f17433ddb26954f0edf5b2f95c42155ae9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 08:39:44 +0100 Subject: vt: ioctl, switch VT_IS_IN_USE and VT_BUSY to inlines These two were macros. Switch them to static inlines, so that it's more understandable what they are doing. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219073951.16151-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt_ioctl.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index dc8c5a34f8eb..934fd46e7370 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -40,10 +40,25 @@ #include char vt_dont_switch; -extern struct tty_driver *console_driver; -#define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) -#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_is_sel(vc_cons[i].d)) +static inline bool vt_in_use(unsigned int i) +{ + extern struct tty_driver *console_driver; + + return console_driver->ttys[i] && console_driver->ttys[i]->count; +} + +static inline bool vt_busy(int i) +{ + if (vt_in_use(i)) + return true; + if (i == fg_console) + return true; + if (vc_is_sel(vc_cons[i].d)) + return true; + + return false; +} /* * Console (vt and kd) routines, as defined by USL SVR4 manual, and by @@ -289,7 +304,7 @@ static int vt_disallocate(unsigned int vc_num) int ret = 0; console_lock(); - if (VT_BUSY(vc_num)) + if (vt_busy(vc_num)) ret = -EBUSY; else if (vc_num) vc = vc_deallocate(vc_num); @@ -311,7 +326,7 @@ static void vt_disallocate_all(void) console_lock(); for (i = 1; i < MAX_NR_CONSOLES; i++) - if (!VT_BUSY(i)) + if (!vt_busy(i)) vc[i] = vc_deallocate(i); else vc[i] = NULL; @@ -648,7 +663,7 @@ int vt_ioctl(struct tty_struct *tty, state = 1; /* /dev/tty0 is always open */ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) - if (VT_IS_IN_USE(i)) + if (vt_in_use(i)) state |= mask; ret = put_user(state, &vtstat->v_state); } @@ -661,7 +676,7 @@ int vt_ioctl(struct tty_struct *tty, case VT_OPENQRY: /* FIXME: locking ? - but then this is a stupid API */ for (i = 0; i < MAX_NR_CONSOLES; ++i) - if (! VT_IS_IN_USE(i)) + if (!vt_in_use(i)) break; uival = i < MAX_NR_CONSOLES ? (i+1) : -1; goto setint; -- cgit From e24cd4e6d6aa3ca741cdfdfc01118c4016acebea Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 19 Feb 2020 22:23:13 -0800 Subject: n_tty: Distribute switch variables for initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Variables declared in a switch statement before any case statements cannot be automatically initialized with compiler instrumentation (as they are not part of any execution flow). With GCC's proposed automatic stack variable initialization feature, this triggers a warning (and they don't get initialized). Clang's automatic stack variable initialization (via CONFIG_INIT_STACK_ALL=y) doesn't throw a warning, but it also doesn't initialize such variables[1]. Note that these warnings (or silent skipping) happen before the dead-store elimination optimization phase, so even when the automatic initializations are later elided in favor of direct initializations, the warnings remain. To avoid these problems, move such variables into the "case" where they're used or lift them up into the main function body. drivers/tty/n_tty.c: In function ‘__process_echoes’: drivers/tty/n_tty.c:657:18: warning: statement will never be executed [-Wswitch-unreachable] 657 | unsigned int num_chars, num_bs; | ^~~~~~~~~ [1] https://bugs.llvm.org/show_bug.cgi?id=44916 Reviewed-by: Jiri Slaby Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20200220062313.69209-1-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 640fdd1e4c1d..1794d84e7bf6 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -654,9 +654,9 @@ static size_t __process_echoes(struct tty_struct *tty) op = echo_buf(ldata, tail + 1); switch (op) { + case ECHO_OP_ERASE_TAB: { unsigned int num_chars, num_bs; - case ECHO_OP_ERASE_TAB: if (MASK(ldata->echo_commit) == MASK(tail + 2)) goto not_yet_stored; num_chars = echo_buf(ldata, tail + 2); @@ -687,7 +687,7 @@ static size_t __process_echoes(struct tty_struct *tty) } tail += 3; break; - + } case ECHO_OP_SET_CANON_COL: ldata->canon_column = ldata->column; tail += 2; -- cgit From 101f227c24038aed5bd821414fdd9e9a3509484a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 08:39:45 +0100 Subject: vt: selection, remove 2 local variables from set_selection_kernel multiplier and mode are not actually needed: * multiplier is used only in kmalloc_array, so use "use_unicode ? 4 : 1" directly * mode is used only to assign a bool in this manner: if (cond) x = true; else x = false; So do "x = cond" directly. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219073951.16151-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 714992693974..6541c09d8bba 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -191,9 +191,9 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) struct vc_data *vc = vc_cons[fg_console].d; int new_sel_start, new_sel_end, spc; char *bp, *obp; - int i, ps, pe, multiplier; + int i, ps, pe; u32 c; - int mode, ret = 0; + int ret = 0; poke_blanked_console(); @@ -224,11 +224,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) clear_selection(); sel_cons = vc_cons[fg_console].d; } - mode = vt_do_kdgkbmode(fg_console); - if (mode == K_UNICODE) - use_unicode = 1; - else - use_unicode = 0; + use_unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; switch (v->sel_mode) { @@ -312,8 +308,8 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) sel_end = new_sel_end; /* Allocate a new buffer before freeing the old one ... */ - multiplier = use_unicode ? 4 : 1; /* chars can take up to 4 bytes */ - bp = kmalloc_array((sel_end - sel_start) / 2 + 1, multiplier, + /* chars can take up to 4 bytes with unicode */ + bp = kmalloc_array((sel_end - sel_start) / 2 + 1, use_unicode ? 4 : 1, GFP_KERNEL); if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); -- cgit From 555b4ef79797f10079760b3c8712d9ed99c9d680 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 08:39:46 +0100 Subject: vt: selection, localize use_unicode use_unicode needs not be global. It is used only in set_selection_kernel and sel_pos (a callee). It is also always set there prior calling sel_pos. So make use_unicode local and rename it to plain shorter "unicode". Finally, propagate it to sel_pos via parameter. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219073951.16151-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 6541c09d8bba..33f94293f45e 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -41,7 +41,6 @@ extern void poke_blanked_console(void); /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ struct vc_data *sel_cons; /* must not be deallocated */ -static int use_unicode; static volatile int sel_start = -1; /* cleared by clear_selection */ static int sel_end; static int sel_buffer_lth; @@ -64,9 +63,9 @@ static inline void highlight_pointer(const int where) } static u32 -sel_pos(int n) +sel_pos(int n, bool unicode) { - if (use_unicode) + if (unicode) return screen_glyph_unicode(sel_cons, n / 2); return inverse_translate(sel_cons, screen_glyph(sel_cons, n), 0); @@ -194,6 +193,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) int i, ps, pe; u32 c; int ret = 0; + bool unicode; poke_blanked_console(); @@ -224,7 +224,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) clear_selection(); sel_cons = vc_cons[fg_console].d; } - use_unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; + unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; switch (v->sel_mode) { @@ -233,21 +233,21 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) new_sel_end = pe; break; case TIOCL_SELWORD: /* word-by-word selection */ - spc = isspace(sel_pos(ps)); + spc = isspace(sel_pos(ps, unicode)); for (new_sel_start = ps; ; ps -= 2) { - if ((spc && !isspace(sel_pos(ps))) || - (!spc && !inword(sel_pos(ps)))) + if ((spc && !isspace(sel_pos(ps, unicode))) || + (!spc && !inword(sel_pos(ps, unicode)))) break; new_sel_start = ps; if (!(ps % vc->vc_size_row)) break; } - spc = isspace(sel_pos(pe)); + spc = isspace(sel_pos(pe, unicode)); for (new_sel_end = pe; ; pe += 2) { - if ((spc && !isspace(sel_pos(pe))) || - (!spc && !inword(sel_pos(pe)))) + if ((spc && !isspace(sel_pos(pe, unicode))) || + (!spc && !inword(sel_pos(pe, unicode)))) break; new_sel_end = pe; if (!((pe + 2) % vc->vc_size_row)) @@ -273,12 +273,12 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) /* select to end of line if on trailing space */ if (new_sel_end > new_sel_start && !atedge(new_sel_end, vc->vc_size_row) && - isspace(sel_pos(new_sel_end))) { + isspace(sel_pos(new_sel_end, unicode))) { for (pe = new_sel_end + 2; ; pe += 2) - if (!isspace(sel_pos(pe)) || + if (!isspace(sel_pos(pe, unicode)) || atedge(pe, vc->vc_size_row)) break; - if (isspace(sel_pos(pe))) + if (isspace(sel_pos(pe, unicode))) new_sel_end = pe; } if (sel_start == -1) /* no current selection */ @@ -309,7 +309,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) /* Allocate a new buffer before freeing the old one ... */ /* chars can take up to 4 bytes with unicode */ - bp = kmalloc_array((sel_end - sel_start) / 2 + 1, use_unicode ? 4 : 1, + bp = kmalloc_array((sel_end - sel_start) / 2 + 1, unicode ? 4 : 1, GFP_KERNEL); if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); @@ -322,8 +322,8 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) obp = bp; for (i = sel_start; i <= sel_end; i += 2) { - c = sel_pos(i); - if (use_unicode) + c = sel_pos(i, unicode); + if (unicode) bp += store_utf8(c, bp); else *bp++ = c; -- cgit From 9256d09f1da178f67d37b054cb4aaadf816bf05b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 08:39:47 +0100 Subject: vt: selection, create struct from console selection globals Move all the selection global variables to a structure vc_selection, instantiated as vc_sel. This helps to group all the variables together and see what should be protected by the embedded lock too. It might be used later also for per-console selection support. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219073951.16151-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 94 +++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 46 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 33f94293f45e..0cd7072b6a56 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -38,14 +38,17 @@ extern void poke_blanked_console(void); /* FIXME: all this needs locking */ -/* Variables for selection control. */ -/* Use a dynamic buffer, instead of static (Dec 1994) */ -struct vc_data *sel_cons; /* must not be deallocated */ -static volatile int sel_start = -1; /* cleared by clear_selection */ -static int sel_end; -static int sel_buffer_lth; -static char *sel_buffer; -static DEFINE_MUTEX(sel_lock); +static struct vc_selection { + struct mutex lock; + struct vc_data *cons; /* must not be deallocated */ + char *buffer; + unsigned int buf_len; + volatile int start; /* cleared by clear_selection */ + int end; +} vc_sel = { + .lock = __MUTEX_INITIALIZER(vc_sel.lock), + .start = -1, +}; /* clear_selection, highlight and highlight_pointer can be called from interrupt (via scrollback/front) */ @@ -53,22 +56,21 @@ static DEFINE_MUTEX(sel_lock); /* set reverse video on characters s-e of console with selection. */ static inline void highlight(const int s, const int e) { - invert_screen(sel_cons, s, e-s+2, 1); + invert_screen(vc_sel.cons, s, e-s+2, 1); } /* use complementary color to show the pointer */ static inline void highlight_pointer(const int where) { - complement_pos(sel_cons, where); + complement_pos(vc_sel.cons, where); } static u32 sel_pos(int n, bool unicode) { if (unicode) - return screen_glyph_unicode(sel_cons, n / 2); - return inverse_translate(sel_cons, screen_glyph(sel_cons, n), - 0); + return screen_glyph_unicode(vc_sel.cons, n / 2); + return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), 0); } /** @@ -80,16 +82,16 @@ sel_pos(int n, bool unicode) void clear_selection(void) { highlight_pointer(-1); /* hide the pointer */ - if (sel_start != -1) { - highlight(sel_start, sel_end); - sel_start = -1; + if (vc_sel.start != -1) { + highlight(vc_sel.start, vc_sel.end); + vc_sel.start = -1; } } EXPORT_SYMBOL_GPL(clear_selection); bool vc_is_sel(struct vc_data *vc) { - return vc == sel_cons; + return vc == vc_sel.cons; } /* @@ -216,13 +218,13 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) return 0; } - if (ps > pe) /* make sel_start <= sel_end */ + if (ps > pe) /* make vc_sel.start <= vc_sel.end */ swap(ps, pe); - mutex_lock(&sel_lock); - if (sel_cons != vc_cons[fg_console].d) { + mutex_lock(&vc_sel.lock); + if (vc_sel.cons != vc_cons[fg_console].d) { clear_selection(); - sel_cons = vc_cons[fg_console].d; + vc_sel.cons = vc_cons[fg_console].d; } unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; @@ -281,35 +283,35 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) if (isspace(sel_pos(pe, unicode))) new_sel_end = pe; } - if (sel_start == -1) /* no current selection */ + if (vc_sel.start == -1) /* no current selection */ highlight(new_sel_start, new_sel_end); - else if (new_sel_start == sel_start) + else if (new_sel_start == vc_sel.start) { - if (new_sel_end == sel_end) /* no action required */ + if (new_sel_end == vc_sel.end) /* no action required */ goto unlock; - else if (new_sel_end > sel_end) /* extend to right */ - highlight(sel_end + 2, new_sel_end); + else if (new_sel_end > vc_sel.end) /* extend to right */ + highlight(vc_sel.end + 2, new_sel_end); else /* contract from right */ - highlight(new_sel_end + 2, sel_end); + highlight(new_sel_end + 2, vc_sel.end); } - else if (new_sel_end == sel_end) + else if (new_sel_end == vc_sel.end) { - if (new_sel_start < sel_start) /* extend to left */ - highlight(new_sel_start, sel_start - 2); + if (new_sel_start < vc_sel.start) /* extend to left */ + highlight(new_sel_start, vc_sel.start - 2); else /* contract from left */ - highlight(sel_start, new_sel_start - 2); + highlight(vc_sel.start, new_sel_start - 2); } else /* some other case; start selection from scratch */ { clear_selection(); highlight(new_sel_start, new_sel_end); } - sel_start = new_sel_start; - sel_end = new_sel_end; + vc_sel.start = new_sel_start; + vc_sel.end = new_sel_end; /* Allocate a new buffer before freeing the old one ... */ /* chars can take up to 4 bytes with unicode */ - bp = kmalloc_array((sel_end - sel_start) / 2 + 1, unicode ? 4 : 1, + bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1, GFP_KERNEL); if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); @@ -317,11 +319,11 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) ret = -ENOMEM; goto unlock; } - kfree(sel_buffer); - sel_buffer = bp; + kfree(vc_sel.buffer); + vc_sel.buffer = bp; obp = bp; - for (i = sel_start; i <= sel_end; i += 2) { + for (i = vc_sel.start; i <= vc_sel.end; i += 2) { c = sel_pos(i, unicode); if (unicode) bp += store_utf8(c, bp); @@ -339,9 +341,9 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) obp = bp; } } - sel_buffer_lth = bp - sel_buffer; + vc_sel.buf_len = bp - vc_sel.buffer; unlock: - mutex_unlock(&sel_lock); + mutex_unlock(&vc_sel.lock); return ret; } EXPORT_SYMBOL_GPL(set_selection_kernel); @@ -372,26 +374,26 @@ int paste_selection(struct tty_struct *tty) tty_buffer_lock_exclusive(&vc->port); add_wait_queue(&vc->paste_wait, &wait); - mutex_lock(&sel_lock); - while (sel_buffer && sel_buffer_lth > pasted) { + mutex_lock(&vc_sel.lock); + while (vc_sel.buffer && vc_sel.buf_len > pasted) { set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { ret = -EINTR; break; } if (tty_throttled(tty)) { - mutex_unlock(&sel_lock); + mutex_unlock(&vc_sel.lock); schedule(); - mutex_lock(&sel_lock); + mutex_lock(&vc_sel.lock); continue; } __set_current_state(TASK_RUNNING); - count = sel_buffer_lth - pasted; - count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL, + count = vc_sel.buf_len - pasted; + count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL, count); pasted += count; } - mutex_unlock(&sel_lock); + mutex_unlock(&vc_sel.lock); remove_wait_queue(&vc->paste_wait, &wait); __set_current_state(TASK_RUNNING); -- cgit From f400991bf872debffb01c46da882dc97d7e3248e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 08:39:48 +0100 Subject: vt: switch vt_dont_switch to bool vt_dont_switch is pure boolean, no need for whole char. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219073951.16151-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt_ioctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 693d9d7ffb68..38948ac5fc49 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -39,7 +39,7 @@ #include #include -char vt_dont_switch; +bool vt_dont_switch; static inline bool vt_in_use(unsigned int i) { @@ -1026,12 +1026,12 @@ int vt_ioctl(struct tty_struct *tty, case VT_LOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; - vt_dont_switch = 1; + vt_dont_switch = true; break; case VT_UNLOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; - vt_dont_switch = 0; + vt_dont_switch = false; break; case VT_GETHIFONTMASK: ret = put_user(vc->vc_hi_font_mask, -- cgit From 6ff66e081374655a70d04a0e77e8a58f3a6b6f59 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 08:39:50 +0100 Subject: vt: selection, remove redeclaration of poke_blanked_console It is declared in vt_kern.h, so no need to declare it in selection.c which includes the header. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219073951.16151-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 0cd7072b6a56..eaf11729ef9e 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -35,8 +35,6 @@ /* Don't take this from : 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') -extern void poke_blanked_console(void); - /* FIXME: all this needs locking */ static struct vc_selection { struct mutex lock; -- cgit From bc80932cc25af5cca28574a2aa293f37a1660837 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Feb 2020 08:39:51 +0100 Subject: vt: selection, indent switch-case properly Shift the cases one level left as this is how we are supposed to write the switch-case code according to the CodingStyle. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200219073951.16151-9-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 72 ++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 37 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index eaf11729ef9e..b9c517463efa 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -226,45 +226,43 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) } unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; - switch (v->sel_mode) - { - case TIOCL_SELCHAR: /* character-by-character selection */ + switch (v->sel_mode) { + case TIOCL_SELCHAR: /* character-by-character selection */ + new_sel_start = ps; + new_sel_end = pe; + break; + case TIOCL_SELWORD: /* word-by-word selection */ + spc = isspace(sel_pos(ps, unicode)); + for (new_sel_start = ps; ; ps -= 2) { + if ((spc && !isspace(sel_pos(ps, unicode))) || + (!spc && !inword(sel_pos(ps, unicode)))) + break; new_sel_start = ps; + if (!(ps % vc->vc_size_row)) + break; + } + + spc = isspace(sel_pos(pe, unicode)); + for (new_sel_end = pe; ; pe += 2) { + if ((spc && !isspace(sel_pos(pe, unicode))) || + (!spc && !inword(sel_pos(pe, unicode)))) + break; new_sel_end = pe; - break; - case TIOCL_SELWORD: /* word-by-word selection */ - spc = isspace(sel_pos(ps, unicode)); - for (new_sel_start = ps; ; ps -= 2) - { - if ((spc && !isspace(sel_pos(ps, unicode))) || - (!spc && !inword(sel_pos(ps, unicode)))) - break; - new_sel_start = ps; - if (!(ps % vc->vc_size_row)) - break; - } - spc = isspace(sel_pos(pe, unicode)); - for (new_sel_end = pe; ; pe += 2) - { - if ((spc && !isspace(sel_pos(pe, unicode))) || - (!spc && !inword(sel_pos(pe, unicode)))) - break; - new_sel_end = pe; - if (!((pe + 2) % vc->vc_size_row)) - break; - } - break; - case TIOCL_SELLINE: /* line-by-line selection */ - new_sel_start = ps - ps % vc->vc_size_row; - new_sel_end = pe + vc->vc_size_row - - pe % vc->vc_size_row - 2; - break; - case TIOCL_SELPOINTER: - highlight_pointer(pe); - goto unlock; - default: - ret = -EINVAL; - goto unlock; + if (!((pe + 2) % vc->vc_size_row)) + break; + } + break; + case TIOCL_SELLINE: /* line-by-line selection */ + new_sel_start = ps - ps % vc->vc_size_row; + new_sel_end = pe + vc->vc_size_row + - pe % vc->vc_size_row - 2; + break; + case TIOCL_SELPOINTER: + highlight_pointer(pe); + goto unlock; + default: + ret = -EINVAL; + goto unlock; } /* remove the pointer */ -- cgit From 67f468d4ae9fd3589f8086103c13686923f82a57 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 29 Feb 2020 23:09:41 +0100 Subject: tty: serial: atmel_serial: Drop GPIO includes Nothing in this driver uses the symbols from these GPIO includes so drop them. These are probably just historical artifacts from befor mctrl_gpio was used. Cc: Ludovic Desroches Cc: Razvan Stefanescu Signed-off-by: Linus Walleij Reviewed-by: Ludovic Desroches Link: https://lore.kernel.org/r/20200229220941.205599-1-linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index a39c87a7c2e1..d1ab6a0a5c74 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -20,15 +20,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include -#include #include #include #include -- cgit From 8145e85f8245ec92516b331ccf0bdc833fe3ef17 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 29 Feb 2020 22:23:31 +0100 Subject: tty: serial: lantiq: Drop GPIO include Nothing in this driver uses the symbols from so drop this include. Cc: Rahul Tanwar Cc: Songjun Wu Cc: Martin Blumenstingl Cc: John Crispin Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20200229212331.174946-1-linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/lantiq.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index f67226df30d4..c5e46ff972e4 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include -- cgit From 97cbaf2c829b476887582f5ae92363ebea27cc47 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 1 Mar 2020 00:18:42 +0100 Subject: tty: serial: cpm_uart: Convert to use GPIO descriptors The CPM UART (PowerPC) has an open coded GPIO modem control handling. Since I can't test this I can't just migrate it to the serial mctrl GPIO helper library though I wish I could. I do second best and convert it to GPIO descriptors at least. Cc: Rasmus Villemoes Cc: Christophe Leroy Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20200229231842.247563-1-linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/cpm_uart/cpm_uart.h | 4 ++- drivers/tty/serial/cpm_uart/cpm_uart_core.c | 48 +++++++++++++---------------- 2 files changed, 24 insertions(+), 28 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h index 9f175a92fb5d..f775b042457a 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart.h +++ b/drivers/tty/serial/cpm_uart/cpm_uart.h @@ -13,6 +13,8 @@ #include #include +struct gpio_desc; + #if defined(CONFIG_CPM2) #include "cpm_uart_cpm2.h" #elif defined(CONFIG_CPM1) @@ -80,7 +82,7 @@ struct uart_cpm_port { int wait_closing; /* value to combine with opcode to form cpm command */ u32 command; - int gpios[NUM_GPIOS]; + struct gpio_desc *gpios[NUM_GPIOS]; }; extern int cpm_uart_nr; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index d4b81b06e0cb..a04f74d2e854 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -30,8 +30,7 @@ #include #include #include -#include -#include +#include #include #include @@ -88,11 +87,11 @@ static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) struct uart_cpm_port *pinfo = container_of(port, struct uart_cpm_port, port); - if (pinfo->gpios[GPIO_RTS] >= 0) - gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); + if (pinfo->gpios[GPIO_RTS]) + gpiod_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); - if (pinfo->gpios[GPIO_DTR] >= 0) - gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR)); + if (pinfo->gpios[GPIO_DTR]) + gpiod_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR)); } static unsigned int cpm_uart_get_mctrl(struct uart_port *port) @@ -101,23 +100,23 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port) container_of(port, struct uart_cpm_port, port); unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - if (pinfo->gpios[GPIO_CTS] >= 0) { - if (gpio_get_value(pinfo->gpios[GPIO_CTS])) + if (pinfo->gpios[GPIO_CTS]) { + if (gpiod_get_value(pinfo->gpios[GPIO_CTS])) mctrl &= ~TIOCM_CTS; } - if (pinfo->gpios[GPIO_DSR] >= 0) { - if (gpio_get_value(pinfo->gpios[GPIO_DSR])) + if (pinfo->gpios[GPIO_DSR]) { + if (gpiod_get_value(pinfo->gpios[GPIO_DSR])) mctrl &= ~TIOCM_DSR; } - if (pinfo->gpios[GPIO_DCD] >= 0) { - if (gpio_get_value(pinfo->gpios[GPIO_DCD])) + if (pinfo->gpios[GPIO_DCD]) { + if (gpiod_get_value(pinfo->gpios[GPIO_DCD])) mctrl &= ~TIOCM_CAR; } - if (pinfo->gpios[GPIO_RI] >= 0) { - if (!gpio_get_value(pinfo->gpios[GPIO_RI])) + if (pinfo->gpios[GPIO_RI]) { + if (!gpiod_get_value(pinfo->gpios[GPIO_RI])) mctrl |= TIOCM_RNG; } @@ -1139,6 +1138,7 @@ static int cpm_uart_init_port(struct device_node *np, { const u32 *data; void __iomem *mem, *pram; + struct device *dev = pinfo->port.dev; int len; int ret; int i; @@ -1211,29 +1211,23 @@ static int cpm_uart_init_port(struct device_node *np, } for (i = 0; i < NUM_GPIOS; i++) { - int gpio; + struct gpio_desc *gpiod; - pinfo->gpios[i] = -1; + pinfo->gpios[i] = NULL; - gpio = of_get_gpio(np, i); + gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS); - if (gpio_is_valid(gpio)) { - ret = gpio_request(gpio, "cpm_uart"); - if (ret) { - pr_err("can't request gpio #%d: %d\n", i, ret); - continue; - } + if (gpiod) { if (i == GPIO_RTS || i == GPIO_DTR) - ret = gpio_direction_output(gpio, 0); + ret = gpiod_direction_output(gpiod, 0); else - ret = gpio_direction_input(gpio); + ret = gpiod_direction_input(gpiod); if (ret) { pr_err("can't set direction for gpio #%d: %d\n", i, ret); - gpio_free(gpio); continue; } - pinfo->gpios[i] = gpio; + pinfo->gpios[i] = gpiod; } } -- cgit From 9fa3c4b1fa379f2b55859c6d27ba0563aac06516 Mon Sep 17 00:00:00 2001 From: Roja Rani Yarubandi Date: Wed, 4 Mar 2020 16:52:03 +0530 Subject: tty: serial: qcom_geni_serial: Fix GPIO swapping with workaround Add capability to support RX-TX, CTS-RTS pins swap in HW. Configure UART_IO_MACRO_CTRL register accordingly if RX-TX pair or CTS-RTS pair or both pairs swapped. Signed-off-by: Roja Rani Yarubandi Reviewed-by: Stephen Boyd Tested-by: Matthias Kaehlcke Reviewed-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20200304112203.408-1-rojay@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 0bd1684cabb3..272bae0eebc7 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -21,6 +21,7 @@ /* UART specific GENI registers */ #define SE_UART_LOOPBACK_CFG 0x22c +#define SE_UART_IO_MACRO_CTRL 0x240 #define SE_UART_TX_TRANS_CFG 0x25c #define SE_UART_TX_WORD_LEN 0x268 #define SE_UART_TX_STOP_BIT_LEN 0x26c @@ -95,6 +96,12 @@ #define CTS_RTS_SORTED BIT(1) #define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED) +/* UART pin swap value */ +#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0) +#define IO_MACRO_IO0_SEL 0x3 +#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4) +#define IO_MACRO_IO2_IO3_SWAP 0x4640 + #ifdef CONFIG_CONSOLE_POLL #define CONSOLE_RX_BYTES_PW 1 #else @@ -119,6 +126,8 @@ struct qcom_geni_serial_port { unsigned int tx_remaining; int wakeup_irq; + bool rx_tx_swap; + bool cts_rts_swap; }; static const struct uart_ops qcom_geni_console_pops; @@ -836,6 +845,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) struct qcom_geni_serial_port *port = to_dev_port(uport, uport); u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; u32 proto; + u32 pin_swap; if (uart_console(uport)) { port->tx_bytes_pw = 1; @@ -856,6 +866,20 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) get_tx_fifo_size(port); writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT); + + pin_swap = readl(uport->membase + SE_UART_IO_MACRO_CTRL); + if (port->rx_tx_swap) { + pin_swap &= ~DEFAULT_IO_MACRO_IO2_IO3_MASK; + pin_swap |= IO_MACRO_IO2_IO3_SWAP; + } + if (port->cts_rts_swap) { + pin_swap &= ~DEFAULT_IO_MACRO_IO0_IO1_MASK; + pin_swap |= IO_MACRO_IO0_SEL; + } + /* Configure this register if RX-TX, CTS-RTS pins are swapped */ + if (port->rx_tx_swap || port->cts_rts_swap) + writel(pin_swap, uport->membase + SE_UART_IO_MACRO_CTRL); + /* * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. @@ -1299,6 +1323,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (!console) port->wakeup_irq = platform_get_irq_optional(pdev, 1); + if (of_property_read_bool(pdev->dev.of_node, "rx-tx-swap")) + port->rx_tx_swap = true; + + if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap")) + port->cts_rts_swap = true; + uport->private_data = drv; platform_set_drvdata(pdev, port); port->handle_rx = console ? handle_rx_console : handle_rx_uart; -- cgit From 9be1064fe524b396cca449b2fe4252b7919a245f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 21 Feb 2020 22:23:31 +0100 Subject: serial: ar933x_uart: add RS485 support Emulate half-duplex operation and use mctrl_gpio to add support for RS485 tranceiver with transmit/receive switch hooked to RTS GPIO line. This is needed to make use of the RS485 port found on Teltonika RUT955. Signed-off-by: Daniel Golle Link: https://lore.kernel.org/r/20200221212331.GA21467@makrotopia.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/ar933x_uart.c | 113 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 880b96201530..e71af33f8d80 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1269,6 +1269,7 @@ config SERIAL_AR933X tristate "AR933X serial port support" depends on HAVE_CLK && ATH79 select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB help If you have an Atheros AR933X SOC based board and want to use the built-in UART of the SoC, say Y to this option. diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index ea12f10610b6..7e7f1398019f 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,8 @@ #include +#include "serial_mctrl_gpio.h" + #define DRIVER_NAME "ar933x-uart" #define AR933X_UART_MAX_SCALE 0xff @@ -47,6 +50,8 @@ struct ar933x_uart_port { unsigned int min_baud; unsigned int max_baud; struct clk *clk; + struct mctrl_gpios *gpios; + struct gpio_desc *rts_gpiod; }; static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, @@ -100,6 +105,18 @@ static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up) ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); } +static inline void ar933x_uart_start_rx_interrupt(struct ar933x_uart_port *up) +{ + up->ier |= AR933X_UART_INT_RX_VALID; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static inline void ar933x_uart_stop_rx_interrupt(struct ar933x_uart_port *up) +{ + up->ier &= ~AR933X_UART_INT_RX_VALID; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) { unsigned int rdata; @@ -125,11 +142,21 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port) static unsigned int ar933x_uart_get_mctrl(struct uart_port *port) { - return TIOCM_CAR; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); + int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + mctrl_gpio_get(up->gpios, &ret); + + return ret; } static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); + + mctrl_gpio_set(up->gpios, mctrl); } static void ar933x_uart_start_tx(struct uart_port *port) @@ -140,6 +167,37 @@ static void ar933x_uart_start_tx(struct uart_port *port) ar933x_uart_start_tx_interrupt(up); } +static void ar933x_uart_wait_tx_complete(struct ar933x_uart_port *up) +{ + unsigned int status; + unsigned int timeout = 60000; + + /* Wait up to 60ms for the character(s) to be sent. */ + do { + status = ar933x_uart_read(up, AR933X_UART_CS_REG); + if (--timeout == 0) + break; + udelay(1); + } while (status & AR933X_UART_CS_TX_BUSY); + + if (timeout == 0) + dev_err(up->port.dev, "waiting for TX timed out\n"); +} + +static void ar933x_uart_rx_flush(struct ar933x_uart_port *up) +{ + unsigned int status; + + /* clear RX_VALID interrupt */ + ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_RX_VALID); + + /* remove characters from the RX FIFO */ + do { + ar933x_uart_write(up, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); + status = ar933x_uart_read(up, AR933X_UART_DATA_REG); + } while (status & AR933X_UART_DATA_RX_CSR); +} + static void ar933x_uart_stop_tx(struct uart_port *port) { struct ar933x_uart_port *up = @@ -153,8 +211,7 @@ static void ar933x_uart_stop_rx(struct uart_port *port) struct ar933x_uart_port *up = container_of(port, struct ar933x_uart_port, port); - up->ier &= ~AR933X_UART_INT_RX_VALID; - ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); + ar933x_uart_stop_rx_interrupt(up); } static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) @@ -336,11 +393,20 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) { struct circ_buf *xmit = &up->port.state->xmit; + struct serial_rs485 *rs485conf = &up->port.rs485; int count; + bool half_duplex_send = false; if (uart_tx_stopped(&up->port)) return; + if ((rs485conf->flags & SER_RS485_ENABLED) && + (up->port.x_char || !uart_circ_empty(xmit))) { + ar933x_uart_stop_rx_interrupt(up); + gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND)); + half_duplex_send = true; + } + count = up->port.fifosize; do { unsigned int rdata; @@ -368,8 +434,14 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - if (!uart_circ_empty(xmit)) + if (!uart_circ_empty(xmit)) { ar933x_uart_start_tx_interrupt(up); + } else if (half_duplex_send) { + ar933x_uart_wait_tx_complete(up); + ar933x_uart_rx_flush(up); + ar933x_uart_start_rx_interrupt(up); + gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND)); + } } static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) @@ -427,8 +499,7 @@ static int ar933x_uart_startup(struct uart_port *port) AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE); /* Enable RX interrupts */ - up->ier = AR933X_UART_INT_RX_VALID; - ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); + ar933x_uart_start_rx_interrupt(up); spin_unlock_irqrestore(&up->port.lock, flags); @@ -511,6 +582,21 @@ static const struct uart_ops ar933x_uart_ops = { .verify_port = ar933x_uart_verify_port, }; +static int ar933x_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485conf) +{ + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); + + if ((rs485conf->flags & SER_RS485_ENABLED) && + !up->rts_gpiod) { + dev_err(port->dev, "RS485 needs rts-gpio\n"); + return 1; + } + port->rs485 = *rs485conf; + return 0; +} + #ifdef CONFIG_SERIAL_AR933X_CONSOLE static struct ar933x_uart_port * ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; @@ -680,6 +766,8 @@ static int ar933x_uart_probe(struct platform_device *pdev) goto err_disable_clk; } + uart_get_rs485_mode(&pdev->dev, &port->rs485); + port->mapbase = mem_res->start; port->line = id; port->irq = irq_res->start; @@ -690,6 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) port->regshift = 2; port->fifosize = AR933X_UART_FIFO_SIZE; port->ops = &ar933x_uart_ops; + port->rs485_config = ar933x_config_rs485; baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); @@ -697,6 +786,18 @@ static int ar933x_uart_probe(struct platform_device *pdev) baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); + up->gpios = mctrl_gpio_init(port, 0); + if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) + return PTR_ERR(up->gpios); + + up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS); + + if ((port->rs485.flags & SER_RS485_ENABLED) && + !up->rts_gpiod) { + dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); + port->rs485.flags &= ~SER_RS485_ENABLED; + } + #ifdef CONFIG_SERIAL_AR933X_CONSOLE ar933x_console_ports[up->port.line] = up; #endif -- cgit From 5a08a4877aed53ba92ffef6b1e24fb092a490757 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Wed, 26 Feb 2020 16:23:19 -0600 Subject: tty: imx serial: Implement support for reversing TX and RX polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The peripheral has support for inverting its input and/or output signals. This is useful if the hardware flips polarity of the peripheral's signal, such as swapped +/- pins on an RS-422 transceiver, or an inverting level shifter. Add support for these control registers via the device tree binding. As part of this change, make the writes of the various registers more uniform by moving the UCR3 block up near the other registers' blocks, since the INVT bit must be set before enabling the peripheral. Signed-off-by: George Hilliard Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20200226222319.18383-3-ghilliard@kopismobile.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d337782b3648..f4d68109bc8b 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -195,6 +195,8 @@ struct imx_port { unsigned int have_rtscts:1; unsigned int have_rtsgpio:1; unsigned int dte_mode:1; + unsigned int inverted_tx:1; + unsigned int inverted_rx:1; struct clk *clk_ipg; struct clk *clk_per; const struct imx_uart_data *devdata; @@ -1335,7 +1337,7 @@ static int imx_uart_startup(struct uart_port *port) int retval, i; unsigned long flags; int dma_is_inited = 0; - u32 ucr1, ucr2, ucr4; + u32 ucr1, ucr2, ucr3, ucr4; retval = clk_prepare_enable(sport->clk_per); if (retval) @@ -1387,11 +1389,29 @@ static int imx_uart_startup(struct uart_port *port) imx_uart_writel(sport, ucr1, UCR1); - ucr4 = imx_uart_readl(sport, UCR4) & ~UCR4_OREN; + ucr4 = imx_uart_readl(sport, UCR4) & ~(UCR4_OREN | UCR4_INVR); if (!sport->dma_is_enabled) ucr4 |= UCR4_OREN; + if (sport->inverted_rx) + ucr4 |= UCR4_INVR; imx_uart_writel(sport, ucr4, UCR4); + ucr3 = imx_uart_readl(sport, UCR3) & ~UCR3_INVT; + /* + * configure tx polarity before enabling tx + */ + if (sport->inverted_tx) + ucr3 |= UCR3_INVT; + + if (!imx_uart_is_imx1(sport)) { + ucr3 |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD; + + if (sport->dte_mode) + /* disable broken interrupts */ + ucr3 &= ~(UCR3_RI | UCR3_DCD); + } + imx_uart_writel(sport, ucr3, UCR3); + ucr2 = imx_uart_readl(sport, UCR2) & ~UCR2_ATEN; ucr2 |= (UCR2_RXEN | UCR2_TXEN); if (!sport->have_rtscts) @@ -1404,20 +1424,6 @@ static int imx_uart_startup(struct uart_port *port) ucr2 &= ~UCR2_RTSEN; imx_uart_writel(sport, ucr2, UCR2); - if (!imx_uart_is_imx1(sport)) { - u32 ucr3; - - ucr3 = imx_uart_readl(sport, UCR3); - - ucr3 |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD; - - if (sport->dte_mode) - /* disable broken interrupts */ - ucr3 &= ~(UCR3_RI | UCR3_DCD); - - imx_uart_writel(sport, ucr3, UCR3); - } - /* * Enable modem status interrupts */ @@ -2184,6 +2190,12 @@ static int imx_uart_probe_dt(struct imx_port *sport, if (of_get_property(np, "rts-gpios", NULL)) sport->have_rtsgpio = 1; + if (of_get_property(np, "fsl,inverted-tx", NULL)) + sport->inverted_tx = 1; + + if (of_get_property(np, "fsl,inverted-rx", NULL)) + sport->inverted_rx = 1; + return 0; } #else -- cgit From e32a83c70cf987df8937760fa263296acf84f963 Mon Sep 17 00:00:00 2001 From: Changqi Hu Date: Wed, 26 Feb 2020 16:53:45 +0800 Subject: serial: 8250-mtk: modify mtk uart power and clock management MTK uart design no need to control uart clock, so we just control bus clock in runtime function. Add uart clock used count to avoid repeatedly switching the clock. Signed-off-by: Changqi Hu Link: https://lore.kernel.org/r/1582707225-26815-1-git-send-email-changqi.hu@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mtk.c | 50 ++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 18 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 4d067f515f74..f839380c2f4c 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -32,6 +32,7 @@ #define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */ #define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */ #define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */ +#define MTK_UART_DEBUG0 0x18 #define MTK_UART_IER_XOFFI 0x20 /* Enable XOFF character interrupt */ #define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */ #define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */ @@ -388,9 +389,18 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, static int __maybe_unused mtk8250_runtime_suspend(struct device *dev) { struct mtk8250_data *data = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(data->line); - clk_disable_unprepare(data->uart_clk); - clk_disable_unprepare(data->bus_clk); + /* wait until UART in idle status */ + while + (serial_in(up, MTK_UART_DEBUG0)); + + if (data->clk_count == 0U) { + dev_dbg(dev, "%s clock count is 0\n", __func__); + } else { + clk_disable_unprepare(data->bus_clk); + data->clk_count--; + } return 0; } @@ -400,16 +410,16 @@ static int __maybe_unused mtk8250_runtime_resume(struct device *dev) struct mtk8250_data *data = dev_get_drvdata(dev); int err; - err = clk_prepare_enable(data->uart_clk); - if (err) { - dev_warn(dev, "Can't enable clock\n"); - return err; - } - - err = clk_prepare_enable(data->bus_clk); - if (err) { - dev_warn(dev, "Can't enable bus clock\n"); - return err; + if (data->clk_count > 0U) { + dev_dbg(dev, "%s clock count is %d\n", __func__, + data->clk_count); + } else { + err = clk_prepare_enable(data->bus_clk); + if (err) { + dev_warn(dev, "Can't enable bus clock\n"); + return err; + } + data->clk_count++; } return 0; @@ -419,12 +429,14 @@ static void mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { if (!state) - pm_runtime_get_sync(port->dev); + if (!mtk8250_runtime_resume(port->dev)) + pm_runtime_get_sync(port->dev); serial8250_do_pm(port, state, old); if (state) - pm_runtime_put_sync_suspend(port->dev); + if (!pm_runtime_put_sync_suspend(port->dev)) + mtk8250_runtime_suspend(port->dev); } #ifdef CONFIG_SERIAL_8250_DMA @@ -501,6 +513,8 @@ static int mtk8250_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + data->clk_count = 0; + if (pdev->dev.of_node) { err = mtk8250_probe_of(pdev, &uart.port, data); if (err) @@ -533,6 +547,7 @@ static int mtk8250_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); + pm_runtime_enable(&pdev->dev); err = mtk8250_runtime_resume(&pdev->dev); if (err) return err; @@ -541,9 +556,6 @@ static int mtk8250_probe(struct platform_device *pdev) if (data->line < 0) return data->line; - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1); return 0; @@ -556,11 +568,13 @@ static int mtk8250_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); serial8250_unregister_port(data->line); - mtk8250_runtime_suspend(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mtk8250_runtime_suspend(&pdev->dev); + return 0; } -- cgit From 1b91d97c66ef32a80dc3098df2f5fe3392342625 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 5 Mar 2020 15:08:22 +0200 Subject: serial: 8250_lpss: Add ->setup() for Elkhart Lake ports The ->setup() callback is mandatory for the devices. Provide it for Elkhart Lake UART ports. Note, for time being it's empty, but in the future it might require an additional configuration such as DMA. Reported-by: Raymond Tan Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200305130822.36850-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpss.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 60eff3240c8a..4dee8a9e0c95 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -156,6 +156,11 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) return 0; } +static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) +{ + return 0; +} + #ifdef CONFIG_SERIAL_8250_DMA static const struct dw_dma_platform_data qrk_serial_dma_pdata = { .nr_channels = 2, @@ -356,6 +361,7 @@ static const struct lpss8250_board byt_board = { static const struct lpss8250_board ehl_board = { .freq = 200000000, .base_baud = 12500000, + .setup = ehl_serial_setup, }; static const struct lpss8250_board qrk_board = { -- cgit From 7ba87cfec71a21d195f08675a7e8603bf461ee32 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Thu, 5 Mar 2020 18:32:28 +0800 Subject: tty: serial: make SERIAL_SPRD not depend on ARCH_SPRD Remove the dependency with ARCH_SPRD from sprd serial/console Kconfig-s, since we want them can be built-in when ARCH_SPRD is set as 'm'. Signed-off-by: Chunyan Zhang Link: https://lore.kernel.org/r/20200305103228.9686-2-zhang.lyra@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index e71af33f8d80..b43dce785a58 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1443,7 +1443,6 @@ config SERIAL_MEN_Z135 config SERIAL_SPRD tristate "Support for Spreadtrum serial" - depends on ARCH_SPRD select SERIAL_CORE help This enables the driver for the Spreadtrum's serial. -- cgit From 4f5f588737560f1eac2e2df3cdd7f3dc0f2fea5e Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Mon, 2 Mar 2020 02:15:21 +0530 Subject: tty: serial: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header files related to tty serial drivers. For C header files Documentation/process/license-rules.rst mandates C-like comments (opposed to C source files where C++ style should be used). Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46. Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Link: https://lore.kernel.org/r/20200301204517.GA10368@nishad Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 2 +- drivers/tty/serial/8250/8250_dwlib.h | 2 +- drivers/tty/serial/atmel_serial.h | 2 +- drivers/tty/serial/cpm_uart/cpm_uart.h | 2 +- drivers/tty/serial/icom.h | 2 +- drivers/tty/serial/ifx6x60.h | 2 +- drivers/tty/serial/jsm/jsm.h | 2 +- drivers/tty/serial/pic32_uart.h | 2 +- drivers/tty/serial/serial_mctrl_gpio.h | 2 +- drivers/tty/serial/sirfsoc_uart.h | 2 +- drivers/tty/serial/stm32-usart.h | 2 +- drivers/tty/serial/timbuart.h | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 33ad9d6de532..32881e21b0c8 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for 8250/16550-type serial ports * diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h index 87a4db2a8aba..9a12953832d3 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* Synopsys DesignWare 8250 library header file. */ #include diff --git a/drivers/tty/serial/atmel_serial.h b/drivers/tty/serial/atmel_serial.h index d811d4f2d0c0..0d8a0f9cc5c3 100644 --- a/drivers/tty/serial/atmel_serial.h +++ b/drivers/tty/serial/atmel_serial.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * include/linux/atmel_serial.h * diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h index f775b042457a..6113b953ce25 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart.h +++ b/drivers/tty/serial/cpm_uart/cpm_uart.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver for CPM (SCC/SMC) serial ports * diff --git a/drivers/tty/serial/icom.h b/drivers/tty/serial/icom.h index 8a77e739b333..26e3aa7b01e2 100644 --- a/drivers/tty/serial/icom.h +++ b/drivers/tty/serial/icom.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * icom.h * diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h index c5a2514212ff..cacca5be7390 100644 --- a/drivers/tty/serial/ifx6x60.h +++ b/drivers/tty/serial/ifx6x60.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /**************************************************************************** * * Driver for the IFX spi modem. diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index 7a128aaa3a66..8489c07f4cd5 100644 --- a/drivers/tty/serial/jsm/jsm.h +++ b/drivers/tty/serial/jsm/jsm.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /************************************************************************ * Copyright 2003 Digi International (www.digi.com) * diff --git a/drivers/tty/serial/pic32_uart.h b/drivers/tty/serial/pic32_uart.h index 2f2b56927dc6..b15639cc336b 100644 --- a/drivers/tty/serial/pic32_uart.h +++ b/drivers/tty/serial/pic32_uart.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * PIC32 Integrated Serial Driver. * diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index 1b2ff503b2c2..b134a0ffc894 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Helpers for controlling modem lines via GPIO * diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index 637b09d3fe79..fb88ac565227 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Drivers for CSR SiRFprimaII onboard UARTs. * diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index a175c1094dc8..db8bf0d4982d 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) Maxime Coquelin 2015 * Copyright (C) STMicroelectronics SA 2017 diff --git a/drivers/tty/serial/timbuart.h b/drivers/tty/serial/timbuart.h index fb00b172117d..007e59af636d 100644 --- a/drivers/tty/serial/timbuart.h +++ b/drivers/tty/serial/timbuart.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * timbuart.c timberdale FPGA GPIO driver * Copyright (c) 2009 Intel Corporation -- cgit From f8c3686c65f099f0915bbf96885765594d675d5b Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 20 Feb 2020 18:46:07 +0100 Subject: serial: earlycon: prefer EARLYCON_DECLARE() variant If a driver exposes early consoles with EARLYCON_DECLARE() and OF_EARLYCON_DECLARE(), pefer the non-OF variant if the user specifies it by earlycon=, The rationale behind this is that some drivers register multiple setup functions under the same driver name. Eg. OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup); EARLYCON_DECLARE(lpuart, lpuart_early_console_setup); EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup); It depends on the order of the entries which console_setup() actually gets called. To make things worse, I guess it also depends on the compiler how these are ordered. Thus always prefer the EARLYCON_DECLARE() ones. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20200220174607.24285-1-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/earlycon.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index c14873b67803..2ae9190b64bb 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -170,6 +170,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) int __init setup_earlycon(char *buf) { const struct earlycon_id **p_match; + bool empty_compatible = true; if (!buf || !buf[0]) return -EINVAL; @@ -177,6 +178,7 @@ int __init setup_earlycon(char *buf) if (early_con.flags & CON_ENABLED) return -EALREADY; +again: for (p_match = __earlycon_table; p_match < __earlycon_table_end; p_match++) { const struct earlycon_id *match = *p_match; @@ -185,6 +187,10 @@ int __init setup_earlycon(char *buf) if (strncmp(buf, match->name, len)) continue; + /* prefer entries with empty compatible */ + if (empty_compatible && *match->compatible) + continue; + if (buf[len]) { if (buf[len] != ',') continue; @@ -195,6 +201,11 @@ int __init setup_earlycon(char *buf) return register_earlycon(buf, match); } + if (empty_compatible) { + empty_compatible = false; + goto again; + } + return -ENOENT; } -- cgit From f45709df7731ad36306a28a3e1af7309d55c35f5 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Feb 2020 14:31:01 +0100 Subject: serial: 8250: Don't touch RTS modem control while in rs485 mode serial8250_do_set_mctrl() currently allows modifying the RTS modem control line even when RTS is used as an rs485 Transmit Enable signal. It is thus possible for user space to interfere with rs485 communication by invoking a TIOCMSET ioctl(). Ignore such change requests and retain the current RTS polarity when in rs485 mode. Note that serial8250_set_mctrl() is always called with port->lock held, so there's no risk that RTS is changed concurrently. Signed-off-by: Lukas Wunner Cc: Matwey V. Kornilov Link: https://lore.kernel.org/r/b1ce34ca9bc4d7bdc6e9852fcf30b1f4e37c8a80.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index f398f162a1fd..a8f4cedde4dc 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1924,6 +1924,13 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) struct uart_8250_port *up = up_to_u8250p(port); unsigned char mcr; + if (port->rs485.flags & SER_RS485_ENABLED) { + if (serial8250_in_MCR(up) & UART_MCR_RTS) + mctrl |= TIOCM_RTS; + else + mctrl &= ~TIOCM_RTS; + } + mcr = serial8250_TIOCM_to_MCR(mctrl); mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; -- cgit From fe7f0fa43cef191a6d17bedf90bacce806c58eba Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Feb 2020 14:31:02 +0100 Subject: serial: 8250: Support rs485 devicetree properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retrieve rs485 devicetree properties on registration of 8250 ports in case they are attached to an rs485 transceiver. If the property "linux,rs485-enabled-at-boot-time" is present, invoke the ->rs485_config() callback to immediately deassert RTS, thereby ceasing control of the bus. Signed-off-by: Lukas Wunner Cc: Giulio Benetti Cc: Uwe Kleine-König Link: https://lore.kernel.org/r/5908ea89b7f9da54872d6634b606d83db032297a.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 4 +++- drivers/tty/serial/8250/8250_port.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index f2a33c9082a6..9a1d09fbb836 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1013,8 +1013,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (uart->port.fifosize && !uart->tx_loadsz) uart->tx_loadsz = uart->port.fifosize; - if (up->port.dev) + if (up->port.dev) { uart->port.dev = up->port.dev; + uart_get_rs485_mode(uart->port.dev, &uart->port.rs485); + } if (up->port.flags & UPF_FIXED_TYPE) uart->port.type = up->port.type; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index a8f4cedde4dc..40efcea8c6e7 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2989,6 +2989,9 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (flags & UART_CONFIG_TYPE) autoconfig(up); + if (port->rs485.flags & SER_RS485_ENABLED) + port->rs485_config(port, &port->rs485); + /* if access method is AU, it is a 16550 with a quirk */ if (port->type == PORT_16550A && port->iotype == UPIO_AU) up->bugs |= UART_BUG_NOMSR; -- cgit From 283e096ffb7077c2b677eee043ff36965e43d37b Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Feb 2020 14:31:03 +0100 Subject: serial: 8250: Deduplicate ->rs485_config() callback Commit e490c9144cfa ("tty: Add software emulated RS485 support for 8250") introduced support to use RTS as an rs485 Transmit Enable signal. Drivers opt in to the feature by calling serial8250_em485_init() from their ->rs485_config() callback. So far there are two drivers doing that, 8250_omap.c and 8250_of.c. Both use an identical callback. We're about to add a third user of that callback, therefore deduplicate it and move it to 8250_port.c. Drivers now opt in to rs485 software emulation by assigning the generic serial8250_rs485_config() callback introduced herein to their .rs485_config struct member. This change allows unexporting serial8250_em485_init() and declaring it static. Signed-off-by: Lukas Wunner Cc: Matwey V. Kornilov Cc: Heiko Schocher Link: https://lore.kernel.org/r/fcef63642dc4eae41ae7842d23747b2bf5d40285.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 2 +- drivers/tty/serial/8250/8250_of.c | 32 +---------------------------- drivers/tty/serial/8250/8250_omap.c | 32 +---------------------------- drivers/tty/serial/8250/8250_port.c | 41 +++++++++++++++++++++++++++++++++++-- 4 files changed, 42 insertions(+), 65 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 32881e21b0c8..83a85210501f 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -156,7 +156,7 @@ void serial8250_rpm_put(struct uart_8250_port *p); void serial8250_rpm_get_tx(struct uart_8250_port *p); void serial8250_rpm_put_tx(struct uart_8250_port *p); -int serial8250_em485_init(struct uart_8250_port *p); +int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485); void serial8250_em485_destroy(struct uart_8250_port *p); /* MCR <-> TIOCM conversion */ diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index ad92f451f3b9..4a68a8785caa 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -25,36 +25,6 @@ struct of_serial_info { int line; }; -static int of_8250_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - /* Clamp the delays to [0, 100ms] */ - rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); - rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); - - port->rs485 = *rs485; - - /* - * Both serial8250_em485_init and serial8250_em485_destroy - * are idempotent - */ - if (rs485->flags & SER_RS485_ENABLED) { - int ret = serial8250_em485_init(up); - - if (ret) { - rs485->flags &= ~SER_RS485_ENABLED; - port->rs485.flags &= ~SER_RS485_ENABLED; - } - return ret; - } - - serial8250_em485_destroy(up); - - return 0; -} - /* * Fill a struct uart_port for a given device node */ @@ -184,7 +154,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->flags |= UPF_SKIP_TEST; port->dev = &ofdev->dev; - port->rs485_config = of_8250_rs485_config; + port->rs485_config = serial8250_em485_config; switch (type) { case PORT_RT2880: diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 6f343ca08440..fff70cb25046 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -714,36 +714,6 @@ static void omap_8250_throttle(struct uart_port *port) pm_runtime_put_autosuspend(port->dev); } -static int omap_8250_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - /* Clamp the delays to [0, 100ms] */ - rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); - rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); - - port->rs485 = *rs485; - - /* - * Both serial8250_em485_init and serial8250_em485_destroy - * are idempotent - */ - if (rs485->flags & SER_RS485_ENABLED) { - int ret = serial8250_em485_init(up); - - if (ret) { - rs485->flags &= ~SER_RS485_ENABLED; - port->rs485.flags &= ~SER_RS485_ENABLED; - } - return ret; - } - - serial8250_em485_destroy(up); - - return 0; -} - static void omap_8250_unthrottle(struct uart_port *port) { struct omap8250_priv *priv = port->private_data; @@ -1187,7 +1157,7 @@ static int omap8250_probe(struct platform_device *pdev) up.port.shutdown = omap_8250_shutdown; up.port.throttle = omap_8250_throttle; up.port.unthrottle = omap_8250_unthrottle; - up.port.rs485_config = omap_8250_rs485_config; + up.port.rs485_config = serial8250_em485_config; up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); ret = of_alias_get_id(np, "serial"); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 40efcea8c6e7..73244806d701 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -615,7 +615,7 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put); * * Return 0 - success, -errno - otherwise */ -int serial8250_em485_init(struct uart_8250_port *p) +static int serial8250_em485_init(struct uart_8250_port *p) { if (p->em485) return 0; @@ -636,7 +636,6 @@ int serial8250_em485_init(struct uart_8250_port *p) return 0; } -EXPORT_SYMBOL_GPL(serial8250_em485_init); /** * serial8250_em485_destroy() - put uart_8250_port into normal state @@ -664,6 +663,44 @@ void serial8250_em485_destroy(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_em485_destroy); +/** + * serial8250_em485_config() - generic ->rs485_config() callback + * @port: uart port + * @rs485: rs485 settings + * + * Generic callback usable by 8250 uart drivers to activate rs485 settings + * if the uart is incapable of driving RTS as a Transmit Enable signal in + * hardware, relying on software emulation instead. + */ +int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + /* clamp the delays to [0, 100ms] */ + rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); + rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); + + port->rs485 = *rs485; + + /* + * Both serial8250_em485_init() and serial8250_em485_destroy() + * are idempotent. + */ + if (rs485->flags & SER_RS485_ENABLED) { + int ret = serial8250_em485_init(up); + + if (ret) { + rs485->flags &= ~SER_RS485_ENABLED; + port->rs485.flags &= ~SER_RS485_ENABLED; + } + return ret; + } + + serial8250_em485_destroy(up); + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_em485_config); + /* * These two wrappers ensure that enable_runtime_pm_tx() can be called more than * once and disable_runtime_pm_tx() will still disable RPM because the fifo is -- cgit From 6d3e54e1955ed1cd2da9a90c944290e91772cbcb Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Feb 2020 14:31:04 +0100 Subject: serial: 8250: Sanitize rs485 config harder Amend the generic ->rs485_config() callback to sanitize RTS polarity and zero-fill the padding (in addition to the existing sanitization of the RTS delays). Signed-off-by: Lukas Wunner Cc: Matwey V. Kornilov Link: https://lore.kernel.org/r/ff833721bc372d38678f289eb2a44dbf016d5203.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 73244806d701..d281aea061d6 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -676,10 +676,18 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) { struct uart_8250_port *up = up_to_u8250p(port); + /* pick sane settings if the user hasn't */ + if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) == + !!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { + rs485->flags |= SER_RS485_RTS_ON_SEND; + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + } + /* clamp the delays to [0, 100ms] */ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); + memset(rs485->padding, 0, sizeof(rs485->padding)); port->rs485 = *rs485; /* -- cgit From 41a70b7f4734fc4f8982a31c8c505357b4adacaa Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Feb 2020 14:31:05 +0100 Subject: serial: 8250: Deduplicate rs485 active_timer assignment When rs485 transmission over an 8250 port stops, __stop_tx() assigns active_timer = NULL before calling __stop_tx_rs485(). That function in turn either assigns active_timer = stop_tx_timer and rearms the timer (in case a delay_rts_after_send needs to be observed) or directly calls __do_stop_tx_rs485(). Move the assignment active_timer = NULL to __stop_tx_rs485() into the branch which directly calls __do_stop_tx_rs485(), thereby avoiding a duplicate assignment and simplifying the code. Signed-off-by: Lukas Wunner Cc: Matwey V. Kornilov Link: https://lore.kernel.org/r/bca638405550eaf92f0c6060b553b687f35885e0.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index d281aea061d6..1a71625a0d43 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1498,6 +1498,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p) p->port.rs485.delay_rts_after_send); } else { __do_stop_tx_rs485(p); + em485->active_timer = NULL; } } @@ -1522,8 +1523,6 @@ static inline void __stop_tx(struct uart_8250_port *p) if ((lsr & BOTH_EMPTY) != BOTH_EMPTY) return; - em485->active_timer = NULL; - __stop_tx_rs485(p); } __do_stop_tx(p); -- cgit From 058bc104f7ca5c83d81695ee96f03dbd93bae518 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Feb 2020 14:31:06 +0100 Subject: serial: 8250: Generalize rs485 software emulation Commit e490c9144cfa ("tty: Add software emulated RS485 support for 8250") introduced support to use RTS as an rs485 Transmit Enable signal. So far the only drivers taking advantage of it are 8250_omap.c and 8250_of.c. We're about to make use of the feature in 8250_bcm2835aux.c as well. The bcm2835aux differs from omap chips by inverting the meaning of RTS in the MCR register. Moreover, omap achieves half-duplex mode by disabling the RX interrupt and clearing the RX FIFO when TX stops. The bcm2835aux requires disabling the receiver instead. Support these behavioral differences by generalizing the rs485 emulation: Introduce ->rs485_start_tx() and ->rs485_stop_tx() callbacks in struct uart_8250_port, provide generic implementations containing the existing code and use them as callbacks in 8250_omap.c and 8250_of.c. start_tx_rs485() is idempotent in that it recognizes whether RTS is already asserted. Achieve the same by introducing a tx_stopped flag in struct uart_8250_em485. This may even perform a little better on arches where memory access is faster than mmio access. Signed-off-by: Lukas Wunner Cc: Matwey V. Kornilov Link: https://lore.kernel.org/r/5ac0464ae4414708e723a1e0d52b0c1b2bd41b9b.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 2 + drivers/tty/serial/8250/8250_core.c | 2 + drivers/tty/serial/8250/8250_of.c | 7 +++- drivers/tty/serial/8250/8250_omap.c | 2 + drivers/tty/serial/8250/8250_port.c | 82 ++++++++++++++++++++++++------------- 5 files changed, 64 insertions(+), 31 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 83a85210501f..52bb21205bb6 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -157,6 +157,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p); void serial8250_rpm_put_tx(struct uart_8250_port *p); int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485); +void serial8250_em485_start_tx(struct uart_8250_port *p); +void serial8250_em485_stop_tx(struct uart_8250_port *p); void serial8250_em485_destroy(struct uart_8250_port *p); /* MCR <-> TIOCM conversion */ diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 9a1d09fbb836..f6eb00406ddf 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1007,6 +1007,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.unthrottle = up->port.unthrottle; uart->port.rs485_config = up->port.rs485_config; uart->port.rs485 = up->port.rs485; + uart->rs485_start_tx = up->rs485_start_tx; + uart->rs485_stop_tx = up->rs485_stop_tx; uart->dma = up->dma; /* Take tx_loadsz from fifosize if it wasn't set separately */ diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 4a68a8785caa..65e9045dafe6 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -29,11 +29,12 @@ struct of_serial_info { * Fill a struct uart_port for a given device node */ static int of_platform_serial_setup(struct platform_device *ofdev, - int type, struct uart_port *port, + int type, struct uart_8250_port *up, struct of_serial_info *info) { struct resource resource; struct device_node *np = ofdev->dev.of_node; + struct uart_port *port = &up->port; u32 clk, spd, prop; int ret, irq; @@ -155,6 +156,8 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->dev = &ofdev->dev; port->rs485_config = serial8250_em485_config; + up->rs485_start_tx = serial8250_em485_start_tx; + up->rs485_stop_tx = serial8250_em485_stop_tx; switch (type) { case PORT_RT2880: @@ -201,7 +204,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev) return -ENOMEM; memset(&port8250, 0, sizeof(port8250)); - ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info); + ret = of_platform_serial_setup(ofdev, port_type, &port8250, info); if (ret) goto err_free; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index fff70cb25046..dd69226ce918 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1158,6 +1158,8 @@ static int omap8250_probe(struct platform_device *pdev) up.port.throttle = omap_8250_throttle; up.port.unthrottle = omap_8250_unthrottle; up.port.rs485_config = serial8250_em485_config; + up.rs485_start_tx = serial8250_em485_start_tx; + up.rs485_stop_tx = serial8250_em485_stop_tx; up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); ret = of_alias_get_id(np, "serial"); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 1a71625a0d43..8e8cca690bf9 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -557,17 +557,6 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) } } -static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p) -{ - unsigned char mcr = serial8250_in_MCR(p); - - if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) - mcr |= UART_MCR_RTS; - else - mcr &= ~UART_MCR_RTS; - serial8250_out_MCR(p, mcr); -} - static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t); static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t); @@ -632,7 +621,9 @@ static int serial8250_em485_init(struct uart_8250_port *p) p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx; p->em485->port = p; p->em485->active_timer = NULL; - serial8250_em485_rts_after_send(p); + p->em485->tx_stopped = true; + + p->rs485_stop_tx(p); return 0; } @@ -1439,9 +1430,21 @@ static void serial8250_stop_rx(struct uart_port *port) serial8250_rpm_put(up); } -static void __do_stop_tx_rs485(struct uart_8250_port *p) +/** + * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback + * @up: uart 8250 port + * + * Generic callback usable by 8250 uart drivers to stop rs485 transmission. + */ +void serial8250_em485_stop_tx(struct uart_8250_port *p) { - serial8250_em485_rts_after_send(p); + unsigned char mcr = serial8250_in_MCR(p); + + if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) + mcr |= UART_MCR_RTS; + else + mcr &= ~UART_MCR_RTS; + serial8250_out_MCR(p, mcr); /* * Empty the RX FIFO, we are not interested in anything @@ -1455,6 +1458,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p) serial_port_out(&p->port, UART_IER, p->ier); } } +EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); + static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) { struct uart_8250_em485 *em485; @@ -1467,8 +1472,9 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) serial8250_rpm_get(p); spin_lock_irqsave(&p->port.lock, flags); if (em485->active_timer == &em485->stop_tx_timer) { - __do_stop_tx_rs485(p); + p->rs485_stop_tx(p); em485->active_timer = NULL; + em485->tx_stopped = true; } spin_unlock_irqrestore(&p->port.lock, flags); serial8250_rpm_put(p); @@ -1489,7 +1495,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p) struct uart_8250_em485 *em485 = p->em485; /* - * __do_stop_tx_rs485 is going to set RTS according to config + * rs485_stop_tx() is going to set RTS according to config * AND flush RX FIFO if required. */ if (p->port.rs485.delay_rts_after_send > 0) { @@ -1497,8 +1503,9 @@ static void __stop_tx_rs485(struct uart_8250_port *p) start_hrtimer_ms(&em485->stop_tx_timer, p->port.rs485.delay_rts_after_send); } else { - __do_stop_tx_rs485(p); + p->rs485_stop_tx(p); em485->active_timer = NULL; + em485->tx_stopped = true; } } @@ -1572,25 +1579,42 @@ static inline void __start_tx(struct uart_port *port) } } -static inline void start_tx_rs485(struct uart_port *port) +/** + * serial8250_em485_start_tx() - generic ->rs485_start_tx() callback + * @up: uart 8250 port + * + * Generic callback usable by 8250 uart drivers to start rs485 transmission. + * Assumes that setting the RTS bit in the MCR register means RTS is high. + * (Some chips use inverse semantics.) Further assumes that reception is + * stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the + * UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.) + */ +void serial8250_em485_start_tx(struct uart_8250_port *up) { - struct uart_8250_port *up = up_to_u8250p(port); - struct uart_8250_em485 *em485 = up->em485; - unsigned char mcr; + unsigned char mcr = serial8250_in_MCR(up); if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) serial8250_stop_rx(&up->port); + if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) + mcr |= UART_MCR_RTS; + else + mcr &= ~UART_MCR_RTS; + serial8250_out_MCR(up, mcr); +} +EXPORT_SYMBOL_GPL(serial8250_em485_start_tx); + +static inline void start_tx_rs485(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + struct uart_8250_em485 *em485 = up->em485; + em485->active_timer = NULL; - mcr = serial8250_in_MCR(up); - if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) != - !!(mcr & UART_MCR_RTS)) { - if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) - mcr |= UART_MCR_RTS; - else - mcr &= ~UART_MCR_RTS; - serial8250_out_MCR(up, mcr); + if (em485->tx_stopped) { + em485->tx_stopped = false; + + up->rs485_start_tx(up); if (up->port.rs485.delay_rts_before_send > 0) { em485->active_timer = &em485->start_tx_timer; -- cgit From f93bf75891147602d55b90937628157cc13dbdb8 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Feb 2020 14:31:07 +0100 Subject: serial: 8250_bcm2835aux: Support rs485 software emulation Amend 8250_bcm2835aux.c to support rs485 as introduced for 8250_omap.c by commit e490c9144cfa ("tty: Add software emulated RS485 support for 8250"). The bcm2835aux differs from omap chips by inverting the meaning of RTS in the MCR register: If the bit is clear, RTS is high. With omap, it's apparently the other way round. Moreover, omap achieves half-duplex mode by disabling the UART_IER_RDI interrupt and clearing the RX FIFO when TX stops. This approach doesn't work on bcm2835aux because the UART_LSR_DR bit is set even when UART_IER_RDI is disabled. Consequently, serial8250_handle_irq() invokes serial8250_rx_chars() to empty the FIFO and characters are received even though the user requested half-duplex. Solve by disabling the receiver using the non-standard CNTL register. Cache that register in the driver's private data for performance. Set the private data pointer before calling serial8250_register_8250_port() to prevent a null pointer deref in case one of the rs485 callbacks is invoked immediately after port registration. Signed-off-by: Lukas Wunner Cc: Matwey V. Kornilov Link: https://lore.kernel.org/r/dd86460e20a8f979b7272a0bde73640312b902b1.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm2835aux.c | 62 ++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index 5cc03bf24f85..12d03e678295 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -6,6 +6,10 @@ * * Based on 8250_lpc18xx.c: * Copyright (C) 2015 Joachim Eastwood + * + * The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't + * take advantage of it yet. When adding support, be sure not to enable it + * simultaneously to rs485. */ #include @@ -16,16 +20,64 @@ #include "8250.h" +#define BCM2835_AUX_UART_CNTL 8 +#define BCM2835_AUX_UART_CNTL_RXEN 0x01 /* Receiver enable */ +#define BCM2835_AUX_UART_CNTL_TXEN 0x02 /* Transmitter enable */ +#define BCM2835_AUX_UART_CNTL_AUTORTS 0x04 /* RTS set by RX fill level */ +#define BCM2835_AUX_UART_CNTL_AUTOCTS 0x08 /* CTS stops transmitter */ +#define BCM2835_AUX_UART_CNTL_RTS3 0x00 /* RTS set until 3 chars left */ +#define BCM2835_AUX_UART_CNTL_RTS2 0x10 /* RTS set until 2 chars left */ +#define BCM2835_AUX_UART_CNTL_RTS1 0x20 /* RTS set until 1 chars left */ +#define BCM2835_AUX_UART_CNTL_RTS4 0x30 /* RTS set until 4 chars left */ +#define BCM2835_AUX_UART_CNTL_RTSINV 0x40 /* Invert auto RTS polarity */ +#define BCM2835_AUX_UART_CNTL_CTSINV 0x80 /* Invert auto CTS polarity */ + /** * struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART * @clk: clock producer of the port's uartclk * @line: index of the port's serial8250_ports[] entry + * @cntl: cached copy of CNTL register */ struct bcm2835aux_data { struct clk *clk; int line; + u32 cntl; }; +static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) +{ + if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { + struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev); + + data->cntl &= ~BCM2835_AUX_UART_CNTL_RXEN; + serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl); + } + + /* + * On the bcm2835aux, the MCR register contains no other + * flags besides RTS. So no need for a read-modify-write. + */ + if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) + serial8250_out_MCR(up, 0); + else + serial8250_out_MCR(up, UART_MCR_RTS); +} + +static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up) +{ + if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) + serial8250_out_MCR(up, 0); + else + serial8250_out_MCR(up, UART_MCR_RTS); + + if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { + struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev); + + data->cntl |= BCM2835_AUX_UART_CNTL_RXEN; + serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl); + } +} + static int bcm2835aux_serial_probe(struct platform_device *pdev) { struct uart_8250_port up = { }; @@ -47,6 +99,14 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) up.port.fifosize = 8; up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP; + up.port.rs485_config = serial8250_em485_config; + up.rs485_start_tx = bcm2835aux_rs485_start_tx; + up.rs485_stop_tx = bcm2835aux_rs485_stop_tx; + + /* initialize cached copy with power-on reset value */ + data->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN; + + platform_set_drvdata(pdev, data); /* get the clock - this also enables the HW */ data->clk = devm_clk_get(&pdev->dev, NULL); @@ -102,8 +162,6 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) } data->line = ret; - platform_set_drvdata(pdev, data); - return 0; dis_clk: -- cgit From 7f9803072ff636fc22ad941ff059e020e9d77ed4 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Feb 2020 14:31:08 +0100 Subject: serial: 8250: Support console on software emulated rs485 ports Commit e490c9144cfa ("tty: Add software emulated RS485 support for 8250") introduced support to use RTS as an rs485 Transmit Enable signal if data is transmitted through the tty layer. Console messages bypass the tty layer and instead are emitted via serial8250_console_write(). Amend that function to drive RTS as well, allowing for a console on rs485 ports. Note that serial8250_console_write() may be called concurrently to the tty layer accessing the port. The two protect their accesses with the port lock, but serial8250_console_write() may find RTS still being asserted by the tty layer, in which case it shouldn't be deasserted after the console message has been printed. Recognize such situations by checking the em485->tx_stopped flag. If a delay_rts_before_send or delay_rts_after_send has been specified, serial8250_console_write() busy-waits for its duration. Optimizations for those wait times are conceivable: E.g. if RTS is already asserted, we could check whether em485->start_tx_timer is active and wait only for the remaining expire time. But this would require calling into the hrtimer infrastructure, which involves acquiring locks and potentially reprogramming timer hardware. Such operations seem too risky in the context of console printout, which needs to work even when the kernel has crashed and emits a BUG splat. So I've gone with a simplistic solution which just always waits for the full delay. Signed-off-by: Lukas Wunner Cc: Matwey V. Kornilov Link: https://lore.kernel.org/r/65edffce4670a19e598015c03cbe46f1ffd93e43.1582895077.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 8e8cca690bf9..0879bb8855cf 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -3204,6 +3204,7 @@ static void serial8250_console_restore(struct uart_8250_port *up) void serial8250_console_write(struct uart_8250_port *up, const char *s, unsigned int count) { + struct uart_8250_em485 *em485 = up->em485; struct uart_port *port = &up->port; unsigned long flags; unsigned int ier; @@ -3234,6 +3235,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, up->canary = 0; } + if (em485) { + if (em485->tx_stopped) + up->rs485_start_tx(up); + mdelay(port->rs485.delay_rts_before_send); + } + uart_console_write(port, s, count, serial8250_console_putchar); /* @@ -3243,6 +3250,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, wait_for_xmitr(up, BOTH_EMPTY); serial_port_out(port, UART_IER, ier); + if (em485) { + mdelay(port->rs485.delay_rts_before_send); + if (em485->tx_stopped) + up->rs485_stop_tx(up); + } + /* * The receive handling will happen properly because the * receive ready bit will still be set; it is not cleared -- cgit From eaee41727e6d8a7d2b94421c25e82b00cb2fded5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 2 Mar 2020 17:51:34 +0000 Subject: sysctl/sysrq: Remove __sysrq_enabled copy Many embedded boards have a disconnected TTL level serial which can generate some garbage that can lead to spurious false sysrq detects. Currently, sysrq can be either completely disabled for serial console or always disabled (with CONFIG_MAGIC_SYSRQ_SERIAL), since commit 732dbf3a6104 ("serial: do not accept sysrq characters via serial port") At Arista, we have such boards that can generate BREAK and random garbage. While disabling sysrq for serial console would solve the problem with spurious false sysrq triggers, it's also desirable to have a way to enable sysrq back. Having the way to enable sysrq was beneficial to debug lockups with a manual investigation in field and on the other side preventing false sysrq detections. As a preparation to add sysrq_toggle_support() call into uart, remove a private copy of sysrq_enabled from sysctl - it should reflect the actual status of sysrq. Furthermore, the private copy isn't correct already in case sysrq_always_enabled is true. So, remove __sysrq_enabled and use a getter-helper sysrq_mask() to check sysrq_key_op enabled status. Cc: Iurii Zaikin Cc: Jiri Slaby Cc: Luis Chamberlain Cc: Kees Cook Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Dmitry Safonov Link: https://lore.kernel.org/r/20200302175135.269397-2-dima@arista.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/sysrq.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index f724962a5906..5e0d0813da55 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -63,6 +63,18 @@ static bool sysrq_on(void) return sysrq_enabled || sysrq_always_enabled; } +/** + * sysrq_mask - Getter for sysrq_enabled mask. + * + * Return: 1 if sysrq is always enabled, enabled sysrq_key_op mask otherwise. + */ +int sysrq_mask(void) +{ + if (sysrq_always_enabled) + return 1; + return sysrq_enabled; +} + /* * A value of 1 means 'all', other nonzero values are an op mask: */ -- cgit From 68af43173d3fcece70bef49cb992c64c4c68ff23 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 2 Mar 2020 17:51:35 +0000 Subject: serial/sysrq: Add MAGIC_SYSRQ_SERIAL_SEQUENCE Many embedded boards have a disconnected TTL level serial which can generate some garbage that can lead to spurious false sysrq detects. Currently, sysrq can be either completely disabled for serial console or always disabled (with CONFIG_MAGIC_SYSRQ_SERIAL), since commit 732dbf3a6104 ("serial: do not accept sysrq characters via serial port") At Arista, we have such boards that can generate BREAK and random garbage. While disabling sysrq for serial console would solve the problem with spurious false sysrq triggers, it's also desirable to have a way to enable sysrq back. As a measure of balance between on and off options, add MAGIC_SYSRQ_SERIAL_SEQUENCE which is a string sequence that can enable sysrq if it follows BREAK on a serial line. The longer the string - the less likely it may be in the garbage. Having the way to enable sysrq was beneficial to debug lockups with a manual investigation in field and on the other side preventing false sysrq detections. Based-on-patch-by: Vasiliy Khoruzhick Signed-off-by: Dmitry Safonov Link: https://lore.kernel.org/r/20200302175135.269397-3-dima@arista.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 75 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 5444293fe2e8..863e3e0c2d39 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -20,6 +20,7 @@ #include #include /* for serial_state and serial_icounter_struct */ #include +#include #include #include #include @@ -40,6 +41,8 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) +#define SYSRQ_TIMEOUT (HZ * 5) + static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); @@ -3084,6 +3087,56 @@ void uart_insert_char(struct uart_port *port, unsigned int status, } EXPORT_SYMBOL_GPL(uart_insert_char); +#ifdef CONFIG_MAGIC_SYSRQ_SERIAL +static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE; + +static void uart_sysrq_on(struct work_struct *w) +{ + sysrq_toggle_support(1); + pr_info("SysRq is enabled by magic sequence on serial\n"); +} +static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on); + +/** + * uart_try_toggle_sysrq - Enables SysRq from serial line + * @port: uart_port structure where char(s) after BREAK met + * @ch: new character in the sequence after received BREAK + * + * Enables magic SysRq when the required sequence is met on port + * (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE). + * + * Returns false if @ch is out of enabling sequence and should be + * handled some other way, true if @ch was consumed. + */ +static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) +{ + if (ARRAY_SIZE(sysrq_toggle_seq) <= 1) + return false; + + BUILD_BUG_ON(ARRAY_SIZE(sysrq_toggle_seq) >= U8_MAX); + if (sysrq_toggle_seq[port->sysrq_seq] != ch) { + port->sysrq_seq = 0; + return false; + } + + /* Without the last \0 */ + if (++port->sysrq_seq < (ARRAY_SIZE(sysrq_toggle_seq) - 1)) { + port->sysrq = jiffies + SYSRQ_TIMEOUT; + return true; + } + + schedule_work(&sysrq_enable_work); + + port->sysrq = 0; + return true; +} +#else +static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) +{ + return false; +} +#endif + int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) { if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL)) @@ -3093,9 +3146,13 @@ int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) return 0; if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch); - port->sysrq = 0; - return 1; + if (sysrq_mask()) { + handle_sysrq(ch); + port->sysrq = 0; + return 1; + } + if (uart_try_toggle_sysrq(port, ch)) + return 1; } port->sysrq = 0; @@ -3112,9 +3169,13 @@ int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) return 0; if (ch && time_before(jiffies, port->sysrq)) { - port->sysrq_ch = ch; - port->sysrq = 0; - return 1; + if (sysrq_mask()) { + port->sysrq_ch = ch; + port->sysrq = 0; + return 1; + } + if (uart_try_toggle_sysrq(port, ch)) + return 1; } port->sysrq = 0; @@ -3154,7 +3215,7 @@ int uart_handle_break(struct uart_port *port) if (port->has_sysrq) { if (port->cons && port->cons->index == port->line) { if (!port->sysrq) { - port->sysrq = jiffies + HZ*5; + port->sysrq = jiffies + SYSRQ_TIMEOUT; return 1; } port->sysrq = 0; -- cgit From d24e163af05c93e923aff76e01e6e30182cb38e3 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Fri, 6 Mar 2020 15:47:01 +0300 Subject: tty: mips_ejtag_fdc: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark mips_ejtag_fdc_encode() methods switch-case-4 as expecting to fall through. This patch fixes the following warning: drivers/tty/mips_ejtag_fdc.c: In function ‘mips_ejtag_fdc_encode’: drivers/tty/mips_ejtag_fdc.c:245:13: warning: this statement may fall through [-Wimplicit-fallthrough=] word.word &= 0x00ffffff; ~~~~~~~~~~^~~~~~~~~~~~~ drivers/tty/mips_ejtag_fdc.c:246:2: note: here case 3: ^~~~ Signed-off-by: Serge Semin Signed-off-by: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Link: https://lore.kernel.org/r/20200306124913.151A68030792@mail.baikalelectronics.ru Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mips_ejtag_fdc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty') diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 620d8488b83e..21e76a2ec182 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -243,6 +243,7 @@ done: /* Fall back to a 3 byte encoding */ word.bytes = 3; word.word &= 0x00ffffff; + /* Fall through */ case 3: /* 3 byte encoding */ word.word |= 0x82000000; -- cgit From 4cbd7814bbd595061fcb6d6355d63f04179161cd Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Fri, 6 Mar 2020 20:26:38 -0800 Subject: tty: sifive: Finish transmission before changing the clock SiFive's UART has a software controller clock divider that produces the final baud rate clock. Whenever the clock that drives the UART is changed this divider must be updated accordingly, and given that these two events are controlled by software they cannot be done atomically. During the period between updating the UART's driving clock and internal divider the UART will transmit a different baud rate than what the user has configured, which will probably result in a corrupted transmission stream. The SiFive UART has a FIFO, but due to an issue with the programming interface there is no way to directly determine when the UART has finished transmitting. We're essentially restricted to dead reckoning in order to figure that out: we can use the FIFO's TX busy register to figure out when the last frame has begun transmission and just delay for a long enough that the last frame is guaranteed to get out. As far as the actual implementation goes: I've modified the existing existing clock notifier function to drain both the FIFO and the shift register in on PRE_RATE_CHANGE. As far as I know there is no hardware flow control in this UART, so there's no good way to ask the other end to stop transmission while we can't receive (inserting software flow control messages seems like a bad idea here). Signed-off-by: Palmer Dabbelt Tested-by: Yash Shah Link: https://lore.kernel.org/r/20200307042637.83728-1-palmer@dabbelt.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sifive.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index d5f81b98e4d7..d34031e842d0 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -618,10 +618,10 @@ static void sifive_serial_shutdown(struct uart_port *port) * * On the V0 SoC, the UART IP block is derived from the CPU clock source * after a synchronous divide-by-two divider, so any CPU clock rate change - * requires the UART baud rate to be updated. This presumably could corrupt any - * serial word currently being transmitted or received. It would probably - * be better to stop receives and transmits, then complete the baud rate - * change, then re-enable them. + * requires the UART baud rate to be updated. This presumably corrupts any + * serial word currently being transmitted or received. In order to avoid + * corrupting the output data stream, we drain the transmit queue before + * allowing the clock's rate to be changed. */ static int sifive_serial_clk_notifier(struct notifier_block *nb, unsigned long event, void *data) @@ -629,6 +629,26 @@ static int sifive_serial_clk_notifier(struct notifier_block *nb, struct clk_notifier_data *cnd = data; struct sifive_serial_port *ssp = notifier_to_sifive_serial_port(nb); + if (event == PRE_RATE_CHANGE) { + /* + * The TX watermark is always set to 1 by this driver, which + * means that the TX busy bit will lower when there are 0 bytes + * left in the TX queue -- in other words, when the TX FIFO is + * empty. + */ + __ssp_wait_for_xmitr(ssp); + /* + * On the cycle the TX FIFO goes empty there is still a full + * UART frame left to be transmitted in the shift register. + * The UART provides no way for software to directly determine + * when that last frame has been transmitted, so we just sleep + * here instead. As we're not tracking the number of stop bits + * they're just worst cased here. The rest of the serial + * framing parameters aren't configurable by software. + */ + udelay(DIV_ROUND_UP(12 * 1000 * 1000, ssp->baud_rate)); + } + if (event == POST_RATE_CHANGE && ssp->clkin_rate != cnd->new_rate) { ssp->clkin_rate = cnd->new_rate; __ssp_update_div(ssp); -- cgit From cfb7bdfc69782717f83657d9d888e84961dfc5ad Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 11 Mar 2020 11:00:27 +0200 Subject: serial: pic32_uart: Use uart_console() helper Use uart_console() helper in instead of open coded variant. Note, SERIAL_CORE_CONSOLE is selected by SERIAL_PIC32_CONSOLE, thus no functional changes expected. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200311090027.64441-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pic32_uart.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index 484b7e8d5381..0a12fb11e698 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -768,11 +768,6 @@ static int __init pic32_console_init(void) } console_initcall(pic32_console_init); -static inline bool is_pic32_console_port(struct uart_port *port) -{ - return port->cons && port->cons->index == port->line; -} - /* * Late console initialization. */ @@ -873,8 +868,7 @@ static int pic32_uart_probe(struct platform_device *pdev) } #ifdef CONFIG_SERIAL_PIC32_CONSOLE - if (is_pic32_console_port(port) && - (pic32_console.flags & CON_ENABLED)) { + if (uart_console(port) && (pic32_console.flags & CON_ENABLED)) { /* The peripheral clock has been enabled by console_setup, * so disable it till the port is used. */ -- cgit From 207f6f34fb101aecb27a1487434491e958229e5b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Mar 2020 15:30:57 +0200 Subject: tty/serial: atmel: Use uart_console() helper Use uart_console() helper in instead of open coded variant. Note, SERIAL_CORE_CONSOLE is selected by SERIAL_ATMEL_CONSOLE, thus no functional changes expected. Signed-off-by: Andy Shevchenko Acked-by: Richard Genoud Link: https://lore.kernel.org/r/20200310133057.86840-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d1ab6a0a5c74..8d7080efad9b 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2676,18 +2676,8 @@ static struct console atmel_console = { #define ATMEL_CONSOLE_DEVICE (&atmel_console) -static inline bool atmel_is_console_port(struct uart_port *port) -{ - return port->cons && port->cons->index == port->line; -} - #else #define ATMEL_CONSOLE_DEVICE NULL - -static inline bool atmel_is_console_port(struct uart_port *port) -{ - return false; -} #endif static struct uart_driver atmel_uart = { @@ -2716,14 +2706,14 @@ static int atmel_serial_suspend(struct platform_device *pdev, struct uart_port *port = platform_get_drvdata(pdev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (atmel_is_console_port(port) && console_suspend_enabled) { + if (uart_console(port) && console_suspend_enabled) { /* Drain the TX shifter */ while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXEMPTY)) cpu_relax(); } - if (atmel_is_console_port(port) && !console_suspend_enabled) { + if (uart_console(port) && !console_suspend_enabled) { /* Cache register values as we won't get a full shutdown/startup * cycle */ @@ -2759,7 +2749,7 @@ static int atmel_serial_resume(struct platform_device *pdev) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; - if (atmel_is_console_port(port) && !console_suspend_enabled) { + if (uart_console(port) && !console_suspend_enabled) { atmel_uart_writel(port, ATMEL_US_MR, atmel_port->cache.mr); atmel_uart_writel(port, ATMEL_US_IER, atmel_port->cache.imr); atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->cache.brgr); @@ -2913,7 +2903,7 @@ static int atmel_serial_probe(struct platform_device *pdev) goto err_add_port; #ifdef CONFIG_SERIAL_ATMEL_CONSOLE - if (atmel_is_console_port(&atmel_port->uart) + if (uart_console(&atmel_port->uart) && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { /* * The serial core enabled the clock for us, so undo @@ -2956,7 +2946,7 @@ err_add_port: kfree(atmel_port->rx_ring.buf); atmel_port->rx_ring.buf = NULL; err_alloc_ring: - if (!atmel_is_console_port(&atmel_port->uart)) { + if (!uart_console(&atmel_port->uart)) { clk_put(atmel_port->clk); atmel_port->clk = NULL; } -- cgit From 159381df1442f3c781ae3de05b5c6130fd4ee058 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 6 Mar 2020 22:44:30 +0100 Subject: tty: serial: fsl_lpuart: fix DMA operation when using IOMMU The DMA channel might not be available at probe time. This is esp. the case if the DMA controller has an IOMMU mapping. There is also another caveat. If there is no DMA controller at all, dma_request_chan() will also return -EPROBE_DEFER. Thus we cannot test for -EPROBE_DEFER in probe(). Otherwise the lpuart driver will fail to probe if, for example, the DMA driver is not enabled in the kernel configuration. To workaround this, we request the DMA channel in _startup(). Other serial drivers do it the same way. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20200306214433.23215-2-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 88 ++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 31 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index c31b8f3db6bf..33798df4d727 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1493,36 +1493,67 @@ static void rx_dma_timer_init(struct lpuart_port *sport) static void lpuart_tx_dma_startup(struct lpuart_port *sport) { u32 uartbaud; + int ret; - if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) { - init_waitqueue_head(&sport->dma_wait); - sport->lpuart_dma_tx_use = true; - if (lpuart_is_32(sport)) { - uartbaud = lpuart32_read(&sport->port, UARTBAUD); - lpuart32_write(&sport->port, - uartbaud | UARTBAUD_TDMAE, UARTBAUD); - } else { - writeb(readb(sport->port.membase + UARTCR5) | - UARTCR5_TDMAS, sport->port.membase + UARTCR5); - } + sport->dma_tx_chan = dma_request_chan(sport->port.dev, "tx"); + if (IS_ERR(sport->dma_tx_chan)) { + dev_info_once(sport->port.dev, + "DMA tx channel request failed, operating without tx DMA (%ld)\n", + PTR_ERR(sport->dma_tx_chan)); + sport->dma_tx_chan = NULL; + goto err; + } + + ret = lpuart_dma_tx_request(&sport->port); + if (!ret) + goto err; + + init_waitqueue_head(&sport->dma_wait); + sport->lpuart_dma_tx_use = true; + if (lpuart_is_32(sport)) { + uartbaud = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, + uartbaud | UARTBAUD_TDMAE, UARTBAUD); } else { - sport->lpuart_dma_tx_use = false; + writeb(readb(sport->port.membase + UARTCR5) | + UARTCR5_TDMAS, sport->port.membase + UARTCR5); } + + return; + +err: + sport->lpuart_dma_tx_use = false; } static void lpuart_rx_dma_startup(struct lpuart_port *sport) { - if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { - /* set Rx DMA timeout */ - sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); - if (!sport->dma_rx_timeout) - sport->dma_rx_timeout = 1; + int ret; - sport->lpuart_dma_rx_use = true; - rx_dma_timer_init(sport); - } else { - sport->lpuart_dma_rx_use = false; + sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx"); + if (IS_ERR(sport->dma_rx_chan)) { + dev_info_once(sport->port.dev, + "DMA rx channel request failed, operating without rx DMA (%ld)\n", + PTR_ERR(sport->dma_rx_chan)); + sport->dma_rx_chan = NULL; + goto err; } + + ret = lpuart_start_rx_dma(sport); + if (ret) + goto err; + + /* set Rx DMA timeout */ + sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); + if (!sport->dma_rx_timeout) + sport->dma_rx_timeout = 1; + + sport->lpuart_dma_rx_use = true; + rx_dma_timer_init(sport); + + return; + +err: + sport->lpuart_dma_rx_use = false; } static int lpuart_startup(struct uart_port *port) @@ -1615,6 +1646,11 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport) dmaengine_terminate_all(sport->dma_tx_chan); } } + + if (sport->dma_tx_chan) + dma_release_channel(sport->dma_tx_chan); + if (sport->dma_rx_chan) + dma_release_channel(sport->dma_rx_chan); } static void lpuart_shutdown(struct uart_port *port) @@ -2520,16 +2556,6 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.rs485_config(&sport->port, &sport->port.rs485); - sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx"); - if (!sport->dma_tx_chan) - dev_info(sport->port.dev, "DMA tx channel request failed, " - "operating without tx DMA\n"); - - sport->dma_rx_chan = dma_request_slave_channel(sport->port.dev, "rx"); - if (!sport->dma_rx_chan) - dev_info(sport->port.dev, "DMA rx channel request failed, " - "operating without rx DMA\n"); - return 0; failed_attach_port: -- cgit From a092ab25fdaa445b821f5959e458350696fce44c Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 6 Mar 2020 22:44:31 +0100 Subject: tty: serial: fsl_lpuart: fix DMA mapping Use the correct device to request the DMA mapping. Otherwise the IOMMU doesn't get the mapping and it will generate a page fault. The error messages look like: [ 19.012140] arm-smmu 5000000.iommu: Unhandled context fault: fsr=0x402, iova=0xbbfff800, fsynr=0x3e0021, cbfrsynra=0x828, cb=9 [ 19.023593] arm-smmu 5000000.iommu: Unhandled context fault: fsr=0x402, iova=0xbbfff800, fsynr=0x3e0021, cbfrsynra=0x828, cb=9 This was tested on a custom board with a LS1028A SoC. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20200306214433.23215-3-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 48 ++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 33798df4d727..f45f97cb769c 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -409,6 +409,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport) struct circ_buf *xmit = &sport->port.state->xmit; struct scatterlist *sgl = sport->tx_sgl; struct device *dev = sport->port.dev; + struct dma_chan *chan = sport->dma_tx_chan; int ret; if (sport->dma_tx_in_progress) @@ -427,17 +428,19 @@ static void lpuart_dma_tx(struct lpuart_port *sport) sg_set_buf(sgl + 1, xmit->buf, xmit->head); } - ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + ret = dma_map_sg(chan->device->dev, sgl, sport->dma_tx_nents, + DMA_TO_DEVICE); if (!ret) { dev_err(dev, "DMA mapping error for TX.\n"); return; } - sport->dma_tx_desc = dmaengine_prep_slave_sg(sport->dma_tx_chan, sgl, + sport->dma_tx_desc = dmaengine_prep_slave_sg(chan, sgl, ret, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); if (!sport->dma_tx_desc) { - dma_unmap_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents, + DMA_TO_DEVICE); dev_err(dev, "Cannot prepare TX slave DMA!\n"); return; } @@ -446,7 +449,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport) sport->dma_tx_desc->callback_param = sport; sport->dma_tx_in_progress = true; sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc); - dma_async_issue_pending(sport->dma_tx_chan); + dma_async_issue_pending(chan); } static bool lpuart_stopped_or_empty(struct uart_port *port) @@ -459,11 +462,13 @@ static void lpuart_dma_tx_complete(void *arg) struct lpuart_port *sport = arg; struct scatterlist *sgl = &sport->tx_sgl[0]; struct circ_buf *xmit = &sport->port.state->xmit; + struct dma_chan *chan = sport->dma_tx_chan; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); - dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents, + DMA_TO_DEVICE); xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1); @@ -529,15 +534,16 @@ static bool lpuart_is_32(struct lpuart_port *sport) static void lpuart_flush_buffer(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + struct dma_chan *chan = sport->dma_tx_chan; u32 val; if (sport->lpuart_dma_tx_use) { if (sport->dma_tx_in_progress) { - dma_unmap_sg(sport->port.dev, &sport->tx_sgl[0], + dma_unmap_sg(chan->device->dev, &sport->tx_sgl[0], sport->dma_tx_nents, DMA_TO_DEVICE); sport->dma_tx_in_progress = false; } - dmaengine_terminate_all(sport->dma_tx_chan); + dmaengine_terminate_all(chan); } if (lpuart_is_32(sport)) { @@ -993,6 +999,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) struct tty_port *port = &sport->port.state->port; struct dma_tx_state state; enum dma_status dmastat; + struct dma_chan *chan = sport->dma_rx_chan; struct circ_buf *ring = &sport->rx_ring; unsigned long flags; int count = 0; @@ -1053,10 +1060,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) spin_lock_irqsave(&sport->port.lock, flags); - dmastat = dmaengine_tx_status(sport->dma_rx_chan, - sport->dma_rx_cookie, - &state); - + dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state); if (dmastat == DMA_ERROR) { dev_err(sport->port.dev, "Rx DMA transfer failed!\n"); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1064,7 +1068,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) } /* CPU claims ownership of RX DMA buffer */ - dma_sync_sg_for_cpu(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); + dma_sync_sg_for_cpu(chan->device->dev, &sport->rx_sgl, 1, + DMA_FROM_DEVICE); /* * ring->head points to the end of data already written by the DMA. @@ -1106,7 +1111,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) sport->port.icount.rx += count; } - dma_sync_sg_for_device(sport->port.dev, &sport->rx_sgl, 1, + dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1138,6 +1143,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) struct tty_port *port = &sport->port.state->port; struct tty_struct *tty = port->tty; struct ktermios *termios = &tty->termios; + struct dma_chan *chan = sport->dma_rx_chan; baud = tty_get_baud_rate(tty); @@ -1159,7 +1165,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) return -ENOMEM; sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len); - nent = dma_map_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); + nent = dma_map_sg(chan->device->dev, &sport->rx_sgl, 1, + DMA_FROM_DEVICE); if (!nent) { dev_err(sport->port.dev, "DMA Rx mapping error\n"); @@ -1170,7 +1177,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_rx_sconfig.src_maxburst = 1; dma_rx_sconfig.direction = DMA_DEV_TO_MEM; - ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig); + ret = dmaengine_slave_config(chan, &dma_rx_sconfig); if (ret < 0) { dev_err(sport->port.dev, @@ -1178,7 +1185,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) return ret; } - sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan, + sport->dma_rx_desc = dmaengine_prep_dma_cyclic(chan, sg_dma_address(&sport->rx_sgl), sport->rx_sgl.length, sport->rx_sgl.length / 2, @@ -1192,7 +1199,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) sport->dma_rx_desc->callback = lpuart_dma_rx_complete; sport->dma_rx_desc->callback_param = sport; sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); - dma_async_issue_pending(sport->dma_rx_chan); + dma_async_issue_pending(chan); if (lpuart_is_32(sport)) { unsigned long temp = lpuart32_read(&sport->port, UARTBAUD); @@ -1210,11 +1217,12 @@ static void lpuart_dma_rx_free(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + struct dma_chan *chan = sport->dma_rx_chan; - if (sport->dma_rx_chan) - dmaengine_terminate_all(sport->dma_rx_chan); + if (chan) + dmaengine_terminate_all(chan); - dma_unmap_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); + dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); kfree(sport->rx_ring.buf); sport->rx_ring.tail = 0; sport->rx_ring.head = 0; -- cgit From c2f448cff22a7ed09281f02bde084b0ce3bc61ed Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 6 Mar 2020 22:44:32 +0100 Subject: tty: serial: fsl_lpuart: add LS1028A support The LS1028A uses little endian register access and has a different FIFO size encoding. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20200306214433.23215-4-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index f45f97cb769c..1d4f75716e32 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -234,6 +234,7 @@ static DEFINE_IDA(fsl_lpuart_ida); enum lpuart_type { VF610_LPUART, LS1021A_LPUART, + LS1028A_LPUART, IMX7ULP_LPUART, IMX8QXP_LPUART, }; @@ -278,11 +279,16 @@ static const struct lpuart_soc_data vf_data = { .iotype = UPIO_MEM, }; -static const struct lpuart_soc_data ls_data = { +static const struct lpuart_soc_data ls1021a_data = { .devtype = LS1021A_LPUART, .iotype = UPIO_MEM32BE, }; +static const struct lpuart_soc_data ls1028a_data = { + .devtype = LS1028A_LPUART, + .iotype = UPIO_MEM32, +}; + static struct lpuart_soc_data imx7ulp_data = { .devtype = IMX7ULP_LPUART, .iotype = UPIO_MEM32, @@ -297,7 +303,8 @@ static struct lpuart_soc_data imx8qxp_data = { static const struct of_device_id lpuart_dt_ids[] = { { .compatible = "fsl,vf610-lpuart", .data = &vf_data, }, - { .compatible = "fsl,ls1021a-lpuart", .data = &ls_data, }, + { .compatible = "fsl,ls1021a-lpuart", .data = &ls1021a_data, }, + { .compatible = "fsl,ls1028a-lpuart", .data = &ls1028a_data, }, { .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, }, { .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, }, { /* sentinel */ } @@ -307,6 +314,11 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids); /* Forward declare this for the dma callbacks*/ static void lpuart_dma_tx_complete(void *arg); +static inline bool is_ls1028a_lpuart(struct lpuart_port *sport) +{ + return sport->devtype == LS1028A_LPUART; +} + static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport) { return sport->devtype == IMX8QXP_LPUART; @@ -1626,6 +1638,17 @@ static int lpuart32_startup(struct uart_port *port) sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); + /* + * The LS1028A has a fixed length of 16 words. Although it supports the + * RX/TXSIZE fields their encoding is different. Eg the reference manual + * states 0b101 is 16 words. + */ + if (is_ls1028a_lpuart(sport)) { + sport->rxfifo_size = 16; + sport->txfifo_size = 16; + sport->port.fifosize = sport->txfifo_size; + } + spin_lock_irqsave(&sport->port.lock, flags); lpuart32_setup_watermark_enable(sport); -- cgit From e33253f3b74b5fb2a3436c26c56252a3a8159228 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 6 Mar 2020 22:44:33 +0100 Subject: tty: serial: fsl_lpuart: add LS1028A earlycon support Add a early_console_setup() for the LS1028A SoC with 32bit, little endian access. If the bootloader does a fixup of the clock-frequency node the baudrate divisor register will automatically be set. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20200306214433.23215-5-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 51 ++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 1d4f75716e32..9c6a018b1390 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1878,11 +1878,12 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&sport->port.lock, flags); } -static void -lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate) +static void __lpuart32_serial_setbrg(struct uart_port *port, + unsigned int baudrate, bool use_rx_dma, + bool use_tx_dma) { u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp; - u32 clk = sport->port.uartclk; + u32 clk = port->uartclk; /* * The idea is to use the best OSR (over-sampling rate) possible. @@ -1928,10 +1929,10 @@ lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate) /* handle buadrate outside acceptable rate */ if (baud_diff > ((baudrate / 100) * 3)) - dev_warn(sport->port.dev, + dev_warn(port->dev, "unacceptable baud rate difference of more than 3%%\n"); - tmp = lpuart32_read(&sport->port, UARTBAUD); + tmp = lpuart32_read(port, UARTBAUD); if ((osr > 3) && (osr < 8)) tmp |= UARTBAUD_BOTHEDGE; @@ -1942,14 +1943,23 @@ lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate) tmp &= ~UARTBAUD_SBR_MASK; tmp |= sbr & UARTBAUD_SBR_MASK; - if (!sport->lpuart_dma_rx_use) + if (!use_rx_dma) tmp &= ~UARTBAUD_RDMAE; - if (!sport->lpuart_dma_tx_use) + if (!use_tx_dma) tmp &= ~UARTBAUD_TDMAE; - lpuart32_write(&sport->port, tmp, UARTBAUD); + lpuart32_write(port, tmp, UARTBAUD); +} + +static void lpuart32_serial_setbrg(struct lpuart_port *sport, + unsigned int baudrate) +{ + __lpuart32_serial_setbrg(&sport->port, baudrate, + sport->lpuart_dma_rx_use, + sport->lpuart_dma_tx_use); } + static void lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -2443,6 +2453,30 @@ static int __init lpuart32_early_console_setup(struct earlycon_device *device, return 0; } +static int __init ls1028a_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + u32 cr; + + if (!device->port.membase) + return -ENODEV; + + device->port.iotype = UPIO_MEM32; + device->con->write = lpuart32_early_write; + + /* set the baudrate */ + if (device->port.uartclk && device->baud) + __lpuart32_serial_setbrg(&device->port, device->baud, + false, false); + + /* enable transmitter */ + cr = lpuart32_read(&device->port, UARTCTRL); + cr |= UARTCTRL_TE; + lpuart32_write(&device->port, cr, UARTCTRL); + + return 0; +} + static int __init lpuart32_imx_early_console_setup(struct earlycon_device *device, const char *opt) { @@ -2457,6 +2491,7 @@ static int __init lpuart32_imx_early_console_setup(struct earlycon_device *devic } OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup); +OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1028a-lpuart", ls1028a_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup); EARLYCON_DECLARE(lpuart, lpuart_early_console_setup); EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup); -- cgit From b685e6febde68ae1f022e084f2d0df82e573c44c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 11 Mar 2020 09:31:30 +0100 Subject: tty: serial: ifx6x60: Use helper variable for dev The &spi->dev is used so many times that the code gets visibly better by introducing a simple dev helper variable. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20200311083131.693908-1-linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ifx6x60.c | 45 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 31033d517e82..32a0ccef9339 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -992,22 +992,23 @@ static int ifx_spi_spi_probe(struct spi_device *spi) int srdy; struct ifx_modem_platform_data *pl_data; struct ifx_spi_device *ifx_dev; + struct device *dev = &spi->dev; if (saved_ifx_dev) { - dev_dbg(&spi->dev, "ignoring subsequent detection"); + dev_dbg(dev, "ignoring subsequent detection"); return -ENODEV; } - pl_data = dev_get_platdata(&spi->dev); + pl_data = dev_get_platdata(dev); if (!pl_data) { - dev_err(&spi->dev, "missing platform data!"); + dev_err(dev, "missing platform data!"); return -ENODEV; } /* initialize structure to hold our device variables */ ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL); if (!ifx_dev) { - dev_err(&spi->dev, "spi device allocation failed"); + dev_err(dev, "spi device allocation failed"); return -ENOMEM; } saved_ifx_dev = ifx_dev; @@ -1026,7 +1027,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) spi->bits_per_word = spi_bpw; ret = spi_setup(spi); if (ret) { - dev_err(&spi->dev, "SPI setup wasn't successful %d", ret); + dev_err(dev, "SPI setup wasn't successful %d", ret); kfree(ifx_dev); return -ENODEV; } @@ -1049,7 +1050,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) &ifx_dev->tx_bus, GFP_KERNEL); if (!ifx_dev->tx_buffer) { - dev_err(&spi->dev, "DMA-TX buffer allocation failed"); + dev_err(dev, "DMA-TX buffer allocation failed"); ret = -ENOMEM; goto error_ret; } @@ -1058,7 +1059,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) &ifx_dev->rx_bus, GFP_KERNEL); if (!ifx_dev->rx_buffer) { - dev_err(&spi->dev, "DMA-RX buffer allocation failed"); + dev_err(dev, "DMA-RX buffer allocation failed"); ret = -ENOMEM; goto error_ret; } @@ -1075,7 +1076,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) /* create our tty port */ ret = ifx_spi_create_port(ifx_dev); if (ret != 0) { - dev_err(&spi->dev, "create default tty port failed"); + dev_err(dev, "create default tty port failed"); goto error_ret; } @@ -1085,21 +1086,21 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ifx_dev->gpio.srdy = pl_data->srdy; ifx_dev->gpio.reset_out = pl_data->rst_out; - dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d", + dev_info(dev, "gpios %d, %d, %d, %d, %d", ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy, ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out); /* Configure gpios */ ret = gpio_request(ifx_dev->gpio.reset, "ifxModem"); if (ret < 0) { - dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)", + dev_err(dev, "Unable to allocate GPIO%d (RESET)", ifx_dev->gpio.reset); goto error_ret; } ret += gpio_direction_output(ifx_dev->gpio.reset, 0); ret += gpio_export(ifx_dev->gpio.reset, 1); if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)", + dev_err(dev, "Unable to configure GPIO%d (RESET)", ifx_dev->gpio.reset); ret = -EBUSY; goto error_ret2; @@ -1109,7 +1110,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret += gpio_direction_output(ifx_dev->gpio.po, 0); ret += gpio_export(ifx_dev->gpio.po, 1); if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (ON)", + dev_err(dev, "Unable to configure GPIO%d (ON)", ifx_dev->gpio.po); ret = -EBUSY; goto error_ret3; @@ -1117,14 +1118,14 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem"); if (ret < 0) { - dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)", + dev_err(dev, "Unable to allocate GPIO%d (MRDY)", ifx_dev->gpio.mrdy); goto error_ret3; } ret += gpio_export(ifx_dev->gpio.mrdy, 1); ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0); if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)", + dev_err(dev, "Unable to configure GPIO%d (MRDY)", ifx_dev->gpio.mrdy); ret = -EBUSY; goto error_ret4; @@ -1132,7 +1133,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem"); if (ret < 0) { - dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)", + dev_err(dev, "Unable to allocate GPIO%d (SRDY)", ifx_dev->gpio.srdy); ret = -EBUSY; goto error_ret4; @@ -1140,7 +1141,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret += gpio_export(ifx_dev->gpio.srdy, 1); ret += gpio_direction_input(ifx_dev->gpio.srdy); if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)", + dev_err(dev, "Unable to configure GPIO%d (SRDY)", ifx_dev->gpio.srdy); ret = -EBUSY; goto error_ret5; @@ -1148,14 +1149,14 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem"); if (ret < 0) { - dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)", + dev_err(dev, "Unable to allocate GPIO%d (RESET_OUT)", ifx_dev->gpio.reset_out); goto error_ret5; } ret += gpio_export(ifx_dev->gpio.reset_out, 1); ret += gpio_direction_input(ifx_dev->gpio.reset_out); if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)", + dev_err(dev, "Unable to configure GPIO%d (RESET_OUT)", ifx_dev->gpio.reset_out); ret = -EBUSY; goto error_ret6; @@ -1166,7 +1167,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, ifx_dev); if (ret) { - dev_err(&spi->dev, "Unable to get irq %x\n", + dev_err(dev, "Unable to get irq %x\n", gpio_to_irq(ifx_dev->gpio.reset_out)); goto error_ret6; } @@ -1177,14 +1178,14 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME, ifx_dev); if (ret) { - dev_err(&spi->dev, "Unable to get irq %x", + dev_err(dev, "Unable to get irq %x", gpio_to_irq(ifx_dev->gpio.srdy)); goto error_ret7; } /* set pm runtime power state and register with power system */ - pm_runtime_set_active(&spi->dev); - pm_runtime_enable(&spi->dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); /* handle case that modem is already signaling SRDY */ /* no outgoing tty open at this point, this just satisfies the -- cgit From 9a8da6082ddb4689baf34dcdf2a53985e25753f3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 11 Mar 2020 09:31:31 +0100 Subject: tty: serial: ifx6x60: Convert to GPIO descriptors This driver for the Intel MID never seems to have been properly integrated upstream: the platform data in is not used anywhere in the kernel and haven't been since it was merged into the kernel in 2010. There might be out-of-tree users, so I don't want to delete the driver, but I will refactor it to use GPIO descriptors, which means that out-of-tree users will need to adapt. There are several examples in the kernel of how to provide the resources necessary for using GPIO descriptors to pass in the GPIO lines, for the MID platform in particular, it will suffice to inspect the code in files like: arch/x86/platform/intel-mid/device_libs/platform_bt.c This refactoring transfers all GPIOs in the driver, including a hard-coded "PMU reset" in the driver to use GPIO descriptors instead. The following named GPIO descriptors need to be supplied: - reset - power - mrdy - srdy - rst_out - pmu_reset Cc: Russ Gorby Signed-off-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200311083131.693908-2-linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ifx6x60.c | 170 +++++++++++++++---------------------------- drivers/tty/serial/ifx6x60.h | 13 ++-- 2 files changed, 65 insertions(+), 118 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 32a0ccef9339..7d16fe41932f 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include @@ -61,7 +61,6 @@ #define IFX_SPI_HEADER_F (-2) #define PO_POST_DELAY 200 -#define IFX_MDM_RST_PMU 4 /* forward reference */ static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev); @@ -81,7 +80,7 @@ static struct notifier_block ifx_modem_reboot_notifier_block = { static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev) { - gpio_set_value(IFX_MDM_RST_PMU, 1); + gpiod_set_value(ifx_dev->gpio.pmu_reset, 1); msleep(PO_POST_DELAY); return 0; @@ -107,7 +106,7 @@ static int ifx_modem_reboot_callback(struct notifier_block *nfb, */ static inline void mrdy_set_high(struct ifx_spi_device *ifx) { - gpio_set_value(ifx->gpio.mrdy, 1); + gpiod_set_value(ifx->gpio.mrdy, 1); } /** @@ -117,7 +116,7 @@ static inline void mrdy_set_high(struct ifx_spi_device *ifx) */ static inline void mrdy_set_low(struct ifx_spi_device *ifx) { - gpio_set_value(ifx->gpio.mrdy, 0); + gpiod_set_value(ifx->gpio.mrdy, 0); } /** @@ -244,7 +243,7 @@ static inline void swap_buf_32(unsigned char *buf, int len, void *end) */ static void mrdy_assert(struct ifx_spi_device *ifx_dev) { - int val = gpio_get_value(ifx_dev->gpio.srdy); + int val = gpiod_get_value(ifx_dev->gpio.srdy); if (!val) { if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) { @@ -691,7 +690,7 @@ complete_exit: clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags)); queue_length = kfifo_len(&ifx_dev->tx_fifo); - srdy = gpio_get_value(ifx_dev->gpio.srdy); + srdy = gpiod_get_value(ifx_dev->gpio.srdy); if (!srdy) ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY); @@ -898,7 +897,7 @@ static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev) static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev) { struct ifx_spi_device *ifx_dev = dev; - int val = gpio_get_value(ifx_dev->gpio.reset_out); + int val = gpiod_get_value(ifx_dev->gpio.reset_out); int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state); if (val == 0) { @@ -954,14 +953,14 @@ static int ifx_spi_reset(struct ifx_spi_device *ifx_dev) * to reset properly */ set_bit(MR_START, &ifx_dev->mdm_reset_state); - gpio_set_value(ifx_dev->gpio.po, 0); - gpio_set_value(ifx_dev->gpio.reset, 0); + gpiod_set_value(ifx_dev->gpio.po, 0); + gpiod_set_value(ifx_dev->gpio.reset, 0); msleep(25); - gpio_set_value(ifx_dev->gpio.reset, 1); + gpiod_set_value(ifx_dev->gpio.reset, 1); msleep(1); - gpio_set_value(ifx_dev->gpio.po, 1); + gpiod_set_value(ifx_dev->gpio.po, 1); msleep(1); - gpio_set_value(ifx_dev->gpio.po, 0); + gpiod_set_value(ifx_dev->gpio.po, 0); ret = wait_event_timeout(ifx_dev->mdm_reset_wait, test_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state), @@ -1080,107 +1079,68 @@ static int ifx_spi_spi_probe(struct spi_device *spi) goto error_ret; } - ifx_dev->gpio.reset = pl_data->rst_pmu; - ifx_dev->gpio.po = pl_data->pwr_on; - ifx_dev->gpio.mrdy = pl_data->mrdy; - ifx_dev->gpio.srdy = pl_data->srdy; - ifx_dev->gpio.reset_out = pl_data->rst_out; - - dev_info(dev, "gpios %d, %d, %d, %d, %d", - ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy, - ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out); - - /* Configure gpios */ - ret = gpio_request(ifx_dev->gpio.reset, "ifxModem"); - if (ret < 0) { - dev_err(dev, "Unable to allocate GPIO%d (RESET)", - ifx_dev->gpio.reset); + ifx_dev->gpio.reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ifx_dev->gpio.reset)) { + dev_err(dev, "could not obtain reset GPIO\n"); + ret = PTR_ERR(ifx_dev->gpio.reset); goto error_ret; } - ret += gpio_direction_output(ifx_dev->gpio.reset, 0); - ret += gpio_export(ifx_dev->gpio.reset, 1); - if (ret) { - dev_err(dev, "Unable to configure GPIO%d (RESET)", - ifx_dev->gpio.reset); - ret = -EBUSY; - goto error_ret2; - } - - ret = gpio_request(ifx_dev->gpio.po, "ifxModem"); - ret += gpio_direction_output(ifx_dev->gpio.po, 0); - ret += gpio_export(ifx_dev->gpio.po, 1); - if (ret) { - dev_err(dev, "Unable to configure GPIO%d (ON)", - ifx_dev->gpio.po); - ret = -EBUSY; - goto error_ret3; - } - - ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem"); - if (ret < 0) { - dev_err(dev, "Unable to allocate GPIO%d (MRDY)", - ifx_dev->gpio.mrdy); - goto error_ret3; - } - ret += gpio_export(ifx_dev->gpio.mrdy, 1); - ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0); - if (ret) { - dev_err(dev, "Unable to configure GPIO%d (MRDY)", - ifx_dev->gpio.mrdy); - ret = -EBUSY; - goto error_ret4; + gpiod_set_consumer_name(ifx_dev->gpio.reset, "ifxModem reset"); + ifx_dev->gpio.po = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW); + if (IS_ERR(ifx_dev->gpio.po)) { + dev_err(dev, "could not obtain power GPIO\n"); + ret = PTR_ERR(ifx_dev->gpio.po); + goto error_ret; } - - ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem"); - if (ret < 0) { - dev_err(dev, "Unable to allocate GPIO%d (SRDY)", - ifx_dev->gpio.srdy); - ret = -EBUSY; - goto error_ret4; + gpiod_set_consumer_name(ifx_dev->gpio.po, "ifxModem power"); + ifx_dev->gpio.mrdy = devm_gpiod_get(dev, "mrdy", GPIOD_OUT_LOW); + if (IS_ERR(ifx_dev->gpio.mrdy)) { + dev_err(dev, "could not obtain mrdy GPIO\n"); + ret = PTR_ERR(ifx_dev->gpio.mrdy); + goto error_ret; } - ret += gpio_export(ifx_dev->gpio.srdy, 1); - ret += gpio_direction_input(ifx_dev->gpio.srdy); - if (ret) { - dev_err(dev, "Unable to configure GPIO%d (SRDY)", - ifx_dev->gpio.srdy); - ret = -EBUSY; - goto error_ret5; + gpiod_set_consumer_name(ifx_dev->gpio.mrdy, "ifxModem mrdy"); + ifx_dev->gpio.srdy = devm_gpiod_get(dev, "srdy", GPIOD_IN); + if (IS_ERR(ifx_dev->gpio.srdy)) { + dev_err(dev, "could not obtain srdy GPIO\n"); + ret = PTR_ERR(ifx_dev->gpio.srdy); + goto error_ret; } - - ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem"); - if (ret < 0) { - dev_err(dev, "Unable to allocate GPIO%d (RESET_OUT)", - ifx_dev->gpio.reset_out); - goto error_ret5; + gpiod_set_consumer_name(ifx_dev->gpio.srdy, "ifxModem srdy"); + ifx_dev->gpio.reset_out = devm_gpiod_get(dev, "rst_out", GPIOD_IN); + if (IS_ERR(ifx_dev->gpio.reset_out)) { + dev_err(dev, "could not obtain rst_out GPIO\n"); + ret = PTR_ERR(ifx_dev->gpio.reset_out); + goto error_ret; } - ret += gpio_export(ifx_dev->gpio.reset_out, 1); - ret += gpio_direction_input(ifx_dev->gpio.reset_out); - if (ret) { - dev_err(dev, "Unable to configure GPIO%d (RESET_OUT)", - ifx_dev->gpio.reset_out); - ret = -EBUSY; - goto error_ret6; + gpiod_set_consumer_name(ifx_dev->gpio.reset_out, "ifxModem reset out"); + ifx_dev->gpio.pmu_reset = devm_gpiod_get(dev, "pmu_reset", GPIOD_ASIS); + if (IS_ERR(ifx_dev->gpio.pmu_reset)) { + dev_err(dev, "could not obtain pmu_reset GPIO\n"); + ret = PTR_ERR(ifx_dev->gpio.pmu_reset); + goto error_ret; } + gpiod_set_consumer_name(ifx_dev->gpio.pmu_reset, "ifxModem PMU reset"); - ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out), + ret = request_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_spi_reset_interrupt, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, ifx_dev); if (ret) { dev_err(dev, "Unable to get irq %x\n", - gpio_to_irq(ifx_dev->gpio.reset_out)); - goto error_ret6; + gpiod_to_irq(ifx_dev->gpio.reset_out)); + goto error_ret; } ret = ifx_spi_reset(ifx_dev); - ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy), + ret = request_irq(gpiod_to_irq(ifx_dev->gpio.srdy), ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME, ifx_dev); if (ret) { dev_err(dev, "Unable to get irq %x", - gpio_to_irq(ifx_dev->gpio.srdy)); - goto error_ret7; + gpiod_to_irq(ifx_dev->gpio.srdy)); + goto error_ret2; } /* set pm runtime power state and register with power system */ @@ -1191,7 +1151,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) /* no outgoing tty open at this point, this just satisfies the * modem's read and should reset communication properly */ - srdy = gpio_get_value(ifx_dev->gpio.srdy); + srdy = gpiod_get_value(ifx_dev->gpio.srdy); if (srdy) { mrdy_assert(ifx_dev); @@ -1200,18 +1160,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi) mrdy_set_low(ifx_dev); return 0; -error_ret7: - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev); -error_ret6: - gpio_free(ifx_dev->gpio.srdy); -error_ret5: - gpio_free(ifx_dev->gpio.mrdy); -error_ret4: - gpio_free(ifx_dev->gpio.reset); -error_ret3: - gpio_free(ifx_dev->gpio.po); error_ret2: - gpio_free(ifx_dev->gpio.reset_out); + free_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_dev); error_ret: ifx_spi_free_device(ifx_dev); saved_ifx_dev = NULL; @@ -1235,14 +1185,8 @@ static int ifx_spi_spi_remove(struct spi_device *spi) pm_runtime_disable(&spi->dev); /* free irq */ - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev); - free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev); - - gpio_free(ifx_dev->gpio.srdy); - gpio_free(ifx_dev->gpio.mrdy); - gpio_free(ifx_dev->gpio.reset); - gpio_free(ifx_dev->gpio.po); - gpio_free(ifx_dev->gpio.reset_out); + free_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_dev); + free_irq(gpiod_to_irq(ifx_dev->gpio.srdy), ifx_dev); /* free allocations */ ifx_spi_free_device(ifx_dev); diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h index cacca5be7390..ecb841d928a7 100644 --- a/drivers/tty/serial/ifx6x60.h +++ b/drivers/tty/serial/ifx6x60.h @@ -10,6 +10,8 @@ #ifndef _IFX6X60_H #define _IFX6X60_H +struct gpio_desc; + #define DRVNAME "ifx6x60" #define TTYNAME "ttyIFX" @@ -94,11 +96,12 @@ struct ifx_spi_device { struct { /* gpio lines */ - unsigned short srdy; /* slave-ready gpio */ - unsigned short mrdy; /* master-ready gpio */ - unsigned short reset; /* modem-reset gpio */ - unsigned short po; /* modem-on gpio */ - unsigned short reset_out; /* modem-in-reset gpio */ + struct gpio_desc *srdy; /* slave-ready gpio */ + struct gpio_desc *mrdy; /* master-ready gpio */ + struct gpio_desc *reset; /* modem-reset gpio */ + struct gpio_desc *po; /* modem-on gpio */ + struct gpio_desc *reset_out; /* modem-in-reset gpio */ + struct gpio_desc *pmu_reset; /* PMU reset gpio */ /* state/stats */ int unack_srdy_int_nb; } gpio; -- cgit From f9d690b6ece7ec9a6ff6b588df95a010ab2d66f9 Mon Sep 17 00:00:00 2001 From: satya priya Date: Fri, 6 Mar 2020 12:17:07 +0530 Subject: tty: serial: qcom_geni_serial: Allocate port->rx_fifo buffer in probe To fix the RX cancel command failure, rx_fifo buffer needs to be flushed in stop_rx() by calling handle_rx().In handle_rx() the data in rx_fifo buffer is read and then dropped, not sent to upper layers. If set_termios is called before startup, by this time memory is not allocated to port->rx_fifo buffer, which leads to a NULL pointer dereference. To avoid this NULL pointer dereference allocate memory to port->rx_fifo in probe itself. Signed-off-by: satya priya Reported-by: Stephen Boyd Link: https://lore.kernel.org/r/1583477228-32231-2-git-send-email-skakit@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 272bae0eebc7..1a61c970f7d6 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -120,7 +120,7 @@ struct qcom_geni_serial_port { unsigned int baud; unsigned int tx_bytes_pw; unsigned int rx_bytes_pw; - u32 *rx_fifo; + void *rx_fifo; u32 loopback; bool brk; @@ -514,7 +514,6 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop) { - unsigned char *buf; struct tty_port *tport; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); u32 num_bytes_pw = port->tx_fifo_width / BITS_PER_BYTE; @@ -526,8 +525,7 @@ static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop) if (drop) return 0; - buf = (unsigned char *)port->rx_fifo; - ret = tty_insert_flip_string(tport, buf, bytes); + ret = tty_insert_flip_string(tport, port->rx_fifo, bytes); if (ret != bytes) { dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n", __func__, ret, bytes); @@ -892,12 +890,6 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) false, false, true); geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2); geni_se_select_mode(&port->se, GENI_SE_FIFO); - if (!uart_console(uport)) { - port->rx_fifo = devm_kcalloc(uport->dev, - port->rx_fifo_depth, sizeof(u32), GFP_KERNEL); - if (!port->rx_fifo) - return -ENOMEM; - } port->setup = true; return 0; @@ -1308,6 +1300,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS; port->tx_fifo_width = DEF_FIFO_WIDTH_BITS; + if (!console) { + port->rx_fifo = devm_kcalloc(uport->dev, + port->rx_fifo_depth, sizeof(u32), GFP_KERNEL); + if (!port->rx_fifo) + return -ENOMEM; + } + port->name = devm_kasprintf(uport->dev, GFP_KERNEL, "qcom_geni_serial_%s%d", uart_console(uport) ? "console" : "uart", uport->line); -- cgit From 2ce5eace42b859cabef898877b38a0429f931370 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Mar 2020 19:43:34 +0200 Subject: serial: core: Use string length for SysRq magic sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiler is not happy about using ARRAY_SIZE() in comparison to smaller type: CC drivers/tty/serial/serial_core.o .../serial_core.c: In function ‘uart_try_toggle_sysrq’: .../serial_core.c:3222:24: warning: comparison is always false due to limited range of data type [-Wtype-limits] 3222 | if (++port->sysrq_seq < (ARRAY_SIZE(sysrq_toggle_seq) - 1)) { | ^ Looking at the code it appears that there is an additional weirdness, i.e. use ARRAY_SIZE() against simple string literal. Yes, the idea probably was to allow '\0' in the sequence, but it's impractical: kernel configuration won't accept it to begin with followed by a comment about '\0' before comparison in question. Drop all these by switching to strlen() and convert code accordingly. Note, GCC seems clever enough to calculate string length at compile time. Fixes: 68af43173d3f ("serial/sysrq: Add MAGIC_SYSRQ_SERIAL_SEQUENCE") Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200310174337.74109-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 863e3e0c2d39..f5c8cf847532 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3110,7 +3110,9 @@ static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on); */ static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) { - if (ARRAY_SIZE(sysrq_toggle_seq) <= 1) + int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq); + + if (!sysrq_toggle_seq_len) return false; BUILD_BUG_ON(ARRAY_SIZE(sysrq_toggle_seq) >= U8_MAX); @@ -3119,8 +3121,7 @@ static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) return false; } - /* Without the last \0 */ - if (++port->sysrq_seq < (ARRAY_SIZE(sysrq_toggle_seq) - 1)) { + if (++port->sysrq_seq < sysrq_toggle_seq_len) { port->sysrq = jiffies + SYSRQ_TIMEOUT; return true; } -- cgit From b18896ff3a92fe320ad5262009f0b90e04b8a203 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Mar 2020 19:43:35 +0200 Subject: serial: core: Print escaped SysRq Magic sequence if enabled It is useful to see on the serial console the magic sequence itself to enable SysRq without rummaging source code. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200310174337.74109-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f5c8cf847532..c93d4e600f91 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3092,8 +3092,11 @@ static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE; static void uart_sysrq_on(struct work_struct *w) { + int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq); + sysrq_toggle_support(1); - pr_info("SysRq is enabled by magic sequence on serial\n"); + pr_info("SysRq is enabled by magic sequence '%*pE' on serial\n", + sysrq_toggle_seq_len, sysrq_toggle_seq); } static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on); -- cgit From e140ef36925f54770fccb8e42be8cc8365221b51 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Mar 2020 19:43:36 +0200 Subject: serial: core: Use uart_console() helper in SysRq code Use uart_console() helper in SysRq code instead of open coded variant. This eliminates the conditional entirely for SERIAL_CORE_CONSOLE=n case. While here, refactor the conditional to be more compact. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200310174337.74109-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index c93d4e600f91..752655c80f73 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3216,14 +3216,12 @@ int uart_handle_break(struct uart_port *port) if (port->handle_break) port->handle_break(port); - if (port->has_sysrq) { - if (port->cons && port->cons->index == port->line) { - if (!port->sysrq) { - port->sysrq = jiffies + SYSRQ_TIMEOUT; - return 1; - } - port->sysrq = 0; + if (port->has_sysrq && uart_console(port)) { + if (!port->sysrq) { + port->sysrq = jiffies + SYSRQ_TIMEOUT; + return 1; } + port->sysrq = 0; } if (port->flags & UPF_SAK) -- cgit From da9a5aa3402db0ff3b57216d8dbf2478e1046cae Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Mar 2020 19:43:37 +0200 Subject: serial: core: Refactor uart_unlock_and_check_sysrq() Refactor uart_unlock_and_check_sysrq() to: - explicitly show that we release a port lock which makes static analyzers happy: CHECK drivers/tty/serial/serial_core.c .../serial_core.c:3290:17: warning: context imbalance in 'uart_unlock_and_check_sysrq' - unexpected unlock - use flags instead of irqflags to avoid confusion with IRQ flags - provide one return point - be more compact Signed-off-by: Andy Shevchenko Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Link: https://lore.kernel.org/r/20200310174337.74109-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 752655c80f73..38ef6afddce8 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3187,22 +3187,19 @@ int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) } EXPORT_SYMBOL_GPL(uart_prepare_sysrq_char); -void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags) +void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long flags) +__releases(&port->lock) { - int sysrq_ch; + if (port->has_sysrq) { + int sysrq_ch = port->sysrq_ch; - if (!port->has_sysrq) { - spin_unlock_irqrestore(&port->lock, irqflags); - return; + port->sysrq_ch = 0; + spin_unlock_irqrestore(&port->lock, flags); + if (sysrq_ch) + handle_sysrq(sysrq_ch); + } else { + spin_unlock_irqrestore(&port->lock, flags); } - - sysrq_ch = port->sysrq_ch; - port->sysrq_ch = 0; - - spin_unlock_irqrestore(&port->lock, irqflags); - - if (sysrq_ch) - handle_sysrq(sysrq_ch); } EXPORT_SYMBOL_GPL(uart_unlock_and_check_sysrq); -- cgit From c57c1644c266a42579dccd919c11d247be48cca5 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 23 Feb 2020 23:34:50 -0800 Subject: vt: drop redundant might_sleep() in do_con_write() The might_sleep() in do_con_write() is redundant because console_lock() already contains might_sleep(). Remove it. Signed-off-by: Eric Biggers Link: https://lore.kernel.org/r/20200224073450.292892-1-ebiggers@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index c4d75edde923..2123bb09214c 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2577,8 +2577,6 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co if (in_interrupt()) return count; - might_sleep(); - console_lock(); vc = tty->driver_data; if (vc == NULL) { -- cgit From 1aa6e058dd6cd04471b1f21298270014daf48ac9 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 24 Feb 2020 00:03:26 -0800 Subject: vt: vt_ioctl: remove unnecessary console allocation checks The vc_cons_allocated() checks in vt_ioctl() and vt_compat_ioctl() are unnecessary because they can only be reached by calling ioctl() on an open tty, which implies the corresponding virtual console is allocated. And even if the virtual console *could* be freed concurrently, then these checks would be broken since they aren't done under console_lock, and the vc_data is dereferenced before them anyway. So, remove these unneeded checks to avoid confusion. Signed-off-by: Eric Biggers Link: https://lore.kernel.org/r/20200224080326.295046-1-ebiggers@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt_ioctl.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 38948ac5fc49..7297997fcf04 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -350,22 +350,13 @@ int vt_ioctl(struct tty_struct *tty, { struct vc_data *vc = tty->driver_data; struct console_font_op op; /* used in multiple places here */ - unsigned int console; + unsigned int console = vc->vc_num; unsigned char ucval; unsigned int uival; void __user *up = (void __user *)arg; int i, perm; int ret = 0; - console = vc->vc_num; - - - if (!vc_cons_allocated(console)) { /* impossible? */ - ret = -ENOIOCTLCMD; - goto out; - } - - /* * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. @@ -1195,14 +1186,9 @@ long vt_compat_ioctl(struct tty_struct *tty, { struct vc_data *vc = tty->driver_data; struct console_font_op op; /* used in multiple places here */ - unsigned int console = vc->vc_num; void __user *up = compat_ptr(arg); int perm; - - if (!vc_cons_allocated(console)) /* impossible? */ - return -ENOIOCTLCMD; - /* * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. -- cgit From e83766334f96b3396a71c7baa3b0b53dfd5190cd Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 13 Mar 2020 13:46:51 -0700 Subject: tty: serial: qcom_geni_serial: No need to stop tx/rx on UART shutdown On a board using qcom_geni_serial I found that I could no longer interact with kdb if I got a crash after the "agetty" running on the same serial port was killed. This meant that various classes of crashes that happened at reboot time were undebuggable. Reading through the code, I couldn't figure out why qcom_geni_serial felt the need to run so much code at port shutdown time. All we need to do is disable the interrupt. After I make this change then a hardcoded kgdb_breakpoint in some late shutdown code now allows me to interact with the debugger. I also could freely close / re-open the port without problems. Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP") Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20200313134635.1.Icf54c533065306b02b880c46dfd401d8db34e213@changeid Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 1a61c970f7d6..a77f05b7a649 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -825,17 +825,11 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port) static void qcom_geni_serial_shutdown(struct uart_port *uport) { - unsigned long flags; - /* Stop the console before stopping the current tx */ if (uart_console(uport)) console_stop(uport->cons); disable_irq(uport->irq); - spin_lock_irqsave(&uport->lock, flags); - qcom_geni_serial_stop_tx(uport); - qcom_geni_serial_stop_rx(uport); - spin_unlock_irqrestore(&uport->lock, flags); } static int qcom_geni_serial_port_setup(struct uart_port *uport) -- cgit From d49e7953f9b9f5e50c12dda95f4041fb877cdc71 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 13 Mar 2020 13:46:52 -0700 Subject: tty: serial: qcom_geni_serial: Don't try to manually disable the console The geni serial driver's shutdown code had a special case to call console_stop(). Grepping through the code, it was the only serial driver doing something like this (the only other caller of console_stop() was in serial_core.c). As far as I can tell there's no reason to call console_stop() in the geni code. ...and a good reason _not_ to call it. Specifically if you have an agetty running on the same serial port as the console then killing the agetty kills your console and if you start the agetty again the console doesn't come back. Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP") Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20200313134635.2.I3648fac6c98b887742934146ac2729ecb7232eb1@changeid Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index a77f05b7a649..6119090ce045 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -825,10 +825,6 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port) static void qcom_geni_serial_shutdown(struct uart_port *uport) { - /* Stop the console before stopping the current tx */ - if (uart_console(uport)) - console_stop(uport->cons); - disable_irq(uport->irq); } -- cgit From 5b30dee6cc07fd91eedcb3a1ba1b81af8512c011 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 16 Mar 2020 07:45:44 +0100 Subject: vt: selection, fix double lock introduced by a merge The merge commit cb05c6c82fb0 (Merge 5.6-rc5 into tty-next) introduced a double lock to set_selection_kernel. vc_sel.lock is locked both in set_selection_kernel and its callee __set_selection_kernel now. Remove the latter. Signed-off-by: Jiri Slaby Cc: Stephen Rothwell Link: https://lore.kernel.org/r/20200316064544.4799-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 1a069979866c..582184dd386c 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -219,7 +219,6 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct * if (ps > pe) /* make vc_sel.start <= vc_sel.end */ swap(ps, pe); - mutex_lock(&vc_sel.lock); if (vc_sel.cons != vc_cons[fg_console].d) { clear_selection(); vc_sel.cons = vc_cons[fg_console].d; -- cgit From b18d1c2efa47f7fbf20a7ca4e121a991c3272326 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 16 Mar 2020 07:49:10 +0100 Subject: tty: n_hdlc, remove FILE and LINE from pr_debug As Joe suggests, dynamic debug can print module name and line number along with message. So remove __FILE__ and __LINE__ from all those pr_debug calls. Out of curiosity, I measured the savings, 200 bytes of code are gone. Signed-off-by: Jiri Slaby Suggested-by: Joe Perches Link: https://lore.kernel.org/r/20200316064910.4941-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index cd1319d26c45..991f49ee4026 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -226,8 +226,7 @@ static int n_hdlc_tty_open(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty->disc_data; - pr_debug("%s(%d)%s() called (device=%s)\n", - __FILE__, __LINE__, __func__, tty->name); + pr_debug("%s() called (device=%s)\n", __func__, tty->name); /* There should not be an existing table for this slot. */ if (n_hdlc) { @@ -283,8 +282,7 @@ check_again: tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); while (tbuf) { - pr_debug("%s(%d)sending frame %p, count=%d\n", - __FILE__, __LINE__, tbuf, tbuf->count); + pr_debug("sending frame %p, count=%d\n", tbuf, tbuf->count); /* Send the next block of data to device */ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); @@ -301,8 +299,7 @@ check_again: actual = tbuf->count; if (actual == tbuf->count) { - pr_debug("%s(%d)frame %p completed\n", - __FILE__, __LINE__, tbuf); + pr_debug("frame %p completed\n", tbuf); /* free current transmit buffer */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf); @@ -313,8 +310,7 @@ check_again: /* get next pending transmit buffer */ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); } else { - pr_debug("%s(%d)frame %p pending\n", - __FILE__, __LINE__, tbuf); + pr_debug("frame %p pending\n", tbuf); /* * the buffer was not accepted by driver, @@ -366,19 +362,16 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, register struct n_hdlc *n_hdlc = tty->disc_data; register struct n_hdlc_buf *buf; - pr_debug("%s(%d)%s() called count=%d\n", - __FILE__, __LINE__, __func__, count); + pr_debug("%s() called count=%d\n", __func__, count); /* verify line is using HDLC discipline */ if (n_hdlc->magic != HDLC_MAGIC) { - pr_err("%s(%d) line not using HDLC discipline\n", - __FILE__, __LINE__); + pr_err("line not using HDLC discipline\n"); return; } if (count > maxframe) { - pr_debug("%s(%d) rx count>maxframesize, data discarded\n", - __FILE__, __LINE__); + pr_debug("rx count>maxframesize, data discarded\n"); return; } @@ -395,8 +388,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, } if (!buf) { - pr_debug("%s(%d) no more rx buffers, data discarded\n", - __FILE__, __LINE__); + pr_debug("no more rx buffers, data discarded\n"); return; } @@ -509,8 +501,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, DECLARE_WAITQUEUE(wait, current); struct n_hdlc_buf *tbuf; - pr_debug("%s(%d)%s() called count=%zd\n", __FILE__, __LINE__, __func__, - count); + pr_debug("%s() called count=%zd\n", __func__, count); if (n_hdlc->magic != HDLC_MAGIC) return -EIO; @@ -578,7 +569,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned long flags; struct n_hdlc_buf *buf = NULL; - pr_debug("%s(%d)%s() called %d\n", __FILE__, __LINE__, __func__, cmd); + pr_debug("%s() called %d\n", __func__, cmd); /* Verify the status of the device */ if (n_hdlc->magic != HDLC_MAGIC) @@ -677,8 +668,8 @@ static void n_hdlc_alloc_buf(struct n_hdlc_buf_list *list, unsigned int count, for (i = 0; i < count; i++) { buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL); if (!buf) { - pr_debug("%s(%d)%s(), kmalloc() failed for %s buffer %u\n", - __FILE__, __LINE__, __func__, name, i); + pr_debug("%s(), kmalloc() failed for %s buffer %u\n", + __func__, name, i); return; } n_hdlc_buf_put(list, buf); -- cgit From 85af37056a72c5e2e5758a44c94c78cbdf3658e3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 16 Mar 2020 07:59:09 +0100 Subject: vt: use min() to limit intervals Instead of awkward ternary operator with comparison, use simple min() for blankinterval and vesa_off_interval. No functional change intended and "objdump -d" proves that. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200316065911.11024-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 2123bb09214c..6311f91d3cc7 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1927,7 +1927,7 @@ static void setterm_command(struct vc_data *vc) update_attr(vc); break; case 9: /* set blanking interval */ - blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60; + blankinterval = min(vc->vc_par[1], 60U) * 60; poke_blanked_console(); break; case 10: /* set bell frequency in Hz */ @@ -1951,7 +1951,7 @@ static void setterm_command(struct vc_data *vc) poke_blanked_console(); break; case 14: /* set vesa powerdown interval */ - vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ; + vesa_off_interval = min(vc->vc_par[1], 60U) * 60 * HZ; break; case 15: /* activate the previous console */ set_console(last_console); -- cgit From f0e8e3da22abd0015348760b2ea26bf45fdf3030 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 16 Mar 2020 07:59:10 +0100 Subject: vt: selection, use rounddown() for start/endline computation We have a helper called rounddown for these modulo computations. So use it. No functional change intended and "objdump -d" proves that. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200316065911.11024-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 582184dd386c..d54a549c5892 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -252,9 +252,9 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct * } break; case TIOCL_SELLINE: /* line-by-line selection */ - new_sel_start = ps - ps % vc->vc_size_row; - new_sel_end = pe + vc->vc_size_row - - pe % vc->vc_size_row - 2; + new_sel_start = rounddown(ps, vc->vc_size_row); + new_sel_end = rounddown(pe, vc->vc_size_row) + + vc->vc_size_row - 2; break; case TIOCL_SELPOINTER: highlight_pointer(pe); -- cgit From c3a834e87c2cd8ffe1c485a23892bb136c439ba0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 16 Mar 2020 07:59:11 +0100 Subject: vt: indent switch-case in setterm_command properly Shift cases one level left. This makes the code more readable and some lines need not wrap anymore. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20200316065911.11024-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 120 ++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 61 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6311f91d3cc7..bbc26d73209a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1902,67 +1902,65 @@ static void set_mode(struct vc_data *vc, int on_off) /* console_lock is held */ static void setterm_command(struct vc_data *vc) { - switch(vc->vc_par[0]) { - case 1: /* set color for underline mode */ - if (vc->vc_can_do_color && - vc->vc_par[1] < 16) { - vc->vc_ulcolor = color_table[vc->vc_par[1]]; - if (vc->vc_underline) - update_attr(vc); - } - break; - case 2: /* set color for half intensity mode */ - if (vc->vc_can_do_color && - vc->vc_par[1] < 16) { - vc->vc_halfcolor = color_table[vc->vc_par[1]]; - if (vc->vc_intensity == 0) - update_attr(vc); - } - break; - case 8: /* store colors as defaults */ - vc->vc_def_color = vc->vc_attr; - if (vc->vc_hi_font_mask == 0x100) - vc->vc_def_color >>= 1; - default_attr(vc); - update_attr(vc); - break; - case 9: /* set blanking interval */ - blankinterval = min(vc->vc_par[1], 60U) * 60; - poke_blanked_console(); - break; - case 10: /* set bell frequency in Hz */ - if (vc->vc_npar >= 1) - vc->vc_bell_pitch = vc->vc_par[1]; - else - vc->vc_bell_pitch = DEFAULT_BELL_PITCH; - break; - case 11: /* set bell duration in msec */ - if (vc->vc_npar >= 1) - vc->vc_bell_duration = (vc->vc_par[1] < 2000) ? - msecs_to_jiffies(vc->vc_par[1]) : 0; - else - vc->vc_bell_duration = DEFAULT_BELL_DURATION; - break; - case 12: /* bring specified console to the front */ - if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1)) - set_console(vc->vc_par[1] - 1); - break; - case 13: /* unblank the screen */ - poke_blanked_console(); - break; - case 14: /* set vesa powerdown interval */ - vesa_off_interval = min(vc->vc_par[1], 60U) * 60 * HZ; - break; - case 15: /* activate the previous console */ - set_console(last_console); - break; - case 16: /* set cursor blink duration in msec */ - if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 && - vc->vc_par[1] <= USHRT_MAX) - vc->vc_cur_blink_ms = vc->vc_par[1]; - else - vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS; - break; + switch (vc->vc_par[0]) { + case 1: /* set color for underline mode */ + if (vc->vc_can_do_color && vc->vc_par[1] < 16) { + vc->vc_ulcolor = color_table[vc->vc_par[1]]; + if (vc->vc_underline) + update_attr(vc); + } + break; + case 2: /* set color for half intensity mode */ + if (vc->vc_can_do_color && vc->vc_par[1] < 16) { + vc->vc_halfcolor = color_table[vc->vc_par[1]]; + if (vc->vc_intensity == 0) + update_attr(vc); + } + break; + case 8: /* store colors as defaults */ + vc->vc_def_color = vc->vc_attr; + if (vc->vc_hi_font_mask == 0x100) + vc->vc_def_color >>= 1; + default_attr(vc); + update_attr(vc); + break; + case 9: /* set blanking interval */ + blankinterval = min(vc->vc_par[1], 60U) * 60; + poke_blanked_console(); + break; + case 10: /* set bell frequency in Hz */ + if (vc->vc_npar >= 1) + vc->vc_bell_pitch = vc->vc_par[1]; + else + vc->vc_bell_pitch = DEFAULT_BELL_PITCH; + break; + case 11: /* set bell duration in msec */ + if (vc->vc_npar >= 1) + vc->vc_bell_duration = (vc->vc_par[1] < 2000) ? + msecs_to_jiffies(vc->vc_par[1]) : 0; + else + vc->vc_bell_duration = DEFAULT_BELL_DURATION; + break; + case 12: /* bring specified console to the front */ + if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1)) + set_console(vc->vc_par[1] - 1); + break; + case 13: /* unblank the screen */ + poke_blanked_console(); + break; + case 14: /* set vesa powerdown interval */ + vesa_off_interval = min(vc->vc_par[1], 60U) * 60 * HZ; + break; + case 15: /* activate the previous console */ + set_console(last_console); + break; + case 16: /* set cursor blink duration in msec */ + if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 && + vc->vc_par[1] <= USHRT_MAX) + vc->vc_cur_blink_ms = vc->vc_par[1]; + else + vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS; + break; } } -- cgit From 72cc06be190a206abc3fcab236c6eddd5ebe0767 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Mon, 16 Mar 2020 18:19:28 +0800 Subject: serial: sprd: check console via stdout-path in addition The SPRD serial driver need to know which serial port would be used as console in an early period during initialization, the purpose is to keep the console port alive as possible even if there's some error caused by no clock configured under serial devicetree nodes. But with the patch [1], the console port couldn't be identified if missing console command line. So this patch adds using another interface to do check by reading stdout-path. [1] https://lore.kernel.org/lkml/20190826072929.7696-4-zhang.lyra@gmail.com/ Signed-off-by: Chunyan Zhang Reviewed-by: Baolin Wang Link: https://lore.kernel.org/r/20200316101930.9962-2-zhang.lyra@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sprd_serial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 3d3c70634589..18706333f146 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -1147,7 +1147,8 @@ static bool sprd_uart_is_console(struct uart_port *uport) { struct console *cons = sprd_uart_driver.cons; - if (cons && cons->index >= 0 && cons->index == uport->line) + if ((cons && cons->index >= 0 && cons->index == uport->line) || + of_console_check(uport->dev->of_node, SPRD_TTY_NAME, uport->line)) return true; return false; -- cgit From f1b49d5a07131a723a7fcf83310c060dac116965 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Mon, 16 Mar 2020 18:19:29 +0800 Subject: serial: sprd: remove __init from sprd_console_setup The function sprd_console_setup() would be called from .probe() which can be called after freeing __init functions, for example the .probe() would return -EPROBE_DEFER since it depends on clock modules. Signed-off-by: Chunyan Zhang Reviewed-by: Baolin Wang Link: https://lore.kernel.org/r/20200316101930.9962-3-zhang.lyra@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sprd_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 18706333f146..914862844790 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -1013,7 +1013,7 @@ static void sprd_console_write(struct console *co, const char *s, spin_unlock_irqrestore(&port->lock, flags); } -static int __init sprd_console_setup(struct console *co, char *options) +static int sprd_console_setup(struct console *co, char *options) { struct sprd_uart_port *sprd_uart_port; int baud = 115200; -- cgit From efc176929a3505a30c3993ddd393b40893649bd2 Mon Sep 17 00:00:00 2001 From: Lanqing Liu Date: Mon, 16 Mar 2020 11:13:33 +0800 Subject: serial: sprd: Fix a dereference warning We should validate if the 'sup' is NULL or not before freeing DMA memory, to fix below warning. "drivers/tty/serial/sprd_serial.c:1141 sprd_remove() error: we previously assumed 'sup' could be null (see line 1132)" Fixes: f4487db58eb7 ("serial: sprd: Add DMA mode support") Reported-by: Dan Carpenter Signed-off-by: Lanqing Liu Cc: stable Link: https://lore.kernel.org/r/e2bd92691538e95b04a2c2a728f3292e1617018f.1584325957.git.liuhhome@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sprd_serial.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 914862844790..509781ee26bf 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -1132,14 +1132,13 @@ static int sprd_remove(struct platform_device *dev) if (sup) { uart_remove_one_port(&sprd_uart_driver, &sup->port); sprd_port[sup->port.line] = NULL; + sprd_rx_free_buf(sup); sprd_ports_num--; } if (!sprd_ports_num) uart_unregister_driver(&sprd_uart_driver); - sprd_rx_free_buf(sup); - return 0; } -- cgit From 7e13d0a6b189169d9339a6ef96383cd6f0e00b2c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 6 Mar 2020 11:23:01 +0100 Subject: Revert "tty: serial: samsung_tty: build it for any platform" This reverts commit 175b558d0efb8b4f33aa7bd2c1b5389b912d3019. When the user configures a kernel without support for Samsung SoCs, it makes no sense to ask the user about enabling "Samsung SoC serial support", as Samsung serial ports can only be found on Samsung SoCs. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200306102301.16870-1-geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b43dce785a58..aa6d82175491 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -237,6 +237,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" + depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, -- cgit From a3cb39d258efef830181606134cfb0f7babe8c8e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 Feb 2020 13:40:12 +0200 Subject: serial: core: Allow detach and attach serial device for console In the future we would like to disable power management on the serial devices used as kernel consoles to avoid weird behaviour in some cases. However, disabling PM may prevent system to go to deep sleep states, which in its turn leads to the higher power consumption. Tony Lindgren proposed a work around, i.e. allow user to detach such consoles to make PM working again. In case user wants to see what's going on, it also provides a mechanism to attach console back. Link: https://lists.openwall.net/linux-kernel/2018/09/29/65 Suggested-by: Tony Lindgren Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200217114016.49856-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 60 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 38ef6afddce8..66a5e2faf57e 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1922,7 +1922,7 @@ static inline bool uart_console_enabled(struct uart_port *port) */ static inline void uart_port_spin_lock_init(struct uart_port *port) { - if (uart_console_enabled(port)) + if (uart_console(port)) return; spin_lock_init(&port->lock); @@ -2751,6 +2751,56 @@ static ssize_t iomem_reg_shift_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); } +static ssize_t console_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; + bool console = false; + + mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (uport) + console = uart_console_enabled(uport); + mutex_unlock(&port->mutex); + + return sprintf(buf, "%c\n", console ? 'Y' : 'N'); +} + +static ssize_t console_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; + bool oldconsole, newconsole; + int ret; + + ret = kstrtobool(buf, &newconsole); + if (ret) + return ret; + + mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (uport) { + oldconsole = uart_console_enabled(uport); + if (oldconsole && !newconsole) { + ret = unregister_console(uport->cons); + } else if (!oldconsole && newconsole) { + if (uart_console(uport)) + register_console(uport->cons); + else + ret = -ENOENT; + } + } else { + ret = -ENXIO; + } + mutex_unlock(&port->mutex); + + return ret < 0 ? ret : count; +} + static DEVICE_ATTR_RO(uartclk); static DEVICE_ATTR_RO(type); static DEVICE_ATTR_RO(line); @@ -2764,6 +2814,7 @@ static DEVICE_ATTR_RO(custom_divisor); static DEVICE_ATTR_RO(io_type); static DEVICE_ATTR_RO(iomem_base); static DEVICE_ATTR_RO(iomem_reg_shift); +static DEVICE_ATTR_RW(console); static struct attribute *tty_dev_attrs[] = { &dev_attr_uartclk.attr, @@ -2779,12 +2830,13 @@ static struct attribute *tty_dev_attrs[] = { &dev_attr_io_type.attr, &dev_attr_iomem_base.attr, &dev_attr_iomem_reg_shift.attr, - NULL, - }; + &dev_attr_console.attr, + NULL +}; static const struct attribute_group tty_dev_attr_group = { .attrs = tty_dev_attrs, - }; +}; /** * uart_add_one_port - attach a driver-defined port structure -- cgit From bedb404e91bb2908d9921fc736a518a9d89525fc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 Feb 2020 13:40:15 +0200 Subject: serial: 8250_port: Don't use power management for kernel console Doing any kind of power management for kernel console is really bad idea. First of all, it runs in poll and atomic mode. This fact attaches a limitation on the functions that might be called. For example, pm_runtime_get_sync() might sleep and thus can't be used. This call needs, for example, to bring the device to powered on state on the system, where the power on sequence may require on-atomic operations, such as Intel Cherrytrail with ACPI enumerated UARTs. That said, on ACPI enabled platforms it might even call firmware for a job. On the other hand pm_runtime_get() doesn't guarantee that device will become powered on fast enough. Besides that, imagine the case when console is about to print a kernel Oops and it's powered off. In such an emergency case calling the complex functions is not the best what we can do, taking into consideration that user wants to see at least something of the last kernel word before it passes away. Here we modify the 8250 console code to prevent runtime power management. Note, there is a behaviour change for OMAP boards. It will require to detach kernel console to become idle. Link: https://lists.openwall.net/linux-kernel/2018/09/29/65 Suggested-by: Russell King Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200217114016.49856-6-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 9 +++++++++ drivers/tty/serial/8250/8250_port.c | 24 ++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index f6eb00406ddf..45d9117cab68 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -608,6 +608,14 @@ static int univ8250_console_setup(struct console *co, char *options) return retval; } +static int univ8250_console_exit(struct console *co) +{ + struct uart_port *port; + + port = &serial8250_ports[co->index].port; + return serial8250_console_exit(port); +} + /** * univ8250_console_match - non-standard console matching * @co: registering console @@ -666,6 +674,7 @@ static struct console univ8250_console = { .write = univ8250_console_write, .device = uart_console_device, .setup = univ8250_console_setup, + .exit = univ8250_console_exit, .match = univ8250_console_match, .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 0879bb8855cf..c156a30c4dec 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -3200,6 +3200,9 @@ static void serial8250_console_restore(struct uart_8250_port *up) * any possible real use of the port... * * The console_lock must be held when we get here. + * + * Doing runtime PM is really a bad idea for the kernel console. + * Thus, we assume the function is called when device is powered up. */ void serial8250_console_write(struct uart_8250_port *up, const char *s, unsigned int count) @@ -3212,8 +3215,6 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, touch_nmi_watchdog(); - serial8250_rpm_get(up); - if (oops_in_progress) locked = spin_trylock_irqsave(&port->lock, flags); else @@ -3268,7 +3269,6 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, if (locked) spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); } static unsigned int probe_baud(struct uart_port *port) @@ -3292,6 +3292,7 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe) int bits = 8; int parity = 'n'; int flow = 'n'; + int ret; if (!port->iobase && !port->membase) return -ENODEV; @@ -3301,7 +3302,22 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe) else if (probe) baud = probe_baud(port); - return uart_set_options(port, port->cons, baud, parity, bits, flow); + ret = uart_set_options(port, port->cons, baud, parity, bits, flow); + if (ret) + return ret; + + if (port->dev) + pm_runtime_get_sync(port->dev); + + return 0; +} + +int serial8250_console_exit(struct uart_port *port) +{ + if (port->dev) + pm_runtime_put_sync(port->dev); + + return 0; } #endif /* CONFIG_SERIAL_8250_CONSOLE */ -- cgit From 089b6d36549160b535e109cd07ed6d578b81de46 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 Feb 2020 13:40:16 +0200 Subject: serial: 8250_port: Disable DMA operations for kernel console It would be too tricky and error prone to allow DMA operations on kernel console. One of the concern is when DMA is a separate device, for example on Intel CherryTrail platforms, and might need special work around to be functional, see the commit eebb3e8d8aaf ("ACPI / LPSS: override power state for LPSS DMA device") for more information. Another one is that kernel console is used in atomic context, e.g. when printing crucial information to the user (Oops or crash), and DMA may not serve due to power management complications including non-atomic ACPI calls but not limited to it (see above). Besides that, other concerns are described in the commit 84b40e3b57ee ("serial: 8250: omap: Disable DMA for console UART") done for OMAP UART and may be repeated here. Disable any kind of DMA operations on kernel console due to above concerns. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200217114016.49856-7-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index c156a30c4dec..4440867b7d20 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2367,9 +2367,14 @@ dont_test_tx_en: * Request DMA channels for both RX and TX. */ if (up->dma) { - retval = serial8250_request_dma(up); - if (retval) { - dev_warn_ratelimited(port->dev, "failed to request DMA\n"); + const char *msg = NULL; + + if (uart_console(port)) + msg = "forbid DMA for kernel console"; + else if (serial8250_request_dma(up)) + msg = "failed to request DMA"; + if (msg) { + dev_warn_ratelimited(port->dev, "%s\n", msg); up->dma = NULL; } } -- cgit From 630db5cbc7b444bf47cd717906abb092a2ab5724 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Wed, 18 Mar 2020 08:40:27 +0800 Subject: tty: serial: Add CONSOLE_POLL support to SiFive UART Add CONSOLE_POLL support for future KGDB porting. Signed-off-by: Vincent Chen Changes since v1: 1. Fix the compile error reported by kbuild test robot Link: https://lore.kernel.org/r/1584492027-23236-1-git-send-email-vincent.chen@sifive.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sifive.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index d34031e842d0..13eadcb8aec4 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -729,6 +729,29 @@ static const char *sifive_serial_type(struct uart_port *port) return port->type == PORT_SIFIVE_V0 ? "SiFive UART v0" : NULL; } +#ifdef CONFIG_CONSOLE_POLL +static int sifive_serial_poll_get_char(struct uart_port *port) +{ + struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); + char is_empty, ch; + + ch = __ssp_receive_char(ssp, &is_empty); + if (is_empty) + return NO_POLL_CHAR; + + return ch; +} + +static void sifive_serial_poll_put_char(struct uart_port *port, + unsigned char c) +{ + struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); + + __ssp_wait_for_xmitr(ssp); + __ssp_transmit_char(ssp, c); +} +#endif /* CONFIG_CONSOLE_POLL */ + /* * Early console support */ @@ -897,6 +920,10 @@ static const struct uart_ops sifive_serial_uops = { .request_port = sifive_serial_request_port, .config_port = sifive_serial_config_port, .verify_port = sifive_serial_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = sifive_serial_poll_get_char, + .poll_put_char = sifive_serial_poll_put_char, +#endif }; static struct uart_driver sifive_serial_uart_driver = { -- cgit From 4b7349cb4e26e79429ecd619eb588bf384f69fdb Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 18 Mar 2020 18:50:48 +0800 Subject: serial: sprd: getting port index via serial aliases only This patch simplifies the process of getting serial port number, with this patch, serial devices must have aliases configured in devicetree. The serial port searched out via sprd_port array maybe wrong if we don't have serial alias defined in devicetree, and specify console with command line, we would get the wrong port number if other serial ports probe failed before console's. So using aliases is mandatory. Reviewed-by: Baolin Wang Signed-off-by: Chunyan Zhang Link: https://lore.kernel.org/r/20200318105049.19623-2-zhang.lyra@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sprd_serial.c | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 509781ee26bf..23baf8cf1a3b 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -1102,29 +1102,6 @@ static struct uart_driver sprd_uart_driver = { .cons = SPRD_CONSOLE, }; -static int sprd_probe_dt_alias(int index, struct device *dev) -{ - struct device_node *np; - int ret = index; - - if (!IS_ENABLED(CONFIG_OF)) - return ret; - - np = dev->of_node; - if (!np) - return ret; - - ret = of_alias_get_id(np, "serial"); - if (ret < 0) - ret = index; - else if (ret >= ARRAY_SIZE(sprd_port) || sprd_port[ret] != NULL) { - dev_warn(dev, "requested serial port %d not available.\n", ret); - ret = index; - } - - return ret; -} - static int sprd_remove(struct platform_device *dev) { struct sprd_uart_port *sup = platform_get_drvdata(dev); @@ -1203,14 +1180,11 @@ static int sprd_probe(struct platform_device *pdev) int index; int ret; - for (index = 0; index < ARRAY_SIZE(sprd_port); index++) - if (sprd_port[index] == NULL) - break; - - if (index == ARRAY_SIZE(sprd_port)) - return -EBUSY; - - index = sprd_probe_dt_alias(index, &pdev->dev); + index = of_alias_get_id(pdev->dev.of_node, "serial"); + if (index < 0 || index >= ARRAY_SIZE(sprd_port)) { + dev_err(&pdev->dev, "got a wrong serial alias id %d\n", index); + return -EINVAL; + } sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]), GFP_KERNEL); -- cgit From 72534077475fc489f8358c0e214cc1a4d658c8c2 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 18 Mar 2020 18:50:49 +0800 Subject: serial: sprd: remove redundant sprd_port cleanup We don't need to cleanup sprd_port anymore, since we've dropped the way of using the sprd_port[] array to get port index. Reviewed-by: Baolin Wang Signed-off-by: Chunyan Zhang Link: https://lore.kernel.org/r/20200318105049.19623-3-zhang.lyra@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sprd_serial.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 23baf8cf1a3b..9a7ae6384edf 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -1236,10 +1236,8 @@ static int sprd_probe(struct platform_device *pdev) sprd_ports_num++; ret = uart_add_one_port(&sprd_uart_driver, up); - if (ret) { - sprd_port[index] = NULL; + if (ret) sprd_remove(pdev); - } platform_set_drvdata(pdev, up); -- cgit From e2c2e7987106efbb576d7a46fbc9298fafd0b844 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 14 Feb 2020 15:14:55 +0100 Subject: tty: nozomi: fix spelling mistake "reserverd" -> "reserved" The reserved bits should be named reserved. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200214141455.20902-1-alexandre.belloni@bootlin.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/nozomi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index ed99948f3b7f..4b82ec30c789 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -301,7 +301,7 @@ struct ctrl_dl { unsigned int DCD:1; unsigned int RI:1; unsigned int CTS:1; - unsigned int reserverd:4; + unsigned int reserved:4; u8 port; } __attribute__ ((packed)); -- cgit From e39c0ffe8cc3cce212928168236bfd0c22965235 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Mar 2020 10:29:30 +0100 Subject: tty: serial: pch_uart: Use scnprintf() for avoiding potential buffer overflow Since snprintf() returns the would-be-output size instead of the actual output size, the succeeding calls may go beyond the given buffer limit. Fix it by replacing with scnprintf(). Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20200311092930.24433-1-tiwai@suse.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 0a96217dba67..40fa7a27722d 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -310,32 +310,32 @@ static ssize_t port_show_regs(struct file *file, char __user *user_buf, if (!buf) return 0; - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "PCH EG20T port[%d] regs:\n", priv->port.line); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "=================================\n"); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "IER: \t0x%02x\n", ioread8(priv->membase + UART_IER)); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR)); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR)); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR)); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR)); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR)); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "BRCSR: \t0x%02x\n", ioread8(priv->membase + PCH_UART_BRCSR)); lcr = ioread8(priv->membase + UART_LCR); iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL)); - len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM)); iowrite8(lcr, priv->membase + UART_LCR); -- cgit From caa47cc639470485ee0ae3c76d56ccf4cfda2045 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Mar 2020 10:29:05 +0100 Subject: tty: nozomi: Use scnprintf() for avoiding potential buffer overflow Since snprintf() returns the would-be-output size instead of the actual output size, the succeeding calls may go beyond the given buffer limit. Fix it by replacing with scnprintf(). Also rewrite the code in a standard if-form instead of ugly conditional operators. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20200311092905.24362-1-tiwai@suse.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/nozomi.c | 67 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 4b82ec30c789..d42b854cb7df 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -839,40 +839,39 @@ static char *interrupt2str(u16 interrupt) static char buf[TMP_BUF_MAX]; char *p = buf; - interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; - interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "MDM_DL2 ") : NULL; - - interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "MDM_UL1 ") : NULL; - interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "MDM_UL2 ") : NULL; - - interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "DIAG_DL1 ") : NULL; - interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "DIAG_DL2 ") : NULL; - - interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "DIAG_UL ") : NULL; - - interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "APP1_DL ") : NULL; - interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "APP2_DL ") : NULL; - - interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "APP1_UL ") : NULL; - interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "APP2_UL ") : NULL; - - interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "CTRL_DL ") : NULL; - interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "CTRL_UL ") : NULL; - - interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), - "RESET ") : NULL; + if (interrupt & MDM_DL1) + p += scnprintf(p, TMP_BUF_MAX, "MDM_DL1 "); + if (interrupt & MDM_DL2) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "MDM_DL2 "); + if (interrupt & MDM_UL1) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "MDM_UL1 "); + if (interrupt & MDM_UL2) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "MDM_UL2 "); + if (interrupt & DIAG_DL1) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "DIAG_DL1 "); + if (interrupt & DIAG_DL2) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "DIAG_DL2 "); + + if (interrupt & DIAG_UL) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "DIAG_UL "); + + if (interrupt & APP1_DL) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "APP1_DL "); + if (interrupt & APP2_DL) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "APP2_DL "); + + if (interrupt & APP1_UL) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "APP1_UL "); + if (interrupt & APP2_UL) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "APP2_UL "); + + if (interrupt & CTRL_DL) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "CTRL_DL "); + if (interrupt & CTRL_UL) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "CTRL_UL "); + + if (interrupt & RESET) + p += scnprintf(p, TMP_BUF_MAX - (p - buf), "RESET "); return buf; } -- cgit From bdc3070e3fcd9226cf4206e6b0eeb2d71e109940 Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Sun, 1 Mar 2020 22:34:25 +0530 Subject: tty: hvc: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header file related to the HVC driver. For C header files Documentation/process/license-rules.rst mandates C-like comments (opposed to C source files where C++ style should be used). Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46. Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Link: https://lore.kernel.org/r/20200301170419.GA7125@nishad Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index e9319954c832..18d005814e4b 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * hvc_console.h * Copyright (C) 2005 IBM Corporation -- cgit From db1032f7e485ea95b83ad66bb3d1675ad66de77f Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Mon, 2 Mar 2020 20:06:46 +0530 Subject: tty: n_tracesink: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header file related to Kernel driver API to route trace data. For C header files Documentation/process/license-rules.rst mandates C-like comments (opposed to C source files where C++ style should be used). Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46. Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Link: https://lore.kernel.org/r/20200302143642.GA3335@nishad Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tracesink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_tracesink.h b/drivers/tty/n_tracesink.h index 1b846330c855..7031d515a700 100644 --- a/drivers/tty/n_tracesink.h +++ b/drivers/tty/n_tracesink.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * n_tracesink.h - Kernel driver API to route trace data in kernel space. * -- cgit From 97451855cc3bb9ab0c222a44a66f068278ff6ccb Mon Sep 17 00:00:00 2001 From: Raviteja Narayanam Date: Thu, 19 Mar 2020 15:14:50 +0530 Subject: serial: uartps: Remove unconditional wait inside set_termios set_termios function should not wait for the transmit FIFO empty (CDNS_UART_SR_TXEMPTY) unconditionally. The tty layer takes care of it based on the parameter passed (TCSANOW/TCSADRAIN/TCSAFLUSH). Signed-off-by: Raviteja Narayanam Signed-off-by: Shubhrajyoti Datta Link: https://lore.kernel.org/r/536e190dd5bbb474007a67e6323c048288942a28.1584610774.git.shubhrajyoti.datta@xilinx.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 98db9dc168ff..f3658fc49029 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -693,20 +693,8 @@ static void cdns_uart_set_termios(struct uart_port *port, u32 cval = 0; unsigned int baud, minbaud, maxbaud; unsigned long flags; - unsigned int ctrl_reg, mode_reg, val; - int err; - - /* Wait for the transmit FIFO to empty before making changes */ - if (!(readl(port->membase + CDNS_UART_CR) & - CDNS_UART_CR_TX_DIS)) { - err = readl_poll_timeout(port->membase + CDNS_UART_SR, - val, (val & CDNS_UART_SR_TXEMPTY), - 1000, TX_TIMEOUT); - if (err) { - dev_err(port->dev, "timed out waiting for tx empty"); - return; - } - } + unsigned int ctrl_reg, mode_reg; + spin_lock_irqsave(&port->lock, flags); /* Disable the TX and RX to set baud rate */ -- cgit From 706bbc572d5955272d4b67782a22083f8a6ad16a Mon Sep 17 00:00:00 2001 From: Raviteja Narayanam Date: Thu, 19 Mar 2020 15:14:51 +0530 Subject: serial: uartps: Add TACTIVE check in cdns_uart_tx_empty function Make sure that all bytes are transmitted out of Uart by monitoring CDNS_UART_SR_TACTIVE bit as well. Signed-off-by: Raviteja Narayanam Signed-off-by: Shubhrajyoti Datta Acked-by: Maarten Brock Link: https://lore.kernel.org/r/e2514818af5973be291cc117d07739f068b71639.1584610774.git.shubhrajyoti.datta@xilinx.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index f3658fc49029..6b26f767768e 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -650,8 +650,8 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port) unsigned int status; status = readl(port->membase + CDNS_UART_SR) & - CDNS_UART_SR_TXEMPTY; - return status ? TIOCSER_TEMT : 0; + (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE); + return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0; } /** -- cgit From f19c3f6c8109b8bab000afd35580929958e087a9 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 19 Mar 2020 16:02:29 +0530 Subject: serial: 8250_port: Don't service RX FIFO if throttled When port's throttle callback is called, it should stop pushing any more data into TTY buffer to avoid buffer overflow. This means driver has to stop HW from receiving more data and assert the HW flow control. For UARTs with auto HW flow control (such as 8250_omap) manual assertion of flow control line is not possible and only way is to allow RX FIFO to fill up, thus trigger auto HW flow control logic. Therefore make sure that 8250 generic IRQ handler does not drain data when port is stopped (i.e UART_LSR_DR is unset in read_status_mask). Not servicing, RX FIFO would trigger auto HW flow control when FIFO occupancy reaches preset threshold, thus halting RX. Since, error conditions in UART_LSR register are cleared just by reading the register, data has to be drained in case there are FIFO errors, else error information will lost. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20200319103230.16867-2-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 4440867b7d20..2f973280c34a 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1883,6 +1883,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) unsigned char status; unsigned long flags; struct uart_8250_port *up = up_to_u8250p(port); + bool skip_rx = false; if (iir & UART_IIR_NO_INT) return 0; @@ -1891,7 +1892,20 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial_port_in(port, UART_LSR); - if (status & (UART_LSR_DR | UART_LSR_BI)) { + /* + * If port is stopped and there are no error conditions in the + * FIFO, then don't drain the FIFO, as this may lead to TTY buffer + * overflow. Not servicing, RX FIFO would trigger auto HW flow + * control when FIFO occupancy reaches preset threshold, thus + * halting RX. This only works when auto HW flow control is + * available. + */ + if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) && + (port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) && + !(port->read_status_mask & UART_LSR_DR)) + skip_rx = true; + + if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) { if (!up->dma || handle_rx_dma(up, iir)) status = serial8250_rx_chars(up, status); } -- cgit From f4b042a050062b2dec456adfced13d61341939e2 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 19 Mar 2020 16:02:30 +0530 Subject: serial: 8250: 8250_omap: Fix throttle to call stop_rx() Call stop_rx() to halt reception when throttle is requested. Update unthrottle callback to restart reception. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20200319103230.16867-3-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index dd69226ce918..b0e70390bc55 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -699,14 +699,12 @@ static void omap_8250_shutdown(struct uart_port *port) static void omap_8250_throttle(struct uart_port *port) { struct omap8250_priv *priv = port->private_data; - struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; pm_runtime_get_sync(port->dev); spin_lock_irqsave(&port->lock, flags); - up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); - serial_out(up, UART_IER, up->ier); + port->ops->stop_rx(port); priv->throttled = true; spin_unlock_irqrestore(&port->lock, flags); @@ -727,6 +725,7 @@ static void omap_8250_unthrottle(struct uart_port *port) if (up->dma) up->dma->rx_dma(up); up->ier |= UART_IER_RLSI | UART_IER_RDI; + port->read_status_mask |= UART_LSR_DR; serial_out(up, UART_IER, up->ier); spin_unlock_irqrestore(&port->lock, flags); -- cgit From 4ce35a3617c0ac758c61122b2218b6c8c9ac9398 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 20 Mar 2020 14:52:00 +0200 Subject: serial: 8250_omap: Fix sleeping function called from invalid context during probe When booting j721e the following bug is printed: [ 1.154821] BUG: sleeping function called from invalid context at kernel/sched/completion.c:99 [ 1.154827] in_atomic(): 0, irqs_disabled(): 128, non_block: 0, pid: 12, name: kworker/0:1 [ 1.154832] 3 locks held by kworker/0:1/12: [ 1.154836] #0: ffff000840030728 ((wq_completion)events){+.+.}, at: process_one_work+0x1d4/0x6e8 [ 1.154852] #1: ffff80001214fdd8 (deferred_probe_work){+.+.}, at: process_one_work+0x1d4/0x6e8 [ 1.154860] #2: ffff00084060b170 (&dev->mutex){....}, at: __device_attach+0x38/0x138 [ 1.154872] irq event stamp: 63096 [ 1.154881] hardirqs last enabled at (63095): [] _raw_spin_unlock_irqrestore+0x70/0x78 [ 1.154887] hardirqs last disabled at (63096): [] _raw_spin_lock_irqsave+0x28/0x80 [ 1.154893] softirqs last enabled at (62254): [] _stext+0x488/0x564 [ 1.154899] softirqs last disabled at (62247): [] irq_exit+0x114/0x140 [ 1.154906] CPU: 0 PID: 12 Comm: kworker/0:1 Not tainted 5.6.0-rc6-next-20200318-00094-g45e4089b0bd3 #221 [ 1.154911] Hardware name: Texas Instruments K3 J721E SoC (DT) [ 1.154917] Workqueue: events deferred_probe_work_func [ 1.154923] Call trace: [ 1.154928] dump_backtrace+0x0/0x190 [ 1.154933] show_stack+0x14/0x20 [ 1.154940] dump_stack+0xe0/0x148 [ 1.154946] ___might_sleep+0x150/0x1f0 [ 1.154952] __might_sleep+0x4c/0x80 [ 1.154957] wait_for_completion_timeout+0x40/0x140 [ 1.154964] ti_sci_set_device_state+0xa0/0x158 [ 1.154969] ti_sci_cmd_get_device_exclusive+0x14/0x20 [ 1.154977] ti_sci_dev_start+0x34/0x50 [ 1.154984] genpd_runtime_resume+0x78/0x1f8 [ 1.154991] __rpm_callback+0x3c/0x140 [ 1.154996] rpm_callback+0x20/0x80 [ 1.155001] rpm_resume+0x568/0x758 [ 1.155007] __pm_runtime_resume+0x44/0xb0 [ 1.155013] omap8250_probe+0x2b4/0x508 [ 1.155019] platform_drv_probe+0x50/0xa0 [ 1.155023] really_probe+0xd4/0x318 [ 1.155028] driver_probe_device+0x54/0xe8 [ 1.155033] __device_attach_driver+0x80/0xb8 [ 1.155039] bus_for_each_drv+0x74/0xc0 [ 1.155044] __device_attach+0xdc/0x138 [ 1.155049] device_initial_probe+0x10/0x18 [ 1.155053] bus_probe_device+0x98/0xa0 [ 1.155058] deferred_probe_work_func+0x74/0xb0 [ 1.155063] process_one_work+0x280/0x6e8 [ 1.155068] worker_thread+0x48/0x430 [ 1.155073] kthread+0x108/0x138 [ 1.155079] ret_from_fork+0x10/0x18 To fix the bug we need to first call pm_runtime_enable() prior to any pm_runtime calls. Reported-by: Tomi Valkeinen Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20200320125200.6772-1-peter.ujfalusi@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index b0e70390bc55..1395ff7b03e7 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1202,6 +1202,7 @@ static int omap8250_probe(struct platform_device *pdev) spin_lock_init(&priv->rx_dma_lock); device_init_wakeup(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); /* @@ -1215,7 +1216,6 @@ static int omap8250_probe(struct platform_device *pdev) pm_runtime_set_autosuspend_delay(&pdev->dev, -1); pm_runtime_irq_safe(&pdev->dev); - pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); -- cgit From 7cf4df30a98175033e9849f7f16c46e96ba47f41 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 19 Mar 2020 16:33:39 +0530 Subject: serial: 8250: 8250_omap: Terminate DMA before pushing data on RX timeout Terminate and flush DMA internal buffers, before pushing RX data to higher layer. Otherwise, this will lead to data corruption, as driver would end up pushing stale buffer data to higher layer while actual data is still stuck inside DMA hardware and has yet not arrived at the memory. While at that, replace deprecated dmaengine_terminate_all() with dmaengine_terminate_async(). Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20200319110344.21348-2-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 1395ff7b03e7..c13b48ad7cdb 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -755,7 +755,10 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); count = dma->rx_size - state.residue; - + if (count < dma->rx_size) + dmaengine_terminate_async(dma->rxchan); + if (!count) + goto unlock; ret = tty_insert_flip_string(tty_port, dma->rx_buf, count); p->port.icount.rx += ret; @@ -817,7 +820,6 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p) spin_unlock_irqrestore(&priv->rx_dma_lock, flags); __dma_rx_do_complete(p); - dmaengine_terminate_all(dma->rxchan); } static int omap_8250_rx_dma(struct uart_8250_port *p) -- cgit From 4bcf59a5dea0f4e768e2b84fc78ce13a7fb27863 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 19 Mar 2020 16:33:40 +0530 Subject: serial: 8250: 8250_omap: Account for data in flight during DMA teardown Take into account data stuck in DMA internal buffers before pushing data to higher layer. dma_tx_state has "in_flight_bytes" member that provides this information. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20200319110344.21348-3-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index c13b48ad7cdb..bf1f2bba1d41 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -741,6 +741,8 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; + struct dma_chan *rxchan = dma->rxchan; + dma_cookie_t cookie; struct dma_tx_state state; int count; unsigned long flags; @@ -751,12 +753,29 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) if (!dma->rx_running) goto unlock; + cookie = dma->rx_cookie; dma->rx_running = 0; - dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + dmaengine_tx_status(rxchan, cookie, &state); - count = dma->rx_size - state.residue; - if (count < dma->rx_size) - dmaengine_terminate_async(dma->rxchan); + count = dma->rx_size - state.residue + state.in_flight_bytes; + if (count < dma->rx_size) { + dmaengine_terminate_async(rxchan); + + /* + * Poll for teardown to complete which guarantees in + * flight data is drained. + */ + if (state.in_flight_bytes) { + int poll_count = 25; + + while (dmaengine_tx_status(rxchan, cookie, NULL) && + poll_count--) + cpu_relax(); + + if (!poll_count) + dev_err(p->port.dev, "teardown incomplete\n"); + } + } if (!count) goto unlock; ret = tty_insert_flip_string(tty_port, dma->rx_buf, count); -- cgit From 789898416749c8f3f081ce731c834c61eeac04fa Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Mar 2020 16:33:41 +0530 Subject: serial: 8250: 8250_omap: Move locking out from __dma_rx_do_complete() Caller functions of __dma_rx_do_complete() already hold rx_dma_lock. Therefore move locking out of the function to avoid need to release and reacquire lock. Signed-off-by: Peter Ujfalusi Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20200319110344.21348-4-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index bf1f2bba1d41..b4c246d5fadf 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -736,22 +736,19 @@ static void omap_8250_unthrottle(struct uart_port *port) #ifdef CONFIG_SERIAL_8250_DMA static int omap_8250_rx_dma(struct uart_8250_port *p); +/* Must be called while priv->rx_dma_lock is held */ static void __dma_rx_do_complete(struct uart_8250_port *p) { - struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; struct dma_chan *rxchan = dma->rxchan; dma_cookie_t cookie; struct dma_tx_state state; int count; - unsigned long flags; int ret; - spin_lock_irqsave(&priv->rx_dma_lock, flags); - if (!dma->rx_running) - goto unlock; + goto out; cookie = dma->rx_cookie; dma->rx_running = 0; @@ -777,13 +774,12 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) } } if (!count) - goto unlock; + goto out; ret = tty_insert_flip_string(tty_port, dma->rx_buf, count); p->port.icount.rx += ret; p->port.icount.buf_overrun += count - ret; -unlock: - spin_unlock_irqrestore(&priv->rx_dma_lock, flags); +out: tty_flip_buffer_push(tty_port); } @@ -836,9 +832,8 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p) if (WARN_ON_ONCE(ret)) priv->rx_dma_broken = true; } - spin_unlock_irqrestore(&priv->rx_dma_lock, flags); - __dma_rx_do_complete(p); + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); } static int omap_8250_rx_dma(struct uart_8250_port *p) -- cgit From 7229b84c20d200853a827b4a807ad4954158cf12 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 19 Mar 2020 16:33:42 +0530 Subject: serial: 8250: 8250_omap: Extend driver data to pass FIFO trigger info Although same 8250 compliant UART IP is reused across different SoC, their integration wrt DMA varies greatly across SoCs. Therefore, different SoC may need to use different FIFO trigger level for DMA event and DMA configuration parameters. Provide a way to pass this information via driver data. This is required to support UART DMA on AM654/J721e SoCs. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20200319110344.21348-5-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 82 +++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 21 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index b4c246d5fadf..fb709e08fc66 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -105,6 +105,8 @@ struct omap8250_priv { u8 delayed_restore; u16 quot; + u8 tx_trigger; + u8 rx_trigger; bool is_suspending; int wakeirq; int wakeups_enabled; @@ -118,6 +120,17 @@ struct omap8250_priv { bool throttled; }; +struct omap8250_dma_params { + u32 rx_size; + u8 rx_trigger; + u8 tx_trigger; +}; + +struct omap8250_platdata { + struct omap8250_dma_params *dma_params; + u8 habit; +}; + #ifdef CONFIG_SERIAL_8250_DMA static void omap_8250_rx_dma_flush(struct uart_8250_port *p); #else @@ -295,8 +308,8 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_RESTORE(16) | OMAP_UART_TCR_HALT(52)); serial_out(up, UART_TI752_TLR, - TRIGGER_TLR_MASK(TX_TRIGGER) << UART_TI752_TLR_TX | - TRIGGER_TLR_MASK(RX_TRIGGER) << UART_TI752_TLR_RX); + TRIGGER_TLR_MASK(priv->tx_trigger) << UART_TI752_TLR_TX | + TRIGGER_TLR_MASK(priv->rx_trigger) << UART_TI752_TLR_RX); serial_out(up, UART_LCR, 0); @@ -435,8 +448,8 @@ static void omap_8250_set_termios(struct uart_port *port, * This is because threshold and trigger values are the same. */ up->fcr = UART_FCR_ENABLE_FIFO; - up->fcr |= TRIGGER_FCR_MASK(TX_TRIGGER) << OMAP_UART_FCR_TX_TRIG; - up->fcr |= TRIGGER_FCR_MASK(RX_TRIGGER) << OMAP_UART_FCR_RX_TRIG; + up->fcr |= TRIGGER_FCR_MASK(priv->tx_trigger) << OMAP_UART_FCR_TX_TRIG; + up->fcr |= TRIGGER_FCR_MASK(priv->rx_trigger) << OMAP_UART_FCR_RX_TRIG; priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY | OMAP_UART_SCR_TX_TRIG_GRANU1_MASK; @@ -1092,18 +1105,30 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } -static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE; -static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; -static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE; +static struct omap8250_dma_params am33xx_dma = { + .rx_size = RX_TRIGGER, + .rx_trigger = RX_TRIGGER, + .tx_trigger = TX_TRIGGER, +}; + +static struct omap8250_platdata am33xx_platdata = { + .dma_params = &am33xx_dma, + .habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE, +}; + +static struct omap8250_platdata omap4_platdata = { + .dma_params = &am33xx_dma, + .habit = UART_ERRATA_CLOCK_DISABLE, +}; static const struct of_device_id omap8250_dt_ids[] = { { .compatible = "ti,am654-uart" }, { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, - { .compatible = "ti,omap4-uart", .data = &omap4_habit, }, - { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, - { .compatible = "ti,am4372-uart", .data = &am3352_habit, }, - { .compatible = "ti,dra742-uart", .data = &dra742_habit, }, + { .compatible = "ti,omap4-uart", .data = &omap4_platdata, }, + { .compatible = "ti,am3352-uart", .data = &am33xx_platdata, }, + { .compatible = "ti,am4372-uart", .data = &am33xx_platdata, }, + { .compatible = "ti,dra742-uart", .data = &omap4_platdata, }, {}, }; MODULE_DEVICE_TABLE(of, omap8250_dt_ids); @@ -1114,10 +1139,10 @@ static int omap8250_probe(struct platform_device *pdev) struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct device_node *np = pdev->dev.of_node; struct omap8250_priv *priv; + const struct omap8250_platdata *pdata; struct uart_8250_port up; int ret; void __iomem *membase; - const struct of_device_id *id; if (!regs || !irq) { dev_err(&pdev->dev, "missing registers or irq\n"); @@ -1198,9 +1223,9 @@ static int omap8250_probe(struct platform_device *pdev) priv->wakeirq = irq_of_parse_and_map(np, 1); - id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev); - if (id && id->data) - priv->habit |= *(u8 *)id->data; + pdata = of_device_get_match_data(&pdev->dev); + if (pdata) + priv->habit |= pdata->habit; if (!up.port.uartclk) { up.port.uartclk = DEFAULT_CLK_SPEED; @@ -1237,6 +1262,8 @@ static int omap8250_probe(struct platform_device *pdev) omap_serial_fill_features_erratas(&up, priv); up.port.handle_irq = omap8250_no_handle_irq; + priv->rx_trigger = RX_TRIGGER; + priv->tx_trigger = TX_TRIGGER; #ifdef CONFIG_SERIAL_8250_DMA /* * Oh DMA support. If there are no DMA properties in the DT then @@ -1248,13 +1275,26 @@ static int omap8250_probe(struct platform_device *pdev) */ ret = of_property_count_strings(np, "dma-names"); if (ret == 2) { + struct omap8250_dma_params *dma_params = NULL; + up.dma = &priv->omap8250_dma; - priv->omap8250_dma.fn = the_no_dma_filter_fn; - priv->omap8250_dma.tx_dma = omap_8250_tx_dma; - priv->omap8250_dma.rx_dma = omap_8250_rx_dma; - priv->omap8250_dma.rx_size = RX_TRIGGER; - priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER; - priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER; + up.dma->fn = the_no_dma_filter_fn; + up.dma->tx_dma = omap_8250_tx_dma; + up.dma->rx_dma = omap_8250_rx_dma; + if (pdata) + dma_params = pdata->dma_params; + + if (dma_params) { + up.dma->rx_size = dma_params->rx_size; + up.dma->rxconf.src_maxburst = dma_params->rx_trigger; + up.dma->txconf.dst_maxburst = dma_params->tx_trigger; + priv->rx_trigger = dma_params->rx_trigger; + priv->tx_trigger = dma_params->tx_trigger; + } else { + up.dma->rx_size = RX_TRIGGER; + up.dma->rxconf.src_maxburst = RX_TRIGGER; + up.dma->txconf.dst_maxburst = TX_TRIGGER; + } } #endif ret = serial8250_register_8250_port(&up); -- cgit From c6689dfd877991f5415628c3ad04d4df9c1cf646 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 19 Mar 2020 16:33:43 +0530 Subject: serial: 8250: 8250_omap: Work around errata causing spurious IRQs with DMA As per Advisory 27 of AM437x Silicon errata document, Spurious UART interrupts may occur when DMA mode (FCR.DMA_MODE) is enabled. The Interrupt Controller flags that a UART interrupt has occurred; however, the associated IT_PENDING bit remains set to 1, indicating that no interrupt is pending. Acknowledge the spurious interrupts for every occurrence as workaround. Errata is applicable to all TI SoCs with this IP. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20200319110344.21348-6-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index fb709e08fc66..9293a3e94f07 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1051,7 +1051,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) iir = serial_port_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) { serial8250_rpm_put(up); - return 0; + return IRQ_HANDLED; } spin_lock_irqsave(&port->lock, flags); -- cgit From c26389f998a865e5eb37e0c90d3a6ded2d2d513b Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Thu, 19 Mar 2020 16:33:44 +0530 Subject: serial: 8250: 8250_omap: Add DMA support for UARTs on K3 SoCs UART on K3 SoCs has configurable RX timeout behavior (controlled via EFR2) and better DMA integration. This allows to transfer as larger amount data per DMA transfer compared to older SoCs. Add support for the same. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20200319110344.21348-7-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 98 ++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 12 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 9293a3e94f07..f34cdb734186 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -40,6 +40,7 @@ * The same errata is applicable to AM335x and DRA7x processors too. */ #define UART_ERRATA_CLOCK_DISABLE (1 << 3) +#define UART_HAS_EFR2 BIT(4) #define OMAP_UART_FCR_RX_TRIG 6 #define OMAP_UART_FCR_TX_TRIG 4 @@ -93,6 +94,10 @@ #define OMAP_UART_REV_52 0x0502 #define OMAP_UART_REV_63 0x0603 +/* Enhanced features register 2 */ +#define UART_OMAP_EFR2 0x23 +#define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6) + struct omap8250_priv { int line; u8 habit; @@ -664,7 +669,7 @@ static int omap_8250_startup(struct uart_port *port) priv->wer |= OMAP_UART_TX_WAKEUP_EN; serial_out(up, UART_OMAP_WER, priv->wer); - if (up->dma) + if (up->dma && !(priv->habit & UART_HAS_EFR2)) up->dma->rx_dma(up); pm_runtime_mark_last_busy(port->dev); @@ -689,6 +694,8 @@ static void omap_8250_shutdown(struct uart_port *port) pm_runtime_get_sync(port->dev); serial_out(up, UART_OMAP_WER, 0); + if (priv->habit & UART_HAS_EFR2) + serial_out(up, UART_OMAP_EFR2, 0x0); up->ier = 0; serial_out(up, UART_IER, 0); @@ -818,8 +825,12 @@ static void __dma_rx_complete(void *param) return; } __dma_rx_do_complete(p); - if (!priv->throttled) - omap_8250_rx_dma(p); + if (!priv->throttled) { + p->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_out(p, UART_IER, p->ier); + if (!(priv->habit & UART_HAS_EFR2)) + omap_8250_rx_dma(p); + } spin_unlock_irqrestore(&p->port.lock, flags); } @@ -862,8 +873,20 @@ static int omap_8250_rx_dma(struct uart_8250_port *p) spin_lock_irqsave(&priv->rx_dma_lock, flags); - if (dma->rx_running) + if (dma->rx_running) { + enum dma_status state; + + state = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, NULL); + if (state == DMA_COMPLETE) { + /* + * Disable RX interrupts to allow RX DMA completion + * callback to run. + */ + p->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial_out(p, UART_IER, p->ier); + } goto out; + } desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM, @@ -1034,6 +1057,46 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) return omap_8250_rx_dma(up); } +static unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up, + u8 iir, unsigned char status) +{ + if ((status & (UART_LSR_DR | UART_LSR_BI)) && + (iir & UART_IIR_RDI)) { + if (handle_rx_dma(up, iir)) { + status = serial8250_rx_chars(up, status); + omap_8250_rx_dma(up); + } + } + + return status; +} + +static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, + unsigned char status) +{ + /* + * Queue a new transfer if FIFO has data. + */ + if ((status & (UART_LSR_DR | UART_LSR_BI)) && + (up->ier & UART_IER_RDI)) { + omap_8250_rx_dma(up); + serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE); + } else if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { + /* + * Disable RX timeout, read IIR to clear + * current timeout condition, clear EFR2 to + * periodic timeouts, re-enable interrupts. + */ + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial_out(up, UART_IER, up->ier); + omap_8250_rx_dma_flush(up); + serial_in(up, UART_IIR); + serial_out(up, UART_OMAP_EFR2, 0x0); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + } +} + /* * This is mostly serial8250_handle_irq(). We have a slightly different DMA * hoook for RX/TX and need different logic for them in the ISR. Therefore we @@ -1042,6 +1105,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) static int omap_8250_dma_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + struct omap8250_priv *priv = up->port.private_data; unsigned char status; unsigned long flags; u8 iir; @@ -1058,12 +1122,11 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) status = serial_port_in(port, UART_LSR); - if (status & (UART_LSR_DR | UART_LSR_BI)) { - if (handle_rx_dma(up, iir)) { - status = serial8250_rx_chars(up, status); - omap_8250_rx_dma(up); - } - } + if (priv->habit & UART_HAS_EFR2) + am654_8250_handle_rx_dma(up, iir, status); + else + status = omap_8250_handle_rx_dma(up, iir, status); + serial8250_modem_status(up); if (status & UART_LSR_THRE && up->dma->tx_err) { if (uart_tx_stopped(&up->port) || @@ -1105,12 +1168,23 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static struct omap8250_dma_params am654_dma = { + .rx_size = SZ_2K, + .rx_trigger = 1, + .tx_trigger = TX_TRIGGER, +}; + static struct omap8250_dma_params am33xx_dma = { .rx_size = RX_TRIGGER, .rx_trigger = RX_TRIGGER, .tx_trigger = TX_TRIGGER, }; +static struct omap8250_platdata am654_platdata = { + .dma_params = &am654_dma, + .habit = UART_HAS_EFR2, +}; + static struct omap8250_platdata am33xx_platdata = { .dma_params = &am33xx_dma, .habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE, @@ -1122,7 +1196,7 @@ static struct omap8250_platdata omap4_platdata = { }; static const struct of_device_id omap8250_dt_ids[] = { - { .compatible = "ti,am654-uart" }, + { .compatible = "ti,am654-uart", .data = &am654_platdata, }, { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, { .compatible = "ti,omap4-uart", .data = &omap4_platdata, }, @@ -1492,7 +1566,7 @@ static int omap8250_runtime_resume(struct device *dev) if (omap8250_lost_context(up)) omap8250_restore_regs(up); - if (up->dma && up->dma->rxchan) + if (up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) omap_8250_rx_dma(up); priv->latency = priv->calc_latency; -- cgit From c97c65f36e5c010181c37dfc39c46bbacabb1e46 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sat, 21 Mar 2020 21:40:31 +0100 Subject: serial: omap: drop unused dt-bindings header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The definitons in the dt-binding's gpio header only contains some constants to be used in device trees. It is not relevant for omap-serial (as the gpio API hides the details) and in fact unused so it can just be dropped. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20200321204031.30369-1-uwe@kleine-koenig.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 48017cec7f2f..80e5149d3182 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -37,8 +37,6 @@ #include #include -#include - #define OMAP_MAX_HSUART_PORTS 10 #define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) -- cgit From d0e7600b914c9fd4935fe6dabf0cd5d71cb94347 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 25 Mar 2020 10:06:57 +0100 Subject: tty: serial: fsl_lpuart: move dma_request_chan() Move dma_request_chan() out of the atomic context. First this call should not be in the atomic context at all and second the dev_info_once() may cause a hang because because the console takes this spinlock, too. Fixes: 159381df1442f ("tty: serial: fsl_lpuart: fix DMA operation when using IOMMU") Reported-by: Leonard Crestez Signed-off-by: Michael Walle Reviewed-by: Fugang Duan Tested-by: Leonard Crestez Link: https://lore.kernel.org/r/20200325090658.25967-1-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 9c6a018b1390..131018979b77 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1510,20 +1510,33 @@ static void rx_dma_timer_init(struct lpuart_port *sport) add_timer(&sport->lpuart_timer); } -static void lpuart_tx_dma_startup(struct lpuart_port *sport) +static void lpuart_request_dma(struct lpuart_port *sport) { - u32 uartbaud; - int ret; - sport->dma_tx_chan = dma_request_chan(sport->port.dev, "tx"); if (IS_ERR(sport->dma_tx_chan)) { dev_info_once(sport->port.dev, "DMA tx channel request failed, operating without tx DMA (%ld)\n", PTR_ERR(sport->dma_tx_chan)); sport->dma_tx_chan = NULL; - goto err; } + sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx"); + if (IS_ERR(sport->dma_rx_chan)) { + dev_info_once(sport->port.dev, + "DMA rx channel request failed, operating without rx DMA (%ld)\n", + PTR_ERR(sport->dma_rx_chan)); + sport->dma_rx_chan = NULL; + } +} + +static void lpuart_tx_dma_startup(struct lpuart_port *sport) +{ + u32 uartbaud; + int ret; + + if (!sport->dma_tx_chan) + goto err; + ret = lpuart_dma_tx_request(&sport->port); if (!ret) goto err; @@ -1549,14 +1562,8 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport) { int ret; - sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx"); - if (IS_ERR(sport->dma_rx_chan)) { - dev_info_once(sport->port.dev, - "DMA rx channel request failed, operating without rx DMA (%ld)\n", - PTR_ERR(sport->dma_rx_chan)); - sport->dma_rx_chan = NULL; + if (!sport->dma_rx_chan) goto err; - } ret = lpuart_start_rx_dma(sport); if (ret) @@ -1592,6 +1599,8 @@ static int lpuart_startup(struct uart_port *port) sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK); + lpuart_request_dma(sport); + spin_lock_irqsave(&sport->port.lock, flags); lpuart_setup_watermark_enable(sport); @@ -1649,11 +1658,12 @@ static int lpuart32_startup(struct uart_port *port) sport->port.fifosize = sport->txfifo_size; } + lpuart_request_dma(sport); + spin_lock_irqsave(&sport->port.lock, flags); lpuart32_setup_watermark_enable(sport); - lpuart_rx_dma_startup(sport); lpuart_tx_dma_startup(sport); -- cgit From d7c53fb081c6347675bcd6fc4a9306111c42c111 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 25 Mar 2020 10:06:58 +0100 Subject: tty: serial: fsl_lpuart: fix return value checking The return value of lpuart_dma_tx_request() is an negative errno on failure and zero on success. Fixes: 159381df1442f ("tty: serial: fsl_lpuart: fix DMA operation when using IOMMU") Reported-by: Leonard Crestez Signed-off-by: Michael Walle Reviewed-by: Fugang Duan Link: https://lore.kernel.org/r/20200325090658.25967-2-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 131018979b77..5d41075964f2 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1538,7 +1538,7 @@ static void lpuart_tx_dma_startup(struct lpuart_port *sport) goto err; ret = lpuart_dma_tx_request(&sport->port); - if (!ret) + if (ret) goto err; init_waitqueue_head(&sport->dma_wait); -- cgit From 3b9c55efb23ebc6edb8190d9afa78b311e49404f Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 25 Mar 2020 16:14:27 +0800 Subject: tty: serial: make SERIAL_SPRD depend on COMMON_CLK kbuild-test reported an error: config: mips-randconfig-a001-20200321 ... >> drivers/tty/serial/sprd_serial.c:1175: undefined reference to `clk_set_parent' Because some mips Kconfig selects HAVE_CLK but not COMMON_CLK and no clk_set_parent implemented, so the error was exposed. So adding dependence on COMMON_CLK can fix this issue. Fixes: 7ba87cfec71a ("tty: serial: make SERIAL_SPRD not depend on ARCH_SPRD") Reported-by: kbuild test robot Signed-off-by: Chunyan Zhang Link: https://lore.kernel.org/r/20200325081427.20312-1-zhang.lyra@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index aa6d82175491..d6644f3d81fc 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1445,6 +1445,7 @@ config SERIAL_MEN_Z135 config SERIAL_SPRD tristate "Support for Spreadtrum serial" select SERIAL_CORE + depends on COMMON_CLK help This enables the driver for the Spreadtrum's serial. -- cgit From ca4463bf8438b403596edd0ec961ca0d4fbe0220 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 21 Mar 2020 20:43:04 -0700 Subject: vt: vt_ioctl: fix VT_DISALLOCATE freeing in-use virtual console The VT_DISALLOCATE ioctl can free a virtual console while tty_release() is still running, causing a use-after-free in con_shutdown(). This occurs because VT_DISALLOCATE considers a virtual console's 'struct vc_data' to be unused as soon as the corresponding tty's refcount hits 0. But actually it may be still being closed. Fix this by making vc_data be reference-counted via the embedded 'struct tty_port'. A newly allocated virtual console has refcount 1. Opening it for the first time increments the refcount to 2. Closing it for the last time decrements the refcount (in tty_operations::cleanup() so that it happens late enough), as does VT_DISALLOCATE. Reproducer: #include #include #include #include int main() { if (fork()) { for (;;) close(open("/dev/tty5", O_RDWR)); } else { int fd = open("/dev/tty10", O_RDWR); for (;;) ioctl(fd, VT_DISALLOCATE, 5); } } KASAN report: BUG: KASAN: use-after-free in con_shutdown+0x76/0x80 drivers/tty/vt/vt.c:3278 Write of size 8 at addr ffff88806a4ec108 by task syz_vt/129 CPU: 0 PID: 129 Comm: syz_vt Not tainted 5.6.0-rc2 #11 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ?-20191223_100556-anatol 04/01/2014 Call Trace: [...] con_shutdown+0x76/0x80 drivers/tty/vt/vt.c:3278 release_tty+0xa8/0x410 drivers/tty/tty_io.c:1514 tty_release_struct+0x34/0x50 drivers/tty/tty_io.c:1629 tty_release+0x984/0xed0 drivers/tty/tty_io.c:1789 [...] Allocated by task 129: [...] kzalloc include/linux/slab.h:669 [inline] vc_allocate drivers/tty/vt/vt.c:1085 [inline] vc_allocate+0x1ac/0x680 drivers/tty/vt/vt.c:1066 con_install+0x4d/0x3f0 drivers/tty/vt/vt.c:3229 tty_driver_install_tty drivers/tty/tty_io.c:1228 [inline] tty_init_dev+0x94/0x350 drivers/tty/tty_io.c:1341 tty_open_by_driver drivers/tty/tty_io.c:1987 [inline] tty_open+0x3ca/0xb30 drivers/tty/tty_io.c:2035 [...] Freed by task 130: [...] kfree+0xbf/0x1e0 mm/slab.c:3757 vt_disallocate drivers/tty/vt/vt_ioctl.c:300 [inline] vt_ioctl+0x16dc/0x1e30 drivers/tty/vt/vt_ioctl.c:818 tty_ioctl+0x9db/0x11b0 drivers/tty/tty_io.c:2660 [...] Fixes: 4001d7b7fc27 ("vt: push down the tty lock so we can see what is left to tackle") Cc: # v3.4+ Reported-by: syzbot+522643ab5729b0421998@syzkaller.appspotmail.com Acked-by: Jiri Slaby Signed-off-by: Eric Biggers Link: https://lore.kernel.org/r/20200322034305.210082-2-ebiggers@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 23 ++++++++++++++++++++++- drivers/tty/vt/vt_ioctl.c | 12 ++++-------- 2 files changed, 26 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index bbc26d73209a..309a39197be0 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1075,6 +1075,17 @@ static void visual_deinit(struct vc_data *vc) module_put(vc->vc_sw->owner); } +static void vc_port_destruct(struct tty_port *port) +{ + struct vc_data *vc = container_of(port, struct vc_data, port); + + kfree(vc); +} + +static const struct tty_port_operations vc_port_ops = { + .destruct = vc_port_destruct, +}; + int vc_allocate(unsigned int currcons) /* return 0 on success */ { struct vt_notifier_param param; @@ -1100,6 +1111,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ vc_cons[currcons].d = vc; tty_port_init(&vc->port); + vc->port.ops = &vc_port_ops; INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); visual_init(vc, currcons, 1); @@ -3250,6 +3262,7 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty) tty->driver_data = vc; vc->port.tty = tty; + tty_port_get(&vc->port); if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; @@ -3285,6 +3298,13 @@ static void con_shutdown(struct tty_struct *tty) console_unlock(); } +static void con_cleanup(struct tty_struct *tty) +{ + struct vc_data *vc = tty->driver_data; + + tty_port_put(&vc->port); +} + static int default_color = 7; /* white */ static int default_italic_color = 2; // green (ASCII) static int default_underline_color = 3; // cyan (ASCII) @@ -3410,7 +3430,8 @@ static const struct tty_operations con_ops = { .throttle = con_throttle, .unthrottle = con_unthrottle, .resize = vt_resize, - .shutdown = con_shutdown + .shutdown = con_shutdown, + .cleanup = con_cleanup, }; static struct cdev vc0_cdev; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 7297997fcf04..f62f498f63c0 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -310,10 +310,8 @@ static int vt_disallocate(unsigned int vc_num) vc = vc_deallocate(vc_num); console_unlock(); - if (vc && vc_num >= MIN_NR_CONSOLES) { - tty_port_destroy(&vc->port); - kfree(vc); - } + if (vc && vc_num >= MIN_NR_CONSOLES) + tty_port_put(&vc->port); return ret; } @@ -333,10 +331,8 @@ static void vt_disallocate_all(void) console_unlock(); for (i = 1; i < MAX_NR_CONSOLES; i++) { - if (vc[i] && i >= MIN_NR_CONSOLES) { - tty_port_destroy(&vc[i]->port); - kfree(vc[i]); - } + if (vc[i] && i >= MIN_NR_CONSOLES) + tty_port_put(&vc[i]->port); } } -- cgit From 7cf64b18b0b96e751178b8d0505d8466ff5a448f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 21 Mar 2020 20:43:05 -0700 Subject: vt: vt_ioctl: fix use-after-free in vt_in_use() vt_in_use() dereferences console_driver->ttys[i] without proper locking. This is broken because the tty can be closed and freed concurrently. We could fix this by using 'READ_ONCE(console_driver->ttys[i]) != NULL' and skipping the check of tty_struct::count. But, looking at console_driver->ttys[i] isn't really appropriate anyway because even if it is NULL the tty can still be in the process of being closed. Instead, fix it by making vt_in_use() require console_lock() and check whether the vt is allocated and has port refcount > 1. This works since following the patch "vt: vt_ioctl: fix VT_DISALLOCATE freeing in-use virtual console" the port refcount is incremented while the vt is open. Reproducer (very unreliable, but it worked for me after a few minutes): #include #include int main() { int fd, nproc; struct vt_stat state; char ttyname[16]; fd = open("/dev/tty10", O_RDONLY); for (nproc = 1; nproc < 8; nproc *= 2) fork(); for (;;) { sprintf(ttyname, "/dev/tty%d", rand() % 8); close(open(ttyname, O_RDONLY)); ioctl(fd, VT_GETSTATE, &state); } } KASAN report: BUG: KASAN: use-after-free in vt_in_use drivers/tty/vt/vt_ioctl.c:48 [inline] BUG: KASAN: use-after-free in vt_ioctl+0x1ad3/0x1d70 drivers/tty/vt/vt_ioctl.c:657 Read of size 4 at addr ffff888065722468 by task syz-vt2/132 CPU: 0 PID: 132 Comm: syz-vt2 Not tainted 5.6.0-rc5-00130-g089b6d3654916 #13 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ?-20191223_100556-anatol 04/01/2014 Call Trace: [...] vt_in_use drivers/tty/vt/vt_ioctl.c:48 [inline] vt_ioctl+0x1ad3/0x1d70 drivers/tty/vt/vt_ioctl.c:657 tty_ioctl+0x9db/0x11b0 drivers/tty/tty_io.c:2660 [...] Allocated by task 136: [...] kzalloc include/linux/slab.h:669 [inline] alloc_tty_struct+0x96/0x8a0 drivers/tty/tty_io.c:2982 tty_init_dev+0x23/0x350 drivers/tty/tty_io.c:1334 tty_open_by_driver drivers/tty/tty_io.c:1987 [inline] tty_open+0x3ca/0xb30 drivers/tty/tty_io.c:2035 [...] Freed by task 41: [...] kfree+0xbf/0x200 mm/slab.c:3757 free_tty_struct+0x8d/0xb0 drivers/tty/tty_io.c:177 release_one_tty+0x22d/0x2f0 drivers/tty/tty_io.c:1468 process_one_work+0x7f1/0x14b0 kernel/workqueue.c:2264 worker_thread+0x8b/0xc80 kernel/workqueue.c:2410 [...] Fixes: 4001d7b7fc27 ("vt: push down the tty lock so we can see what is left to tackle") Cc: # v3.4+ Acked-by: Jiri Slaby Signed-off-by: Eric Biggers Link: https://lore.kernel.org/r/20200322034305.210082-3-ebiggers@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt_ioctl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index f62f498f63c0..daf61c28ba76 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -43,9 +43,15 @@ bool vt_dont_switch; static inline bool vt_in_use(unsigned int i) { - extern struct tty_driver *console_driver; + const struct vc_data *vc = vc_cons[i].d; - return console_driver->ttys[i] && console_driver->ttys[i]->count; + /* + * console_lock must be held to prevent the vc from being deallocated + * while we're checking whether it's in-use. + */ + WARN_CONSOLE_UNLOCKED(); + + return vc && kref_read(&vc->port.kref) > 1; } static inline bool vt_busy(int i) @@ -643,15 +649,16 @@ int vt_ioctl(struct tty_struct *tty, struct vt_stat __user *vtstat = up; unsigned short state, mask; - /* Review: FIXME: Console lock ? */ if (put_user(fg_console + 1, &vtstat->v_active)) ret = -EFAULT; else { state = 1; /* /dev/tty0 is always open */ + console_lock(); /* required by vt_in_use() */ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) if (vt_in_use(i)) state |= mask; + console_unlock(); ret = put_user(state, &vtstat->v_state); } break; @@ -661,10 +668,11 @@ int vt_ioctl(struct tty_struct *tty, * Returns the first available (non-opened) console. */ case VT_OPENQRY: - /* FIXME: locking ? - but then this is a stupid API */ + console_lock(); /* required by vt_in_use() */ for (i = 0; i < MAX_NR_CONSOLES; ++i) if (!vt_in_use(i)) break; + console_unlock(); uival = i < MAX_NR_CONSOLES ? (i+1) : -1; goto setint; -- cgit From 4e36f94e996ebee8a919c6cd419f55e4d08ad4e3 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 27 Mar 2020 15:38:15 +0100 Subject: serial: 8250: Fix rs485 delay after console write Due to a silly copy-paste mistake, commit 7f9803072ff6 ("serial: 8250: Support console on software emulated rs485 ports") erroneously pauses for the duration of delay_rts_before_send after writing to the console, instead of delay_rts_after_send. Mea culpa. Fixes: 7f9803072ff6 ("serial: 8250: Support console on software emulated rs485 ports") Signed-off-by: Lukas Wunner Link: https://lore.kernel.org/r/9dd67f33c90d23f7fafa3b81b1e812ddabf9ca24.1585319447.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 2f973280c34a..a1d3aef3c406 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -3271,7 +3271,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, serial_port_out(port, UART_IER, ier); if (em485) { - mdelay(port->rs485.delay_rts_before_send); + mdelay(port->rs485.delay_rts_after_send); if (em485->tx_stopped) up->rs485_stop_tx(up); } -- cgit From 8d5b305484e8a3216eeb700ed6c6de870306adbd Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 27 Mar 2020 15:38:16 +0100 Subject: serial: 8250: Optimize irq enable after console write Commit 7f9803072ff6 ("serial: 8250: Support console on software emulated rs485 ports") amended serial8250_console_write() with rs485 support, but positioned the invocation of ->rs485_stop_tx() after re-enablement of interrupts. The irq handler and ->console_write() are serialized with the port spinlock, so no problem there, but due to the rs485 delay, the irq handler may unnecessarily spin for a while. Avoid that by moving ->rs485_stop_tx() before re-enablement of interrupts, which also mirrors the order at the beginning of serial8250_console_write(). Signed-off-by: Lukas Wunner Link: https://lore.kernel.org/r/019839cb1f61b01210b6ff9ac9f9079ca77f8411.1585319447.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index a1d3aef3c406..f77bf820b7a3 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -3268,7 +3268,6 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, * and restore the IER */ wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_IER, ier); if (em485) { mdelay(port->rs485.delay_rts_after_send); @@ -3276,6 +3275,8 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, up->rs485_stop_tx(up); } + serial_port_out(port, UART_IER, ier); + /* * The receive handling will happen properly because the * receive ready bit will still be set; it is not cleared -- cgit